- Modello: tipo sugli slot, inRosa() al posto del filtro su attivo in tutte le
letture della rosa di gioco (presenze, convocati, voti, palloni, classifiche,
badge, sollecito); gli allenatori restano solo nei compleanni e in Squadra.
- Permessi: user_roles letto una volta per tutti i ruoli; usePuoGestireEventi()
apre /eventi e il sollecito presenze anche all'allenatore, lato server con
richiediGestoreEventi(). Palloni, sondaggio e messaggi restano all'admin.
- Identità: useGiocatoreInCampo() è null per l'allenatore, così non risponde alle
presenze e non vota; useSonoAllenatore() decide cosa si vede.
- Profilo: per l'allenatore solo Docs (nome, cognome, nascita, telefono, email) e
Opzioni; card avatar e tab Opzioni estratte per riusarle.
- Home, Squadra e partita: niente statistiche personali, badge, cacche e
obiettivi per l'allenatore; in Rosa compare con la dicitura «Allenatore».
- Admin: tipo in «Aggiungi», allenatori a parte in Profili, fuori da conteggi ed
export CSI.
Test unit su rosa di gioco e completamento, route test sull'allenatore.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
In /eventi, sopra la lista cronologica c'è ora una griglia mensile
(condivisa con /calendario tramite le nuove funzioni pure di
src/lib/calendario.ts): ogni giorno è cliccabile e apre un drawer con
gli eventi di quel giorno, da cui si crea, modifica o elimina un
evento. Ogni azione resta raggiungibile in un solo modo: rimosso il
bottone "Nuovo evento" e le icone matita/cestino della lista sotto,
che ora si limita a mostrare gli eventi e ad aprire lo stesso drawer
del giorno al click su una riga.
Il campo "Luogo" di un nuovo evento parte vuoto invece che precompilato
con "Palestra Comunale".
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
npx eslint --fix su test/unit/obiettivi.test.ts, test/integration/obiettivi.test.ts,
BarraSottosezioni.tsx, EventoCard.tsx e calendario.tsx — solo formattazione,
nessuna modifica di comportamento. Verificato con la suite unit (32/32 verde).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
LinkProfilo (header di ogni pagina) e il Calendario (compleanni del mese) usavano
useIo/useRosa, che calcola MVP, pagelle, cacche, palloni e infortuni per l'intera
squadra tramite 6 hook e un useMemo pesante - anche se a entrambi serviva solo
id/nome/nascita/iniziali. Il Calendario in particolare pagava questo costo ad ogni
apertura solo per i compleanni del mese.
- crapp-data.ts: esporta inizialiDa, già usata internamente per il fallback avatar.
- ui-bits.tsx: LinkProfilo usa useGiocatoreBase (sola anagrafica) invece di useIo.
- rosa.ts: nuovo hook useAnagraficaRosa (id, nome, nascita) senza gli altri 5 hook
statistici ne' il useMemo su tutta la rosa.
- eventi.ts: compleanniEventi accetta solo i tre campi che usa, non l'intero
Giocatore.
- calendario.tsx: usa useAnagraficaRosa al posto di useRosa.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- squadra.tsx e classifica.tsx: il contenuto di ogni tab di BarraSottosezioni è ora
memoizzato con useMemo, cosi' uno stato locale o un refetch in background non
ricalcolano piu' anche le sezioni nascoste.
- BottomNav, BarraSottosezioni, calendario: useMotoRidotto (RAM bassa o
prefers-reduced-motion) disattiva sui device deboli la catena di filtri SVG piu'
pesante di .vetro, il backdrop-blur della barra tab e il drag orizzontale;
su iOS e device performanti resta tutto invariato.
- styles.css: rimossa l'utility .materiale, orfana da quando BottomNav e' passata
a .vetro.
- ui-bits.tsx: decoding="async" su TeamLogo.
- todo.md: traccia le cause individuate e lo stato di applicazione di ciascuna.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Regressione mia, introdotta con lo swipe in 9b28a86: la griglia è avvolta in
un `overflow-hidden` che serve a nascondere il mese che entra ed esce di lato.
L'anello del giorno corrente però è `ring-2 ring-offset-1`, quindi disegna 3 px
FUORI dai bordi della cella: sulla prima riga quei 3 px cadono oltre il bordo
del riquadro di ritaglio e vengono tagliati. Sarebbe successo lo stesso
sull'ultima riga e sulle colonne di bordo, se oggi fosse caduto di lunedì o di
domenica.
`p-1` sul contenitore che ritaglia dà all'anello i suoi 4 px di aria dentro il
riquadro; `-mx-1` e `mt-1` al posto di `mt-2` rimettono la griglia esattamente
dov'era, quindi le celle non si spostano di un pixel: cambia solo dove passa il
bordo di ritaglio.
Non si può usare `overflow-x: hidden` da solo: in CSS, se un asse è `hidden` e
l'altro `visible`, quello visibile diventa `auto` e ritaglia comunque, per
giunta creando uno scroll container.
Scartato anche `ring-inset`, che non può essere tagliato per costruzione: nei
giorni in cui oggi coincide con un evento l'anello scuro finirebbe appiccicato
al colore pieno, senza lo stacco bianco che ha adesso.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Avevo sostituito la cella divisa con fondo neutro e puntini colorati. Si
perdeva l'informazione a colpo d'occhio: il colore dice subito che tipo di
impegno c'è, i puntini vanno cercati.
Torna la resa di main: `linear-gradient(135deg, …)` con gli stop duplicati,
che non è una sfumatura ma bande a taglio netto in diagonale, una per tipo. Il
conteggio resta per **tipo** e non per numero di eventi: due partite nello
stesso giorno restano una cella rossa piena, si divide solo se i tipi sono
diversi.
`coloreTipo` sale a livello di modulo: era ricostruito per ogni cella, cioè
una trentina di volte per mese a ogni render.
Nota sul contrasto, per chi tornerà qui. Il numero sta direttamente sulle
bande con un alone bianco in `drop-shadow`, ed è una scelta di resa esplicita:
il colore deve restare pieno fino al bordo. Ha un costo, però, perché nel
frattempo success e training sono stati scuriti da 0.62 a 0.53 per far passare
il testo bianco dei chip: il numero scuro sulle bande scende da 5.6:1 a 3.9:1
sul blu e da 5.7:1 a 4.0:1 sul verde. Se un giorno la leggibilità dà fastidio,
la leva è una parola — `text-foreground` -> testo bianco sulle sole celle
divise, che risale a ~4.9:1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Calendario: il mese si cambiava solo con due frecce da 36 px. Ora si scorre,
e il punto d'arrivo si sceglie proiettando la velocità di rilascio invece che
dalla posizione del dito, così un colpo secco «lancia» il mese. La griglia
entra ed esce dallo stesso lato del gesto, `dragElastic` dà resistenza
progressiva al bordo al posto di uno stop netto.
Le celle con più tipi di evento generavano un gradiente a fette e ci mettevano
sopra un'ombra bianca sul numero per tenerlo leggibile: un cerotto su un
problema di contrasto. Ora fondo neutro e un puntino per tipo, con il numero
sempre su superficie piena. L'etichetta accessibile dice quanti eventi ci
sono, non solo che ce ne sono.
Profilo: le quattro switch «Notifiche convocazioni», «Promemoria allenamenti»,
«Cambi orario» e «Bacheca squadra» erano `defaultChecked` e non facevano
niente — promettevano una funzione che non esiste. Via anche la conferma
nativa prima di *cambiare* la foto: non è un'azione distruttiva, e chiedere
conferma per tutto insegna a rispondere sì senza leggere. Resta su quella che
la rimuove, che è irreversibile.
Home: la sezione «Da confermare» mostrava titolo e contenitore vuoto quando
non c'era altro da confermare, mentre tutte le altre sezioni hanno un empty
state.
Squadra: i badge in riga avevano solo `title=`, che su touch non appare mai —
aggiunto il testo per gli screen reader. I filtri per criterio erano alti
~26 px.
Più, in tutte le schermate: la primitiva `Card` al posto delle classi
ripetute, i bersagli sotto i 44 px portati in misura e il floor tipografico a
12 px.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
convocatiEvento() e compleanniEventi() prendono ora la rosa come parametro
invece di leggere la lista statica; csvScoutMatch() idem. Le schermate di
gestione eventi, dettaglio allenamento/partita, calendario e scout live,
più i widget di presenze/pagelle/voto MVP/voto social/sondaggio
cacche/turno palloni, passano tutte la rosa letta da useRosa() o
useGiocatoriSquadra(): un giocatore aggiunto o disattivato dalla dashboard
admin ora si riflette ovunque.
La classifica e lo storico partite mostravano dati inventati (squadre e
risultati finti) come base, poi sovrascritti dai dati CSI quando
disponibili. Ora classifica, ultimi risultati, storico match e obiettivi
di squadra legati alle vittorie usano solo dati reali (CSI o scout live),
con stati vuoti quando i dati CSI non sono ancora disponibili.
Include anche la correzione di tutti gli errori di formattazione
prettier segnalati da `npm run lint` sul resto del codice sorgente.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
useMeseNav aveva un default hardcoded (anno 2026, mese 7) invece di
calcolare oggi. Chiunque apra /calendario finiva sempre su agosto
2026, indipendentemente dalla data reale.
Co-Authored-By: Claude Mythos <noreply@anthropic.com>
Implementa la voce "Dashboard amministratore" della roadmap v1.1, come descritta
in docs/modules/profilo-giocatore.md, insieme alla parte di profilo che la
alimenta.
- /admin: stato dei profili della squadra, download di documento, certificato e
foto tessera, export CSV con i 12 campi del tesseramento CSI. Un certificato
scaduto non conta come valido.
- Profilo giocatore: dati personali, documento (fronte e retro), certificato e
foto tessera, con widget di completamento in Home che sparisce al 100%.
- I permessi di amministrazione arrivano da user_roles (DD-011) e non più dalla
lista di nomi in crapp-data.ts, che resta come ponte finché
VITE_AUTH_OBBLIGATORIA non viene acceso in produzione.
- Login Google via Supabase Auth: al primo accesso l'account si collega a uno
slot libero di giocatori_squadra, e il vincolo lo fa rispettare il trigger di
M1 (DD-016 regola 2).
Migration additive: M2 crea profili_giocatore, M3 il bucket privato
profili-giocatore. Nessuna tabella v1.0 viene toccata, quindi si possono
applicare senza cambiare il comportamento attuale dell'app.
supabase/config.toml e seed.sql configurano lo stack locale: serve perché il
progetto Supabase è uno solo, condiviso tra sviluppo e produzione.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>