diff --git a/docs/modules/serie-presenze.md b/docs/modules/serie-presenze.md index c563b4c..8d06285 100644 --- a/docs/modules/serie-presenze.md +++ b/docs/modules/serie-presenze.md @@ -137,9 +137,10 @@ Onorato = lo stato salvato è `presente` **o** `ritardo`. Gli stati possibili so Conseguenze da conoscere prima di cambiare qualcosa: -- **`infortunato` azzera la serie**, esattamente come `assente`. Coerente con il conteggio - presenze, ma è una scelta da rivedere se si vuole "congelare" la serie di chi è fermo per - infortunio. +- **`infortunato` congela la serie**: l'evento è escluso a monte (filtrato prima di + `serieSu()`), quindi non conta né come presenza né come buco — la serie resta al valore + di prima. Diverso da `contaPresenzeGiocatore()`, che continua a non contarlo come + presenza (stesso criterio `presente`/`ritardo` di prima, invariato). - **Nessuna risposta azzera la serie.** Un evento passato per cui il giocatore non ha mai toccato l'app equivale a un'assenza. È voluto (la serie premia anche il rispondere), ma significa che eventi storici importati senza presenze schiacciano a zero le serie di tutti. @@ -281,9 +282,10 @@ il costo diventerebbe per-render e andrebbe stabilizzata a monte. - **Cambiare i traguardi di una serie** → l'array `traguardi` in `serieDefs`. Devono restare crescenti (un test lo verifica) e non serve altro: progresso e messaggi si adeguano. -- **Cambiare la regola di presenza** (per esempio non azzerare su `infortunato`) → il - predicato dentro `serieConsecutiva()`. Valutare se allineare anche - `contaPresenzeGiocatore()`, che oggi usa lo stesso criterio. +- **Cambiare la regola di presenza** → il predicato dentro `serieConsecutiva()`. + `infortunato` è già escluso a monte (congela la serie, non la azzera); valutare se + allineare anche `contaPresenzeGiocatore()`, che oggi conta ancora `infortunato` come + assenza ai fini statistici. - **Non azzerare quando manca la risposta** → sempre in quel predicato: distinguere `stato === undefined` e restituire la serie invariata invece di `false`. Richiede di cambiare `serieSu()`, che oggi conosce solo "onorato sì/no". diff --git a/src/lib/presenze.ts b/src/lib/presenze.ts index ba0cd14..e24d4c8 100644 --- a/src/lib/presenze.ts +++ b/src/lib/presenze.ts @@ -68,6 +68,9 @@ export function destinatariSollecito( * Serie di presenze consecutive su eventi già passati, in ordine di data: * ogni presenza (o ritardo) vale +1, qualsiasi altra risposta — o nessuna * risposta — azzera la serie. Senza `tipo` conta partite e allenamenti insieme. + * + * Chi risulta infortunato non ci ha rinunciato: quell'evento è saltato, non conta + * né come presenza né come assenza, e la serie resta congelata al valore di prima. */ export function serieConsecutiva( giocatoreId: string, @@ -76,10 +79,16 @@ export function serieConsecutiva( tipo?: "partita" | "allenamento", oggi: string = oggiIso(), ): number { - return serieSu(giocatoreId, eventi, oggi, tipo, (e) => { - const stato = presenze[e.id]?.[giocatoreId]; - return stato === "presente" || stato === "ritardo"; - }); + return serieSu( + giocatoreId, + eventi.filter((e) => presenze[e.id]?.[giocatoreId] !== "infortunato"), + oggi, + tipo, + (e) => { + const stato = presenze[e.id]?.[giocatoreId]; + return stato === "presente" || stato === "ritardo"; + }, + ); } const ORE_24 = 24 * 60 * 60 * 1000; diff --git a/test/unit/presenze.test.ts b/test/unit/presenze.test.ts index 925bcde..a07534e 100644 --- a/test/unit/presenze.test.ts +++ b/test/unit/presenze.test.ts @@ -62,6 +62,28 @@ assert.equal(serieConsecutiva("g2", eventi, presenze, "allenamento", OGGI), 0); const conConvocati = [...eventi, ev("a6", "allenamento", "2026-08-30", ["g9"])]; assert.equal(serieConsecutiva("g1", conConvocati, presenze, "allenamento", OGGI), 2); +// L'infortunio congela la serie invece di azzerarla come farebbe un'assenza. +const eventiInfortunio: Evento[] = [ + ev("i1", "allenamento", "2026-08-06"), + ev("i2", "allenamento", "2026-08-13"), + ev("i3", "allenamento", "2026-08-20"), +]; +const presenzeInfortunio: MappaPresenze = { + i1: { g1: "presente" }, + i2: { g1: "infortunato" }, + i3: { g1: "presente" }, +}; +assert.equal( + serieConsecutiva("g1", eventiInfortunio, presenzeInfortunio, "allenamento", OGGI), + 2, + "l'infortunio è saltato: i1 e i3 restano consecutivi", +); +assert.equal( + serieConsecutiva("g1", eventiInfortunio.slice(0, 2), presenzeInfortunio, "allenamento", OGGI), + 1, + "l'infortunio come ultimo evento lascia la serie congelata, non la azzera", +); + // --- conteggio presenze: numeratore e denominatore delle statistiche ---------- // a1 presente, a2 assente, a3 ritardo, a4 presente, p1 presente: 4 su 5 passati. assert.equal(contaPresenzeGiocatore("g1", eventi, presenze, OGGI), 4, "il ritardo conta presente");