diff options
Diffstat (limited to 'frontend/app/routes/golf.$gameId.play.tsx')
| -rw-r--r-- | frontend/app/routes/golf.$gameId.play.tsx | 97 |
1 files changed, 91 insertions, 6 deletions
diff --git a/frontend/app/routes/golf.$gameId.play.tsx b/frontend/app/routes/golf.$gameId.play.tsx index ea1b8fd..a2860dd 100644 --- a/frontend/app/routes/golf.$gameId.play.tsx +++ b/frontend/app/routes/golf.$gameId.play.tsx @@ -1,10 +1,17 @@ import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node"; -import { useLoaderData } from "@remix-run/react"; -import { ClientOnly } from "remix-utils/client-only"; +import { ClientLoaderFunctionArgs, useLoaderData } from "@remix-run/react"; +import { useHydrateAtoms } from "jotai/utils"; import { apiGetGame, apiGetToken } from "../.server/api/client"; import { ensureUserLoggedIn } from "../.server/auth"; import GolfPlayApp from "../components/GolfPlayApp.client"; import GolfPlayAppConnecting from "../components/GolfPlayApps/GolfPlayAppConnecting"; +import { + scoreAtom, + setCurrentTimestampAtom, + setDurationSecondsAtom, + submitResultAtom, +} from "../states/play"; +import { PlayerState } from "../types/PlayerState"; export const meta: MetaFunction<typeof loader> = ({ data }) => [ { @@ -25,19 +32,97 @@ export async function loader({ params, request }: LoaderFunctionArgs) { }; const [game, sockToken] = await Promise.all([fetchGame(), fetchSockToken()]); + + const playerState: PlayerState = { + code: "", + score: null, + submitResult: { + status: "waiting_submission", + execResults: game.exec_steps.map((r) => ({ + testcase_id: r.testcase_id, + status: "waiting_submission", + label: r.label, + stdout: "", + stderr: "", + })), + }, + }; + return { game, player: user, sockToken, + playerState, }; } +export async function clientLoader({ serverLoader }: ClientLoaderFunctionArgs) { + const data = await serverLoader<typeof loader>(); + const baseKey = `playerState:${data.game.game_id}:${data.player.user_id}`; + + const localCode = (() => { + const rawValue = window.localStorage.getItem(`${baseKey}:code`); + if (rawValue === null) { + return null; + } + return rawValue; + })(); + + const localScore = (() => { + const rawValue = window.localStorage.getItem(`${baseKey}:score`); + if (rawValue === null || rawValue === "") { + return null; + } + return Number(rawValue); + })(); + + const localSubmissionResult = (() => { + const rawValue = window.localStorage.getItem(`${baseKey}:submissionResult`); + if (rawValue === null) { + return null; + } + const parsed = JSON.parse(rawValue); + if (typeof parsed !== "object") { + return null; + } + return parsed; + })(); + + if (localCode !== null) { + data.playerState.code = localCode; + } + if (localScore !== null) { + data.playerState.score = localScore; + } + if (localSubmissionResult !== null) { + data.playerState.submitResult = localSubmissionResult; + } + + return data; +} +clientLoader.hydrate = true; + +export function HydrateFallback() { + return <GolfPlayAppConnecting />; +} + export default function GolfPlay() { - const { game, player, sockToken } = useLoaderData<typeof loader>(); + const { game, player, sockToken, playerState } = + useLoaderData<typeof loader>(); + + useHydrateAtoms([ + [setCurrentTimestampAtom, undefined], + [setDurationSecondsAtom, game.duration_seconds], + [scoreAtom, playerState.score], + [submitResultAtom, playerState.submitResult], + ]); return ( - <ClientOnly fallback={<GolfPlayAppConnecting />}> - {() => <GolfPlayApp game={game} player={player} sockToken={sockToken} />} - </ClientOnly> + <GolfPlayApp + game={game} + player={player} + initialCode={playerState.code} + sockToken={sockToken} + /> ); } |
