2026-02-20 22:45:56 +01:00
|
|
|
'use client'
|
|
|
|
|
|
2026-03-04 20:18:50 +01:00
|
|
|
import { createContext, useContext, useState, useEffect, useMemo, type ReactNode } from 'react'
|
2026-02-20 22:45:56 +01:00
|
|
|
import { trpc } from '@/lib/trpc/client'
|
|
|
|
|
|
2026-03-04 20:18:50 +01:00
|
|
|
type RoundInfo = {
|
|
|
|
|
id: string
|
|
|
|
|
name: string
|
|
|
|
|
status: string
|
|
|
|
|
competitionId?: string
|
|
|
|
|
roundType?: string
|
|
|
|
|
sortOrder?: number
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-20 22:45:56 +01:00
|
|
|
type Program = {
|
|
|
|
|
id: string
|
|
|
|
|
name: string | null
|
|
|
|
|
year?: number
|
2026-03-04 20:18:50 +01:00
|
|
|
rounds?: RoundInfo[]
|
2026-02-20 22:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type EditionContextValue = {
|
|
|
|
|
programs: Program[]
|
|
|
|
|
selectedProgramId: string
|
|
|
|
|
setSelectedProgramId: (id: string) => void
|
|
|
|
|
activeRoundId: string
|
2026-03-04 20:18:50 +01:00
|
|
|
/** The user-selected round (defaults to best/active round) */
|
|
|
|
|
selectedRoundId: string
|
|
|
|
|
setSelectedRoundId: (id: string) => void
|
|
|
|
|
/** Derived roundType for the selected round */
|
|
|
|
|
selectedRoundType: string
|
|
|
|
|
/** All rounds for the selected program (sorted by sortOrder) */
|
|
|
|
|
rounds: RoundInfo[]
|
2026-02-20 22:45:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const EditionContext = createContext<EditionContextValue | null>(null)
|
|
|
|
|
|
|
|
|
|
export function useEditionContext() {
|
|
|
|
|
const ctx = useContext(EditionContext)
|
|
|
|
|
if (!ctx) throw new Error('useEditionContext must be used within EditionProvider')
|
|
|
|
|
return ctx
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function findBestRound(rounds: Array<{ id: string; status: string }>): string {
|
|
|
|
|
const active = rounds.find(r => r.status === 'ROUND_ACTIVE')
|
|
|
|
|
if (active) return active.id
|
|
|
|
|
const closed = [...rounds].filter(r => r.status === 'ROUND_CLOSED').pop()
|
|
|
|
|
if (closed) return closed.id
|
|
|
|
|
return rounds[0]?.id ?? ''
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function EditionProvider({ children }: { children: ReactNode }) {
|
|
|
|
|
const [selectedProgramId, setSelectedProgramId] = useState<string>('')
|
2026-03-04 20:18:50 +01:00
|
|
|
const [selectedRoundId, setSelectedRoundId] = useState<string>('')
|
2026-02-20 22:45:56 +01:00
|
|
|
|
|
|
|
|
const { data: programs } = trpc.program.list.useQuery(
|
|
|
|
|
{ includeStages: true },
|
|
|
|
|
{ refetchInterval: 30_000 },
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const typedPrograms = (programs ?? []) as Program[]
|
|
|
|
|
const selectedProgram = typedPrograms.find(p => p.id === selectedProgramId)
|
2026-03-04 20:18:50 +01:00
|
|
|
const rounds = useMemo(
|
|
|
|
|
() => ((selectedProgram?.rounds ?? []) as RoundInfo[]).slice().sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0)),
|
|
|
|
|
[selectedProgram?.rounds],
|
|
|
|
|
)
|
2026-02-20 22:45:56 +01:00
|
|
|
const activeRoundId = findBestRound(rounds)
|
|
|
|
|
|
2026-03-04 20:18:50 +01:00
|
|
|
// Auto-select first program
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (typedPrograms.length > 0 && !selectedProgramId) {
|
|
|
|
|
setSelectedProgramId(typedPrograms[0].id)
|
|
|
|
|
}
|
|
|
|
|
}, [typedPrograms, selectedProgramId])
|
|
|
|
|
|
|
|
|
|
// Auto-select best round when program changes or rounds load
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (rounds.length > 0 && (!selectedRoundId || !rounds.some(r => r.id === selectedRoundId))) {
|
|
|
|
|
setSelectedRoundId(findBestRound(rounds))
|
|
|
|
|
}
|
|
|
|
|
}, [rounds, selectedRoundId])
|
|
|
|
|
|
|
|
|
|
const selectedRoundType = rounds.find(r => r.id === selectedRoundId)?.roundType ?? ''
|
|
|
|
|
|
2026-02-20 22:45:56 +01:00
|
|
|
return (
|
|
|
|
|
<EditionContext.Provider
|
|
|
|
|
value={{
|
|
|
|
|
programs: typedPrograms,
|
|
|
|
|
selectedProgramId,
|
|
|
|
|
setSelectedProgramId,
|
|
|
|
|
activeRoundId,
|
2026-03-04 20:18:50 +01:00
|
|
|
selectedRoundId,
|
|
|
|
|
setSelectedRoundId,
|
|
|
|
|
selectedRoundType,
|
|
|
|
|
rounds,
|
2026-02-20 22:45:56 +01:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{children}
|
|
|
|
|
</EditionContext.Provider>
|
|
|
|
|
)
|
|
|
|
|
}
|