import React from 'react'; import { useQuery } from '@tanstack/react-query'; import { getEvents, type TenantEvent } from '../api'; import { useAuth } from '../auth/context'; const STORAGE_KEY = 'tenant-admin.active-event'; export interface EventContextValue { events: TenantEvent[]; isLoading: boolean; isError: boolean; activeEvent: TenantEvent | null; activeSlug: string | null; hasEvents: boolean; hasMultipleEvents: boolean; selectEvent: (slug: string | null) => void; refetch: () => void; } const EventContext = React.createContext(undefined); export function EventProvider({ children }: { children: React.ReactNode }) { const { status } = useAuth(); const [manualEvents, setManualEvents] = React.useState([]); const [manualAttempted, setManualAttempted] = React.useState(false); const [storedSlug, setStoredSlug] = React.useState(() => { if (typeof window === 'undefined') { return null; } return window.localStorage.getItem(STORAGE_KEY); }); const authReady = status === 'authenticated'; const { data: fetchedEvents = [], isLoading: queryLoading, isError, refetch, } = useQuery({ queryKey: ['tenant-events'], queryFn: async () => { try { return await getEvents({ force: true }); } catch (error) { console.warn('[EventContext] Failed to fetch events', error); throw error; } }, staleTime: 60 * 1000, enabled: authReady, initialData: [], }); const events = React.useMemo( () => (authReady ? (manualEvents.length ? manualEvents : fetchedEvents) : []), [authReady, fetchedEvents, manualEvents] ); const isLoading = authReady ? queryLoading || (!manualAttempted && manualEvents.length === 0 && fetchedEvents.length === 0) : status === 'loading'; React.useEffect(() => { if (!authReady || manualAttempted || queryLoading) { return; } if (fetchedEvents.length > 0 && !isError) { return; } setManualAttempted(true); getEvents({ force: true }) .then((list) => { setManualEvents(list ?? []); }) .catch(() => { setManualEvents([]); }); }, [authReady, fetchedEvents.length, isError, manualAttempted, queryLoading]); React.useEffect(() => { if (!events.length || typeof window === 'undefined') { return; } const hasStored = Boolean(storedSlug); const slugExists = hasStored && events.some((event) => event.slug === storedSlug); if (!slugExists) { const shouldAutoselect = events.length === 1; const fallbackSlug = shouldAutoselect ? events[0]?.slug : null; setStoredSlug(fallbackSlug); if (fallbackSlug) { window.localStorage.setItem(STORAGE_KEY, fallbackSlug); } else { window.localStorage.removeItem(STORAGE_KEY); } } }, [events, storedSlug]); const activeEvent = React.useMemo(() => { if (!events.length) { return null; } const matched = events.find((event) => event.slug && event.slug === storedSlug); if (matched) { return matched; } // Only auto-select the single available event. When multiple events exist and // no stored slug is present we intentionally return null to let the UI prompt // for a selection. if (events.length === 1) { return events[0]; } return null; }, [events, storedSlug]); const hasEvents = events.length > 0; const hasMultipleEvents = events.length > 1; const activeSlug = activeEvent?.slug ?? null; const selectEvent = React.useCallback((slug: string | null) => { setStoredSlug(slug); if (typeof window !== 'undefined') { if (slug) { window.localStorage.setItem(STORAGE_KEY, slug); } else { window.localStorage.removeItem(STORAGE_KEY); } } }, []); const value = React.useMemo( () => ({ events, isLoading, isError, activeEvent, activeSlug, hasEvents, hasMultipleEvents, selectEvent, refetch, }), [events, isLoading, isError, activeEvent, activeSlug, hasEvents, hasMultipleEvents, selectEvent, refetch] ); return {children}; } export function useEventContext(): EventContextValue { const ctx = React.useContext(EventContext); if (!ctx) { throw new Error('useEventContext must be used within an EventProvider'); } return ctx; }