Expire a scout session whose timestamp cannot be read.
sessioneScaduta compared Date.now() against NaN when aggiornato_il was not a valid date, and every comparison with NaN is false: the session was reported as still active, so the Scout Live table stayed locked to a player who could no longer release it. An unreadable timestamp now frees the session, which is the safe direction: at worst someone takes over a scouting session that was already unattended. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+13
-3
@@ -24,7 +24,10 @@ export type SessioneScout = {
|
||||
|
||||
export function sessioneScaduta(s: SessioneScout | null): boolean {
|
||||
if (!s) return true;
|
||||
return Date.now() - new Date(s.aggiornato_il).getTime() > SCADENZA_MINUTI * 60_000;
|
||||
const aggiornato = new Date(s.aggiornato_il).getTime();
|
||||
// Timestamp illeggibile: meglio liberare la sessione che lasciarla bloccata per sempre.
|
||||
if (Number.isNaN(aggiornato)) return true;
|
||||
return Date.now() - aggiornato > SCADENZA_MINUTI * 60_000;
|
||||
}
|
||||
|
||||
const storageKey = (eventoId: string) => `crap-scout-session-${eventoId}`;
|
||||
@@ -82,7 +85,10 @@ export function useSessioneScout(eventoId: string | null) {
|
||||
} catch {
|
||||
const onStorage = (e: StorageEvent) => {
|
||||
if (e.key === storageKey(eventoId)) {
|
||||
queryClient.setQueryData(SESSIONE_KEY(eventoId), e.newValue ? (JSON.parse(e.newValue) as SessioneScout) : null);
|
||||
queryClient.setQueryData(
|
||||
SESSIONE_KEY(eventoId),
|
||||
e.newValue ? (JSON.parse(e.newValue) as SessioneScout) : null,
|
||||
);
|
||||
}
|
||||
};
|
||||
window.addEventListener("storage", onStorage);
|
||||
@@ -140,7 +146,11 @@ export function useChiudiSessioneScout() {
|
||||
}
|
||||
|
||||
/** Mantiene viva la sessione mentre lo scout è aperto. */
|
||||
export function useHeartbeatScout(eventoId: string | null, giocatoreId: string | null, attivo: boolean) {
|
||||
export function useHeartbeatScout(
|
||||
eventoId: string | null,
|
||||
giocatoreId: string | null,
|
||||
attivo: boolean,
|
||||
) {
|
||||
useEffect(() => {
|
||||
if (!attivo || !eventoId || !giocatoreId || typeof window === "undefined") return;
|
||||
const id = window.setInterval(() => {
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
/** Check della sessione Scout Live: `bun test/unit/scout-live.test.ts`. */
|
||||
import assert from "node:assert/strict";
|
||||
import type { Evento } from "@/lib/eventi";
|
||||
import {
|
||||
SCADENZA_MINUTI,
|
||||
dataOggi,
|
||||
partitaDiOggi,
|
||||
sessioneScaduta,
|
||||
type SessioneScout,
|
||||
} from "@/lib/scout-live";
|
||||
|
||||
const evento = (id: string, data: string, tipo: Evento["tipo"]): Evento => ({
|
||||
id,
|
||||
tipo,
|
||||
titolo: id,
|
||||
luogo: "",
|
||||
data,
|
||||
ora: "21:00",
|
||||
note: "",
|
||||
convocati: [],
|
||||
campionato: true,
|
||||
casa: true,
|
||||
pagelleChiuse: false,
|
||||
});
|
||||
|
||||
// --- dataOggi ----------------------------------------------------------------
|
||||
assert.match(dataOggi(), /^\d{4}-\d{2}-\d{2}$/);
|
||||
assert.equal(dataOggi(), new Date().toLocaleDateString("sv-SE"), "data locale, non UTC");
|
||||
|
||||
// --- partitaDiOggi -----------------------------------------------------------
|
||||
const eventi = [
|
||||
evento("a1", "2026-09-01", "allenamento"),
|
||||
evento("p1", "2026-09-01", "partita"),
|
||||
evento("p2", "2026-09-02", "partita"),
|
||||
];
|
||||
assert.equal(partitaDiOggi(eventi, "2026-09-01")?.id, "p1", "l'allenamento non si scoutizza");
|
||||
assert.equal(partitaDiOggi(eventi, "2026-09-03"), null, "nessuna partita oggi");
|
||||
assert.equal(partitaDiOggi([], "2026-09-01"), null);
|
||||
|
||||
// --- sessioneScaduta: libera il tavolo dopo SCADENZA_MINUTI ------------------
|
||||
const sessione = (minutiFa: number): SessioneScout => ({
|
||||
evento_id: "p1",
|
||||
giocatore_id: "g1",
|
||||
giocatore_nome: "Tizio",
|
||||
aggiornato_il: new Date(Date.now() - minutiFa * 60_000).toISOString(),
|
||||
});
|
||||
|
||||
assert.equal(sessioneScaduta(null), true, "nessuna sessione = tavolo libero");
|
||||
assert.equal(sessioneScaduta(sessione(0)), false, "appena aggiornata");
|
||||
assert.equal(sessioneScaduta(sessione(SCADENZA_MINUTI - 1)), false, "dentro la finestra");
|
||||
assert.equal(sessioneScaduta(sessione(SCADENZA_MINUTI + 1)), true, "oltre la finestra");
|
||||
assert.equal(
|
||||
sessioneScaduta({ ...sessione(0), aggiornato_il: "data-non-valida" }),
|
||||
true,
|
||||
"timestamp illeggibile: meglio liberare la sessione che bloccarla",
|
||||
);
|
||||
|
||||
console.log("scout-live: ok");
|
||||
Reference in New Issue
Block a user