You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
55 lines
2.0 KiB
TypeScript
55 lines
2.0 KiB
TypeScript
export type LeaderboardRow = {
|
|
player: string
|
|
score: number
|
|
questions: number
|
|
successRate: number
|
|
durationSec: number
|
|
}
|
|
|
|
const baseUrl = import.meta.env.VITE_API_BASE_URL as string | undefined
|
|
const forceApi = import.meta.env.VITE_LEADERBOARD_FORCE_API === 'true'
|
|
const STORAGE_MODE_KEY = 'kf.leaderboard.mode'
|
|
|
|
const fallbackTop10: LeaderboardRow[] = [
|
|
{ player: 'Alice', score: 24, questions: 14, successRate: 86, durationSec: 1680 },
|
|
{ player: 'Bob', score: 22, questions: 13, successRate: 85, durationSec: 1500 },
|
|
{ player: 'Charlie', score: 20, questions: 12, successRate: 83, durationSec: 1800 },
|
|
{ player: 'Diana', score: 18, questions: 11, successRate: 82, durationSec: 1320 },
|
|
{ player: 'Eve', score: 16, questions: 10, successRate: 80, durationSec: 1620 },
|
|
{ player: 'Farah', score: 15, questions: 9, successRate: 78, durationSec: 1730 },
|
|
{ player: 'Gino', score: 14, questions: 9, successRate: 74, durationSec: 1780 },
|
|
{ player: 'Hugo', score: 13, questions: 8, successRate: 75, durationSec: 1650 },
|
|
{ player: 'Ines', score: 12, questions: 8, successRate: 71, durationSec: 1600 },
|
|
{ player: 'Jules', score: 11, questions: 7, successRate: 70, durationSec: 1710 },
|
|
]
|
|
|
|
function hasStorage(): boolean {
|
|
return typeof window !== 'undefined' && typeof window.localStorage !== 'undefined'
|
|
}
|
|
|
|
function shouldUseMockLeaderboard(): boolean {
|
|
if (forceApi) return false
|
|
if (hasStorage()) {
|
|
const mode = window.localStorage.getItem(STORAGE_MODE_KEY)
|
|
if (mode === 'api') return false
|
|
if (mode === 'mock') return true
|
|
}
|
|
return !baseUrl
|
|
}
|
|
|
|
async function json<T>(path: string): Promise<T> {
|
|
const url = baseUrl ? `${baseUrl}${path}` : path
|
|
const res = await fetch(url)
|
|
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
return (await res.json()) as T
|
|
}
|
|
|
|
export const leaderboardClient = {
|
|
async top10(): Promise<LeaderboardRow[]> {
|
|
if (shouldUseMockLeaderboard()) return fallbackTop10
|
|
|
|
const resp = await json<{ items?: LeaderboardRow[] }>(`/leaderboard/top10`)
|
|
return (resp.items ?? []).slice(0, 10)
|
|
},
|
|
}
|