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
|
import { atom } from "jotai";
import type { components } from "../api/schema";
const gameStartedAtAtom = atom<number | null>(null);
export const setGameStartedAtAtom = atom(null, (_, set, value: number | null) =>
set(gameStartedAtAtom, value),
);
export type GameStateKind =
| "loading"
| "waiting"
| "starting"
| "gaming"
| "finished";
type LatestGameState = components["schemas"]["LatestGameState"];
type RankingEntry = components["schemas"]["RankingEntry"];
export const gameStateKindAtom = atom<GameStateKind>((get) => {
const startedAt = get(gameStartedAtAtom);
if (!startedAt) {
return "waiting";
}
const now = get(currentTimestampAtom);
if (!now) {
return "loading";
}
const durationSeconds = get(durationSecondsAtom);
const finishedAt = startedAt + durationSeconds;
if (now < startedAt) {
return "starting";
} else if (now < finishedAt) {
return "gaming";
} else {
return "finished";
}
});
const currentTimestampAtom = atom<number | null>(null);
export const setCurrentTimestampAtom = atom(null, (_, set) =>
set(currentTimestampAtom, Math.floor(Date.now() / 1000)),
);
const durationSecondsAtom = atom<number>(0);
export const setDurationSecondsAtom = atom(null, (_, set, value: number) =>
set(durationSecondsAtom, value),
);
export const startingLeftTimeSecondsAtom = atom<number | null>((get) => {
const startedAt = get(gameStartedAtAtom);
if (startedAt === null) {
return null;
}
const currentTimestamp = get(currentTimestampAtom);
if (currentTimestamp === null) {
return null;
}
return Math.max(0, startedAt - currentTimestamp);
});
export const gamingLeftTimeSecondsAtom = atom<number | null>((get) => {
const startedAt = get(gameStartedAtAtom);
if (startedAt === null) {
return null;
}
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));
});
export const rankingAtom = atom<RankingEntry[]>([]);
const rawLatestGameStatesAtom = atom<{
[key: string]: LatestGameState | undefined;
}>({});
export const latestGameStatesAtom = atom((get) => get(rawLatestGameStatesAtom));
export const setLatestGameStatesAtom = atom(
null,
(_, set, value: { [key: string]: LatestGameState | undefined }) => {
set(rawLatestGameStatesAtom, value);
},
);
|