114 lines
5.4 KiB
JavaScript
114 lines
5.4 KiB
JavaScript
import React from 'react'
|
|
import ProfileWorldHistorySummary from './ProfileWorldHistorySummary'
|
|
import ProfileWorldTimelineList from './ProfileWorldTimelineList'
|
|
|
|
function EmptyState({ isOwner, hasPrivateContext }) {
|
|
return (
|
|
<div className="rounded-[30px] border border-dashed border-white/12 bg-white/[0.03] px-6 py-16 text-center">
|
|
<div className="mx-auto flex h-16 w-16 items-center justify-center rounded-3xl border border-white/10 bg-white/[0.05] text-slate-500">
|
|
<i className="fa-solid fa-globe text-2xl" />
|
|
</div>
|
|
<h3 className="mt-5 text-xl font-semibold text-white">No public worlds timeline yet</h3>
|
|
<p className="mx-auto mt-3 max-w-xl text-sm leading-relaxed text-slate-400">
|
|
{isOwner
|
|
? (hasPrivateContext
|
|
? 'Public world history appears here once a live, publicly visible submission or recognized placement is available. Until then, private-only world activity is still tracked for you above.'
|
|
: 'Public world history appears here once a live, publicly visible submission or recognized placement is available.')
|
|
: 'This creator does not have any public world participation or recognition to show yet.'}
|
|
</p>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function OwnerNote({ ownerContext }) {
|
|
if (!ownerContext) {
|
|
return null
|
|
}
|
|
|
|
const details = [
|
|
ownerContext.pending_submissions ? `${ownerContext.pending_submissions} pending submission${ownerContext.pending_submissions === 1 ? '' : 's'}` : null,
|
|
ownerContext.removed_or_blocked_submissions ? `${ownerContext.removed_or_blocked_submissions} removed or blocked item${ownerContext.removed_or_blocked_submissions === 1 ? '' : 's'}` : null,
|
|
ownerContext.hidden_public_entries ? `${ownerContext.hidden_public_entries} recognition${ownerContext.hidden_public_entries === 1 ? '' : 's'} hidden from public view` : null,
|
|
].filter(Boolean)
|
|
|
|
if (details.length === 0) {
|
|
return null
|
|
}
|
|
|
|
return (
|
|
<div className="rounded-[24px] border border-sky-300/15 bg-sky-400/10 px-5 py-4 text-sm text-sky-100">
|
|
<div className="flex items-start gap-3">
|
|
<div className="mt-0.5 inline-flex h-9 w-9 shrink-0 items-center justify-center rounded-2xl border border-sky-300/20 bg-sky-300/10 text-sky-100">
|
|
<i className="fa-solid fa-eye text-sm" />
|
|
</div>
|
|
<div>
|
|
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-sky-100/80">Private View</div>
|
|
<p className="mt-1 leading-relaxed text-sky-50/90">
|
|
Your public worlds timeline stays strict about visibility, but this profile still tracks {details.join(', ')}.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default function ProfileWorldHistorySection({ history, isOwner }) {
|
|
const entries = Array.isArray(history?.entries) ? history.entries : []
|
|
const highlights = Array.isArray(history?.highlights) ? history.highlights : []
|
|
const highlightIds = new Set(highlights.map((entry) => entry?.id).filter(Boolean))
|
|
const timelineEntries = entries.filter((entry) => !highlightIds.has(entry?.id))
|
|
const hasPrivateContext = Boolean(
|
|
history?.owner_context?.pending_submissions
|
|
|| history?.owner_context?.removed_or_blocked_submissions
|
|
|| history?.owner_context?.hidden_public_entries
|
|
)
|
|
const hasEntries = Boolean(history?.summary?.available) && entries.length > 0
|
|
|
|
return (
|
|
<section className="space-y-6">
|
|
<div className="flex flex-wrap items-end justify-between gap-4">
|
|
<div>
|
|
<div className="text-[11px] font-semibold uppercase tracking-[0.22em] text-slate-500">Worlds History</div>
|
|
<h2 className="mt-2 text-2xl font-semibold tracking-[-0.02em] text-white md:text-3xl">Recurring worlds, challenge outcomes, and standout editions</h2>
|
|
<p className="mt-3 max-w-3xl text-sm leading-relaxed text-slate-400">
|
|
This timeline pulls together edition-aware world participation, featured placements, finalists, winners, and linked challenge results into one creator-facing history layer.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<OwnerNote ownerContext={isOwner ? history?.owner_context : null} />
|
|
|
|
{hasEntries ? (
|
|
<>
|
|
<ProfileWorldHistorySummary history={history} />
|
|
|
|
{highlights.length > 0 ? (
|
|
<div className="space-y-3">
|
|
<div>
|
|
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">Highlights</div>
|
|
<p className="mt-2 text-sm text-slate-400">
|
|
The most recent and highest-signal world appearances surface first so recurring recognition reads like a creator recap, not just a raw list.
|
|
</p>
|
|
</div>
|
|
<ProfileWorldTimelineList entries={highlights} />
|
|
</div>
|
|
) : null}
|
|
|
|
{timelineEntries.length > 0 ? (
|
|
<div className="space-y-3">
|
|
<div>
|
|
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-slate-500">Full Timeline</div>
|
|
<p className="mt-2 text-sm text-slate-400">
|
|
Every public world appearance, challenge-linked outcome, and edition-aware placement remains visible here in chronological order.
|
|
</p>
|
|
</div>
|
|
<ProfileWorldTimelineList entries={timelineEntries} />
|
|
</div>
|
|
) : null}
|
|
</>
|
|
) : (
|
|
<EmptyState isOwner={isOwner} hasPrivateContext={hasPrivateContext} />
|
|
)}
|
|
</section>
|
|
)
|
|
} |