aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app/components/GolfPlayApp.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/app/components/GolfPlayApp.tsx')
-rw-r--r--frontend/app/components/GolfPlayApp.tsx141
1 files changed, 141 insertions, 0 deletions
diff --git a/frontend/app/components/GolfPlayApp.tsx b/frontend/app/components/GolfPlayApp.tsx
new file mode 100644
index 0000000..e8fafbd
--- /dev/null
+++ b/frontend/app/components/GolfPlayApp.tsx
@@ -0,0 +1,141 @@
+import { useAtomValue, useSetAtom } from "jotai";
+import { useContext, useEffect, useState } from "react";
+import { useTimer } from "react-use-precision-timer";
+import { useDebouncedCallback } from "use-debounce";
+import {
+ ApiAuthTokenContext,
+ apiGetGame,
+ apiGetGamePlayLatestState,
+ apiPostGamePlayCode,
+ apiPostGamePlaySubmit,
+} from "../api/client";
+import type { components } from "../api/schema";
+import {
+ gameStateKindAtom,
+ handleSubmitCodePostAtom,
+ handleSubmitCodePreAtom,
+ setCurrentTimestampAtom,
+ setGameStartedAtAtom,
+ setLatestGameStateAtom,
+} from "../states/play";
+import GolfPlayAppFinished from "./GolfPlayApps/GolfPlayAppFinished";
+import GolfPlayAppGaming from "./GolfPlayApps/GolfPlayAppGaming";
+import GolfPlayAppStarting from "./GolfPlayApps/GolfPlayAppStarting";
+import GolfPlayAppWaiting from "./GolfPlayApps/GolfPlayAppWaiting";
+
+type Game = components["schemas"]["Game"];
+type User = components["schemas"]["User"];
+
+type Props = {
+ game: Game;
+ player: User;
+ initialCode: string;
+};
+
+export default function GolfPlayApp({ game, player, initialCode }: Props) {
+ const apiAuthToken = useContext(ApiAuthTokenContext);
+
+ 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) => {
+ console.log("player:c2s:code");
+ if (game.game_type === "1v1") {
+ await apiPostGamePlayCode(apiAuthToken, game.game_id, code);
+ }
+ }, 1000);
+
+ const onCodeSubmit = useDebouncedCallback(async (code: string) => {
+ if (code === "") {
+ return;
+ }
+ console.log("player:c2s:submit");
+ handleSubmitCodePre();
+ await apiPostGamePlaySubmit(apiAuthToken, game.game_id, code);
+ handleSubmitCodePost();
+ }, 1000);
+
+ 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 { state } = await apiGetGamePlayLatestState(
+ apiAuthToken,
+ game.game_id,
+ );
+ setLatestGameState(state);
+ }
+ } catch (error) {
+ console.error(error);
+ } finally {
+ setIsDataPolling(false);
+ }
+ }, 1000);
+
+ return () => {
+ clearInterval(timerId);
+ };
+ }, [
+ isDataPolling,
+ apiAuthToken,
+ game.game_id,
+ gameStateKind,
+ setGameStartedAt,
+ setLatestGameState,
+ ]);
+
+ if (gameStateKind === "waiting") {
+ return (
+ <GolfPlayAppWaiting
+ gameDisplayName={game.display_name}
+ playerProfile={playerProfile}
+ />
+ );
+ } else if (gameStateKind === "starting") {
+ return <GolfPlayAppStarting gameDisplayName={game.display_name} />;
+ } else if (gameStateKind === "gaming") {
+ return (
+ <GolfPlayAppGaming
+ gameDisplayName={game.display_name}
+ playerProfile={playerProfile}
+ problemTitle={game.problem.title}
+ problemDescription={game.problem.description}
+ sampleCode={game.problem.sample_code}
+ initialCode={initialCode}
+ onCodeChange={onCodeChange}
+ onCodeSubmit={onCodeSubmit}
+ />
+ );
+ } else if (gameStateKind === "finished") {
+ return <GolfPlayAppFinished />;
+ } else {
+ return null;
+ }
+}