Files
SkinbaseNova/resources/js/Pages/Studio/StudioChallenges.jsx

194 lines
11 KiB
JavaScript

import React from 'react'
import StudioLayout from '../../Layouts/StudioLayout'
import { usePage } from '@inertiajs/react'
import { studioSurface, trackStudioEvent } from '../../utils/studioEvents'
const summaryCards = [
['active_challenges', 'Active challenges', 'fa-bolt'],
['joined_challenges', 'Joined challenges', 'fa-trophy'],
['entries_submitted', 'Entries submitted', 'fa-paper-plane'],
['featured_entries', 'Featured entries', 'fa-star'],
['winner_entries', 'Winner entries', 'fa-crown'],
['cards_available', 'Challenge-ready cards', 'fa-layer-group'],
]
function formatDate(value) {
if (!value) return 'TBD'
const date = new Date(value)
if (Number.isNaN(date.getTime())) return value
return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })
}
export default function StudioChallenges() {
const { props } = usePage()
const { summary, spotlight, activeChallenges, recentEntries, cardLeaders, reminders } = props
return (
<StudioLayout title={props.title} subtitle={props.description}>
<div className="grid grid-cols-2 gap-4 xl:grid-cols-6">
{summaryCards.map(([key, label, icon]) => (
<div key={key} className="rounded-[26px] border border-white/10 bg-white/[0.03] p-5">
<div className="flex items-center justify-between gap-3">
<span className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">{label}</span>
<i className={`fa-solid ${icon} text-sky-200`} />
</div>
<div className="mt-3 text-3xl font-semibold text-white">{Number(summary?.[key] || 0).toLocaleString()}</div>
</div>
))}
</div>
{spotlight ? (
<section className="mt-6 rounded-[30px] border border-white/10 bg-[radial-gradient(circle_at_top_left,_rgba(56,189,248,0.14),_transparent_34%),radial-gradient(circle_at_bottom_right,_rgba(250,204,21,0.12),_transparent_40%),linear-gradient(135deg,_rgba(15,23,42,0.88),_rgba(2,6,23,0.96))] p-6 shadow-[0_22px_60px_rgba(2,6,23,0.28)]">
<div className="flex flex-col gap-5 lg:flex-row lg:items-end lg:justify-between">
<div className="max-w-3xl">
<p className="text-[11px] font-semibold uppercase tracking-[0.22em] text-sky-200/70">Challenge spotlight</p>
<h2 className="mt-2 text-3xl font-semibold text-white">{spotlight.title}</h2>
<p className="mt-3 text-sm leading-6 text-slate-300">{spotlight.prompt || spotlight.description || 'A featured challenge run is active in Nova Cards right now.'}</p>
<div className="mt-4 flex flex-wrap gap-3 text-xs uppercase tracking-[0.16em] text-slate-400">
<span>{spotlight.status}</span>
<span>{spotlight.official ? 'Official' : 'Community'}</span>
<span>{spotlight.entries_count} entries</span>
<span>{spotlight.is_joined ? `${spotlight.submission_count} submitted` : 'Not joined yet'}</span>
</div>
</div>
<div className="flex flex-wrap gap-3">
<a
href={spotlight.url}
onClick={() => trackStudioEvent('studio_challenge_action_taken', {
surface: studioSurface(),
module: 'challenges',
meta: {
action: 'open_spotlight',
challenge_id: spotlight.id,
},
})}
className="inline-flex items-center gap-2 rounded-full border border-sky-300/20 bg-sky-300/10 px-4 py-2 text-sm font-semibold text-sky-100 transition hover:border-sky-300/35 hover:bg-sky-300/15"
>
Open challenge
</a>
<a href="/studio/cards" className="inline-flex items-center gap-2 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-sm font-semibold text-white transition hover:bg-white/[0.08]">Review cards</a>
</div>
</div>
</section>
) : null}
<div className="mt-6 grid gap-6 xl:grid-cols-[minmax(0,1fr)_360px]">
<section className="rounded-[28px] border border-white/10 bg-white/[0.03] p-6">
<div className="flex items-center justify-between gap-4">
<h2 className="text-lg font-semibold text-white">Open and recent challenge runs</h2>
<a href="/cards/challenges" className="text-xs font-semibold uppercase tracking-[0.18em] text-sky-100">Public archive</a>
</div>
<div className="mt-5 space-y-3">
{(activeChallenges || []).map((challenge) => (
<a
key={challenge.id}
href={challenge.url}
onClick={() => trackStudioEvent('studio_challenge_action_taken', {
surface: studioSurface(),
module: 'challenges',
meta: {
action: 'open_challenge',
challenge_id: challenge.id,
},
})}
className="block rounded-[22px] border border-white/10 bg-black/20 p-4 transition hover:border-white/20"
>
<div className="flex items-start justify-between gap-4">
<div>
<div className="text-base font-semibold text-white">{challenge.title}</div>
<div className="mt-1 text-xs uppercase tracking-[0.16em] text-slate-500">{challenge.status} {challenge.official ? 'official' : 'community'} {challenge.entries_count} entries</div>
<p className="mt-3 text-sm leading-6 text-slate-400">{challenge.prompt || challenge.description || 'Challenge details are available in the public challenge view.'}</p>
</div>
<div className="text-right text-xs uppercase tracking-[0.16em] text-slate-500">
<div>{formatDate(challenge.starts_at)} start</div>
<div className="mt-2">{formatDate(challenge.ends_at)} end</div>
</div>
</div>
<div className="mt-4 flex flex-wrap gap-2 text-xs">
<span className={`rounded-full border px-2.5 py-1 ${challenge.is_joined ? 'border-emerald-300/20 bg-emerald-300/10 text-emerald-100' : 'border-white/10 text-slate-300'}`}>{challenge.is_joined ? `${challenge.submission_count} submitted` : 'Not joined'}</span>
{challenge.featured ? <span className="rounded-full border border-amber-300/20 bg-amber-300/10 px-2.5 py-1 text-amber-100">Featured run</span> : null}
</div>
</a>
))}
</div>
</section>
<section className="rounded-[28px] border border-white/10 bg-white/[0.03] p-6">
<h2 className="text-lg font-semibold text-white">Workflow reminders</h2>
<div className="mt-4 space-y-3">
{(reminders || []).map((item) => (
<a key={item.title} href={item.href} className="block rounded-[22px] border border-white/10 bg-black/20 p-4 transition hover:border-white/20">
<h3 className="text-sm font-semibold text-white">{item.title}</h3>
<p className="mt-2 text-sm leading-6 text-slate-400">{item.body}</p>
<span className="mt-3 inline-flex items-center gap-2 text-sm font-medium text-sky-100">{item.cta}<i className="fa-solid fa-arrow-right" /></span>
</a>
))}
</div>
</section>
</div>
<div className="mt-6 grid gap-6 xl:grid-cols-[minmax(0,1fr)_360px]">
<section className="rounded-[28px] border border-white/10 bg-white/[0.03] p-6">
<h2 className="text-lg font-semibold text-white">Recent submissions</h2>
<div className="mt-4 space-y-3">
{(recentEntries || []).map((entry) => (
<div key={entry.id} className="rounded-[22px] border border-white/10 bg-black/20 p-4">
<div className="flex items-start justify-between gap-4">
<div>
<div className="text-sm font-semibold text-white">{entry.card.title}</div>
<div className="mt-1 text-xs uppercase tracking-[0.16em] text-slate-500">{entry.challenge.title} {entry.status}</div>
</div>
<div className="text-xs uppercase tracking-[0.16em] text-slate-500">{formatDate(entry.submitted_at)}</div>
</div>
{entry.note ? <p className="mt-3 text-sm leading-6 text-slate-400">{entry.note}</p> : null}
<div className="mt-4 flex flex-wrap gap-3 text-sm">
<a
href={entry.challenge.url}
onClick={() => trackStudioEvent('studio_challenge_action_taken', {
surface: studioSurface(),
module: 'challenges',
item_module: 'cards',
item_id: entry.card?.id,
meta: {
action: 'open_submission_challenge',
challenge_id: entry.challenge?.id,
entry_id: entry.id,
},
})}
className="text-sky-100"
>
Challenge
</a>
<a href={entry.card.edit_url} className="text-slate-300">Edit card</a>
<a href={entry.card.analytics_url} className="text-slate-300">Analytics</a>
</div>
</div>
))}
</div>
</section>
<section className="rounded-[28px] border border-white/10 bg-white/[0.03] p-6">
<h2 className="text-lg font-semibold text-white">Cards with challenge traction</h2>
<div className="mt-4 space-y-3">
{(cardLeaders || []).map((card) => (
<div key={card.id} className="rounded-[22px] border border-white/10 bg-black/20 p-4">
<div className="flex items-start justify-between gap-4">
<div>
<div className="text-sm font-semibold text-white">{card.title}</div>
<div className="mt-1 text-xs uppercase tracking-[0.16em] text-slate-500">{card.status} {card.challenge_entries_count} challenge entries</div>
</div>
<a href={card.edit_url} className="text-xs font-semibold uppercase tracking-[0.16em] text-sky-100">Open</a>
</div>
<div className="mt-4 grid grid-cols-2 gap-3 text-sm text-slate-400">
<div><div>Views</div><div className="mt-1 font-semibold text-white">{Number(card.views_count || 0).toLocaleString()}</div></div>
<div><div>Comments</div><div className="mt-1 font-semibold text-white">{Number(card.comments_count || 0).toLocaleString()}</div></div>
</div>
</div>
))}
</div>
</section>
</div>
</StudioLayout>
)
}