aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2025-03-21 09:23:01 +0900
committernsfisis <nsfisis@gmail.com>2025-03-21 09:50:56 +0900
commit80ee46c81dda5331f66aa401435447f22ff187cd (patch)
tree10830e1e882808b0ecbebd2164fd805160558ca2 /frontend/app
parentd379ce3309e5241359b9849fd0170909a140169c (diff)
downloadphperkaigi-2025-albatross-80ee46c81dda5331f66aa401435447f22ff187cd.tar.gz
phperkaigi-2025-albatross-80ee46c81dda5331f66aa401435447f22ff187cd.tar.zst
phperkaigi-2025-albatross-80ee46c81dda5331f66aa401435447f22ff187cd.zip
feat(frontend): show game result in 1v1 watch
Diffstat (limited to 'frontend/app')
-rw-r--r--frontend/app/api/schema.d.ts2
-rw-r--r--frontend/app/components/GolfWatchApp.tsx1
-rw-r--r--frontend/app/components/GolfWatchApps/GolfWatchAppGaming1v1.tsx23
-rw-r--r--frontend/app/states/watch.ts32
4 files changed, 47 insertions, 11 deletions
diff --git a/frontend/app/api/schema.d.ts b/frontend/app/api/schema.d.ts
index 0cace21..6f69292 100644
--- a/frontend/app/api/schema.d.ts
+++ b/frontend/app/api/schema.d.ts
@@ -201,6 +201,8 @@ export interface components {
code: string;
/** @example 100 */
score: number | null;
+ /** @example 946684800 */
+ best_score_submitted_at: number | null;
status: components["schemas"]["ExecutionStatus"];
};
RankingEntry: {
diff --git a/frontend/app/components/GolfWatchApp.tsx b/frontend/app/components/GolfWatchApp.tsx
index cfd5e74..492d555 100644
--- a/frontend/app/components/GolfWatchApp.tsx
+++ b/frontend/app/components/GolfWatchApp.tsx
@@ -138,7 +138,6 @@ export default function GolfWatchApp({
problemTitle={game.problem.title}
problemDescription={game.problem.description}
sampleCode={game.problem.sample_code}
- gameResult={null /* TODO */}
/>
) : (
<GolfWatchAppGamingMultiplayer
diff --git a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming1v1.tsx b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming1v1.tsx
index 63ad5f3..168f5d9 100644
--- a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming1v1.tsx
+++ b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming1v1.tsx
@@ -1,6 +1,8 @@
import { useAtomValue } from "jotai";
import {
calcCodeSize,
+ checkGameResultKind,
+ gameStateKindAtom,
gamingLeftTimeSecondsAtom,
latestGameStatesAtom,
} from "../../states/watch";
@@ -23,7 +25,6 @@ type Props = {
problemTitle: string;
problemDescription: string;
sampleCode: string;
- gameResult: "winA" | "winB" | "draw" | null;
};
export default function GolfWatchAppGaming1v1({
@@ -33,16 +34,16 @@ export default function GolfWatchAppGaming1v1({
problemTitle,
problemDescription,
sampleCode,
- gameResult,
}: Props) {
+ const gameStateKind = useAtomValue(gameStateKindAtom);
const leftTimeSeconds = useAtomValue(gamingLeftTimeSecondsAtom)!;
const latestGameStates = useAtomValue(latestGameStatesAtom);
- const stateA = latestGameStates[`${playerProfileA.id}`];
+ const stateA = latestGameStates[`${playerProfileA.id}`] ?? null;
const codeA = stateA?.code ?? "";
const scoreA = stateA?.score ?? null;
const statusA = stateA?.status ?? "none";
- const stateB = latestGameStates[`${playerProfileB.id}`];
+ const stateB = latestGameStates[`${playerProfileB.id}`] ?? null;
const codeB = stateB?.code ?? "";
const scoreB = stateB?.score ?? null;
const statusB = stateB?.status ?? "none";
@@ -50,10 +51,12 @@ export default function GolfWatchAppGaming1v1({
const codeSizeA = calcCodeSize(codeA);
const codeSizeB = calcCodeSize(codeB);
- const topBg = gameResult
- ? gameResult === "winA"
+ const gameResultKind = checkGameResultKind(gameStateKind, stateA, stateB);
+
+ const topBg = gameResultKind
+ ? gameResultKind === "winA"
? "bg-orange-400"
- : gameResult === "winB"
+ : gameResultKind === "winB"
? "bg-purple-400"
: "bg-sky-600"
: "bg-sky-600";
@@ -76,11 +79,11 @@ export default function GolfWatchAppGaming1v1({
</div>
<div className="font-bold text-center">
<div className="text-gray-100">{gameDisplayName}</div>
- {gameResult ? (
+ {gameResultKind ? (
<div className="text-3xl">
- {gameResult === "winA"
+ {gameResultKind === "winA"
? `勝者 ${playerProfileA.displayName}`
- : gameResult === "winB"
+ : gameResultKind === "winB"
? `勝者 ${playerProfileB.displayName}`
: "引き分け"}
</div>
diff --git a/frontend/app/states/watch.ts b/frontend/app/states/watch.ts
index 8c7faa7..2c255f4 100644
--- a/frontend/app/states/watch.ts
+++ b/frontend/app/states/watch.ts
@@ -93,3 +93,35 @@ export function calcCodeSize(code: string): number {
const utf8Encoded = new TextEncoder().encode(trimmed);
return utf8Encoded.length;
}
+
+export type GameResultKind = "winA" | "winB" | "draw";
+
+export function checkGameResultKind(
+ gameStateKind: GameStateKind,
+ stateA: LatestGameState | null,
+ stateB: LatestGameState | null,
+): GameResultKind | null {
+ if (gameStateKind !== "finished") {
+ return null;
+ }
+
+ const scoreA = stateA?.score;
+ const scoreB = stateB?.score;
+ if (scoreA == null && scoreB == null) {
+ return "draw";
+ }
+ if (scoreA == null) {
+ return "winB";
+ }
+ if (scoreB == null) {
+ return "winA";
+ }
+ if (scoreA === scoreB) {
+ // If score is non-null, state and best_score_submitted_at should also be non-null.
+ const submittedAtA = stateA!.best_score_submitted_at!;
+ const submittedAtB = stateB!.best_score_submitted_at!;
+ return submittedAtA < submittedAtB ? "winA" : "winB";
+ } else {
+ return scoreA < scoreB ? "winA" : "winB";
+ }
+}