From 1fdc6720a0c743683b05c3b211cffe4ada066ce3 Mon Sep 17 00:00:00 2001 From: Davide Grilli Date: Tue, 8 Sep 2026 14:12:49 +0200 Subject: [PATCH] Sistema tutti gli errori di lint (prettier) rimasti su main MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/components/crapp/BarraSottosezioni.tsx | 4 +- src/components/crapp/EventoCard.tsx | 8 +- src/routes/calendario.tsx | 204 ++++++++++----------- test/integration/obiettivi.test.ts | 140 +++++++------- test/unit/obiettivi.test.ts | 10 +- 5 files changed, 188 insertions(+), 178 deletions(-) diff --git a/src/components/crapp/BarraSottosezioni.tsx b/src/components/crapp/BarraSottosezioni.tsx index a919737..1984376 100644 --- a/src/components/crapp/BarraSottosezioni.tsx +++ b/src/components/crapp/BarraSottosezioni.tsx @@ -90,9 +90,7 @@ export function BarraSottosezioni({ aria-label="Sottosezioni" className={cn( "flex flex-nowrap", - riempiLarghezza - ? "w-full" - : "w-max min-w-full", + riempiLarghezza ? "w-full" : "w-max min-w-full", sottolineatura ? "gap-1 px-2 py-1.5" : "snap-x snap-mandatory gap-1.5 px-5", )} > diff --git a/src/components/crapp/EventoCard.tsx b/src/components/crapp/EventoCard.tsx index b63c3aa..993dadf 100644 --- a/src/components/crapp/EventoCard.tsx +++ b/src/components/crapp/EventoCard.tsx @@ -88,8 +88,7 @@ export function EventoCard({ const passato = evento.data < dataOggi(); const cliccabile = Boolean(linkTo); /** Solo gli eventi extra-campo non hanno scheda dedicata: le note restano sulla card. */ - const noteCard = - evento.tipo === "evento" ? evento.note.trim() : ""; + const noteCard = evento.tipo === "evento" ? evento.note.trim() : ""; const stati = evento.tipo === "evento" ? // Se resta un vecchio "infortunato", mostra il bottone solo per poterlo togliere. @@ -193,10 +192,7 @@ export function EventoCard({ {io ? (
diff --git a/src/routes/calendario.tsx b/src/routes/calendario.tsx index 4d508a3..fe65169 100644 --- a/src/routes/calendario.tsx +++ b/src/routes/calendario.tsx @@ -182,7 +182,7 @@ function Calendario() { {g} ))}
- {/* + {/* Il mese si cambia anche con lo swipe: il punto d'arrivo si decide proiettando la velocità di rilascio (come la decelerazione dello scroll iOS), non dalla posizione del dito. @@ -195,112 +195,112 @@ function Calendario() { riga e sulle colonne di bordo. Il padding sta dentro il riquadro di ritaglio, i margini negativi rimettono la griglia dov'era. */} -
- - { - const arrivo = info.offset.x + proietta(info.velocity.x); - if (arrivo < -60) successivo(); - else if (arrivo > 60) precedente(); - }} - initial={ridotto ? { opacity: 0 } : { opacity: 0, x: direzione * 48 }} - animate={{ opacity: 1, x: 0 }} - exit={ridotto ? { opacity: 0 } : { opacity: 0, x: direzione * -48 }} - transition={ridotto ? { duration: 0.2 } : molla.foglio} - className="grid touch-pan-y grid-cols-7 gap-1" - > - {Array.from({ length: offsetLunedi }).map((_, i) => ( - - ))} - {Array.from({ length: giorni }).map((_, i) => { - const giorno = i + 1; - const eventiGiorno = eventiPerGiorno.get(giorno) ?? []; - const haEventi = eventiGiorno.length > 0; - // Attenzione: si conta per **tipo**, non per numero di - // eventi. Due partite nello stesso giorno restano una cella - // rossa piena; si divide solo se i tipi sono diversi. - const tipiGiorno = Array.from(new Set(eventiGiorno.map((e) => e.tipo))); - // Più tipi: la cella si divide in bande a taglio netto (gli - // stop sono duplicati apposta, non è una sfumatura), una per - // tipo, in diagonale. - const sfondo = - tipiGiorno.length > 1 - ? `linear-gradient(135deg, ${tipiGiorno - .map((t, idx) => { - const da = (idx / tipiGiorno.length) * 100; - const a = ((idx + 1) / tipiGiorno.length) * 100; - return `${coloreTipo[t]} ${da}%, ${coloreTipo[t]} ${a}%`; - }) - .join(", ")})` - : undefined; - const tipo = tipiGiorno.length === 1 ? tipiGiorno[0] : undefined; - const isOggi = - !!oggi && oggi.anno === anno && oggi.mese === mese && oggi.giorno === giorno; - const Cella = haEventi ? "button" : "div"; - return ( - apriGiorno(giorno) : undefined} - style={sfondo ? { backgroundImage: sfondo } : undefined} - className={cn( - "relative grid aspect-square place-items-center rounded-xl text-sm font-semibold", - tipo === "partita" && "bg-accent text-accent-foreground", - tipo === "allenamento" && "bg-training text-training-foreground", - tipo === "evento" && "bg-warning text-warning-foreground", - tipo === "compleanno" && "bg-success text-success-foreground", - !tipo && !haEventi && "text-muted-foreground", - !tipo && haEventi && "text-foreground", - haEventi && "cursor-pointer transition-transform active:scale-90", - isOggi && "ring-2 ring-foreground ring-offset-1 ring-offset-card", - )} - aria-label={ - haEventi - ? `${giorno} ${mesiIT[mese]}: ${eventiGiorno.length} ${eventiGiorno.length === 1 ? "evento" : "eventi"}` - : undefined - } - aria-current={isOggi ? "date" : undefined} - > - {/* +
+ + { + const arrivo = info.offset.x + proietta(info.velocity.x); + if (arrivo < -60) successivo(); + else if (arrivo > 60) precedente(); + }} + initial={ridotto ? { opacity: 0 } : { opacity: 0, x: direzione * 48 }} + animate={{ opacity: 1, x: 0 }} + exit={ridotto ? { opacity: 0 } : { opacity: 0, x: direzione * -48 }} + transition={ridotto ? { duration: 0.2 } : molla.foglio} + className="grid touch-pan-y grid-cols-7 gap-1" + > + {Array.from({ length: offsetLunedi }).map((_, i) => ( + + ))} + {Array.from({ length: giorni }).map((_, i) => { + const giorno = i + 1; + const eventiGiorno = eventiPerGiorno.get(giorno) ?? []; + const haEventi = eventiGiorno.length > 0; + // Attenzione: si conta per **tipo**, non per numero di + // eventi. Due partite nello stesso giorno restano una cella + // rossa piena; si divide solo se i tipi sono diversi. + const tipiGiorno = Array.from(new Set(eventiGiorno.map((e) => e.tipo))); + // Più tipi: la cella si divide in bande a taglio netto (gli + // stop sono duplicati apposta, non è una sfumatura), una per + // tipo, in diagonale. + const sfondo = + tipiGiorno.length > 1 + ? `linear-gradient(135deg, ${tipiGiorno + .map((t, idx) => { + const da = (idx / tipiGiorno.length) * 100; + const a = ((idx + 1) / tipiGiorno.length) * 100; + return `${coloreTipo[t]} ${da}%, ${coloreTipo[t]} ${a}%`; + }) + .join(", ")})` + : undefined; + const tipo = tipiGiorno.length === 1 ? tipiGiorno[0] : undefined; + const isOggi = + !!oggi && oggi.anno === anno && oggi.mese === mese && oggi.giorno === giorno; + const Cella = haEventi ? "button" : "div"; + return ( + apriGiorno(giorno) : undefined} + style={sfondo ? { backgroundImage: sfondo } : undefined} + className={cn( + "relative grid aspect-square place-items-center rounded-xl text-sm font-semibold", + tipo === "partita" && "bg-accent text-accent-foreground", + tipo === "allenamento" && "bg-training text-training-foreground", + tipo === "evento" && "bg-warning text-warning-foreground", + tipo === "compleanno" && "bg-success text-success-foreground", + !tipo && !haEventi && "text-muted-foreground", + !tipo && haEventi && "text-foreground", + haEventi && "cursor-pointer transition-transform active:scale-90", + isOggi && "ring-2 ring-foreground ring-offset-1 ring-offset-card", + )} + aria-label={ + haEventi + ? `${giorno} ${mesiIT[mese]}: ${eventiGiorno.length} ${eventiGiorno.length === 1 ? "evento" : "eventi"}` + : undefined + } + aria-current={isOggi ? "date" : undefined} + > + {/* Sulle celle divise il numero sta direttamente sulle bande, staccato dal fondo da un alone bianco: è la resa scelta, il colore deve restare pieno e visibile fino al bordo. */} - - {giorno} - - - ); - })} - - -
-

- Scorri a destra o sinistra per cambiare mese. -

-
- - Partita - - - Allenamento - - - Eventi - - - Compleanni - -
- - + + {giorno} + +
+ ); + })} +
+
+
+

+ Scorri a destra o sinistra per cambiare mese. +

+
+ + Partita + + + Allenamento + + + Eventi + + + Compleanni + +
+ + {admin ? (
diff --git a/test/integration/obiettivi.test.ts b/test/integration/obiettivi.test.ts index 5902b9c..232780c 100644 --- a/test/integration/obiettivi.test.ts +++ b/test/integration/obiettivi.test.ts @@ -96,7 +96,10 @@ if (!locale) { giocatore_id: g.id, stato: presenti.includes(g.id) ? "presente" : "assente", })); - const inseritePresenze = await rest("risposte_presenze", { method: "POST", body: JSON.stringify(righe) }); + const inseritePresenze = await rest("risposte_presenze", { + method: "POST", + body: JSON.stringify(righe), + }); if (!inseritePresenze.ok) { throw new Error(`inserimento presenze fallito: ${await inseritePresenze.text()}`); } @@ -195,7 +198,11 @@ if (!locale) { // Tutta la rosa presente all'allenamento, nessuno alla partita: 50% aggregato sui due. const risposte = [ - ...giocatori.map((g) => ({ evento_id: allenamentoId, giocatore_id: g.id, stato: "presente" })), + ...giocatori.map((g) => ({ + evento_id: allenamentoId, + giocatore_id: g.id, + stato: "presente", + })), ...giocatori.map((g) => ({ evento_id: partitaId, giocatore_id: g.id, stato: "assente" })), ]; const scritte = await rest("risposte_presenze", { @@ -379,65 +386,68 @@ if (!locale) { }, ); - await prova( - "o7 somma presenze calcolate da eventi/risposte reali del database", - async () => { - // o7 non calcola nulla da `ctx`: somma `g.presenze`, un campo già calcolato a monte da - // `contaPresenzeGiocatore()` (che in produzione alimenta `useRosa()`). Qui si esercita - // la stessa funzione pura sui dati appena scritti, per verificare l'intera catena - // DB -> contaPresenzeGiocatore -> o7, non solo la somma finale. - const allenamentoId = `${PREFISSO}-o7-allenamento`; - const partitaId = `${PREFISSO}-o7-partita`; - const OGGI_STR = "2099-01-20"; + await prova("o7 somma presenze calcolate da eventi/risposte reali del database", async () => { + // o7 non calcola nulla da `ctx`: somma `g.presenze`, un campo già calcolato a monte da + // `contaPresenzeGiocatore()` (che in produzione alimenta `useRosa()`). Qui si esercita + // la stessa funzione pura sui dati appena scritti, per verificare l'intera catena + // DB -> contaPresenzeGiocatore -> o7, non solo la somma finale. + const allenamentoId = `${PREFISSO}-o7-allenamento`; + const partitaId = `${PREFISSO}-o7-partita`; + const OGGI_STR = "2099-01-20"; - for (const [id, tipo, data] of [ - [allenamentoId, "allenamento", "2099-01-05"], - [partitaId, "partita", "2099-01-08"], - ] as const) { - const inserito = await rest("eventi_app", { - method: "POST", - body: JSON.stringify({ id, tipo, titolo: `Test obiettivi o7 (${tipo})`, data }), - }); - if (!inserito.ok) throw new Error(`inserimento evento fallito: ${await inserito.text()}`); - } + for (const [id, tipo, data] of [ + [allenamentoId, "allenamento", "2099-01-05"], + [partitaId, "partita", "2099-01-08"], + ] as const) { + const inserito = await rest("eventi_app", { + method: "POST", + body: JSON.stringify({ id, tipo, titolo: `Test obiettivi o7 (${tipo})`, data }), + }); + if (!inserito.ok) throw new Error(`inserimento evento fallito: ${await inserito.text()}`); + } - // g1: presente ai due eventi (2 presenze). g2: presente e in ritardo (2 presenze, - // il ritardo conta). g3: assente a entrambi (0 presenze). - const [g1, g2, g3] = giocatori; - const righe = [ - { evento_id: allenamentoId, giocatore_id: g1!.id, stato: "presente" }, - { evento_id: partitaId, giocatore_id: g1!.id, stato: "presente" }, - { evento_id: allenamentoId, giocatore_id: g2!.id, stato: "presente" }, - { evento_id: partitaId, giocatore_id: g2!.id, stato: "ritardo" }, - { evento_id: allenamentoId, giocatore_id: g3!.id, stato: "assente" }, - { evento_id: partitaId, giocatore_id: g3!.id, stato: "assente" }, - ]; - const inserite = await rest("risposte_presenze", { method: "POST", body: JSON.stringify(righe) }); - if (!inserite.ok) throw new Error(`inserimento presenze fallito: ${await inserite.text()}`); + // g1: presente ai due eventi (2 presenze). g2: presente e in ritardo (2 presenze, + // il ritardo conta). g3: assente a entrambi (0 presenze). + const [g1, g2, g3] = giocatori; + const righe = [ + { evento_id: allenamentoId, giocatore_id: g1!.id, stato: "presente" }, + { evento_id: partitaId, giocatore_id: g1!.id, stato: "presente" }, + { evento_id: allenamentoId, giocatore_id: g2!.id, stato: "presente" }, + { evento_id: partitaId, giocatore_id: g2!.id, stato: "ritardo" }, + { evento_id: allenamentoId, giocatore_id: g3!.id, stato: "assente" }, + { evento_id: partitaId, giocatore_id: g3!.id, stato: "assente" }, + ]; + const inserite = await rest("risposte_presenze", { + method: "POST", + body: JSON.stringify(righe), + }); + if (!inserite.ok) throw new Error(`inserimento presenze fallito: ${await inserite.text()}`); - const eventiReali = (await leggiEventi()).filter( - (e) => e.id === allenamentoId || e.id === partitaId, - ); - const presenzeReali = { - ...(await leggiPresenze(allenamentoId)), - ...(await leggiPresenze(partitaId)), - }; + const eventiReali = (await leggiEventi()).filter( + (e) => e.id === allenamentoId || e.id === partitaId, + ); + const presenzeReali = { + ...(await leggiPresenze(allenamentoId)), + ...(await leggiPresenze(partitaId)), + }; - const rosaConPresenzeReali = [g1!, g2!, g3!].map((g) => ({ - ...g, - presenze: contaPresenzeGiocatore(g.id, eventiReali, presenzeReali, OGGI_STR), - })); + const rosaConPresenzeReali = [g1!, g2!, g3!].map((g) => ({ + ...g, + presenze: contaPresenzeGiocatore(g.id, eventiReali, presenzeReali, OGGI_STR), + })); - const o7 = obiettiviSquadra(rosaConPresenzeReali, { eventi: [], presenze: {}, pagelle: [] }) - .find((o) => o.id === "o7")!; + const o7 = obiettiviSquadra(rosaConPresenzeReali, { + eventi: [], + presenze: {}, + pagelle: [], + }).find((o) => o.id === "o7")!; - assert.equal( - o7.valore, - 4, - "g1 (2) + g2 (2, il ritardo conta) + g3 (0) = 4, calcolate dal database", - ); - }, - ); + assert.equal( + o7.valore, + 4, + "g1 (2) + g2 (2, il ritardo conta) + g3 (0) = 4, calcolate dal database", + ); + }); await prova("o12/o13 media e conteggio pagelle vere lette da pagelle_voti", async () => { const matchId = `${PREFISSO}-o12-m1`; @@ -522,20 +532,26 @@ if (!locale) { }); if (!inserite.ok) throw new Error(`inserimento presenze fallito: ${await inserite.text()}`); - const eventiReali = (await leggiEventi()).filter((e) => - eventi.some(([id]) => id === e.id), - ); + const eventiReali = (await leggiEventi()).filter((e) => eventi.some(([id]) => id === e.id)); const presenzeReali: MappaPresenze = {}; for (const [id] of eventi) Object.assign(presenzeReali, await leggiPresenze(id)); const rosaConSerieReali = [g1!, g2!, g3!].map((g) => ({ ...g, - serieAllenamenti: serieConsecutiva(g.id, eventiReali, presenzeReali, "allenamento", OGGI_STR), + serieAllenamenti: serieConsecutiva( + g.id, + eventiReali, + presenzeReali, + "allenamento", + OGGI_STR, + ), })); - const o11 = obiettiviSquadra(rosaConSerieReali, { eventi: [], presenze: {}, pagelle: [] }).find( - (o) => o.id === "o11", - )!; + const o11 = obiettiviSquadra(rosaConSerieReali, { + eventi: [], + presenze: {}, + pagelle: [], + }).find((o) => o.id === "o11")!; assert.equal( o11.valore, 1, diff --git a/test/unit/obiettivi.test.ts b/test/unit/obiettivi.test.ts index 81115c8..24fad30 100644 --- a/test/unit/obiettivi.test.ts +++ b/test/unit/obiettivi.test.ts @@ -126,7 +126,10 @@ assert.equal(trova(obiettiviSquadra(giocatori, soloCompleanni, OGGI_AGOSTO), "o2 assert.equal(o1Agosto.scadenza, "2026-08-31", "scadenza = ultimo giorno del mese"); const o1Settembre = trova(obiettiviSquadra(giocatori, contestoVuoto, OGGI_SETTEMBRE), "o1"); - assert.ok(o1Settembre.titolo.includes("settembre"), "titolo o1 riflette il mese iniettato (settembre)"); + assert.ok( + o1Settembre.titolo.includes("settembre"), + "titolo o1 riflette il mese iniettato (settembre)", + ); assert.equal(o1Settembre.scadenza, "2026-09-30", "scadenza = ultimo giorno di settembre (30 gg)"); // La scadenza di o2 ("Tutti rispondono alle convocazioni") era una data fissa @@ -197,10 +200,7 @@ assert.equal(trova(obiettiviSquadra(giocatori, soloCompleanni, OGGI_AGOSTO), "o2 ); const dueEventiRisposte: ContestoObiettivi = { - eventi: [ - evento("dr1", "2026-08-03", "allenamento"), - evento("dr2", "2026-08-17", "partita"), - ], + eventi: [evento("dr1", "2026-08-03", "allenamento"), evento("dr2", "2026-08-17", "partita")], presenze: { dr1: Object.fromEntries(giocatori.map((g) => [g.id, "presente" as const])), dr2: {},