Scout live: selezione giocatore ordinabile e conteggio dei + nel riquadro

Il titolo diventa «Selezione giocatore», con un selettore (componente Select dell'app) per
ordinare per cognome o per numero. Nel riquadro di ogni giocatore, al posto dei punti delle
azioni (sempre 0), compaiono i + del set in corso senza la ricezione.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5.5 committed 2026-11-02 08:24:42 +01:00
1 parent 44194d6d54
commit 5fd7c895b3
3 files changed
+64 -9

No files matched your search

+18
View File
@@ -96,6 +96,24 @@ export function contaValutazioni(
return out;
}
/**
* I + di un giocatore in un set, esclusa la ricezione (che qui non vale come punto messo a
* terra): quello che compare nel suo riquadro dello scout.
*/
export function contaPiuSenzaRicezione(
valutazioni: Valutazione[],
giocatoreId: string,
set: number,
): number {
return valutazioni.filter(
(v) =>
v.giocatoreId === giocatoreId &&
v.set === set &&
v.segno === "+" &&
v.fondamentale !== "ricezione",
).length;
}
export type ScoutMatch = {
id: string;
data: string;
+27 -9
View File
@@ -3,6 +3,7 @@ import { createFileRoute, useNavigate } from "@tanstack/react-router";
import { Undo2, Save, CheckCircle2, Radio, Lock, CalendarX2, LogOut } from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { Select } from "@/components/crapp/ui-bits";
import { formatData } from "@/lib/crapp-data";
import type { Evento } from "@/lib/eventi";
import { useAnagraficaRosa } from "@/lib/rosa";
@@ -26,10 +27,10 @@ import {
} from "@/lib/scout-live";
import {
azioniMeta,
contaPiuSenzaRicezione,
contaValutazioni,
fondamentali,
useSalvaScoutMatch,
totaliPerGiocatore,
type Azione,
type AzioneTipo,
type Fondamentale,
@@ -202,6 +203,7 @@ function ScoutBoard({
const [setChiusi, setSetChiusi] = useState<Array<[number, number]>>(base.setChiusi);
const [azioni, setAzioni] = useState<Azione[]>(base.azioni);
const [valutazioni, setValutazioni] = useState<Valutazione[]>(base.valutazioni ?? []);
const [ordine, setOrdine] = useState<"cognome" | "numero">("cognome");
const [selezionato, setSelezionato] = useState<string | null>(null);
const salva = useSalvaStatoScout();
const cancella = useCancellaStatoScout();
@@ -216,8 +218,13 @@ function ScoutBoard({
const presenti = rosa.filter(
(g) => risposte[g.id] === "presente" || risposte[g.id] === "ritardo",
);
return presenti.length > 0 ? presenti : rosa;
}, [risposte, rosa]);
const elenco = presenti.length > 0 ? presenti : rosa;
return [...elenco].sort((a, b) =>
ordine === "numero"
? a.numero - b.numero
: a.cognome.localeCompare(b.cognome, "it") || a.numero - b.numero,
);
}, [risposte, rosa, ordine]);
// Salvataggio condiviso: se chi scouta si disconnette, il prossimo riprende da qui.
useEffect(() => {
@@ -236,7 +243,6 @@ function ScoutBoard({
const azioniSet = azioni.filter((a) => a.set === setCorrente);
const puntiNoi = azioniSet.filter((a) => azioniMeta[a.tipo].nostro).length;
const puntiLoro = azioniSet.length - puntiNoi;
const totali = useMemo(() => totaliPerGiocatore(azioni), [azioni]);
function valuta(fondamentale: Fondamentale, segno: Valutazione["segno"]) {
if (!selezionato) {
@@ -351,13 +357,25 @@ function ScoutBoard({
</header>
<section className="px-5 pt-4">
<p className="mb-2 text-[13px] font-bold uppercase tracking-wide text-muted-foreground">
1. Tocca il giocatore
</p>
<div className="mb-2 flex items-center justify-between gap-2">
<p className="text-[13px] font-bold uppercase tracking-wide text-muted-foreground">
Selezione giocatore
</p>
<div className="w-40 shrink-0">
<Select
value={ordine}
onChange={(e) => setOrdine(e.target.value as "cognome" | "numero")}
aria-label="Ordina i giocatori"
>
<option value="cognome">Per cognome</option>
<option value="numero">Per numero</option>
</Select>
</div>
</div>
<div className="grid grid-cols-4 gap-2">
{convocati.map((g) => {
const attivo = selezionato === g.id;
const t = totali.get(g.id);
const piu = contaPiuSenzaRicezione(valutazioni, g.id, setCorrente);
return (
<button
key={g.id}
@@ -376,7 +394,7 @@ function ScoutBoard({
attivo ? "text-accent-foreground/70" : "text-muted-foreground",
)}
>
{t ? `${t.punti}p` : "0p"}
+{piu}
</p>
</button>
);
+19
View File
@@ -3,6 +3,7 @@ import assert from "node:assert/strict";
import { giocatori } from "@/lib/crapp-data";
import {
azioniMeta,
contaPiuSenzaRicezione,
contaValutazioni,
fondamentali,
giocatoriConScout,
@@ -139,3 +140,21 @@ assert.deepEqual(
"giocatore senza valutazioni",
);
assert.equal(totaliPerGiocatore([]).size, 0, "le valutazioni non sono azioni: nessun punto");
// --- + del riquadro giocatore: tutti i fondamentali tranne la ricezione, nel set -------
const piuVal = [
v("g1", "battuta", "+"),
v("g1", "attacco", "+"),
v("g1", "muro", "+"),
v("g1", "ricezione", "+"),
v("g1", "attacco", "-"),
v("g1", "battuta", "+", 2),
v("g2", "attacco", "+"),
];
assert.equal(
contaPiuSenzaRicezione(piuVal, "g1", 1),
3,
"niente ricezione, niente −, solo il set 1",
);
assert.equal(contaPiuSenzaRicezione(piuVal, "g1", 2), 1);
assert.equal(contaPiuSenzaRicezione(piuVal, "g3", 1), 0);