Avviso certificati: mostra anche chi non l'ha caricato (DD-046), versione 1.2.3

Il giocatore senza certificato vede una card rossa cliccabile, l'admin
l'elenco dei mancanti sopra scaduti e in scadenza. Nessuna migration.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5.5 committed 2026-10-04 14:15:17 +02:00
1 parent 008f0d784c
commit f49351e536
11 files changed
+164 -51

No files matched your search

+9
View File
@@ -13,6 +13,15 @@ versioni `0.y.z` erano pre-release.
## [Non rilasciato]
## [1.2.3] - 2026-10-04
Nella Home si vede anche chi non ha caricato il certificato medico. Nessuna migration.
### Modificato
- **Avviso certificati mancanti** — nella Home chi non ha caricato il certificato medico compare in una card rossa:
il giocatore vede il proprio avviso, l'admin l'elenco di chi manca, sopra scaduti e in scadenza (DD-046).
## [1.2.2] - 2026-10-01
Meno notifiche automatiche e un profilo più snello: gli avvisi dei palloni e delle presenze partono una sola volta, il
+3 -3
View File
@@ -38,9 +38,9 @@ Tutto quello che è rilasciato, fino alla versione 1.0.0 (vedi `CHANGELOG.md`).
calcolata dal CSI
- [x] Ruolo allenatore — gestisce gli eventi e sollecita le presenze, profilo ridotto senza
stagione e badge ([specifica](modules/allenatore.md), DD-034)
- [x] Avviso certificati in scadenza — in Home, giallo nei 7 giorni prima e nero dopo la
scadenza: agli admin con i nomi dei giocatori, al giocatore solo per il proprio
([specifica](modules/profilo-giocatore.md#avviso-certificati), DD-035)
- [x] Avviso certificati in scadenza — in Home, giallo nei 7 giorni prima, nero dopo la
scadenza e rosso se il certificato manca (DD-046): agli admin con i nomi dei giocatori, al giocatore solo per il proprio
([specifica](modules/profilo-giocatore.md#avviso-certificati), DD-035, DD-046)
- [x] Notifiche email — ogni notifica in-app inviata anche per email agli account registrati,
da un worker Docker sull'host di casa via Gmail, con interruttore «Email» in Profilo
([specifica](modules/notifiche-email.md), DD-036)
+3 -2
View File
@@ -1,7 +1,7 @@
# DD-035 — Avviso certificati: calcolato in Home, visibile solo al titolare e agli admin
**Data:** 24 settembre 2026
**Stato:** Accettata (implementata, versione 1.1.0). La soglia del giocatore è stata alzata a 30 giorni da [DD-041](DD-041.md); quella dello staff resta 7.
**Stato:** Accettata (implementata, versione 1.1.0). La soglia del giocatore è stata alzata a 30 giorni da [DD-041](DD-041.md); quella dello staff resta 7. [DD-046](DD-046.md) aggiunge l'avviso per chi non ha caricato il certificato.
**Contesto**
Il certificato medico ha una data di scadenza (`profili_giocatore.certificato_scadenza`), ma
@@ -40,7 +40,8 @@ certificato viene rinnovato. Specifica completa in
esiste per nessuna push (DD-025), e le push vanno riservate agli eventi importanti
([EFFICIENZA_CLOUD.md](../EFFICIENZA_CLOUD.md)).
- Includere i certificati mancanti → è un problema diverso (profilo incompleto), già coperto
dal widget «Completa il tuo profilo» e dalla tab Profili.
dal widget «Completa il tuo profilo» e dalla tab Profili. _Superata da [DD-046](DD-046.md):
anche i mancanti hanno un avviso, rosso._
**Conseguenze**
+33
View File
@@ -0,0 +1,33 @@
# DD-046 — Avviso certificati: anche chi non l'ha caricato
**Data:** 4 ottobre 2026
**Stato:** Accettata (modifica [DD-035](DD-035.md): il certificato mancante non è più escluso dall'avviso)
**Contesto**
L'avviso certificati di DD-035 guarda solo la scadenza e salta chi non ha mai caricato il
certificato («è un problema diverso»). Per l'admin significa che chi non ha caricato nulla non
compare in Home, pur essendo un caso più grave di uno scaduto.
**Decisione**
1. Un giocatore in rosa **senza data o senza file** del certificato è **mancante**.
2. L'**admin** vede la card rossa «Certificati mancanti» con l'elenco, **sopra** scaduti e in
scadenza; il suo nome non compare se è anche giocatore.
3. Il **giocatore** mancante vede la card rossa «Certificato mancante», cliccabile verso il tab
documenti. Vale anche per l'admin che è giocatore.
4. Nessuna soglia: l'avviso resta finché il certificato non è caricato. Il rosso è `destructive`,
già nel tema; giallo e nero degli altri avvisi non cambiano.
**Alternative scartate**
- Stesso nero degli scaduti → non distingue «scaduto» da «mai caricato», che è più grave.
- Solo elenco admin → l'admin che è anche giocatore sarebbe l'unico a non vedere il proprio buco.
**Conseguenze**
- `avvisiCertificati()` restituisce anche `mancanti`; `avvisiCertificatiUtente()` anche
`personaleMancante`.
- Un giocatore appena entrato in rosa compare tra i mancanti finché non carica il file.
**Riesame**
Se i giocatori nuovi riempiono l'elenco senza motivo, aggiungere un periodo di tolleranza.
+1
View File
@@ -86,6 +86,7 @@ Una decisione sostituita non si cancella: si cambia il suo **Stato** e si rimand
| [DD-038](DD-038.md) | Tre canali per ogni notifica |
| [DD-039](DD-039.md) | Niente promemoria all'allenatore |
| [DD-040](DD-040.md) | Palloni e solleciti automatici |
| [DD-046](DD-046.md) | Avviso certificati mancanti |
| [DD-045](DD-045.md) | Sollecito presenze: un solo avviso a 24 ore |
| [DD-044](DD-044.md) | Via la foto tessera dal profilo |
| [DD-043](DD-043.md) | Niente promemoria evento a 24 e 3 ore |
+20 -18
View File
@@ -117,12 +117,12 @@ staff.
| Giocatore | `GIORNI_AVVISO_CERTIFICATO_GIOCATORE = 30` |
| Admin | `GIORNI_AVVISO_CERTIFICATO = 7` |
| Condizione | Stato | Avviso |
| --------------------- | ----------- | ------------------ |
| `giorni > soglia` | valido | nessuno |
| `0 ≤ giorni ≤ soglia` | in scadenza | giallo (`warning`) |
| `giorni < 0` | scaduto | nero (`primary`) |
| data o file mancanti | mancante | nessuno |
| Condizione | Stato | Avviso |
| --------------------- | ----------- | ------------------------------ |
| `giorni > soglia` | valido | nessuno |
| `0 ≤ giorni ≤ soglia` | in scadenza | giallo (`warning`) |
| `giorni < 0` | scaduto | nero (`primary`) |
| data o file mancanti | mancante | rosso (`destructive`) (DD-046) |
Esempio: scadenza il 5 ottobre 2026. Dal 5 settembre l'avviso giallo compare solo al
giocatore; dal 28 settembre anche agli admin; dal 6 ottobre è nero per entrambi.
@@ -130,8 +130,10 @@ giocatore; dal 28 settembre anche agli admin; dal 6 ottobre è nero per entrambi
- Il giorno della scadenza il certificato vale ancora, coerente con `statoScadenza()`: il
giocatore compare nel giallo con «scade oggi» e passa al nero dal giorno dopo.
- L'avviso nero resta finché il giocatore non aggiorna la data: non c'è un limite di tempo.
- Il certificato **mancante** non genera avviso: è un problema diverso, già visibile nella
tab Profili di `/admin` e nel widget di completamento del giocatore.
- Il certificato **mancante** (nessuna data o nessun file) ha un avviso rosso, più grave dello
scaduto (DD-046): il giocatore vede «Certificato mancante» (cliccabile, porta ai documenti),
l'admin la card «Certificati mancanti» con l'elenco, in cima alle altre, senza il proprio
nome. Non ha soglie: resta finché il file non è caricato.
- Sono esclusi i giocatori disattivati e gli allenatori: conta solo la rosa (`inRosa()`,
cioè `attivo` e `tipo = 'giocatore'`).
@@ -190,16 +192,16 @@ la Home non deve rompersi per un dato accessorio.
#### Implementazione
| Pezzo | Ruolo |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GIORNI_AVVISO_CERTIFICATO` (`profili-core.ts`) | la soglia dello staff, 7 |
| `GIORNI_AVVISO_CERTIFICATO_GIOCATORE` | la soglia del giocatore, 30 (DD-041) |
| `giorniAllaScadenza(scadenza, oggi)` | differenza in giorni di calendario tra due date `AAAA-MM-GG`, negativa se scaduto |
| `avvisiCertificati(rosa, profili, oggi, soglia)` | funzione pura (`soglia` di default 7): restituisce `{ scaduti, inScadenza }`, ognuno una lista ordinata di `{ giocatoreId, nome, cognome, scadenza, giorni }` |
| `avvisiCertificatiUtente(rosa, profili, oggi, utente)` | funzione pura: `{ personale, staff }` per chi guarda; l'admin giocatore ha entrambi, senza il suo nome nello staff (DD-041) |
| `testoScadenza(giorni)` | «scade oggi» / «scade domani» / «scade tra N giorni» |
| `src/components/crapp/AvvisoCertificati.tsx` | legge `useGiocatoriSquadra()`, `useProfili()`, `useIsAdmin()` e l'utente corrente; sceglie avviso dello staff o personale e disegna le card |
| `src/routes/index.tsx` | monta `<AvvisoCertificati />` subito dopo `<PromemoriaPalloni />` |
| Pezzo | Ruolo |
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GIORNI_AVVISO_CERTIFICATO` (`profili-core.ts`) | la soglia dello staff, 7 |
| `GIORNI_AVVISO_CERTIFICATO_GIOCATORE` | la soglia del giocatore, 30 (DD-041) |
| `giorniAllaScadenza(scadenza, oggi)` | differenza in giorni di calendario tra due date `AAAA-MM-GG`, negativa se scaduto |
| `avvisiCertificati(rosa, profili, oggi, soglia)` | funzione pura (`soglia` di default 7): restituisce `{ scaduti, inScadenza, mancanti }`; le prime due sono liste ordinate di `{ giocatoreId, nome, cognome, scadenza, giorni }`, `mancanti` di `{ giocatoreId, nome, cognome }` (DD-046) |
| `avvisiCertificatiUtente(rosa, profili, oggi, utente)` | funzione pura: `{ personale, personaleMancante, staff }` per chi guarda; l'admin giocatore ha entrambi, senza il suo nome nello staff (DD-041) |
| `testoScadenza(giorni)` | «scade oggi» / «scade domani» / «scade tra N giorni» |
| `src/components/crapp/AvvisoCertificati.tsx` | legge `useGiocatoriSquadra()`, `useProfili()`, `useIsAdmin()` e l'utente corrente; sceglie avviso dello staff o personale e disegna le card |
| `src/routes/index.tsx` | monta `<AvvisoCertificati />` subito dopo `<PromemoriaPalloni />` |
- "Oggi" viene da `oggiISO()` (`palloni-core.ts`), in ora locale. Non da
`new Date().toISOString()`, che è in UTC e tra mezzanotte e le 2 darebbe il giorno prima.