Obiettivi cliccabili con card di dettaglio; presenze del mese sui convocati
Ogni obiettivo di squadra apre un drawer che spiega come si calcola, cosa conta, cosa è una presenza persa, cosa resta fuori, periodo, fonte dei dati ed esempio. «90% di presenze del mese» usa ora i convocati dell'evento come posti (tutta la rosa se non ce ne sono), come le presenze collettive: chi non è convocato non abbassa più la percentuale. Test unit, card e integrazione; docs aggiornate. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6b8cc33512
commit
c2c3b249f2
10 files changed
+779
-73
No files matched your search
@@ -15,6 +15,9 @@ versioni `0.y.z` erano pre-release.
|
||||
|
||||
### Aggiunto
|
||||
|
||||
- **Obiettivi cliccabili** — toccando un obiettivo (in Squadra o nella card della Home) si apre una card che
|
||||
spiega tutto: come si calcola, cosa conta e cosa no, periodo di validità, fonte dei dati, un esempio. Nessuna
|
||||
migration.
|
||||
- **Notifica di compleanno** — ogni giorno, dalle 8:00, il festeggiato riceve un messaggio di auguri e tutti gli altri membri
|
||||
attivi, allenatori compresi, il solo avviso «Oggi è il compleanno di …»; con più compleanni lo stesso giorno un solo
|
||||
messaggio a testa. Push, centro notifiche ed email. Il 29 febbraio non è gestito (DD-047, issue #11). Migration
|
||||
@@ -22,6 +25,8 @@ versioni `0.y.z` erano pre-release.
|
||||
|
||||
### Modificato
|
||||
|
||||
- **Obiettivo «90% di presenze del mese»** — i posti sono i convocati di ogni partita e allenamento (tutta la rosa se
|
||||
non ce ne sono), come nelle presenze collettive: chi non è convocato non abbassa più la percentuale. Nessuna migration.
|
||||
- **Obiettivo «1 evento di squadra al mese»** — si completa quando arriva l'ora dell'evento, non appena viene
|
||||
creato. Un evento futuro non conta finché la sua data e ora non sono passate. Nessuna migration.
|
||||
- **Obiettivo «Presenze collettive»** — sostituisce «250 presenze complessive»: è la percentuale di presenze di tutta la
|
||||
|
||||
@@ -39,7 +39,7 @@ corrente dinamico (vedi sotto).
|
||||
|
||||
| id | Obiettivo | Calcolo | Target | Fonte |
|
||||
| ----- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ---------------------------------- |
|
||||
| `o1` | 90% presenze del mese | risposte presente/ritardo su partite+allenamenti del mese corrente (dinamico) | 90% | `risposte_presenze` |
|
||||
| `o1` | 90% presenze del mese | presente/ritardo su partite+allenamenti del mese corrente; posti = convocati dell'evento, tutta la rosa se vuoto (dinamico) | 90% | `risposte_presenze` |
|
||||
| `o2` | Tutti rispondono alle convocazioni | risposte totali / eventi possibili (esclusi i compleanni) | 90% | `risposte_presenze` |
|
||||
| `o7` | Presenze collettive | % di presenze (presente/ritardo) su tutti gli allenamenti e le partite definiti, passati e futuri; posti = convocati dell'evento (tutta la rosa se vuoto) | 90 | `eventi_app` + `risposte_presenze` |
|
||||
| `o12` | Media pagelle da 7.5 | media di tutti i voti, arrotondata a una cifra decimale | 7.5 | `pagelle_voti` |
|
||||
@@ -51,7 +51,12 @@ corrente dinamico (vedi sotto).
|
||||
| `o6` | 1 evento di squadra al mese | eventi di tipo "evento" nel mese corrente la cui data e ora sono già passate (dinamico) | 1 | `eventi_app` |
|
||||
|
||||
Mostrati in `squadra.tsx` (elenco completo con barra di progresso) e in `index.tsx` (home: il
|
||||
primo obiettivo non completato). Un obiettivo che supera il 90% genera anche una notifica
|
||||
primo obiettivo non completato).
|
||||
Ogni obiettivo è **cliccabile**: apre la card di dettaglio (`ObiettivoDrawer`, stesso drawer dei
|
||||
badge) con stato attuale, come si calcola, cosa conta e cosa no, quando vale, da dove arrivano i
|
||||
dati e un esempio con numeri. Per le due percentuali di presenze (`o1`, `o7`) la card distingue «Presenza persa» (assente, forse, infortunato, nessuna risposta: il posto resta vuoto) da «Non entra nel calcolo» (cene, eventi di squadra, compleanni). I testi stanno nel campo `dettaglio` di ogni obiettivo in
|
||||
`obiettivi.ts`: chi cambia il calcolo o il target di un obiettivo aggiorna anche il suo
|
||||
`dettaglio`, altrimenti la card mente. Un obiettivo che supera il 90% genera anche una notifica
|
||||
smart (`notifiche-smart.ts`). I target fissi (200 pagelle, 7.5 di media, 1/5/10
|
||||
vittorie) sono scelte editoriali da rivedere a mano a ogni stagione — nessuna configurazione o
|
||||
UI per farlo, si cambia il numero in `obiettivi.ts`. Fa eccezione "Continuità di squadra"
|
||||
@@ -75,8 +80,9 @@ passaggio a completato compare al refresh successivo.
|
||||
|
||||
`o7` ("Presenze collettive") invece **non** si azzera: copre tutta la stagione, cioè tutti gli
|
||||
allenamenti e le partite in calendario, passati e futuri (le risposte sugli eventi futuri sono
|
||||
conferme). Differisce da `o1` per periodo (stagione, non mese) e perché i posti sono i convocati
|
||||
di ciascun evento, non sempre l'intera rosa. Non c'è un confine di stagione esplicito: conta ciò
|
||||
conferme). Differisce da `o1` solo per il periodo (stagione, non mese): anche in `o1` i posti sono i
|
||||
convocati di ciascun evento, così chi non è convocato non pesa; con la stessa funzione
|
||||
`percentualePresenze()`. Non c'è un confine di stagione esplicito: conta ciò
|
||||
che c'è in `eventi_app`.
|
||||
|
||||
`o2` ("Tutti rispondono alle convocazioni") non si azzera — aggrega su tutti gli eventi in
|
||||
@@ -156,14 +162,22 @@ Dettagli completi (endpoint, identificativi di stagione, altri limiti del colleg
|
||||
Tutti e 10 gli obiettivi hanno unit test **e** integration test end-to-end (dati scritti/letti
|
||||
da un backend reale, non solo funzione pura con contesto costruito a mano).
|
||||
|
||||
| Obiettivi | Unit test | Integration test |
|
||||
| ---------- | ----------------------------- | -------------------------------------------------------- |
|
||||
| o1, o2, o6 | `test/unit/obiettivi.test.ts` | `test/integration/obiettivi.test.ts` (Supabase locale) |
|
||||
| o7 | `test/unit/obiettivi.test.ts` | `test/integration/obiettivi.test.ts` (Supabase locale) |
|
||||
| o11 | `test/unit/obiettivi.test.ts` | `test/integration/obiettivi.test.ts` (Supabase locale) |
|
||||
| o12, o13 | `test/unit/obiettivi.test.ts` | `test/integration/obiettivi.test.ts` (Supabase locale) |
|
||||
| o3, o4, o5 | `test/unit/obiettivi.test.ts` | `test/integration/api.test.ts` (CSI reale in produzione) |
|
||||
| Obiettivi | Unit test | Integration test |
|
||||
| ---------- | ----------------------------- | -------------------------------------------------------------------------------- |
|
||||
| o1, o2, o6 | `test/unit/obiettivi.test.ts` | `test/integration/obiettivi.test.ts` (Supabase locale, o1 anche con i convocati) |
|
||||
| o7 | `test/unit/obiettivi.test.ts` | `test/integration/obiettivi.test.ts` (Supabase locale) |
|
||||
| o11 | `test/unit/obiettivi.test.ts` | `test/integration/obiettivi.test.ts` (Supabase locale) |
|
||||
| o12, o13 | `test/unit/obiettivi.test.ts` | `test/integration/obiettivi.test.ts` (Supabase locale) |
|
||||
| o3, o4, o5 | `test/unit/obiettivi.test.ts` | `test/integration/api.test.ts` (CSI reale in produzione) |
|
||||
|
||||
- **Presenze (o1, o7), casi limite** (`test/unit/obiettivi.test.ts`): solo partite e allenamenti
|
||||
contano, assente/forse/infortunato/nessuna risposta sono posti vuoti, il non convocato non pesa,
|
||||
confine di mese nel fuso Europe/Rome, convocato fuori rosa, rosa vuota, arrotondamento e soglia
|
||||
del 90%. Verificato anche con mutazioni (posti = tutta la rosa; eventi di squadra contati): il test
|
||||
diventa rosso.
|
||||
- **Card di dettaglio** (`test/unit/obiettivi-dettaglio.test.ts`): ogni obiettivo ha tutti i testi,
|
||||
«Presenza persa» solo su o1/o7, la card renderizzata mostra tutte le sezioni e lo stato
|
||||
in corso/completato.
|
||||
- **o1/o2/o6** (Supabase locale): scrive eventi e risposte veri su `eventi_app`/
|
||||
`risposte_presenze`, li rilegge con `leggiEventi()` (la stessa funzione server dell'app) e una
|
||||
query REST equivalente a `fetchPresenze()`. Copre: contesto vuoto, aggregazione su più eventi,
|
||||
|
||||
Reference in new issue
Block a user