Scout live: valutazioni − / + per fondamentale e per set
Per ogni convocato un − o un + su battuta, ricezione, attacco e muro, separato per set e fuori dal punteggio (DD-053, migration m39: colonna scout_partite.valutazioni). Lo stato in corso le salva in scout_live.stato; il CSV admin ha la tabella per set. Nella pagina dello scout tolti il blocco avversario/campo, i tasti delle azioni e il tabellone del punteggio; il titolo della sezione mostra cognome e numero del giocatore. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
09dba1890d
commit
51b7a10c99
16 files changed
+367
-120
No files matched your search
+2
-1
@@ -34,7 +34,7 @@ function iniziali(nome: string, cognome: string): string {
|
||||
export function useAnagraficaRosa({
|
||||
conAllenatori = false,
|
||||
}: { conAllenatori?: boolean } = {}): Array<
|
||||
Pick<Giocatore, "id" | "nome" | "ruolo" | "numero" | "nascita">
|
||||
Pick<Giocatore, "id" | "nome" | "ruolo" | "numero" | "nascita"> & { cognome: string }
|
||||
> {
|
||||
const { righe: squadra } = useGiocatoriSquadra();
|
||||
return useMemo(
|
||||
@@ -44,6 +44,7 @@ export function useAnagraficaRosa({
|
||||
.map((g) => ({
|
||||
id: g.id,
|
||||
nome: nomeCompleto(g),
|
||||
cognome: g.cognome,
|
||||
ruolo: g.ruolo,
|
||||
numero: g.numero,
|
||||
nascita: g.nascita ?? "",
|
||||
|
||||
+33
-1
@@ -1,5 +1,11 @@
|
||||
import type { Giocatore } from "./crapp-data";
|
||||
import { azioniMeta, totaliPerGiocatore, type ScoutMatch } from "./scout-store";
|
||||
import {
|
||||
azioniMeta,
|
||||
contaValutazioni,
|
||||
fondamentali,
|
||||
totaliPerGiocatore,
|
||||
type ScoutMatch,
|
||||
} from "./scout-store";
|
||||
|
||||
/** Riga CSV con separatore ";" (Excel IT), riusata anche dall'export tesseramento. */
|
||||
export function rigaCsv(campi: Array<string | number>) {
|
||||
@@ -34,6 +40,32 @@ export function csvScoutMatch(match: ScoutMatch, rosa: Giocatore[]): string {
|
||||
if (!t) continue;
|
||||
righe.push(rigaCsv([g.numero, g.nome, g.ruolo, t.punti, t.ace, t.muri, t.errori]));
|
||||
}
|
||||
if (match.valutazioni.length > 0) {
|
||||
righe.push("");
|
||||
righe.push(
|
||||
rigaCsv([
|
||||
"Set",
|
||||
"Numero",
|
||||
"Giocatore",
|
||||
...fondamentali.flatMap((f) => [`${f.label} +`, `${f.label} -`]),
|
||||
]),
|
||||
);
|
||||
const sets = [...new Set(match.valutazioni.map((v) => v.set))].sort((x, y) => x - y);
|
||||
for (const set of sets) {
|
||||
for (const g of rosa) {
|
||||
if (!match.valutazioni.some((v) => v.set === set && v.giocatoreId === g.id)) continue;
|
||||
const c = contaValutazioni(match.valutazioni, g.id, set);
|
||||
righe.push(
|
||||
rigaCsv([
|
||||
set,
|
||||
g.numero,
|
||||
g.nome,
|
||||
...fondamentali.flatMap((f) => [c[f.id].piu, c[f.id].meno]),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
righe.push("");
|
||||
righe.push(rigaCsv(["Set", "Giocatore", "Azione"]));
|
||||
for (const a of match.azioni) {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import type { Azione } from "./scout-store";
|
||||
import type { Azione, Valutazione } from "./scout-store";
|
||||
|
||||
/** Stato condiviso di uno scout in corso: chi prende il controllo riparte da qui. */
|
||||
export type StatoScout = {
|
||||
azioni: Azione[];
|
||||
/** Assente negli stati salvati prima dell'introduzione delle valutazioni. */
|
||||
valutazioni?: Valutazione[];
|
||||
setChiusi: Array<[number, number]>;
|
||||
avversario: string;
|
||||
casa: boolean;
|
||||
@@ -12,6 +14,7 @@ export type StatoScout = {
|
||||
|
||||
export const statoIniziale = (avversario: string, casa: boolean): StatoScout => ({
|
||||
azioni: [],
|
||||
valutazioni: [],
|
||||
setChiusi: [],
|
||||
avversario,
|
||||
casa,
|
||||
|
||||
+41
-1
@@ -60,6 +60,42 @@ export type Azione = {
|
||||
ts: number;
|
||||
};
|
||||
|
||||
/** I fondamentali valutabili con − / + durante lo scout (non toccano il punteggio). */
|
||||
export type Fondamentale = "battuta" | "ricezione" | "attacco" | "muro";
|
||||
|
||||
export const fondamentali: Array<{ id: Fondamentale; label: string }> = [
|
||||
{ id: "battuta", label: "Battuta" },
|
||||
{ id: "ricezione", label: "Ricezione" },
|
||||
{ id: "attacco", label: "Attacco" },
|
||||
{ id: "muro", label: "Muro" },
|
||||
];
|
||||
|
||||
export type Valutazione = {
|
||||
id: string;
|
||||
giocatoreId: string;
|
||||
fondamentale: Fondamentale;
|
||||
segno: "+" | "-";
|
||||
set: number;
|
||||
ts: number;
|
||||
};
|
||||
|
||||
export type ConteggioValutazioni = Record<Fondamentale, { piu: number; meno: number }>;
|
||||
|
||||
/** Conta i + e i − di un giocatore per fondamentale, in un set (o in tutti se `set` manca). */
|
||||
export function contaValutazioni(
|
||||
valutazioni: Valutazione[],
|
||||
giocatoreId: string,
|
||||
set?: number,
|
||||
): ConteggioValutazioni {
|
||||
const out = {} as ConteggioValutazioni;
|
||||
for (const f of fondamentali) out[f.id] = { piu: 0, meno: 0 };
|
||||
for (const v of valutazioni) {
|
||||
if (v.giocatoreId !== giocatoreId || (set !== undefined && v.set !== set)) continue;
|
||||
out[v.fondamentale][v.segno === "+" ? "piu" : "meno"] += 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
export type ScoutMatch = {
|
||||
id: string;
|
||||
data: string;
|
||||
@@ -69,6 +105,7 @@ export type ScoutMatch = {
|
||||
setLoro: number;
|
||||
parziali: Array<[number, number]>;
|
||||
azioni: Azione[];
|
||||
valutazioni: Valutazione[];
|
||||
};
|
||||
|
||||
type RigaScoutPartita = {
|
||||
@@ -80,6 +117,7 @@ type RigaScoutPartita = {
|
||||
set_loro: number;
|
||||
parziali: unknown;
|
||||
azioni: unknown;
|
||||
valutazioni: unknown;
|
||||
};
|
||||
|
||||
function daRiga(r: RigaScoutPartita): ScoutMatch {
|
||||
@@ -92,6 +130,7 @@ function daRiga(r: RigaScoutPartita): ScoutMatch {
|
||||
setLoro: r.set_loro,
|
||||
parziali: (r.parziali as Array<[number, number]> | null) ?? [],
|
||||
azioni: (r.azioni as Azione[] | null) ?? [],
|
||||
valutazioni: (r.valutazioni as Valutazione[] | null) ?? [],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -100,7 +139,7 @@ export const SCOUT_MATCHES_KEY = ["scout-partite"] as const;
|
||||
async function fetchScoutMatches(): Promise<ScoutMatch[]> {
|
||||
const { data, error } = await supabase
|
||||
.from("scout_partite")
|
||||
.select("id, data, avversario, casa, set_nostri, set_loro, parziali, azioni")
|
||||
.select("id, data, avversario, casa, set_nostri, set_loro, parziali, azioni, valutazioni")
|
||||
.order("creato_il", { ascending: false });
|
||||
if (error) throw error;
|
||||
return (data ?? []).map(daRiga);
|
||||
@@ -131,6 +170,7 @@ export function useSalvaScoutMatch() {
|
||||
set_loro: input.match.setLoro,
|
||||
parziali: JSON.parse(JSON.stringify(input.match.parziali)),
|
||||
azioni: JSON.parse(JSON.stringify(input.match.azioni)),
|
||||
valutazioni: JSON.parse(JSON.stringify(input.match.valutazioni)),
|
||||
});
|
||||
if (error) throw error;
|
||||
return input.match;
|
||||
|
||||
Reference in new issue
Block a user