/** * Schedule Composable * * Manages SBA schedule data fetching and week navigation. * Fetches current season/week and scheduled games from SBA API. */ import type { SbaCurrent, SbaScheduledGame } from '~/types' export function useSchedule() { const config = useRuntimeConfig() const apiUrl = useApiUrl() // State - use useState for SSR-safe persistence across hydration // Regular ref() creates new state on each call, breaking after hydration const current = useState('schedule-current', () => null) const selectedSeason = useState('schedule-season', () => 0) const selectedWeek = useState('schedule-week', () => 0) const games = useState('schedule-games', () => []) const loading = useState('schedule-loading', () => false) const error = useState('schedule-error', () => null) // Track if we've initialized const initialized = useState('schedule-initialized', () => false) /** * Get headers for SSR-compatible requests */ function getHeaders(): Record { const headers: Record = {} if (import.meta.server) { const event = useRequestEvent() const cookieHeader = event?.node.req.headers.cookie if (cookieHeader) { headers['Cookie'] = cookieHeader } } return headers } /** * Fetch current season and week from SBA API */ async function fetchCurrent(): Promise { try { error.value = null const response = await $fetch(`${apiUrl}/api/schedule/current`, { credentials: 'include', headers: getHeaders(), }) current.value = response // Initialize selected to current if not already set if (!initialized.value) { selectedSeason.value = response.season selectedWeek.value = response.week initialized.value = true } console.log('[useSchedule] Current:', response) } catch (err: any) { console.error('[useSchedule] Failed to fetch current:', err) error.value = err.data?.detail || err.message || 'Failed to fetch current season/week' throw err } } /** * Fetch games for the selected week */ async function fetchGames(): Promise { if (!selectedSeason.value || !selectedWeek.value) { console.warn('[useSchedule] No season/week selected') return } try { loading.value = true error.value = null const response = await $fetch( `${apiUrl}/api/schedule/games`, { credentials: 'include', headers: getHeaders(), params: { season: selectedSeason.value, week: selectedWeek.value, }, } ) games.value = response console.log(`[useSchedule] Loaded ${response.length} games for S${selectedSeason.value} W${selectedWeek.value}`) } catch (err: any) { console.error('[useSchedule] Failed to fetch games:', err) error.value = err.data?.detail || err.message || 'Failed to fetch schedule games' games.value = [] } finally { loading.value = false } } /** * Initialize schedule data (fetch current + games) */ async function initialize(): Promise { try { loading.value = true await fetchCurrent() await fetchGames() } catch { // Error already set in fetchCurrent } finally { loading.value = false } } /** * Navigate to next week */ function nextWeek(): void { selectedWeek.value++ fetchGames() } /** * Navigate to previous week */ function prevWeek(): void { if (selectedWeek.value > 1) { selectedWeek.value-- fetchGames() } } /** * Jump back to current week */ function goToCurrentWeek(): void { if (current.value) { selectedSeason.value = current.value.season selectedWeek.value = current.value.week fetchGames() } } /** * Set specific week (useful for direct navigation) */ function setWeek(week: number): void { if (week >= 1) { selectedWeek.value = week fetchGames() } } /** * Check if currently viewing the current week */ const isCurrentWeek = computed(() => { if (!current.value) return false return ( selectedSeason.value === current.value.season && selectedWeek.value === current.value.week ) }) return { // State - return refs directly for proper reactivity in templates current, selectedSeason, selectedWeek, games, loading, error, initialized, // Computed isCurrentWeek, // Actions initialize, fetchCurrent, fetchGames, nextWeek, prevWeek, goToCurrentWeek, setWeek, } }