import { useAtomValue, useSetAtom } from "jotai"; import { useHydrateAtoms } from "jotai/utils"; import { useContext, useEffect, useState } from "react"; import { useTimer } from "react-use-precision-timer"; import { useDebouncedCallback } from "use-debounce"; import { ApiClientContext } from "../api/client"; import type { components } from "../api/schema"; import { gameStateKindAtom, handleSubmitCodePostAtom, handleSubmitCodePreAtom, setCurrentTimestampAtom, setDurationSecondsAtom, setGameStartedAtAtom, setLatestGameStateAtom, } from "../states/play"; import GolfPlayAppGaming from "./GolfPlayApps/GolfPlayAppGaming"; import GolfPlayAppLoading from "./GolfPlayApps/GolfPlayAppLoading"; import GolfPlayAppStarting from "./GolfPlayApps/GolfPlayAppStarting"; import GolfPlayAppWaiting from "./GolfPlayApps/GolfPlayAppWaiting"; type Game = components["schemas"]["Game"]; type User = components["schemas"]["User"]; type LatestGameState = components["schemas"]["LatestGameState"]; type Props = { game: Game; player: User; initialGameState: LatestGameState; }; export default function GolfPlayApp({ game, player, initialGameState }: Props) { useHydrateAtoms([ [setDurationSecondsAtom, game.duration_seconds], [setGameStartedAtAtom, game.started_at ?? null], [setLatestGameStateAtom, initialGameState], ]); const apiClient = useContext(ApiClientContext)!; const gameStateKind = useAtomValue(gameStateKindAtom); const setGameStartedAt = useSetAtom(setGameStartedAtAtom); const setCurrentTimestamp = useSetAtom(setCurrentTimestampAtom); const handleSubmitCodePre = useSetAtom(handleSubmitCodePreAtom); const handleSubmitCodePost = useSetAtom(handleSubmitCodePostAtom); const setLatestGameState = useSetAtom(setLatestGameStateAtom); useTimer({ delay: 1000, startImmediately: true }, setCurrentTimestamp); const playerProfile = { id: player.user_id, displayName: player.display_name, iconPath: player.icon_path ?? null, }; const onCodeChange = useDebouncedCallback(async (code: string) => { if (game.game_type === "1v1") { console.log("player:c2s:code"); await apiClient.postGamePlayCode(game.game_id, code); } }, 1000); const onCodeSubmit = useDebouncedCallback( async (code: string) => { if (code === "") { return; } console.log("player:c2s:submit"); handleSubmitCodePre(); await apiClient.postGamePlaySubmit(game.game_id, code); await new Promise((resolve) => setTimeout(resolve, 1000)); handleSubmitCodePost(); }, 1000, { leading: true }, ); const [isDataPolling, setIsDataPolling] = useState(false); useEffect(() => { if (isDataPolling) { return; } const timerId = setInterval(async () => { if (isDataPolling) { return; } setIsDataPolling(true); try { if (gameStateKind === "waiting") { const { game: g } = await apiClient.getGame(game.game_id); if (g.started_at != null) { setGameStartedAt(g.started_at); } } else if (gameStateKind === "gaming") { const { state } = await apiClient.getGamePlayLatestState( game.game_id, ); setLatestGameState(state); } } catch (error) { console.error(error); } finally { setIsDataPolling(false); } }, 1000); return () => { clearInterval(timerId); }; }, [ isDataPolling, apiClient, game.game_id, gameStateKind, setGameStartedAt, setLatestGameState, ]); if (gameStateKind === "loading") { return ; } else if (gameStateKind === "waiting") { return ( ); } else if (gameStateKind === "starting") { return ; } else if (gameStateKind === "gaming" || gameStateKind === "finished") { return ( ); } }