Avvisi in Home: componente condiviso, più leggibili; turno palloni ridisegnato
Certificati e turno palloni usano lo stesso componente Avviso: icona propria per ogni caso (il colore non è l'unico segnale), testo più grande, elenchi di persone in righe con dettaglio a destra e conteggio, freccia sulle card cliccabili, comparsa graduale. Il turno palloni ha la pillola «Oggi»/«In arrivo» e i messaggi in riquadri. Solo aspetto: testi e regole di comparsa invariati. Test del componente, CHANGELOG, ARCHITECTURE e test/README aggiornati. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
e7ae2c1884
commit
519f9aaff4
7 files changed
+258
-74
No files matched your search
+1
-1
@@ -26,7 +26,7 @@ la consegna effettiva a schermo bloccato richiede un telefono e il servizio push
|
||||
|
||||
| Cartella | Cosa verifica | Serve rete? |
|
||||
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- |
|
||||
| `unit/` | Logica di dominio pura: badge, serie, palloni, pagelle, MVP, cacche, scout, obiettivi (calcolo e card di dettaglio), notifiche, parsing CSI, dati della rosa. Più le funzioni pure isolabili nei moduli con hook/rete (validazione upload, guardie push, JWT VAPID, cattura errori, avatar, guardia admin delle route, lettura del `.env` ed elenco dei bucket dello script di backup, logica del worker in `mailer/` (email e push dei promemoria), preferenza «Email» e avviso del sondaggio) | No |
|
||||
| `unit/` | Logica di dominio pura: badge, serie, palloni, pagelle, MVP, cacche, scout, obiettivi (calcolo e card di dettaglio), avvisi in Home, notifiche, parsing CSI, dati della rosa. Più le funzioni pure isolabili nei moduli con hook/rete (validazione upload, guardie push, JWT VAPID, cattura errori, avatar, guardia admin delle route, lettura del `.env` ed elenco dei bucket dello script di backup, logica del worker in `mailer/` (email e push dei promemoria), preferenza «Email» e avviso del sondaggio) | No |
|
||||
| `integration/` | Le route `/api/public/*` sul server di sviluppo: risposte, cache, validazione degli input. Più schema e permessi del Profilo Giocatore (`schema-profili`) contro il database configurato; permessi per ruolo, incluse le policy di M11, le deroghe dell'amministratore e le tabelle lasciate aperte di proposito (`permessi`), accesso alle route di notifica (`permessi-route`), semantica degli upsert e vincoli (`scritture`), le letture lato server delle route push (`lettori-server`) e la pulizia a cascata dei dati collegati alla cancellazione di un evento (`pulizia-evento`, M14) la funzione di bonifica delle righe orfane (`bonifica-evento`, M16), il centro notifiche in-app (`notifiche-utente`, M17), la coda delle email e le sue funzioni RPC (`notifiche-email`, M22), i promemoria evento che non ricompaiono se eliminati (`promemoria-eventi`, M23), la coda delle push dei promemoria (`push-promemoria`, M24), i job automatici di turno palloni e sollecito presenze con revoca, finestre e testi identici al codice (`notifiche-automatiche`, M26-M28 e M30, DD-040, DD-042, DD-043 e DD-045: palloni un solo avviso a 3 ore, sollecito uno solo a 24 ore, nessun promemoria evento) la colonna `foto_path` eliminata (`foto-tessera-rimossa`, M29, DD-044) e il sondaggio in-app/email (`sondaggio-notifiche`, M24), i destinatari delle notifiche per ruolo (`destinatari-notifiche`: promemoria, messaggio dello staff, sondaggio, sollecito e turno palloni con allenatore e giocatore), gli avvisi di compleanno con ora, più compleanni lo stesso giorno, registro e 29 febbraio (`notifiche-compleanno`, M31, DD-047), la nascita pubblica sincronizzata dal profilo (`nascita-pubblica`, M18) e il suo backfill per i profili preesistenti (`backfill-nascita-esistenti`, M19 — unico test che esegue SQL diretto via `docker exec` nel container Postgres, perché PostgREST non espone quell'update multi-tabella come RPC) sul database locale | Sì |
|
||||
| `e2e/` | Percorsi completi sull'app servita: schermate, dati CSI fino alla pagina, file PWA, 404 | Sì |
|
||||
| `helpers/` | Avvio del server di test e mini-harness condiviso | — |
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/** Check del componente degli avvisi in Home: `bun test/unit/avviso.test.ts`. */
|
||||
import assert from "node:assert/strict";
|
||||
import { createElement } from "react";
|
||||
import { renderToStaticMarkup } from "react-dom/server";
|
||||
import { CalendarClock, FileX } from "lucide-react";
|
||||
import { CorpoAvviso, type TonoAvviso } from "@/components/crapp/Avviso";
|
||||
|
||||
const html = (p: Parameters<typeof CorpoAvviso>[0]) =>
|
||||
renderToStaticMarkup(createElement(CorpoAvviso, p));
|
||||
|
||||
// --- ogni tono ha il suo colore, e l'icona è decorativa (il titolo dice già tutto) ---
|
||||
const classi: Record<TonoAvviso, string> = {
|
||||
critico: "bg-destructive",
|
||||
attenzione: "bg-warning",
|
||||
scaduto: "bg-primary",
|
||||
azione: "bg-accent-grad",
|
||||
};
|
||||
for (const [tono, classe] of Object.entries(classi) as [TonoAvviso, string][]) {
|
||||
const h = html({ tono, icona: FileX, titolo: "Titolo" });
|
||||
assert.ok(h.includes(classe), `${tono}: classe colore ${classe}`);
|
||||
assert.ok(h.includes("Titolo"), `${tono}: titolo`);
|
||||
assert.ok(h.includes('aria-hidden="true"'), `${tono}: icona nascosta ai lettori di schermo`);
|
||||
}
|
||||
|
||||
// --- testi: un paragrafo per frase ---------------------------------------------------
|
||||
const conTesti = html({
|
||||
tono: "attenzione",
|
||||
icona: CalendarClock,
|
||||
titolo: "Certificato in scadenza",
|
||||
testi: ["Prima frase.", "Seconda frase."],
|
||||
});
|
||||
assert.equal((conTesti.match(/<p /g) ?? []).length, 3, "titolo + due paragrafi");
|
||||
assert.ok(!conTesti.includes("<ul"), "senza elenco niente lista");
|
||||
|
||||
// --- elenco: righe chi/cosa, conteggio solo con più di una riga ----------------------
|
||||
const una = html({
|
||||
tono: "critico",
|
||||
icona: FileX,
|
||||
titolo: "Certificati mancanti",
|
||||
elenco: [{ chi: "Mario Rossi", cosa: "non caricato" }],
|
||||
});
|
||||
assert.ok(una.includes("Mario Rossi") && una.includes("non caricato"), "riga con chi e cosa");
|
||||
assert.ok(!una.includes("persone"), "una sola riga: nessun conteggio");
|
||||
|
||||
const tre = html({
|
||||
tono: "critico",
|
||||
icona: FileX,
|
||||
titolo: "Certificati mancanti",
|
||||
elenco: [
|
||||
{ chi: "Mario Rossi", cosa: "non caricato" },
|
||||
{ chi: "Luca Bianchi", cosa: "non caricato" },
|
||||
{ chi: "Anna Verdi", cosa: "non caricato" },
|
||||
],
|
||||
});
|
||||
assert.equal((tre.match(/<li /g) ?? []).length, 3, "una riga per persona");
|
||||
assert.ok(tre.includes('aria-label="3 persone"'), "conteggio accessibile");
|
||||
|
||||
// --- freccia solo se la card porta altrove -------------------------------------------
|
||||
const base = { tono: "scaduto", icona: FileX, titolo: "t" } as const;
|
||||
assert.ok(!html(base).includes("lucide-chevron-right"), "senza link niente freccia");
|
||||
assert.ok(
|
||||
html({ ...base, cliccabile: true }).includes("lucide-chevron-right"),
|
||||
"con link la freccia",
|
||||
);
|
||||
|
||||
// --- etichetta e riquadri (turno palloni) --------------------------------------------
|
||||
const palloni = html({
|
||||
tono: "azione",
|
||||
icona: FileX,
|
||||
titolo: "Turno palloni",
|
||||
etichetta: "Oggi",
|
||||
testi: ["Porta i palloni."],
|
||||
riquadri: true,
|
||||
});
|
||||
assert.ok(palloni.includes("Oggi"), "etichetta mostrata");
|
||||
assert.ok(palloni.includes("bg-black/15"), "il messaggio è in un riquadro");
|
||||
assert.ok(palloni.includes("bg-black/25"), "etichetta in pillola");
|
||||
assert.ok(!html({ ...base }).includes("bg-black/25"), "senza etichetta niente pillola");
|
||||
assert.ok(
|
||||
!html({ ...base, testi: ["x"] }).includes("bg-black/15"),
|
||||
"senza riquadri testo semplice",
|
||||
);
|
||||
|
||||
console.log("avviso: ok");
|
||||
Reference in new issue
Block a user