update
This commit is contained in:
108
resources/js/Pages/Leaderboard/LeaderboardPage.jsx
Normal file
108
resources/js/Pages/Leaderboard/LeaderboardPage.jsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Head, usePage } from '@inertiajs/react'
|
||||
import LeaderboardTabs from '../../components/leaderboard/LeaderboardTabs'
|
||||
import LeaderboardList from '../../components/leaderboard/LeaderboardList'
|
||||
|
||||
const TYPE_TABS = [
|
||||
{ value: 'creator', label: 'Creators' },
|
||||
{ value: 'artwork', label: 'Artworks' },
|
||||
{ value: 'story', label: 'Stories' },
|
||||
]
|
||||
|
||||
const PERIOD_TABS = [
|
||||
{ value: 'daily', label: 'Daily' },
|
||||
{ value: 'weekly', label: 'Weekly' },
|
||||
{ value: 'monthly', label: 'Monthly' },
|
||||
{ value: 'all_time', label: 'All-time' },
|
||||
]
|
||||
|
||||
const API_BY_TYPE = {
|
||||
creator: '/api/leaderboard/creators',
|
||||
artwork: '/api/leaderboard/artworks',
|
||||
story: '/api/leaderboard/stories',
|
||||
}
|
||||
|
||||
export default function LeaderboardPage() {
|
||||
const { props } = usePage()
|
||||
const { initialType = 'creator', initialPeriod = 'weekly', initialData = { items: [] }, meta = {} } = props
|
||||
|
||||
const [type, setType] = useState(initialType)
|
||||
const [period, setPeriod] = useState(initialPeriod)
|
||||
const [data, setData] = useState(initialData)
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (type === initialType && period === initialPeriod) {
|
||||
return
|
||||
}
|
||||
|
||||
let cancelled = false
|
||||
|
||||
async function load() {
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await window.axios.get(`${API_BY_TYPE[type]}?period=${period}`)
|
||||
if (!cancelled && response.data) {
|
||||
setData(response.data)
|
||||
}
|
||||
} finally {
|
||||
if (!cancelled) {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
load()
|
||||
|
||||
try {
|
||||
const url = new URL(window.location.href)
|
||||
url.searchParams.set('type', type === 'creator' ? 'creators' : `${type}s`)
|
||||
url.searchParams.set('period', period === 'all_time' ? 'all' : period)
|
||||
window.history.replaceState({}, '', url.toString())
|
||||
} catch (_) {}
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [type, period, initialType, initialPeriod])
|
||||
|
||||
const items = Array.isArray(data?.items) ? data.items : []
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{meta?.title || 'Leaderboard | Skinbase'}</title>
|
||||
<meta name="description" content={meta?.description || 'Top creators, artworks, and stories on Skinbase.'} />
|
||||
</Head>
|
||||
|
||||
<div className="min-h-screen bg-[radial-gradient(circle_at_top,rgba(14,165,233,0.14),transparent_34%),linear-gradient(180deg,#020617_0%,#0f172a_48%,#020617_100%)] pb-16 text-slate-100">
|
||||
<div className="mx-auto w-full max-w-7xl px-4 py-8 sm:px-6 lg:px-8">
|
||||
<header className="rounded-[2rem] border border-white/10 bg-slate-950/70 px-6 py-8 shadow-[0_35px_120px_rgba(2,6,23,0.75)] backdrop-blur">
|
||||
<p className="text-xs font-semibold uppercase tracking-[0.28em] text-sky-300">Skinbase Competition Board</p>
|
||||
<h1 className="mt-4 max-w-3xl text-4xl font-black tracking-tight text-white sm:text-5xl">
|
||||
Top creators, standout artworks, and stories with momentum.
|
||||
</h1>
|
||||
<p className="mt-4 max-w-2xl text-sm leading-6 text-slate-300 sm:text-base">
|
||||
Switch between creators, artworks, and stories, then filter by daily, weekly, monthly, or all-time performance.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
<div className="mt-6 space-y-4">
|
||||
<LeaderboardTabs items={TYPE_TABS} active={type} onChange={setType} sticky label="Leaderboard type" />
|
||||
<LeaderboardTabs items={PERIOD_TABS} active={period} onChange={setPeriod} label="Leaderboard period" />
|
||||
</div>
|
||||
|
||||
{loading ? (
|
||||
<div className="mt-6 rounded-3xl border border-white/10 bg-white/[0.03] px-6 py-5 text-sm text-slate-400">
|
||||
Refreshing leaderboard...
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className="mt-8">
|
||||
<LeaderboardList items={items} type={type} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user