fix: handle server behavior around reconnects, fix fetching reservations
This commit is contained in:
@@ -23,6 +23,8 @@ export default function PlayPage() {
|
|||||||
role,
|
role,
|
||||||
username,
|
username,
|
||||||
status,
|
status,
|
||||||
|
isInMatch,
|
||||||
|
shouldGoFirst,
|
||||||
send,
|
send,
|
||||||
subscribe,
|
subscribe,
|
||||||
reconnectAttempts,
|
reconnectAttempts,
|
||||||
@@ -86,13 +88,25 @@ export default function PlayPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (status === "connected" && gamePhase === "idle") {
|
if (status === "connected" && gamePhase === "idle") {
|
||||||
setGamePhase("connected");
|
// Mid-match reconnect can remount with phase idle while still in a match; avoid
|
||||||
|
// the pre-queue "connected" / Ready Up state until we know we are not in-game.
|
||||||
|
setGamePhase(isInMatch ? "playing" : "connected");
|
||||||
|
if (isInMatch) {
|
||||||
|
const color: 1 | 2 = shouldGoFirst ? 1 : 2;
|
||||||
|
setMyColor(color);
|
||||||
|
myColorRef.current = color;
|
||||||
|
|
||||||
|
setIsMyTurn(shouldGoFirst);
|
||||||
|
isMyTurnRef.current = shouldGoFirst;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
role,
|
role,
|
||||||
status,
|
status,
|
||||||
router,
|
router,
|
||||||
gamePhase,
|
gamePhase,
|
||||||
|
isInMatch,
|
||||||
shouldRedirectToConnect,
|
shouldRedirectToConnect,
|
||||||
clearRedirectFlag,
|
clearRedirectFlag,
|
||||||
]);
|
]);
|
||||||
@@ -102,7 +116,11 @@ export default function PlayPage() {
|
|||||||
switch (msg.type) {
|
switch (msg.type) {
|
||||||
case "CONNECT_ACK":
|
case "CONNECT_ACK":
|
||||||
case "RECONNECT_ACK":
|
case "RECONNECT_ACK":
|
||||||
setGamePhase((prev) => (prev === "idle" ? "connected" : prev));
|
setGamePhase((prev) => {
|
||||||
|
if (prev !== "idle") return prev;
|
||||||
|
if (isInMatch) return "playing";
|
||||||
|
return "connected";
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ERROR":
|
case "ERROR":
|
||||||
@@ -193,7 +211,7 @@ export default function PlayPage() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return unsubscribe;
|
return unsubscribe;
|
||||||
}, [resetGame, send, subscribe]);
|
}, [resetGame, send, subscribe, isInMatch, username]);
|
||||||
|
|
||||||
const handleColumnClick = useCallback(
|
const handleColumnClick = useCallback(
|
||||||
(col: number) => {
|
(col: number) => {
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ export default function AdminSettingsPanel() {
|
|||||||
break;
|
break;
|
||||||
case "RESERVATION_LIST":
|
case "RESERVATION_LIST":
|
||||||
setReservations(message.reservations);
|
setReservations(message.reservations);
|
||||||
|
setActionFeedback("Loaded reservations.");
|
||||||
break;
|
break;
|
||||||
case "RESERVATION_ADD":
|
case "RESERVATION_ADD":
|
||||||
setReservations((prev) => {
|
setReservations((prev) => {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ interface ConnectionContextValue {
|
|||||||
username: string;
|
username: string;
|
||||||
status: ConnectionStatus;
|
status: ConnectionStatus;
|
||||||
isInMatch: boolean;
|
isInMatch: boolean;
|
||||||
|
shouldGoFirst: boolean;
|
||||||
isAdmin: boolean;
|
isAdmin: boolean;
|
||||||
reconnectAttempts: number;
|
reconnectAttempts: number;
|
||||||
shouldRedirectToConnect: boolean;
|
shouldRedirectToConnect: boolean;
|
||||||
@@ -70,6 +71,7 @@ export function ConnectionProvider({
|
|||||||
const [username, setUsername] = useState("");
|
const [username, setUsername] = useState("");
|
||||||
const [status, setStatus] = useState<ConnectionStatus>("idle");
|
const [status, setStatus] = useState<ConnectionStatus>("idle");
|
||||||
const [isInMatch, setIsInMatch] = useState(false);
|
const [isInMatch, setIsInMatch] = useState(false);
|
||||||
|
const [shouldGoFirst, setShouldGoFirst] = useState(false);
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
const [reconnectAttempts, setReconnectAttempts] = useState(0);
|
const [reconnectAttempts, setReconnectAttempts] = useState(0);
|
||||||
const [shouldRedirectToConnect, setShouldRedirectToConnect] = useState(false);
|
const [shouldRedirectToConnect, setShouldRedirectToConnect] = useState(false);
|
||||||
@@ -81,6 +83,7 @@ export function ConnectionProvider({
|
|||||||
const reconnectDeadlineRef = useRef<number | null>(null);
|
const reconnectDeadlineRef = useRef<number | null>(null);
|
||||||
const reconnectActiveRef = useRef(false);
|
const reconnectActiveRef = useRef(false);
|
||||||
const isInMatchRef = useRef(false);
|
const isInMatchRef = useRef(false);
|
||||||
|
const shouldGoFirstRef = useRef(false);
|
||||||
const sessionRef = useRef<SessionState | null>(null);
|
const sessionRef = useRef<SessionState | null>(null);
|
||||||
|
|
||||||
const clearReconnectTimer = useCallback(() => {
|
const clearReconnectTimer = useCallback(() => {
|
||||||
@@ -202,6 +205,8 @@ export function ConnectionProvider({
|
|||||||
if (parsed.type === "GAME_START") {
|
if (parsed.type === "GAME_START") {
|
||||||
isInMatchRef.current = true;
|
isInMatchRef.current = true;
|
||||||
setIsInMatch(true);
|
setIsInMatch(true);
|
||||||
|
shouldGoFirstRef.current = parsed.goesFirst;
|
||||||
|
setShouldGoFirst(parsed.goesFirst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -377,6 +382,7 @@ export function ConnectionProvider({
|
|||||||
username,
|
username,
|
||||||
status,
|
status,
|
||||||
isInMatch,
|
isInMatch,
|
||||||
|
shouldGoFirst,
|
||||||
isAdmin,
|
isAdmin,
|
||||||
reconnectAttempts,
|
reconnectAttempts,
|
||||||
shouldRedirectToConnect,
|
shouldRedirectToConnect,
|
||||||
@@ -394,6 +400,7 @@ export function ConnectionProvider({
|
|||||||
username,
|
username,
|
||||||
status,
|
status,
|
||||||
isInMatch,
|
isInMatch,
|
||||||
|
shouldGoFirst,
|
||||||
isAdmin,
|
isAdmin,
|
||||||
reconnectAttempts,
|
reconnectAttempts,
|
||||||
shouldRedirectToConnect,
|
shouldRedirectToConnect,
|
||||||
|
|||||||
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
/// <reference path="./.next/types/routes.d.ts" />
|
import "./.next/dev/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@@ -10,7 +14,7 @@
|
|||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "react-jsx",
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
@@ -18,10 +22,20 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./*"]
|
"@/*": [
|
||||||
|
"./*"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"target": "ES2017"
|
"target": "ES2017"
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": [
|
||||||
"exclude": ["node_modules"]
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
".next/dev/types/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user