diff --git a/src/components/crapp/EventoCard.tsx b/src/components/crapp/EventoCard.tsx
index aa476ce..51fabc4 100644
--- a/src/components/crapp/EventoCard.tsx
+++ b/src/components/crapp/EventoCard.tsx
@@ -1,9 +1,10 @@
import { MapPin, Clock, Users, Cake, ArrowRight } from "lucide-react";
import { Link } from "@tanstack/react-router";
import { cn } from "@/lib/utils";
-import { formatData, giocatori, statoMeta, type Stato } from "@/lib/crapp-data";
+import { formatData, statoMeta, type Stato } from "@/lib/crapp-data";
import type { Evento } from "@/lib/eventi";
import { Barra } from "@/components/motion/Barra";
+import { useGiocatoriSquadra } from "@/lib/giocatori-squadra";
import { usePresenzeEvento, useSalvaPresenza } from "@/lib/presenze";
import { useGiocatoreCorrente } from "@/lib/user-store";
@@ -36,16 +37,18 @@ export function EventoCard({
const { risposte } = usePresenzeEvento(evento.id);
const salva = useSalvaPresenza();
const io = useGiocatoreCorrente();
+ const { righe: squadra } = useGiocatoriSquadra();
+ const rosa = squadra.filter((g) => g.attivo);
const stato = io ? risposte[io.id] : undefined;
- const presentiVeri = giocatori.filter(
+ const presentiVeri = rosa.filter(
(g) => risposte[g.id] === "presente" || risposte[g.id] === "ritardo",
).length;
const tipo =
evento.tipo === "partita" && !evento.campionato
? { label: "Amichevole", className: "bg-accent/70 text-accent-foreground" }
: tipoMeta[evento.tipo];
- const totale = giocatori.length;
- const perc = Math.round((presentiVeri / totale) * 100);
+ const totale = rosa.length;
+ const perc = totale ? Math.round((presentiVeri / totale) * 100) : 0;
const isCompleanno = evento.tipo === "compleanno";
if (isCompleanno) {
diff --git a/src/components/crapp/Pagelle.tsx b/src/components/crapp/Pagelle.tsx
index fe6ceb3..cb23062 100644
--- a/src/components/crapp/Pagelle.tsx
+++ b/src/components/crapp/Pagelle.tsx
@@ -3,7 +3,7 @@ import { ClipboardCheck, Lock } from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { Avatar } from "@/components/crapp/Avatar";
-import { giocatori } from "@/lib/crapp-data";
+import type { Giocatore } from "@/lib/crapp-data";
import { useGiocatoreCorrente } from "@/lib/user-store";
import { mieiVoti, pagellePartita, usePagelle, useVotaPagella } from "@/lib/pagelle";
@@ -12,11 +12,11 @@ const voti = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
/** Pagelle di fine partita: voto anonimo 1-10 a ciascun compagno. */
export function Pagelle({
matchId,
- convocati = giocatori,
+ convocati,
chiuse = false,
}: {
matchId: string;
- convocati?: typeof giocatori;
+ convocati: Giocatore[];
chiuse?: boolean;
}) {
const io = useGiocatoreCorrente();
diff --git a/src/components/crapp/RosaPresenze.tsx b/src/components/crapp/RosaPresenze.tsx
index b16c018..8cafd8d 100644
--- a/src/components/crapp/RosaPresenze.tsx
+++ b/src/components/crapp/RosaPresenze.tsx
@@ -4,8 +4,9 @@ import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { Avatar } from "@/components/crapp/Avatar";
import { Barra } from "@/components/motion/Barra";
-import { giocatori, statoMeta, type Stato } from "@/lib/crapp-data";
+import { statoMeta, type Giocatore, type Stato } from "@/lib/crapp-data";
import { usePresenzeEvento, useSalvaPresenza } from "@/lib/presenze";
+import { useRosa } from "@/lib/rosa";
import { useGiocatoreCorrente } from "@/lib/user-store";
import { useIsAdmin } from "@/lib/ruoli";
@@ -16,13 +17,13 @@ export function RosaPresenze({ eventoId }: { eventoId: string }) {
const salva = useSalvaPresenza();
const io = useGiocatoreCorrente();
const admin = useIsAdmin();
+ const rosa = useRosa();
const [sollecito, setSollecito] = useState(false);
- const mancanti = giocatori.filter((g) => !risposte[g.id]);
- const risposteN = giocatori.length - mancanti.length;
- const perc = Math.round((risposteN / giocatori.length) * 100);
- const daSollecitare =
- mancanti.length + giocatori.filter((g) => risposte[g.id] === "forse").length;
+ const mancanti = rosa.filter((g) => !risposte[g.id]);
+ const risposteN = rosa.length - mancanti.length;
+ const perc = rosa.length ? Math.round((risposteN / rosa.length) * 100) : 0;
+ const daSollecitare = mancanti.length + rosa.filter((g) => risposte[g.id] === "forse").length;
async function sollecita() {
setSollecito(true);
@@ -51,7 +52,7 @@ export function RosaPresenze({ eventoId }: { eventoId: string }) {
- Hanno risposto {risposteN}/{giocatori.length}
+ Hanno risposto {risposteN}/{rosa.length}
{perc}%
@@ -59,7 +60,7 @@ export function RosaPresenze({ eventoId }: { eventoId: string }) {
{ordine.map((s) => {
- const n = giocatori.filter((g) => risposte[g.id] === s).length;
+ const n = rosa.filter((g) => risposte[g.id] === s).length;
return (
{
- const lista = giocatori.filter((g) => risposte[g.id] === s);
+ const lista = rosa.filter((g) => risposte[g.id] === s);
if (lista.length === 0) return null;
return (
r.evento_id === eventoId);
const mia = dellaPartita.find((r) => r.giocatore_id === io?.id);
@@ -18,7 +19,10 @@ export function SondaggioCacche({ eventoId }: { eventoId: string }) {
const classifica = [...dellaPartita]
.sort((a, b) => b.quantita - a.quantita)
.slice(0, 3)
- .map((r) => ({ ...r, nome: giocatori.find((g) => g.id === r.giocatore_id)?.nome ?? "—" }));
+ .map((r) => {
+ const g = squadra.find((g) => g.id === r.giocatore_id);
+ return { ...r, nome: g ? nomeCompleto(g) : "—" };
+ });
async function rispondi(quantita: number) {
if (!io) return;
diff --git a/src/components/crapp/TurnoPalloni.tsx b/src/components/crapp/TurnoPalloni.tsx
index da02d8a..8428344 100644
--- a/src/components/crapp/TurnoPalloni.tsx
+++ b/src/components/crapp/TurnoPalloni.tsx
@@ -3,7 +3,7 @@ import { Check, CircleDot, Loader2, Pencil } from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { Avatar } from "@/components/crapp/Avatar";
-import { giocatori } from "@/lib/crapp-data";
+import { nomeCompleto, useGiocatoriSquadra } from "@/lib/giocatori-squadra";
import { useAssegnaTurno, useTurniPalloni } from "@/lib/palloni";
import { useGiocatoreCorrente } from "@/lib/user-store";
@@ -12,10 +12,12 @@ export function TurnoPalloni({ eventoId }: { eventoId: string }) {
const { salvati, turni, isPending } = useTurniPalloni();
const assegna = useAssegnaTurno();
const io = useGiocatoreCorrente();
+ const { righe: squadra } = useGiocatoriSquadra();
+ const rosa = squadra.filter((g) => g.attivo);
const id = turni[eventoId];
const proposto = !salvati[eventoId];
- const giocatore = giocatori.find((g) => g.id === id);
+ const giocatore = rosa.find((g) => g.id === id);
function scegli(giocatoreId: string) {
setAperto(false);
@@ -46,7 +48,7 @@ export function TurnoPalloni({ eventoId }: { eventoId: string }) {
{isPending || assegna.isPending ? (
) : null}
- {giocatore ? giocatore.nome : "Da assegnare"}
+ {giocatore ? nomeCompleto(giocatore) : "Da assegnare"}
{proposto && giocatore ? (
proposto
@@ -59,7 +61,7 @@ export function TurnoPalloni({ eventoId }: { eventoId: string }) {
{aperto ? (
- {giocatori.map((g) => (
+ {rosa.map((g) => (
))}
diff --git a/src/components/crapp/VotazioneMvp.tsx b/src/components/crapp/VotazioneMvp.tsx
index f48c9ee..d678964 100644
--- a/src/components/crapp/VotazioneMvp.tsx
+++ b/src/components/crapp/VotazioneMvp.tsx
@@ -2,7 +2,7 @@ import { useState } from "react";
import { Crown, Vote } from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
-import { giocatori } from "@/lib/crapp-data";
+import { nomeCompleto, useGiocatoriSquadra } from "@/lib/giocatori-squadra";
import { useGiocatoreCorrente } from "@/lib/user-store";
import { conteggioPartita, mioVoto, useVotaMvp, useVotiMvp, type VotoMvp } from "@/lib/mvp-voti";
@@ -11,6 +11,8 @@ export function VotazioneMvp({ matchId }: { matchId: string }) {
const io = useGiocatoreCorrente();
const voti = useVotiMvp();
const vota = useVotaMvp();
+ const { righe: squadra } = useGiocatoriSquadra();
+ const rosa = squadra.filter((g) => g.attivo);
const [aperto, setAperto] = useState(false);
const tutti: VotoMvp[] = voti.data ?? [];
@@ -69,12 +71,12 @@ export function VotazioneMvp({ matchId }: { matchId: string }) {
{aperto ? (
- {giocatori.map((g) => (
+ {rosa.map((g) => (
))}
diff --git a/src/components/crapp/VotoSocial.tsx b/src/components/crapp/VotoSocial.tsx
index 5d66460..881b248 100644
--- a/src/components/crapp/VotoSocial.tsx
+++ b/src/components/crapp/VotoSocial.tsx
@@ -2,7 +2,7 @@ import { useState } from "react";
import { Check, Crown, Sparkles } from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
-import { giocatori } from "@/lib/crapp-data";
+import { nomeCompleto, useGiocatoriSquadra } from "@/lib/giocatori-squadra";
import { useGiocatoreCorrente } from "@/lib/user-store";
import {
categorieSocial,
@@ -18,6 +18,8 @@ export function VotoSocial({ matchId }: { matchId: string }) {
const io = useGiocatoreCorrente();
const voti = useVotiSocial();
const vota = useVotaSocial();
+ const { righe: squadra } = useGiocatoriSquadra();
+ const rosa = squadra.filter((g) => g.attivo);
const [aperta, setAperta] = useState
(null);
const tutti = voti.data ?? [];
@@ -93,14 +95,14 @@ export function VotoSocial({ matchId }: { matchId: string }) {
{isOpen ? (
- {giocatori
+ {rosa
.filter((g) => g.id !== io?.id)
.map((g) => (
))}
diff --git a/src/lib/eventi.ts b/src/lib/eventi.ts
index 78cce06..a3aa316 100644
--- a/src/lib/eventi.ts
+++ b/src/lib/eventi.ts
@@ -1,6 +1,6 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { supabase } from "@/integrations/supabase/client";
-import { giocatori } from "./crapp-data";
+import type { Giocatore } from "./crapp-data";
export type EventoTipo = "partita" | "allenamento" | "evento" | "compleanno";
@@ -158,8 +158,9 @@ export function useEliminaEvento() {
}
/** Compleanni della rosa, come eventi di calendario dell'anno indicato. */
-export function compleanniEventi(anno = new Date().getFullYear()): Evento[] {
- return giocatori
+export function compleanniEventi(rosa: Giocatore[], anno = new Date().getFullYear()): Evento[] {
+ return rosa
+ .filter((g) => g.nascita)
.map((g) => {
const md = g.nascita.slice(5);
const eta = anno - Number(g.nascita.slice(0, 4));
@@ -181,7 +182,7 @@ export function compleanniEventi(anno = new Date().getFullYear()): Evento[] {
}
/** Rosa convocata per un evento: se non specificata vale tutta la rosa. */
-export function convocatiEvento(evento: Evento | null) {
- if (!evento || evento.convocati.length === 0) return giocatori;
- return giocatori.filter((g) => evento.convocati.includes(g.id));
+export function convocatiEvento(evento: Evento | null, rosa: Giocatore[]) {
+ if (!evento || evento.convocati.length === 0) return rosa;
+ return rosa.filter((g) => evento.convocati.includes(g.id));
}
diff --git a/src/lib/scout-export.ts b/src/lib/scout-export.ts
index 9cf4e22..bafe5cc 100644
--- a/src/lib/scout-export.ts
+++ b/src/lib/scout-export.ts
@@ -1,4 +1,4 @@
-import { giocatori } from "./crapp-data";
+import type { Giocatore } from "./crapp-data";
import { azioniMeta, totaliPerGiocatore, type ScoutMatch } from "./scout-store";
/** Riga CSV con separatore ";" (Excel IT), riusata anche dall'export tesseramento. */
@@ -12,7 +12,7 @@ export function rigaCsv(campi: Array) {
}
/** Esporta la scoutizzazione di una partita in CSV (separatore ";" per Excel IT). */
-export function csvScoutMatch(match: ScoutMatch): string {
+export function csvScoutMatch(match: ScoutMatch, rosa: Giocatore[]): string {
const righe: string[] = [];
righe.push(
rigaCsv([
@@ -29,7 +29,7 @@ export function csvScoutMatch(match: ScoutMatch): string {
righe.push("");
righe.push(rigaCsv(["Numero", "Giocatore", "Ruolo", "Punti", "Ace", "Muri", "Errori"]));
const totali = totaliPerGiocatore(match.azioni);
- for (const g of giocatori) {
+ for (const g of rosa) {
const t = totali.get(g.id);
if (!t) continue;
righe.push(rigaCsv([g.numero, g.nome, g.ruolo, t.punti, t.ace, t.muri, t.errori]));
@@ -37,7 +37,7 @@ export function csvScoutMatch(match: ScoutMatch): string {
righe.push("");
righe.push(rigaCsv(["Set", "Giocatore", "Azione"]));
for (const a of match.azioni) {
- const g = giocatori.find((x) => x.id === a.giocatoreId);
+ const g = rosa.find((x) => x.id === a.giocatoreId);
righe.push(rigaCsv([a.set, g?.nome ?? "—", azioniMeta[a.tipo].label]));
}
return righe.join("\n");
diff --git a/src/routes/allenamento.$id.tsx b/src/routes/allenamento.$id.tsx
index fcd32eb..456f8fe 100644
--- a/src/routes/allenamento.$id.tsx
+++ b/src/routes/allenamento.$id.tsx
@@ -1,8 +1,9 @@
import { createFileRoute, Link } from "@tanstack/react-router";
import { ArrowLeft, MapPin, Clock, Users, Dumbbell, CalendarDays } from "lucide-react";
import { PageHeader, Section } from "@/components/crapp/ui-bits";
-import { formatData, giocatori } from "@/lib/crapp-data";
+import { formatData } from "@/lib/crapp-data";
import { convocatiEvento, useEvento } from "@/lib/eventi";
+import { useRosa } from "@/lib/rosa";
import { TurnoPalloni } from "@/components/crapp/TurnoPalloni";
import { RosaPresenze } from "@/components/crapp/RosaPresenze";
import { usePresenzeEvento } from "@/lib/presenze";
@@ -34,7 +35,8 @@ function AllenamentoDetail() {
const { id } = Route.useParams();
const { evento } = useEvento(id);
const { risposte } = usePresenzeEvento(id);
- const presentiVeri = giocatori.filter(
+ const rosa = useRosa();
+ const presentiVeri = rosa.filter(
(g) => risposte[g.id] === "presente" || risposte[g.id] === "ritardo",
).length;
@@ -90,7 +92,7 @@ function AllenamentoDetail() {
- Conferme: {presentiVeri}/{convocatiEvento(evento).length}
+ Conferme: {presentiVeri}/{convocatiEvento(evento, rosa).length}
diff --git a/src/routes/calendario.tsx b/src/routes/calendario.tsx
index 1c932dc..ed01735 100644
--- a/src/routes/calendario.tsx
+++ b/src/routes/calendario.tsx
@@ -6,6 +6,7 @@ import { cn } from "@/lib/utils";
import { EventoCard, linkPerEvento } from "@/components/crapp/EventoCard";
import { PageHeader, Section } from "@/components/crapp/ui-bits";
import { compleanniEventi, useEventi, type Evento } from "@/lib/eventi";
+import { useRosa } from "@/lib/rosa";
import { useGiocatoreCorrente } from "@/lib/user-store";
import { useIsAdmin } from "@/lib/ruoli";
import {
@@ -100,11 +101,12 @@ function Calendario() {
const io = useGiocatoreCorrente();
const admin = useIsAdmin();
const { eventi } = useEventi();
+ const rosa = useRosa();
const { anno, mese, precedente, successivo } = useMeseNav();
const { giorni, offsetLunedi } = giorniDelMese(anno, mese);
const mesePrefix = `${anno}-${pad2(mese + 1)}`;
- const compleanni = compleanniEventi(anno);
+ const compleanni = compleanniEventi(rosa, anno);
const compleanniMese = compleanni.filter((c) => c.data.startsWith(mesePrefix));
const eventiMese = eventi.filter((e) => e.data.startsWith(mesePrefix));
diff --git a/src/routes/eventi.tsx b/src/routes/eventi.tsx
index b870418..39803ac 100644
--- a/src/routes/eventi.tsx
+++ b/src/routes/eventi.tsx
@@ -4,7 +4,8 @@ import { ArrowLeft, CalendarPlus, Loader2, Pencil, Trash2 } from "lucide-react";
import { toast } from "sonner";
import { cn } from "@/lib/utils";
import { PageHeader, Section } from "@/components/crapp/ui-bits";
-import { formatData, giocatori } from "@/lib/crapp-data";
+import { formatData } from "@/lib/crapp-data";
+import { nomeCompleto, useGiocatoriSquadra } from "@/lib/giocatori-squadra";
import {
categoriaEvento,
daCategoria,
@@ -50,9 +51,11 @@ function GestioneEventi() {
const io = useGiocatoreCorrente();
const admin = useIsAdmin();
const { eventi, isPending } = useEventi();
+ const { righe: squadra } = useGiocatoriSquadra();
const salva = useSalvaEvento();
const elimina = useEliminaEvento();
const [bozza, setBozza] = useState(null);
+ const rosa = squadra.filter((g) => g.attivo);
if (!io || !admin) {
return (
@@ -228,7 +231,7 @@ function GestioneEventi() {
label={`Convocati (${bozza.convocati.length === 0 ? "tutta la rosa" : bozza.convocati.length})`}
>
- {giocatori.map((g) => {
+ {rosa.map((g) => {
const scelto = bozza.convocati.includes(g.id);
return (
);
})}
diff --git a/src/routes/partita.$id.tsx b/src/routes/partita.$id.tsx
index 64ac78d..f324424 100644
--- a/src/routes/partita.$id.tsx
+++ b/src/routes/partita.$id.tsx
@@ -2,8 +2,9 @@ import { createFileRoute, Link } from "@tanstack/react-router";
import { ArrowLeft, MapPin, Clock, Users, Trophy, Swords, Download } from "lucide-react";
import { cn } from "@/lib/utils";
import { PageHeader, Section } from "@/components/crapp/ui-bits";
-import { formatData, giocatori } from "@/lib/crapp-data";
+import { formatData } from "@/lib/crapp-data";
import { convocatiEvento, useEvento } from "@/lib/eventi";
+import { useRosa } from "@/lib/rosa";
import { useCsi } from "@/lib/csi";
import { matchDaPartitaCsi, partiteGiocate } from "@/lib/csi-core";
import { Pagelle } from "@/components/crapp/Pagelle";
@@ -49,7 +50,8 @@ function PartitaDetail() {
const scoutMatches = useScoutMatches();
const { data: csi } = useCsi();
const { risposte } = usePresenzeEvento(id);
- const presentiVeri = giocatori.filter(
+ const rosa = useRosa();
+ const presentiVeri = rosa.filter(
(g) => risposte[g.id] === "presente" || risposte[g.id] === "ritardo",
).length;
@@ -67,7 +69,7 @@ function PartitaDetail() {
);
}
- const convocati = convocatiEvento(evento);
+ const convocati = convocatiEvento(evento, rosa);
const scout = scoutMatches.find((m) => m.id === evento.id || m.data === evento.data) ?? null;
const csiMatch = csi
? partiteGiocate(csi.partite).find((p) => p.data === evento.data)
@@ -229,7 +231,7 @@ function PartitaDetail() {
{[...totaliPerGiocatore(scout.azioni).entries()].map(([gid, t]) => {
- const g = giocatori.find((x) => x.id === gid);
+ const g = rosa.find((x) => x.id === gid);
if (!g) return null;
return (
- scaricaCsv(`scout-${scout.data}-${scout.avversario}.csv`, csvScoutMatch(scout))
+ scaricaCsv(
+ `scout-${scout.data}-${scout.avversario}.csv`,
+ csvScoutMatch(scout, rosa),
+ )
}
className="premi mt-4 flex w-full items-center justify-center gap-2 rounded-2xl bg-accent-grad py-3 text-sm font-bold uppercase text-accent-foreground shadow-pop"
>
diff --git a/src/routes/scout.tsx b/src/routes/scout.tsx
index 7a45436..b7f2815 100644
--- a/src/routes/scout.tsx
+++ b/src/routes/scout.tsx
@@ -3,8 +3,9 @@ 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 { giocatori, formatData } from "@/lib/crapp-data";
+import { formatData } from "@/lib/crapp-data";
import type { Evento } from "@/lib/eventi";
+import { useRosa } from "@/lib/rosa";
import { useGiocatoreCorrente } from "@/lib/user-store";
import { useIsAdmin } from "@/lib/ruoli";
import { usePresenzeEvento } from "@/lib/presenze";
@@ -214,15 +215,16 @@ function ScoutBoard({
const cancella = useCancellaStatoScout();
const salvaMatch = useSalvaScoutMatch();
const { risposte } = usePresenzeEvento(partita.id);
+ const rosa = useRosa();
const finito = useRef(false);
/** In campo solo chi ha confermato la presenza (anche in ritardo). */
const convocati = useMemo(() => {
- const presenti = giocatori.filter(
+ const presenti = rosa.filter(
(g) => risposte[g.id] === "presente" || risposte[g.id] === "ritardo",
);
- return presenti.length > 0 ? presenti : giocatori;
- }, [risposte]);
+ return presenti.length > 0 ? presenti : rosa;
+ }, [risposte, rosa]);
// Salvataggio condiviso: se chi scouta si disconnette, il prossimo riprende da qui.
useEffect(() => {
@@ -453,7 +455,7 @@ function ScoutBoard({
) : (
{ultime.map((a, i) => {
- const g = giocatori.find((x) => x.id === a.giocatoreId);
+ const g = rosa.find((x) => x.id === a.giocatoreId);
return (