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:
1 parent
44194d6d54
commit
5fd7c895b3
3 files changed
+64
-9
No files matched your search
@@ -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
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
Reference in new issue
Block a user