aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app/components/GolfWatchApp.tsx
blob: fe7193286599623e4b5ab9b45f07a080aabd74e4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { 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,
	setCurrentTimestampAtom,
	setGameStartedAtAtom,
	setLatestGameStatesAtom,
	setRankingAtom,
} from "../states/watch";
import GolfWatchAppGaming from "./GolfWatchApps/GolfWatchAppGaming";
import GolfWatchAppStarting from "./GolfWatchApps/GolfWatchAppStarting";
import GolfWatchAppWaiting from "./GolfWatchApps/GolfWatchAppWaiting";

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 setRanking = useSetAtom(setRankingAtom);

	useTimer({ delay: 1000, startImmediately: true }, setCurrentTimestamp);

	const playerA = game.main_players[0]!;
	const playerB = game.main_players[1]!;

	const playerProfileA = {
		id: playerA.user_id,
		displayName: playerA.display_name,
		iconPath: playerA.icon_path ?? null,
	};
	const playerProfileB = {
		id: playerB.user_id,
		displayName: playerB.display_name,
		iconPath: playerB.icon_path ?? 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 (
			<GolfWatchAppWaiting
				gameDisplayName={game.display_name}
				playerProfileA={playerProfileA}
				playerProfileB={playerProfileB}
			/>
		);
	} else if (gameStateKind === "starting") {
		return <GolfWatchAppStarting gameDisplayName={game.display_name} />;
	} else if (gameStateKind === "gaming" || gameStateKind === "finished") {
		return (
			<GolfWatchAppGaming
				gameDisplayName={game.display_name}
				playerProfileA={playerProfileA}
				playerProfileB={playerProfileB}
				problemTitle={game.problem.title}
				problemDescription={game.problem.description}
				gameResult={null /* TODO */}
			/>
		);
	} else {
		return null;
	}
}