#
Squadra
G
Set
Pt
{righe.length === 0 ? (
{vuoto}
) : (
righe.map((r) => {
const noi = isNostraSquadra(r.squadra) || r.squadra === "CRAP Volley";
return (
{r.pos}
{r.squadra}
{r.giocate}
{r.setFatti}:{r.setSubiti}
{r.punti}
);
})
)}
);
}
function formatAggiornamento(iso: string) {
const d = new Date(iso);
const oggi = new Date().toDateString() === d.toDateString();
const ora = d.toLocaleTimeString("it-IT", { hour: "2-digit", minute: "2-digit" });
return oggi ? `oggi alle ${ora}` : `il ${d.toLocaleDateString("it-IT")} alle ${ora}`;
}
function Classifica() {
const { tab } = Route.useSearch();
const scoutMatches = useScoutMatches();
const { data: csi } = useCsi();
const votiMvp = useVotiMvp();
const { eventi } = useEventi();
const classifica = useMemo(() => csi?.classifica ?? [], [csi]);
const classificaCoppa = useMemo(() => csi?.classificaCoppa ?? [], [csi]);
const mvpPerMatch = useMemo(() => vincitoriMvp(votiMvp.data ?? []), [votiMvp.data]);
const eventoIdPerData = useMemo(
() => new Map(eventi.filter((e) => e.tipo === "partita").map((e) => [e.data, e.id])),
[eventi],
);
// I voti MVP sono legati all'evento CrAPP, non al referto CSI né allo scout.
const tuttiMatch = useMemo(() => {
const mvpPerData = (data: string) => mvpPerMatch[eventoIdPerData.get(data) ?? ""] ?? "";
const csiGiocate = csi ? partiteGiocate(csi.partite) : [];
return csiGiocate.length
? csiGiocate.map((p) => {
const m = matchDaPartitaCsi(p);
return { ...m, mvp: mvpPerData(m.data), scout: false };
})
: scoutMatches.map((m) => ({
id: m.id,
data: m.data,
avversario: m.avversario,
logoAvversario: "",
casa: m.casa,
setNostri: m.setNostri,
setLoro: m.setLoro,
parziali: m.parziali,
mvp: mvpPerData(m.data),
scout: true,
}));
}, [csi, scoutMatches, mvpPerMatch, eventoIdPerData]);
// Ogni tab è memoizzata: un refetch in background di uno solo dei dati (CSI,
// scout, eventi, voti MVP) non deve ricostruire il JSX dell'altra tab.
const contenutoClassifica = useMemo(
() => (
<>
{csi?.formatoSospetto ? (
) : (
)}
{csi?.formatoSospetto
? "Il portale CSI potrebbe aver cambiato formato: dati da verificare."
: csi
? `Dati CSI aggiornati ${formatAggiornamento(csi.aggiornato)}`
: "Dati CSI in arrivo"}
{classificaCoppa.length > 0 ? (
<>
{tuttiMatch.map((m) => {
const vinta = m.setNostri > m.setLoro;
const eventoId = eventoIdPerData.get(m.data);
const cliccabile = Boolean(eventoId) || !m.scout;
const casa = {
nome: m.casa ? NOME_NOI : m.avversario,
nostro: m.casa,
};
const trasferta = {
nome: m.casa ? m.avversario : NOME_NOI,
nostro: !m.casa,
};
// Badge e parziali in ordine casa–ospite; il colore resta sulla vittoria CRAP.
const setCasa = m.casa ? m.setNostri : m.setLoro;
const setOspite = m.casa ? m.setLoro : m.setNostri;
const contenuto = (
<>
{formatData(m.data)} · MVP {m.mvp || "da votare"}
{m.scout ? " · scoutata" : ""}
{setCasa}-{setOspite}
{cliccabile ? (
) : null}
{m.parziali.map((p, i) => {
const puntiCasa = m.casa ? p[0] : p[1];
const puntiOspite = m.casa ? p[1] : p[0];
const setVintoDaNoi = p[0] > p[1];
return (
{puntiCasa}-{puntiOspite}
);
})}
{eventoId && !m.mvp ? (
Vota MVP
) : null}
>
);
const aria = `${casa.nome} vs ${trasferta.nome}: dettaglio partita`;
if (eventoId) {
return (
{contenuto}
);
}
// Senza evento CrAPP collegato (nessuna creazione automatica dal calendario
// CSI, vedi "Evoluzioni possibili"): le gare scoutate localmente non hanno un
// corrispettivo sul portale da mostrare, quelle CSI sì.
return m.scout ? (
{contenuto}
) : (
{contenuto}
);
})}
),
[tuttiMatch, eventoIdPerData],
);
return (
<>