Chiude il sondaggio cacche al fischio d'inizio, non solo il giorno dopo
sondaggioAperto() restava aperto per sempre una volta passate le 8:00 del giorno della partita, anche nei giorni successivi. Ora chiude esattamente all'ora di inizio (partita alle 21:00 → aperto fino alle 20:59, poi chiuso anche nei giorni seguenti), richiedendo anche l'ora dell'evento oltre alla data. Aggiunta sondaggioTerminato() per distinguere nel messaggio "non ancora aperto" da "già chiuso": altrimenti dopo la partita l'utente avrebbe continuato a leggere "apre alle 8:00". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -38,9 +38,9 @@ Prima versione, pre-release.
|
|||||||
della partita, e può usarlo chiunque sia autenticato: uno per volta, grazie al lock.
|
della partita, e può usarlo chiunque sia autenticato: uno per volta, grazie al lock.
|
||||||
- Votazione MVP legata all'evento CrAPP e non al referto CSI o allo Scout: si apre due ore
|
- Votazione MVP legata all'evento CrAPP e non al referto CSI o allo Scout: si apre due ore
|
||||||
dopo `data`+`ora` della partita, anche senza risultato caricato — [modules/mvp.md](modules/mvp.md).
|
dopo `data`+`ora` della partita, anche senza risultato caricato — [modules/mvp.md](modules/mvp.md).
|
||||||
- Sondaggio pre-partita con apertura programmata alle 8:00 del giorno della partita e
|
- Sondaggio pre-partita aperto dalle 8:00 del giorno della partita fino al fischio d'inizio
|
||||||
pulsante «Avvisa tutti del sondaggio» per gli amministratori
|
(poi resta chiuso, anche nei giorni successivi) e pulsante «Avvisa tutti del sondaggio» per
|
||||||
(`POST /api/public/apri-sondaggio`); nessun cron, l'invio è manuale.
|
gli amministratori (`POST /api/public/apri-sondaggio`); nessun cron, l'invio è manuale.
|
||||||
- Turni palloni con rotazione automatica sulle partite e assegnazione manuale per gli
|
- Turni palloni con rotazione automatica sulle partite e assegnazione manuale per gli
|
||||||
allenamenti, che restano «da assegnare» finché non si sceglie (migration M10).
|
allenamenti, che restano «da assegnare» finché non si sceglie (migration M10).
|
||||||
- Notifiche push con il testo cifrato **dentro** la push (`aes128gcm`, RFC 8291), così
|
- Notifiche push con il testo cifrato **dentro** la push (`aes128gcm`, RFC 8291), così
|
||||||
|
|||||||
@@ -7,7 +7,13 @@ import { nomeCompleto, useGiocatoriSquadra } from "@/lib/giocatori-squadra";
|
|||||||
import { useGiocatoreCorrente } from "@/lib/user-store";
|
import { useGiocatoreCorrente } from "@/lib/user-store";
|
||||||
import { intestazioniAutenticate } from "@/lib/auth";
|
import { intestazioniAutenticate } from "@/lib/auth";
|
||||||
import { useIsAdmin } from "@/lib/ruoli";
|
import { useIsAdmin } from "@/lib/ruoli";
|
||||||
import { mediaPartita, sondaggioAperto, useCacche, useSalvaCacche } from "@/lib/cacche";
|
import {
|
||||||
|
mediaPartita,
|
||||||
|
sondaggioAperto,
|
||||||
|
sondaggioTerminato,
|
||||||
|
useCacche,
|
||||||
|
useSalvaCacche,
|
||||||
|
} from "@/lib/cacche";
|
||||||
|
|
||||||
const opzioni = [0, 1, 2, 3, 4, 5];
|
const opzioni = [0, 1, 2, 3, 4, 5];
|
||||||
|
|
||||||
@@ -15,9 +21,11 @@ const opzioni = [0, 1, 2, 3, 4, 5];
|
|||||||
export function SondaggioCacche({
|
export function SondaggioCacche({
|
||||||
eventoId,
|
eventoId,
|
||||||
dataEvento,
|
dataEvento,
|
||||||
|
oraEvento,
|
||||||
}: {
|
}: {
|
||||||
eventoId: string;
|
eventoId: string;
|
||||||
dataEvento: string;
|
dataEvento: string;
|
||||||
|
oraEvento: string;
|
||||||
}) {
|
}) {
|
||||||
const io = useGiocatoreCorrente();
|
const io = useGiocatoreCorrente();
|
||||||
const { righe } = useCacche();
|
const { righe } = useCacche();
|
||||||
@@ -69,14 +77,16 @@ export function SondaggioCacche({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sondaggioAperto(dataEvento)) {
|
if (!sondaggioAperto(dataEvento, oraEvento)) {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<p className="text-xs font-bold uppercase tracking-wide text-muted-foreground">
|
<p className="text-xs font-bold uppercase tracking-wide text-muted-foreground">
|
||||||
💩 Sondaggio pre-partita
|
💩 Sondaggio pre-partita
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs text-muted-foreground">
|
<p className="mt-1 text-xs text-muted-foreground">
|
||||||
Apre alle 8:00 del giorno della partita: riceverai una notifica.
|
{sondaggioTerminato(dataEvento, oraEvento)
|
||||||
|
? "Sondaggio chiuso: era aperto fino al fischio d'inizio."
|
||||||
|
: "Apre alle 8:00 del giorno della partita: riceverai una notifica."}
|
||||||
</p>
|
</p>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
+33
-4
@@ -5,11 +5,40 @@ import { oggiISO } from "./palloni-core";
|
|||||||
/** Ora di apertura del sondaggio, il giorno stesso della partita. */
|
/** Ora di apertura del sondaggio, il giorno stesso della partita. */
|
||||||
export const ORA_APERTURA_SONDAGGIO = 8;
|
export const ORA_APERTURA_SONDAGGIO = 8;
|
||||||
|
|
||||||
/** Il sondaggio apre alle 8:00 del giorno della partita e da lì resta aperto. */
|
/** Istante del fischio d'inizio: `oraEvento` mancante equivale a fine giornata (non chiude mai prima). */
|
||||||
export function sondaggioAperto(dataEvento: string, adesso = new Date()): boolean {
|
function inizioPartita(dataEvento: string, oraEvento: string): number {
|
||||||
|
return new Date(`${dataEvento}T${oraEvento || "23:59"}:00`).getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Il sondaggio apre alle 8:00 del giorno della partita e chiude al fischio d'inizio. */
|
||||||
|
export function sondaggioAperto(
|
||||||
|
dataEvento: string,
|
||||||
|
oraEvento: string,
|
||||||
|
adesso = new Date(),
|
||||||
|
): boolean {
|
||||||
|
if (dataEvento !== oggiISO(adesso)) return false;
|
||||||
|
const apertura = new Date(`${dataEvento}T00:00:00`);
|
||||||
|
apertura.setHours(ORA_APERTURA_SONDAGGIO, 0, 0, 0);
|
||||||
|
return (
|
||||||
|
adesso.getTime() >= apertura.getTime() &&
|
||||||
|
adesso.getTime() < inizioPartita(dataEvento, oraEvento)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* True se il fischio d'inizio è già passato (oggi o in un giorno precedente): serve a
|
||||||
|
* distinguere, nel messaggio mostrato quando il sondaggio è chiuso, "non ancora aperto"
|
||||||
|
* da "già chiuso" — altrimenti dopo la partita si continuerebbe a dire "apre alle 8:00".
|
||||||
|
*/
|
||||||
|
export function sondaggioTerminato(
|
||||||
|
dataEvento: string,
|
||||||
|
oraEvento: string,
|
||||||
|
adesso = new Date(),
|
||||||
|
): boolean {
|
||||||
const oggi = oggiISO(adesso);
|
const oggi = oggiISO(adesso);
|
||||||
if (dataEvento !== oggi) return dataEvento < oggi;
|
if (dataEvento < oggi) return true;
|
||||||
return adesso.getHours() >= ORA_APERTURA_SONDAGGIO;
|
if (dataEvento > oggi) return false;
|
||||||
|
return adesso.getTime() >= inizioPartita(dataEvento, oraEvento);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sondaggio goliardico pre-partita: quante cacche prima del match di campionato. */
|
/** Sondaggio goliardico pre-partita: quante cacche prima del match di campionato. */
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ function PartitaDetail() {
|
|||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Section titolo="Sondaggio pre-partita">
|
<Section titolo="Sondaggio pre-partita">
|
||||||
<SondaggioCacche eventoId={evento.id} dataEvento={evento.data} />
|
<SondaggioCacche eventoId={evento.id} dataEvento={evento.data} oraEvento={evento.ora} />
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{match ? (
|
{match ? (
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
mediaStagione,
|
mediaStagione,
|
||||||
recordStagione,
|
recordStagione,
|
||||||
sondaggioAperto,
|
sondaggioAperto,
|
||||||
|
sondaggioTerminato,
|
||||||
statisticheCacche,
|
statisticheCacche,
|
||||||
type RigaCacche,
|
type RigaCacche,
|
||||||
} from "@/lib/cacche";
|
} from "@/lib/cacche";
|
||||||
@@ -54,11 +55,67 @@ assert.deepEqual(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// --- sondaggioAperto ---------------------------------------------------------
|
// --- sondaggioAperto ---------------------------------------------------------
|
||||||
const alle = (h: number, m = 0) => new Date(2026, 8, 5, h, m); // 5 settembre 2026
|
// Partita del 5 settembre 2026 alle 21:00.
|
||||||
assert.equal(sondaggioAperto("2026-09-05", alle(7, 59)), false, "prima delle 8 è chiuso");
|
const alle = (h: number, m = 0) => new Date(2026, 8, 5, h, m);
|
||||||
assert.equal(sondaggioAperto("2026-09-05", alle(8)), true, "alle 8 in punto apre");
|
const ORA_PARTITA = "21:00";
|
||||||
assert.equal(sondaggioAperto("2026-09-05", alle(23)), true);
|
|
||||||
assert.equal(sondaggioAperto("2026-09-06", alle(23)), false, "partita di domani: chiuso");
|
assert.equal(
|
||||||
assert.equal(sondaggioAperto("2026-09-04", alle(0, 1)), true, "partita passata: resta aperto");
|
sondaggioAperto("2026-09-05", ORA_PARTITA, alle(7, 59)),
|
||||||
|
false,
|
||||||
|
"prima delle 8 è chiuso",
|
||||||
|
);
|
||||||
|
assert.equal(sondaggioAperto("2026-09-05", ORA_PARTITA, alle(8)), true, "alle 8 in punto apre");
|
||||||
|
assert.equal(
|
||||||
|
sondaggioAperto("2026-09-05", ORA_PARTITA, alle(20, 59)),
|
||||||
|
true,
|
||||||
|
"un minuto prima del fischio d'inizio è ancora aperto",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
sondaggioAperto("2026-09-05", ORA_PARTITA, alle(21, 0)),
|
||||||
|
false,
|
||||||
|
"al fischio d'inizio si chiude",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
sondaggioAperto("2026-09-05", ORA_PARTITA, alle(23)),
|
||||||
|
false,
|
||||||
|
"dopo l'inizio resta chiuso per il resto della giornata",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
sondaggioAperto("2026-09-06", ORA_PARTITA, alle(23)),
|
||||||
|
false,
|
||||||
|
"partita di domani: chiuso",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
sondaggioAperto("2026-09-04", ORA_PARTITA, alle(0, 1)),
|
||||||
|
false,
|
||||||
|
"partita passata: chiuso anche nei giorni successivi",
|
||||||
|
);
|
||||||
|
|
||||||
|
// --- sondaggioTerminato: distingue "non ancora aperto" da "già chiuso" -------
|
||||||
|
assert.equal(
|
||||||
|
sondaggioTerminato("2026-09-05", ORA_PARTITA, alle(7, 59)),
|
||||||
|
false,
|
||||||
|
"prima dell'apertura: non ancora aperto, non terminato",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
sondaggioTerminato("2026-09-05", ORA_PARTITA, alle(20, 59)),
|
||||||
|
false,
|
||||||
|
"in corso: non ancora terminato",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
sondaggioTerminato("2026-09-05", ORA_PARTITA, alle(21, 0)),
|
||||||
|
true,
|
||||||
|
"al fischio d'inizio: terminato",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
sondaggioTerminato("2026-09-06", ORA_PARTITA, alle(23)),
|
||||||
|
false,
|
||||||
|
"partita di domani: non ancora, non terminato",
|
||||||
|
);
|
||||||
|
assert.equal(
|
||||||
|
sondaggioTerminato("2026-09-04", ORA_PARTITA, alle(0, 1)),
|
||||||
|
true,
|
||||||
|
"partita passata: terminato",
|
||||||
|
);
|
||||||
|
|
||||||
console.log("cacche: ok");
|
console.log("cacche: ok");
|
||||||
|
|||||||
Reference in New Issue
Block a user