Avviso certificati mancanti (DD-046), dipendenze aggiornate, 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. Aggiorna @tanstack/react-start alla 1.168.60 (con router, plugin e query) e chiude le vulnerabilità di npm audit: Vercel bloccava il deploy con la 1.168.34. Il tipo di error in __root.tsx diventa unknown, come nel nuovo tipo di TanStack. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
008f0d784c
commit
7347fdba6e
13 files changed
+422
-2102
No files matched your search
@@ -18,7 +18,7 @@ function Card({
|
||||
righe,
|
||||
cliccabile,
|
||||
}: {
|
||||
colore: "warning" | "primary";
|
||||
colore: "warning" | "primary" | "destructive";
|
||||
titolo: string;
|
||||
righe: string[];
|
||||
cliccabile?: boolean;
|
||||
@@ -26,7 +26,9 @@ function Card({
|
||||
const classi = `mx-5 mt-4 block rounded-3xl p-4 shadow-pop ${
|
||||
colore === "warning"
|
||||
? "bg-warning text-warning-foreground"
|
||||
: "bg-primary text-primary-foreground"
|
||||
: colore === "destructive"
|
||||
? "bg-destructive text-destructive-foreground"
|
||||
: "bg-primary text-primary-foreground"
|
||||
} ${cliccabile ? "premi" : ""}`;
|
||||
const contenuto = (
|
||||
<>
|
||||
@@ -50,7 +52,7 @@ function Card({
|
||||
}
|
||||
|
||||
/**
|
||||
* Avviso certificati in scadenza/scaduti (DD-035, DD-041): calcolato al volo, niente push.
|
||||
* Avviso certificati mancanti/scaduti/in scadenza (DD-035, DD-041, DD-046): calcolato al volo, niente push.
|
||||
* Il giocatore lo vede da 30 giorni prima della scadenza, lo staff da 7.
|
||||
*/
|
||||
export function AvvisoCertificati() {
|
||||
@@ -65,8 +67,18 @@ export function AvvisoCertificati() {
|
||||
const oggi = oggiISO();
|
||||
|
||||
// Admin che è anche giocatore: vede il proprio avviso a 30 giorni e quello dello staff (DD-041).
|
||||
const { personale, staff } = avvisiCertificatiUtente(rosa, profili, oggi, { admin, base });
|
||||
const cardPersonale = personale ? (
|
||||
const { personale, personaleMancante, staff } = avvisiCertificatiUtente(rosa, profili, oggi, {
|
||||
admin,
|
||||
base,
|
||||
});
|
||||
const cardPersonale = personaleMancante ? (
|
||||
<Card
|
||||
colore="destructive"
|
||||
titolo="Certificato mancante"
|
||||
cliccabile
|
||||
righe={["Non hai ancora caricato il certificato medico: caricalo nei documenti"]}
|
||||
/>
|
||||
) : personale ? (
|
||||
personale.giorni < 0 ? (
|
||||
<Card
|
||||
colore="primary"
|
||||
@@ -87,10 +99,17 @@ export function AvvisoCertificati() {
|
||||
) : null;
|
||||
|
||||
if (!staff) return cardPersonale;
|
||||
const { scaduti, inScadenza } = staff;
|
||||
const { scaduti, inScadenza, mancanti } = staff;
|
||||
return (
|
||||
<>
|
||||
{cardPersonale}
|
||||
{mancanti.length > 0 ? (
|
||||
<Card
|
||||
colore="destructive"
|
||||
titolo="Certificati mancanti"
|
||||
righe={mancanti.map((m) => `${m.nome} ${m.cognome} — non caricato`)}
|
||||
/>
|
||||
) : null}
|
||||
{scaduti.length > 0 ? (
|
||||
<Card
|
||||
colore="primary"
|
||||
|
||||
+23
-10
@@ -247,14 +247,17 @@ export type AvvisoCertificato = {
|
||||
giorni: number;
|
||||
};
|
||||
|
||||
/** Giocatore in rosa senza certificato caricato (DD-046). */
|
||||
export type CertificatoMancante = Pick<AvvisoCertificato, "giocatoreId" | "nome" | "cognome">;
|
||||
|
||||
function confrontaAvvisi(a: AvvisoCertificato, b: AvvisoCertificato): number {
|
||||
return a.giorni - b.giorni || a.cognome.localeCompare(b.cognome) || a.nome.localeCompare(b.nome);
|
||||
}
|
||||
|
||||
/**
|
||||
* Certificati in scadenza o scaduti nella rosa (DD-035): calcolato al volo da
|
||||
* `certificato_scadenza`, niente stato salvato. Esclude chi non è in rosa e chi non ha
|
||||
* ancora un certificato caricato (è un problema diverso, non un avviso di scadenza).
|
||||
* `certificato_scadenza`, niente stato salvato. Esclude chi non è in rosa. Chi non ha
|
||||
* ancora un certificato caricato non ha una scadenza: finisce in `mancanti` (DD-046).
|
||||
* `soglia` sono i giorni di preavviso: 7 per lo staff, 30 per il giocatore (DD-041).
|
||||
*/
|
||||
export function avvisiCertificati(
|
||||
@@ -262,13 +265,21 @@ export function avvisiCertificati(
|
||||
profili: Record<string, Profilo>,
|
||||
oggi: string,
|
||||
soglia: number = GIORNI_AVVISO_CERTIFICATO,
|
||||
): { scaduti: AvvisoCertificato[]; inScadenza: AvvisoCertificato[] } {
|
||||
): {
|
||||
scaduti: AvvisoCertificato[];
|
||||
inScadenza: AvvisoCertificato[];
|
||||
mancanti: CertificatoMancante[];
|
||||
} {
|
||||
const scaduti: AvvisoCertificato[] = [];
|
||||
const inScadenza: AvvisoCertificato[] = [];
|
||||
const mancanti: CertificatoMancante[] = [];
|
||||
for (const g of rosa) {
|
||||
if (!inRosa(g)) continue;
|
||||
const p = profili[g.id];
|
||||
if (!p?.certificatoScadenza || !p.certificatoPath) continue;
|
||||
if (!p?.certificatoScadenza || !p.certificatoPath) {
|
||||
mancanti.push({ giocatoreId: g.id, nome: g.nome, cognome: g.cognome });
|
||||
continue;
|
||||
}
|
||||
const giorni = giorniAllaScadenza(p.certificatoScadenza, oggi);
|
||||
if (giorni > soglia) continue;
|
||||
const avviso: AvvisoCertificato = {
|
||||
@@ -282,14 +293,15 @@ export function avvisiCertificati(
|
||||
}
|
||||
scaduti.sort(confrontaAvvisi);
|
||||
inScadenza.sort(confrontaAvvisi);
|
||||
return { scaduti, inScadenza };
|
||||
mancanti.sort((a, b) => a.cognome.localeCompare(b.cognome) || a.nome.localeCompare(b.nome));
|
||||
return { scaduti, inScadenza, mancanti };
|
||||
}
|
||||
|
||||
/**
|
||||
* Avvisi certificati per chi guarda la Home (DD-035, DD-041): `personale` è il proprio
|
||||
* certificato (soglia 30 giorni), per chiunque sia un giocatore in rosa; `staff` sono gli
|
||||
* altri della rosa (soglia 7 giorni), solo per l'admin, senza il suo nome perché già nel
|
||||
* personale.
|
||||
* certificato (soglia 30 giorni), per chiunque sia un giocatore in rosa, e `personaleMancante`
|
||||
* dice che non l'ha ancora caricato (DD-046); `staff` sono gli altri della rosa (soglia 7
|
||||
* giorni), solo per l'admin, senza il suo nome perché già nel personale.
|
||||
*/
|
||||
export function avvisiCertificatiUtente(
|
||||
rosa: GiocatoreSquadra[],
|
||||
@@ -298,7 +310,8 @@ export function avvisiCertificatiUtente(
|
||||
utente: { admin: boolean; base: GiocatoreSquadra | null },
|
||||
): {
|
||||
personale: AvvisoCertificato | undefined;
|
||||
staff: { scaduti: AvvisoCertificato[]; inScadenza: AvvisoCertificato[] } | null;
|
||||
personaleMancante: boolean;
|
||||
staff: ReturnType<typeof avvisiCertificati> | null;
|
||||
} {
|
||||
const mio = utente.base
|
||||
? avvisiCertificati([utente.base], profili, oggi, GIORNI_AVVISO_CERTIFICATO_GIOCATORE)
|
||||
@@ -311,5 +324,5 @@ export function avvisiCertificatiUtente(
|
||||
oggi,
|
||||
)
|
||||
: null;
|
||||
return { personale, staff };
|
||||
return { personale, personaleMancante: !!mio && mio.mancanti.length > 0, staff };
|
||||
}
|
||||
@@ -43,7 +43,7 @@ function NotFoundComponent() {
|
||||
);
|
||||
}
|
||||
|
||||
function ErrorComponent({ error, reset }: { error: Error; reset: () => void }) {
|
||||
function ErrorComponent({ error, reset }: { error: unknown; reset: () => void }) {
|
||||
console.error(error);
|
||||
const router = useRouter();
|
||||
|
||||
|
||||
Reference in new issue
Block a user