Replace demo stats with real data
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+8
-37
@@ -82,40 +82,6 @@ function inizialiDa(nome: string) {
|
|||||||
.toUpperCase();
|
.toUpperCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
type StatsDemo = Pick<Giocatore, "presenze" | "streak" | "mvp" | "mediaVoto">;
|
|
||||||
|
|
||||||
/** Statistiche demo: mix di badge bronzo / argento / oro già sbloccati. */
|
|
||||||
const statsDemo: Record<string, StatsDemo> = {
|
|
||||||
"Ivan Cacciari": { presenze: 31, streak: 8, mvp: 5, mediaVoto: 8.7 },
|
|
||||||
"Davide Grilli": { presenze: 27, streak: 5, mvp: 3, mediaVoto: 8.4 },
|
|
||||||
"Nicola Pezzoli": { presenze: 24, streak: 4, mvp: 2, mediaVoto: 8.2 },
|
|
||||||
"Laura Passabì": { presenze: 22, streak: 6, mvp: 3, mediaVoto: 8.1 },
|
|
||||||
"Francesca Tucci": { presenze: 19, streak: 3, mvp: 1, mediaVoto: 7.9 },
|
|
||||||
"Iacopo Ricci": { presenze: 21, streak: 2, mvp: 3, mediaVoto: 7.8 },
|
|
||||||
"Alessandra Brunacci": { presenze: 14, streak: 3, mvp: 1, mediaVoto: 7.5 },
|
|
||||||
"Mattias Bologna": { presenze: 12, streak: 2, mvp: 1, mediaVoto: 7.4 },
|
|
||||||
"Giada Valbonesi": { presenze: 13, streak: 4, mvp: 1, mediaVoto: 7.6 },
|
|
||||||
"Alessio Cocco": { presenze: 11, streak: 1, mvp: 0, mediaVoto: 7.2 },
|
|
||||||
"Mattia Catalano": { presenze: 9, streak: 2, mvp: 0, mediaVoto: 7.0 },
|
|
||||||
"Antonella Loverre": { presenze: 8, streak: 1, mvp: 0, mediaVoto: 6.9 },
|
|
||||||
"Carlo Di Castelnuovo": { presenze: 7, streak: 1, mvp: 0, mediaVoto: 6.8 },
|
|
||||||
"Camilla Esposito": { presenze: 6, streak: 2, mvp: 0, mediaVoto: 6.7 },
|
|
||||||
"Salvador Battistella": { presenze: 20, streak: 5, mvp: 1, mediaVoto: 7.7 },
|
|
||||||
"Silvia Chilese": { presenze: 16, streak: 3, mvp: 0, mediaVoto: 7.3 },
|
|
||||||
"Cristina Titone": { presenze: 15, streak: 2, mvp: 0, mediaVoto: 7.1 },
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Serie demo derivate dalle statistiche: ogni tipo ha il suo contatore. */
|
|
||||||
function serieDa(s?: StatsDemo) {
|
|
||||||
const streak = s?.streak ?? 0;
|
|
||||||
const presenze = s?.presenze ?? 0;
|
|
||||||
return {
|
|
||||||
serieAllenamenti: streak,
|
|
||||||
seriePartite: Math.ceil(streak / 2),
|
|
||||||
serieConferme: presenze >= 20 ? 12 : presenze >= 14 ? 8 : presenze >= 8 ? 4 : 1,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const giocatori: Giocatore[] = rosaCSI.map((r, i) => ({
|
export const giocatori: Giocatore[] = rosaCSI.map((r, i) => ({
|
||||||
id: `g${i + 1}`,
|
id: `g${i + 1}`,
|
||||||
nome: r.nome,
|
nome: r.nome,
|
||||||
@@ -123,14 +89,19 @@ export const giocatori: Giocatore[] = rosaCSI.map((r, i) => ({
|
|||||||
ruolo: r.ruolo,
|
ruolo: r.ruolo,
|
||||||
nascita: r.nascita,
|
nascita: r.nascita,
|
||||||
iniziali: inizialiDa(r.nome),
|
iniziali: inizialiDa(r.nome),
|
||||||
totaliEventi: 32,
|
presenze: 0,
|
||||||
|
totaliEventi: 0,
|
||||||
|
streak: 0,
|
||||||
|
serieAllenamenti: 0,
|
||||||
|
seriePartite: 0,
|
||||||
|
serieConferme: 0,
|
||||||
|
mvp: 0,
|
||||||
|
mediaVoto: 0,
|
||||||
infortuni: 0,
|
infortuni: 0,
|
||||||
ritardi: 0,
|
ritardi: 0,
|
||||||
palloni: 0,
|
palloni: 0,
|
||||||
cacche: 0,
|
cacche: 0,
|
||||||
cacchePartita: 0,
|
cacchePartita: 0,
|
||||||
...(statsDemo[r.nome] ?? { presenze: 0, streak: 0, mvp: 0, mediaVoto: 0 }),
|
|
||||||
...serieDa(statsDemo[r.nome]),
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export type RigaClassifica = {
|
export type RigaClassifica = {
|
||||||
|
|||||||
@@ -84,3 +84,17 @@ export function vincitoriMvp(voti: VotoMvp[]): Record<string, string> {
|
|||||||
export function mioVoto(voti: VotoMvp[], matchId: string, votanteId: string) {
|
export function mioVoto(voti: VotoMvp[], matchId: string, votanteId: string) {
|
||||||
return voti.find((v) => v.match_id === matchId && v.votante_id === votanteId) ?? null;
|
return voti.find((v) => v.match_id === matchId && v.votante_id === votanteId) ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** MVP vinti per giocatore, contando una vittoria per partita votata. */
|
||||||
|
export function mvpVintiPerGiocatore(voti: VotoMvp[]): Record<string, number> {
|
||||||
|
const out: Record<string, number> = {};
|
||||||
|
const matchIds = new Set(voti.map((v) => v.match_id));
|
||||||
|
for (const matchId of matchIds) {
|
||||||
|
const top = conteggioPartita(voti, matchId);
|
||||||
|
if (top.length > 0 && (top.length === 1 || top[0]!.voti > top[1]!.voti)) {
|
||||||
|
const id = top[0]!.id;
|
||||||
|
out[id] = (out[id] ?? 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,41 @@
|
|||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { supabase } from "@/integrations/supabase/client";
|
import { supabase } from "@/integrations/supabase/client";
|
||||||
import type { Stato } from "./crapp-data";
|
import type { Stato } from "./crapp-data";
|
||||||
|
import type { Evento } from "./eventi";
|
||||||
|
|
||||||
export const PRESENZE_KEY = ["risposte-presenze"] as const;
|
export const PRESENZE_KEY = ["risposte-presenze"] as const;
|
||||||
|
|
||||||
/** eventoId -> giocatoreId -> stato */
|
/** eventoId -> giocatoreId -> stato */
|
||||||
export type MappaPresenze = Record<string, Record<string, Stato>>;
|
export type MappaPresenze = Record<string, Record<string, Stato>>;
|
||||||
|
|
||||||
|
/** Allenamenti e partite CrAPP che contano per le statistiche di presenza. */
|
||||||
|
function eventiContanoPresenze(eventi: Evento[], giocatoreId?: string) {
|
||||||
|
return eventi.filter(
|
||||||
|
(e) =>
|
||||||
|
(e.tipo === "partita" || e.tipo === "allenamento") &&
|
||||||
|
(giocatoreId === undefined ||
|
||||||
|
e.convocati.length === 0 ||
|
||||||
|
e.convocati.includes(giocatoreId)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Presenze effettive (presente o in ritardo) su eventi CrAPP. */
|
||||||
|
export function contaPresenzeGiocatore(
|
||||||
|
giocatoreId: string,
|
||||||
|
eventi: Evento[],
|
||||||
|
presenze: MappaPresenze,
|
||||||
|
): number {
|
||||||
|
return eventiContanoPresenze(eventi, giocatoreId).filter((e) => {
|
||||||
|
const stato = presenze[e.id]?.[giocatoreId];
|
||||||
|
return stato === "presente" || stato === "ritardo";
|
||||||
|
}).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Eventi CrAPP rilevanti per il denominatore presenze di un giocatore. */
|
||||||
|
export function totaliEventiGiocatore(giocatoreId: string, eventi: Evento[]): number {
|
||||||
|
return eventiContanoPresenze(eventi, giocatoreId).length;
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchPresenze(): Promise<MappaPresenze> {
|
async function fetchPresenze(): Promise<MappaPresenze> {
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from("risposte_presenze")
|
.from("risposte_presenze")
|
||||||
|
|||||||
+11
-7
@@ -1,6 +1,6 @@
|
|||||||
import { useSyncExternalStore } from "react";
|
import { useSyncExternalStore } from "react";
|
||||||
import { giocatori, type Giocatore } from "./crapp-data";
|
import { giocatori, type Giocatore } from "./crapp-data";
|
||||||
import { conInfortuni, useInfortuniERitardi } from "./infortuni";
|
import { useIo } from "./rosa";
|
||||||
|
|
||||||
const KEY = "crapp-user-v1";
|
const KEY = "crapp-user-v1";
|
||||||
const listeners = new Set<() => void>();
|
const listeners = new Set<() => void>();
|
||||||
@@ -36,9 +36,9 @@ export function resetGiocatore() {
|
|||||||
write(null);
|
write(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Solo lettura locale: nessuna dipendenza da React Query (usabile fuori dal provider). */
|
/** Id del giocatore collegato al dispositivo (localStorage). */
|
||||||
export function useGiocatoreBase(): Giocatore | null {
|
export function useGiocatoreId(): string | null {
|
||||||
const id = useSyncExternalStore(
|
return useSyncExternalStore(
|
||||||
(cb) => {
|
(cb) => {
|
||||||
listeners.add(cb);
|
listeners.add(cb);
|
||||||
return () => listeners.delete(cb);
|
return () => listeners.delete(cb);
|
||||||
@@ -46,11 +46,15 @@ export function useGiocatoreBase(): Giocatore | null {
|
|||||||
() => read(),
|
() => read(),
|
||||||
() => null,
|
() => null,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Anagrafica base dal localStorage: le statistiche restano a zero finché non passa da `useIo`. */
|
||||||
|
export function useGiocatoreBase(): Giocatore | null {
|
||||||
|
const id = useGiocatoreId();
|
||||||
return id ? (giocatori.find((x) => x.id === id) ?? null) : null;
|
return id ? (giocatori.find((x) => x.id === id) ?? null) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Giocatore corrente con statistiche calcolate da dati reali (presenze, MVP, badge, …). */
|
||||||
export function useGiocatoreCorrente(): Giocatore | null {
|
export function useGiocatoreCorrente(): Giocatore | null {
|
||||||
const g = useGiocatoreBase();
|
return useIo();
|
||||||
const { infortuni, ritardi } = useInfortuniERitardi();
|
|
||||||
return g ? conInfortuni(g, infortuni, ritardi) : null;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,9 @@ function Profilo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const percPresenze = Math.round((g.presenze / g.totaliEventi) * 100);
|
const percPresenze = g.totaliEventi
|
||||||
|
? Math.round((g.presenze / g.totaliEventi) * 100)
|
||||||
|
: 0;
|
||||||
|
|
||||||
async function onFile(e: React.ChangeEvent<HTMLInputElement>) {
|
async function onFile(e: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
|
|||||||
@@ -20,8 +20,11 @@ for (const g of giocatori) {
|
|||||||
assert.ok(g.numero > 0, `${g.id}: numero di maglia positivo`);
|
assert.ok(g.numero > 0, `${g.id}: numero di maglia positivo`);
|
||||||
assert.equal(g.iniziali.length, 2, `${g.id}: due iniziali`);
|
assert.equal(g.iniziali.length, 2, `${g.id}: due iniziali`);
|
||||||
assert.equal(g.iniziali, g.iniziali.toUpperCase(), `${g.id}: iniziali maiuscole`);
|
assert.equal(g.iniziali, g.iniziali.toUpperCase(), `${g.id}: iniziali maiuscole`);
|
||||||
assert.ok(g.mediaVoto >= 0 && g.mediaVoto <= 10, `${g.id}: media voto nel range 1-10`);
|
assert.equal(g.mediaVoto, 0, `${g.id}: media voto iniziale a zero`);
|
||||||
assert.ok(g.presenze <= g.totaliEventi, `${g.id}: presenze mai oltre gli eventi totali`);
|
assert.equal(g.presenze, 0, `${g.id}: presenze iniziali a zero`);
|
||||||
|
assert.equal(g.totaliEventi, 0, `${g.id}: totaliEventi iniziale a zero`);
|
||||||
|
assert.equal(g.mvp, 0, `${g.id}: mvp iniziale a zero`);
|
||||||
|
assert.equal(g.streak, 0, `${g.id}: streak iniziale a zero`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- formatData --------------------------------------------------------------
|
// --- formatData --------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user