diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-03-15 23:07:40 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-03-15 23:07:40 +0900 |
| commit | 172b6d3211d040e8d577afda80debce583c3bf7c (patch) | |
| tree | e62023aebb0924e8ad63c37e2d22f0a50a299eff | |
| parent | c2e23841f446489c4d9b7d2b616f3de249159f5f (diff) | |
| download | phperkaigi-2025-albatross-172b6d3211d040e8d577afda80debce583c3bf7c.tar.gz phperkaigi-2025-albatross-172b6d3211d040e8d577afda80debce583c3bf7c.tar.zst phperkaigi-2025-albatross-172b6d3211d040e8d577afda80debce583c3bf7c.zip | |
feat(frontend): show loaing screen
| -rw-r--r-- | frontend/app/components/GolfPlayApp.tsx | 7 | ||||
| -rw-r--r-- | frontend/app/components/GolfPlayApps/GolfPlayAppLoading.tsx | 9 | ||||
| -rw-r--r-- | frontend/app/components/GolfWatchApp.tsx | 7 | ||||
| -rw-r--r-- | frontend/app/components/GolfWatchApps/GolfWatchAppLoading.tsx | 9 | ||||
| -rw-r--r-- | frontend/app/routes/golf.$gameId.play.tsx | 2 | ||||
| -rw-r--r-- | frontend/app/routes/golf.$gameId.watch.tsx | 2 | ||||
| -rw-r--r-- | frontend/app/states/play.ts | 27 | ||||
| -rw-r--r-- | frontend/app/states/watch.ts | 20 |
8 files changed, 63 insertions, 20 deletions
diff --git a/frontend/app/components/GolfPlayApp.tsx b/frontend/app/components/GolfPlayApp.tsx index e8fafbd..0bb66eb 100644 --- a/frontend/app/components/GolfPlayApp.tsx +++ b/frontend/app/components/GolfPlayApp.tsx @@ -20,6 +20,7 @@ import { } from "../states/play"; import GolfPlayAppFinished from "./GolfPlayApps/GolfPlayAppFinished"; import GolfPlayAppGaming from "./GolfPlayApps/GolfPlayAppGaming"; +import GolfPlayAppLoading from "./GolfPlayApps/GolfPlayAppLoading"; import GolfPlayAppStarting from "./GolfPlayApps/GolfPlayAppStarting"; import GolfPlayAppWaiting from "./GolfPlayApps/GolfPlayAppWaiting"; @@ -111,7 +112,9 @@ export default function GolfPlayApp({ game, player, initialCode }: Props) { setLatestGameState, ]); - if (gameStateKind === "waiting") { + if (gameStateKind === "loading") { + return <GolfPlayAppLoading />; + } else if (gameStateKind === "waiting") { return ( <GolfPlayAppWaiting gameDisplayName={game.display_name} @@ -135,7 +138,5 @@ export default function GolfPlayApp({ game, player, initialCode }: Props) { ); } else if (gameStateKind === "finished") { return <GolfPlayAppFinished />; - } else { - return null; } } diff --git a/frontend/app/components/GolfPlayApps/GolfPlayAppLoading.tsx b/frontend/app/components/GolfPlayApps/GolfPlayAppLoading.tsx new file mode 100644 index 0000000..7b424f2 --- /dev/null +++ b/frontend/app/components/GolfPlayApps/GolfPlayAppLoading.tsx @@ -0,0 +1,9 @@ +export default function GolfPlayAppLoading() { + return ( + <div className="min-h-screen bg-gray-100 flex items-center justify-center"> + <div className="text-center"> + <div className="text-6xl font-bold text-black">読込中</div> + </div> + </div> + ); +} diff --git a/frontend/app/components/GolfWatchApp.tsx b/frontend/app/components/GolfWatchApp.tsx index 919fa4f..5cbec3d 100644 --- a/frontend/app/components/GolfWatchApp.tsx +++ b/frontend/app/components/GolfWatchApp.tsx @@ -17,6 +17,7 @@ import { } from "../states/watch"; import GolfWatchAppGaming1v1 from "./GolfWatchApps/GolfWatchAppGaming1v1"; import GolfWatchAppGamingMultiplayer from "./GolfWatchApps/GolfWatchAppGamingMultiplayer"; +import GolfWatchAppLoading from "./GolfWatchApps/GolfWatchAppLoading"; import GolfWatchAppStarting from "./GolfWatchApps/GolfWatchAppStarting"; import GolfWatchAppWaiting1v1 from "./GolfWatchApps/GolfWatchAppWaiting1v1"; import GolfWatchAppWaitingMultiplayer from "./GolfWatchApps/GolfWatchAppWaitingMultiplayer"; @@ -106,7 +107,9 @@ export default function GolfWatchApp({ game }: Props) { setRanking, ]); - if (gameStateKind === "waiting") { + if (gameStateKind === "loading") { + return <GolfWatchAppLoading />; + } else if (gameStateKind === "waiting") { return game.game_type === "1v1" ? ( <GolfWatchAppWaiting1v1 gameDisplayName={game.display_name} @@ -139,7 +142,5 @@ export default function GolfWatchApp({ game }: Props) { gameResult={null /* TODO */} /> ); - } else { - return null; } } diff --git a/frontend/app/components/GolfWatchApps/GolfWatchAppLoading.tsx b/frontend/app/components/GolfWatchApps/GolfWatchAppLoading.tsx new file mode 100644 index 0000000..7169d24 --- /dev/null +++ b/frontend/app/components/GolfWatchApps/GolfWatchAppLoading.tsx @@ -0,0 +1,9 @@ +export default function GolfWatchAppLoading() { + return ( + <div className="min-h-screen bg-gray-100 flex items-center justify-center"> + <div className="text-center"> + <div className="text-6xl font-bold text-black">読込中</div> + </div> + </div> + ); +} diff --git a/frontend/app/routes/golf.$gameId.play.tsx b/frontend/app/routes/golf.$gameId.play.tsx index dc8eb38..1ffe45e 100644 --- a/frontend/app/routes/golf.$gameId.play.tsx +++ b/frontend/app/routes/golf.$gameId.play.tsx @@ -9,7 +9,6 @@ import { } from "../api/client"; import GolfPlayApp from "../components/GolfPlayApp"; import { - setCurrentTimestampAtom, setDurationSecondsAtom, setGameStartedAtAtom, setLatestGameStateAtom, @@ -50,7 +49,6 @@ export default function GolfPlay() { useLoaderData<typeof loader>(); useHydrateAtoms([ - [setCurrentTimestampAtom, undefined], [setDurationSecondsAtom, game.duration_seconds], [setGameStartedAtAtom, game.started_at ?? null], [setLatestGameStateAtom, gameState], diff --git a/frontend/app/routes/golf.$gameId.watch.tsx b/frontend/app/routes/golf.$gameId.watch.tsx index 674abc4..42bde52 100644 --- a/frontend/app/routes/golf.$gameId.watch.tsx +++ b/frontend/app/routes/golf.$gameId.watch.tsx @@ -11,7 +11,6 @@ import { import GolfWatchApp from "../components/GolfWatchApp"; import { rankingAtom, - setCurrentTimestampAtom, setDurationSecondsAtom, setGameStartedAtAtom, setLatestGameStatesAtom, @@ -60,7 +59,6 @@ export default function GolfWatch() { useHydrateAtoms([ [rankingAtom, ranking], - [setCurrentTimestampAtom, undefined], [setDurationSecondsAtom, game.duration_seconds], [setGameStartedAtAtom, game.started_at ?? null], [setLatestGameStatesAtom, gameStates], diff --git a/frontend/app/states/play.ts b/frontend/app/states/play.ts index e7774cb..3acefbf 100644 --- a/frontend/app/states/play.ts +++ b/frontend/app/states/play.ts @@ -6,7 +6,12 @@ export const setGameStartedAtAtom = atom(null, (_, set, value: number | null) => set(gameStartedAtAtom, value), ); -export type GameStateKind = "waiting" | "starting" | "gaming" | "finished"; +export type GameStateKind = + | "loading" + | "waiting" + | "starting" + | "gaming" + | "finished"; type ExecutionStatus = components["schemas"]["ExecutionStatus"]; type LatestGameState = components["schemas"]["LatestGameState"]; @@ -16,9 +21,12 @@ export const gameStateKindAtom = atom<GameStateKind>((get) => { return "waiting"; } + const now = get(currentTimestampAtom); + if (!now) { + return "loading"; + } const durationSeconds = get(durationSecondsAtom); const finishedAt = startedAt + durationSeconds; - const now = get(currentTimestampAtom); if (now < startedAt) { return "starting"; } else if (now < finishedAt) { @@ -28,7 +36,7 @@ export const gameStateKindAtom = atom<GameStateKind>((get) => { } }); -const currentTimestampAtom = atom(0); +const currentTimestampAtom = atom<number | null>(null); export const setCurrentTimestampAtom = atom(null, (_, set) => set(currentTimestampAtom, Math.floor(Date.now() / 1000)), ); @@ -44,6 +52,9 @@ export const startingLeftTimeSecondsAtom = atom<number | null>((get) => { return null; } const currentTimestamp = get(currentTimestampAtom); + if (currentTimestamp === null) { + return null; + } return Math.max(0, startedAt - currentTimestamp); }); @@ -55,6 +66,9 @@ export const gamingLeftTimeSecondsAtom = atom<number | null>((get) => { const durationSeconds = get(durationSecondsAtom); const finishedAt = startedAt + durationSeconds; const currentTimestamp = get(currentTimestampAtom); + if (currentTimestamp === null) { + return null; + } return Math.min(durationSeconds, Math.max(0, finishedAt - currentTimestamp)); }); @@ -72,13 +86,12 @@ export const scoreAtom = atom<number | null>((get) => { return get(rawScoreAtom); }); -const rawIsSubmittingCodeAtom = atom(false); -export const isSubmittingCodeAtom = atom((get) => get(rawIsSubmittingCodeAtom)); +const isSubmittingCodeAtom = atom(false); export const handleSubmitCodePreAtom = atom(null, (_, set) => { - set(rawIsSubmittingCodeAtom, true); + set(isSubmittingCodeAtom, true); }); export const handleSubmitCodePostAtom = atom(null, (_, set) => { - set(rawIsSubmittingCodeAtom, false); + set(isSubmittingCodeAtom, false); }); export const setLatestGameStateAtom = atom( diff --git a/frontend/app/states/watch.ts b/frontend/app/states/watch.ts index d3cc723..463c2cd 100644 --- a/frontend/app/states/watch.ts +++ b/frontend/app/states/watch.ts @@ -6,7 +6,12 @@ export const setGameStartedAtAtom = atom(null, (_, set, value: number | null) => set(gameStartedAtAtom, value), ); -export type GameStateKind = "waiting" | "starting" | "gaming" | "finished"; +export type GameStateKind = + | "loading" + | "waiting" + | "starting" + | "gaming" + | "finished"; type LatestGameState = components["schemas"]["LatestGameState"]; type RankingEntry = components["schemas"]["RankingEntry"]; @@ -16,9 +21,12 @@ export const gameStateKindAtom = atom<GameStateKind>((get) => { return "waiting"; } + const now = get(currentTimestampAtom); + if (!now) { + return "loading"; + } const durationSeconds = get(durationSecondsAtom); const finishedAt = startedAt + durationSeconds; - const now = get(currentTimestampAtom); if (now < startedAt) { return "starting"; } else if (now < finishedAt) { @@ -28,7 +36,7 @@ export const gameStateKindAtom = atom<GameStateKind>((get) => { } }); -const currentTimestampAtom = atom(0); +const currentTimestampAtom = atom<number | null>(null); export const setCurrentTimestampAtom = atom(null, (_, set) => set(currentTimestampAtom, Math.floor(Date.now() / 1000)), ); @@ -44,6 +52,9 @@ export const startingLeftTimeSecondsAtom = atom<number | null>((get) => { return null; } const currentTimestamp = get(currentTimestampAtom); + if (currentTimestamp === null) { + return null; + } return Math.max(0, startedAt - currentTimestamp); }); @@ -55,6 +66,9 @@ export const gamingLeftTimeSecondsAtom = atom<number | null>((get) => { const durationSeconds = get(durationSecondsAtom); const finishedAt = startedAt + durationSeconds; const currentTimestamp = get(currentTimestampAtom); + if (currentTimestamp === null) { + return null; + } return Math.min(durationSeconds, Math.max(0, finishedAt - currentTimestamp)); }); |
