aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app/components/GolfWatchApp.tsx
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-03-08 10:51:41 +0900
committernsfisis <nsfisis@gmail.com>2025-03-08 10:51:41 +0900
commita7ce31249948e4f0c1950de93f3c4f7cdda51cf4 (patch)
treec4c740f0cccd15f825596f7a115f3b8f8eb8ffa7 /frontend/app/components/GolfWatchApp.tsx
parent7f4d16dca85263dcbc7b3bb29f5fc50f4371739d (diff)
parentc06d46eae30c9468535fb6af5e9b822acadbbdb6 (diff)
downloadphperkaigi-2025-albatross-a7ce31249948e4f0c1950de93f3c4f7cdda51cf4.tar.gz
phperkaigi-2025-albatross-a7ce31249948e4f0c1950de93f3c4f7cdda51cf4.tar.zst
phperkaigi-2025-albatross-a7ce31249948e4f0c1950de93f3c4f7cdda51cf4.zip
Merge branch 'phperkaigi-2025'
Diffstat (limited to 'frontend/app/components/GolfWatchApp.tsx')
-rw-r--r--frontend/app/components/GolfWatchApp.tsx143
1 files changed, 143 insertions, 0 deletions
diff --git a/frontend/app/components/GolfWatchApp.tsx b/frontend/app/components/GolfWatchApp.tsx
new file mode 100644
index 0000000..402884f
--- /dev/null
+++ b/frontend/app/components/GolfWatchApp.tsx
@@ -0,0 +1,143 @@
+import { useAtom, useAtomValue, useSetAtom } from "jotai";
+import { useContext, useEffect, useState } from "react";
+import { useTimer } from "react-use-precision-timer";
+import {
+ ApiAuthTokenContext,
+ apiGetGame,
+ apiGetGameWatchLatestStates,
+ apiGetGameWatchRanking,
+} from "../api/client";
+import type { components } from "../api/schema";
+import {
+ gameStateKindAtom,
+ rankingAtom,
+ setCurrentTimestampAtom,
+ setGameStartedAtAtom,
+ setLatestGameStatesAtom,
+} from "../states/watch";
+import GolfWatchAppGaming1v1 from "./GolfWatchApps/GolfWatchAppGaming1v1";
+import GolfWatchAppGamingMultiplayer from "./GolfWatchApps/GolfWatchAppGamingMultiplayer";
+import GolfWatchAppStarting from "./GolfWatchApps/GolfWatchAppStarting";
+import GolfWatchAppWaiting1v1 from "./GolfWatchApps/GolfWatchAppWaiting1v1";
+import GolfWatchAppWaitingMultiplayer from "./GolfWatchApps/GolfWatchAppWaitingMultiplayer";
+
+type Game = components["schemas"]["Game"];
+
+export type Props = {
+ game: Game;
+};
+
+export default function GolfWatchApp({ game }: Props) {
+ const apiAuthToken = useContext(ApiAuthTokenContext);
+
+ const gameStateKind = useAtomValue(gameStateKindAtom);
+ const setGameStartedAt = useSetAtom(setGameStartedAtAtom);
+ const setCurrentTimestamp = useSetAtom(setCurrentTimestampAtom);
+ const setLatestGameStates = useSetAtom(setLatestGameStatesAtom);
+ const [ranking, setRanking] = useAtom(rankingAtom);
+
+ useTimer({ delay: 1000, startImmediately: true }, setCurrentTimestamp);
+
+ const playerA = game.main_players[0];
+ const playerB = game.main_players[1];
+
+ const playerProfileA = playerA
+ ? {
+ id: playerA.user_id,
+ displayName: playerA.display_name,
+ iconPath: playerA.icon_path ?? null,
+ }
+ : null;
+ const playerProfileB = playerB
+ ? {
+ id: playerB.user_id,
+ displayName: playerB.display_name,
+ iconPath: playerB.icon_path ?? null,
+ }
+ : null;
+
+ 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 apiGetGame(apiAuthToken, game.game_id);
+ if (g.started_at != null) {
+ setGameStartedAt(g.started_at);
+ }
+ } else if (gameStateKind === "gaming") {
+ const { states } = await apiGetGameWatchLatestStates(
+ apiAuthToken,
+ game.game_id,
+ );
+ setLatestGameStates(states);
+ const { ranking } = await apiGetGameWatchRanking(
+ apiAuthToken,
+ game.game_id,
+ );
+ setRanking(ranking);
+ }
+ } catch (error) {
+ console.error(error);
+ } finally {
+ setIsDataPolling(false);
+ }
+ }, 1000);
+
+ return () => {
+ clearInterval(timerId);
+ };
+ }, [
+ isDataPolling,
+ apiAuthToken,
+ game.game_id,
+ gameStateKind,
+ setGameStartedAt,
+ setLatestGameStates,
+ setRanking,
+ ]);
+
+ if (gameStateKind === "waiting") {
+ return game.game_type === "1v1" ? (
+ <GolfWatchAppWaiting1v1
+ gameDisplayName={game.display_name}
+ playerProfileA={playerProfileA!}
+ playerProfileB={playerProfileB!}
+ />
+ ) : (
+ <GolfWatchAppWaitingMultiplayer gameDisplayName={game.display_name} />
+ );
+ } else if (gameStateKind === "starting") {
+ return <GolfWatchAppStarting gameDisplayName={game.display_name} />;
+ } else if (gameStateKind === "gaming" || gameStateKind === "finished") {
+ return game.game_type === "1v1" ? (
+ <GolfWatchAppGaming1v1
+ gameDisplayName={game.display_name}
+ playerProfileA={playerProfileA!}
+ playerProfileB={playerProfileB!}
+ problemTitle={game.problem.title}
+ problemDescription={game.problem.description}
+ gameResult={null /* TODO */}
+ />
+ ) : (
+ <GolfWatchAppGamingMultiplayer
+ gameDisplayName={game.display_name}
+ ranking={ranking}
+ problemTitle={game.problem.title}
+ problemDescription={game.problem.description}
+ gameResult={null /* TODO */}
+ />
+ );
+ } else {
+ return null;
+ }
+}