From 1e6df136d8202c8adf65948527f4c3e7583b338c Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
Date: Tue, 4 Mar 2025 22:55:01 +0900
Subject: websocket to polling

---
 frontend/app/routes/golf.$gameId.watch.tsx | 185 ++++++-----------------------
 1 file changed, 36 insertions(+), 149 deletions(-)

(limited to 'frontend/app/routes/golf.$gameId.watch.tsx')

diff --git a/frontend/app/routes/golf.$gameId.watch.tsx b/frontend/app/routes/golf.$gameId.watch.tsx
index 5a41de5..0c07633 100644
--- a/frontend/app/routes/golf.$gameId.watch.tsx
+++ b/frontend/app/routes/golf.$gameId.watch.tsx
@@ -1,21 +1,21 @@
 import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node";
-import { ClientLoaderFunctionArgs, useLoaderData } from "@remix-run/react";
+import { useLoaderData } from "@remix-run/react";
 import { useHydrateAtoms } from "jotai/utils";
-import { apiGetGame, apiGetToken } from "../.server/api/client";
 import { ensureUserLoggedIn } from "../.server/auth";
-import GolfWatchApp from "../components/GolfWatchApp.client";
-import GolfWatchAppConnecting from "../components/GolfWatchApps/GolfWatchAppConnecting";
 import {
-	codeAAtom,
-	codeBAtom,
-	scoreAAtom,
-	scoreBAtom,
+	ApiAuthTokenContext,
+	apiGetGame,
+	apiGetGameWatchLatestStates,
+	apiGetGameWatchRanking,
+} from "../api/client";
+import GolfWatchApp from "../components/GolfWatchApp";
+import {
 	setCurrentTimestampAtom,
 	setDurationSecondsAtom,
-	submitResultAAtom,
-	submitResultBAtom,
+	setGameStartedAtAtom,
+	setLatestGameStatesAtom,
+	setRankingAtom,
 } from "../states/watch";
-import { PlayerState } from "../types/PlayerState";
 
 export const meta: MetaFunction<typeof loader> = ({ data }) => [
 	{
@@ -28,160 +28,47 @@ export const meta: MetaFunction<typeof loader> = ({ data }) => [
 export async function loader({ params, request }: LoaderFunctionArgs) {
 	const { token } = await ensureUserLoggedIn(request);
 
+	const gameId = Number(params.gameId);
+
 	const fetchGame = async () => {
-		return (await apiGetGame(token, Number(params.gameId))).game;
+		return (await apiGetGame(token, gameId)).game;
 	};
-	const fetchSockToken = async () => {
-		return (await apiGetToken(token)).token;
+	const fetchRanking = async () => {
+		return (await apiGetGameWatchRanking(token, gameId)).ranking;
 	};
-
-	const [game, sockToken] = await Promise.all([fetchGame(), fetchSockToken()]);
-
-	if (game.game_type !== "1v1") {
-		throw new Response("Not Found", { status: 404 });
-	}
-
-	const playerStateA: 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: "",
-			})),
-		},
+	const fetchGameStates = async () => {
+		return (await apiGetGameWatchLatestStates(token, gameId)).states;
 	};
-	const playerStateB = structuredClone(playerStateA);
+
+	const [game, ranking, gameStates] = await Promise.all([
+		fetchGame(),
+		fetchRanking(),
+		fetchGameStates(),
+	]);
 
 	return {
+		apiAuthToken: token,
 		game,
-		sockToken,
-		playerStateA,
-		playerStateB,
+		ranking,
+		gameStates,
 	};
 }
 
-export async function clientLoader({ serverLoader }: ClientLoaderFunctionArgs) {
-	const data = await serverLoader<typeof loader>();
-
-	const playerIdA = data.game.players[0]?.user_id;
-	const playerIdB = data.game.players[1]?.user_id;
-
-	if (playerIdA !== null) {
-		const baseKeyA = `watcherState:${data.game.game_id}:${playerIdA}`;
-
-		const localCodeA = (() => {
-			const rawValue = window.localStorage.getItem(`${baseKeyA}:code`);
-
-			if (rawValue === null) {
-				return null;
-			}
-			return rawValue;
-		})();
-
-		const localScoreA = (() => {
-			const rawValue = window.localStorage.getItem(`${baseKeyA}:score`);
-			if (rawValue === null || rawValue === "") {
-				return null;
-			}
-			return Number(rawValue);
-		})();
-
-		const localSubmissionResultA = (() => {
-			const rawValue = window.localStorage.getItem(
-				`${baseKeyA}:submissionResult`,
-			);
-			if (rawValue === null) {
-				return null;
-			}
-			const parsed = JSON.parse(rawValue);
-			if (typeof parsed !== "object") {
-				return null;
-			}
-			return parsed;
-		})();
-
-		if (localCodeA !== null) {
-			data.playerStateA.code = localCodeA;
-		}
-		if (localScoreA !== null) {
-			data.playerStateA.score = localScoreA;
-		}
-		if (localSubmissionResultA !== null) {
-			data.playerStateA.submitResult = localSubmissionResultA;
-		}
-	}
-
-	if (playerIdB !== null) {
-		const baseKeyB = `watcherState:${data.game.game_id}:${playerIdB}`;
-
-		const localCodeB = (() => {
-			const rawValue = window.localStorage.getItem(`${baseKeyB}:code`);
-			if (rawValue === null) {
-				return null;
-			}
-			return rawValue;
-		})();
-
-		const localScoreB = (() => {
-			const rawValue = window.localStorage.getItem(`${baseKeyB}:score`);
-			if (rawValue === null || rawValue === "") {
-				return null;
-			}
-			return Number(rawValue);
-		})();
-
-		const localSubmissionResultB = (() => {
-			const rawValue = window.localStorage.getItem(
-				`${baseKeyB}:submissionResult`,
-			);
-			if (rawValue === null) {
-				return null;
-			}
-			const parsed = JSON.parse(rawValue);
-			if (typeof parsed !== "object") {
-				return null;
-			}
-			return parsed;
-		})();
-
-		if (localCodeB !== null) {
-			data.playerStateB.code = localCodeB;
-		}
-		if (localScoreB !== null) {
-			data.playerStateB.score = localScoreB;
-		}
-		if (localSubmissionResultB !== null) {
-			data.playerStateB.submitResult = localSubmissionResultB;
-		}
-	}
-
-	return data;
-}
-clientLoader.hydrate = true;
-
-export function HydrateFallback() {
-	return <GolfWatchAppConnecting />;
-}
-
 export default function GolfWatch() {
-	const { game, sockToken, playerStateA, playerStateB } =
+	const { apiAuthToken, game, ranking, gameStates } =
 		useLoaderData<typeof loader>();
 
 	useHydrateAtoms([
 		[setCurrentTimestampAtom, undefined],
 		[setDurationSecondsAtom, game.duration_seconds],
-		[codeAAtom, playerStateA.code],
-		[codeBAtom, playerStateB.code],
-		[scoreAAtom, playerStateA.score],
-		[scoreBAtom, playerStateB.score],
-		[submitResultAAtom, playerStateA.submitResult],
-		[submitResultBAtom, playerStateB.submitResult],
+		[setGameStartedAtAtom, game.started_at ?? null],
+		[setRankingAtom, ranking],
+		[setLatestGameStatesAtom, gameStates],
 	]);
 
-	return <GolfWatchApp game={game} sockToken={sockToken} />;
+	return (
+		<ApiAuthTokenContext.Provider value={apiAuthToken}>
+			<GolfWatchApp game={game} />
+		</ApiAuthTokenContext.Provider>
+	);
 }
-- 
cgit v1.3.1

