'use client'; import { createContext, useContext, useEffect, useState } from 'react'; import useSocket from '@/hooks/useSocket'; import { GAME_START, LOCAL_DEFAULTS } from '@/constants'; import type { Dispatch, ReactNode, SetStateAction } from 'react'; import type { GameUpdate, LocalSettings, Settings, Tilt } from '@/types'; const AppContext = createContext(undefined); export interface AppContext { gameData: GameUpdate; isDM: boolean; noGame: boolean; selectCardIndex: number; settings: Settings; tilt: Tilt[]; emitFlip: (cardIndex: number) => void; emitSettings: (gameData: GameUpdate) => void; emitRedraw: (cardIndex: number) => void; emitSelect: (cardID: string) => void; setGameID: (gameID: string) => void; setLocalSettings: Dispatch>; setSelectCardIndex: (cardIndex: number) => void; setTilt: (tilt: Tilt[]) => void; } export function AppProvider({ children }: { children: ReactNode }) { const [gameData, setGameData] = useState({ ...GAME_START }); const [localSettings, setLocalSettings] = useState(() => ({ ...LOCAL_DEFAULTS })); const [gameID, setGameID] = useState(''); const [noGame, setNoGame] = useState(false); const [selectCardIndex, setSelectCardIndex] = useState(-1); const [tilt, setTilt] = useState([]); const { emitFlip, emitRedraw, emitSelect, emitSettings, emitTilt } = useSocket({ gameID, setGameData, setNoGame, }); useEffect(() => { const cardIndex = tilt.findIndex((tilt) => !!tilt); if (tilt[cardIndex]) { emitTilt(cardIndex, tilt[cardIndex]); } else { // cardIndex does not matter // all tilts for this user will be cleared emitTilt(0, { rotateX: 0, rotateY: 0 }); } }, [tilt]); const handleSelect = (cardID: string) => { setSelectCardIndex(-1); emitSelect(selectCardIndex, cardID); }; const { dmID } = gameData; const isDM = !!dmID; const appInterface = { gameData, isDM, noGame, selectCardIndex, settings: { ...gameData.settings, ...localSettings }, tilt, emitFlip, emitSettings, emitRedraw, emitSelect: handleSelect, setGameID, setLocalSettings, setSelectCardIndex, setTilt, }; return {children}; } export function useAppContext(): AppContext { const context = useContext(AppContext); if (!context) throw new Error('useAppContext must be used within AppProvider'); return context; }