import { useState } from "react"; import { createFileRoute } from "@tanstack/react-router"; import { Cake, ChevronDown, Crown, SlidersHorizontal, Trophy } from "lucide-react"; import { cn } from "@/lib/utils"; import { PageHeader, Select, StatTile } from "@/components/crapp/ui-bits"; import { BarraSottosezioni } from "@/components/crapp/BarraSottosezioni"; import { Avatar } from "@/components/crapp/Avatar"; import { formatData } from "@/lib/crapp-data"; import { microcopyObiettivo, progressoObiettivo } from "@/lib/obiettivi"; import { useRosa, useObiettivi } from "@/lib/rosa"; import { usePresenzeUltimoMeseTutti } from "@/lib/presenze-mese"; import { totaliSquadra, useScoutMatches } from "@/lib/scout-store"; import { useCsi } from "@/lib/csi"; import { partiteGiocate } from "@/lib/csi-core"; import { mediaSquadra, usePagelle } from "@/lib/pagelle"; import { Reveal } from "@/components/motion/Reveal"; import { Barra } from "@/components/motion/Barra"; import { Numero } from "@/components/motion/Numero"; import { BadgeDrawer } from "@/components/crapp/BadgeDrawer"; import { Drawer, DrawerClose, DrawerContent, DrawerHeader, DrawerTitle, } from "@/components/ui/drawer"; import { badgeDefs, badgeGiocatore, badgeSegretiSbloccati, descrizioneSoglie, gradiOrdine, gradoMeta, gradoRaggiunto, collezioneBadge, } from "@/lib/badges"; function RuoloBadge({ ruolo }: { ruolo: string }) { return ( {ruolo} ); } export const Route = createFileRoute("/squadra")({ head: () => ({ meta: [ { title: "Squadra CRAP Volley — CrAPP" }, { name: "description", content: "Rosa completa del CRAP Volley: giocatori, dati anagrafici, statistiche stagionali e badge sbloccati.", }, { property: "og:title", content: "Squadra CRAP Volley — CrAPP" }, { property: "og:description", content: "Tutti i giocatori della rosa con dati, statistiche e obiettivi raggiunti.", }, ], }), component: Squadra, }); const criteri = [ { id: "presenze", label: "Presenze" }, { id: "mediaVoto", label: "Media voto" }, { id: "mvp", label: "MVP" }, { id: "palloni", label: "Palloni" }, { id: "cacchePartita", label: "Cacche" }, ] as const; type Criterio = (typeof criteri)[number]["id"]; function valore( g: { presenze: number; mediaVoto: number; mvp: number; palloni: number; cacchePartita: number }, c: Criterio, ) { return g[c] ?? 0; } function Squadra() { const rosa = useRosa(); const mese = usePresenzeUltimoMeseTutti(); const scoutMatches = useScoutMatches(); const { voti: pagelle } = usePagelle(); const [aperto, setAperto] = useState(null); const [criterio, setCriterio] = useState("presenze"); const [filtroAperto, setFiltroAperto] = useState(false); const obiettivi = useObiettivi(); const team = totaliSquadra(scoutMatches); const mediaPresenze = rosa.length ? Math.round( (rosa.reduce((s, g) => s + g.presenze / (g.totaliEventi || 1), 0) / rosa.length) * 100, ) : 0; const ordinati = [...rosa].sort((a, b) => valore(b, criterio) - valore(a, criterio)); const max = ordinati[0] ? valore(ordinati[0], criterio) || 1 : 1; const { data: csi } = useCsi(); const matchGiocati = csi ? partiteGiocate(csi.partite).length : scoutMatches.length; const completati = obiettivi.filter((o) => progressoObiettivo(o) >= 100).length; const mediaObiettivi = obiettivi.length ? Math.round(obiettivi.reduce((s, o) => s + progressoObiettivo(o), 0) / obiettivi.length) : 0; return ( <> {rosa.map((g) => { const stati = badgeGiocatore(g); const sbloccati = [ ...stati.filter((b) => b.grado !== null), ...badgeSegretiSbloccati(g), ]; const isOpen = aperto === g.id; return (
{isOpen ? (

{formatData(g.nascita)}{" "} {g.nascita.slice(0, 4)}

{[ { l: "Presenze", v: `${g.presenze}/${g.totaliEventi}` }, { l: "Presenze 30gg", v: `${mese[g.id]?.percentuale ?? 0}%` }, { l: "Presenze di fila", v: g.streak }, { l: "Media voto", v: g.mediaVoto || "—" }, { l: "MVP", v: g.mvp }, { l: "Cacche/partita 💩", v: g.cacchePartita || "—" }, ].map((s) => (

{s.v}

{s.l}

))}

Badge sbloccati · {collezioneBadge(g).ottenuti}/ {collezioneBadge(g).totali}

{sbloccati.length === 0 ? (

Nessun badge sbloccato per ora.

) : (
{sbloccati.map((b) => { const Icon = b.def.icon; const meta = gradoMeta[b.grado!]; return (

{b.def.nome}

{b.valore} {b.def.unita} {b.prossimaSoglia ? ` · ${b.prossimaSoglia} per ${gradoMeta[b.prossimo!].label.toLowerCase()}` : ""}

{meta.label}

); })}
)}
) : null}
); })} ), }, { id: "stats", label: "Statistiche", contenuto: (
), }, { id: "classifica-giocatori", label: "Classifica", nascondiTitolo: true, contenuto: ( <>
Classifica per
Classifica per
{criteri.map((c) => ( ))}
{ordinati.map((g, i) => (
{i + 1}

{g.nome} {i === 0 ? ( ) : null}

#{g.numero} · {g.ruolo} · {g.streak} presenze consecutive

{valore(g, criterio) || "—"}
))}
), }, { id: "obiettivi", label: "Obiettivi", contenuto: ( <>

Progresso collettivo

{completati}/{obiettivi.length} completati

{obiettivi.map((o, i) => { const pct = progressoObiettivo(o); const fatto = pct >= 100; return ( = 90 ? "ring-accent/40" : "ring-transparent", )} >
{o.emoji}

{o.titolo}

{o.descrizione}

{fatto ? "Completato" : `${pct}%`}

{o.valore}/{o.target} {o.unita} · {pct}% {o.scadenza ? ` · entro il ${formatData(o.scadenza)}` : ""}

{microcopyObiettivo(o)}

{o.impatto}

); })}
), }, { id: "badge", label: "Badge", contenuto: (
{badgeDefs.map((b) => { const Icon = b.icon; return (

{b.nome}

{descrizioneSoglie(b)}

{gradiOrdine.map((grado) => { const meta = gradoMeta[grado]; const quanti = rosa.filter((g) => { const raggiunto = gradoRaggiunto(b, b.valore(g)); return raggiunto ? gradiOrdine.indexOf(raggiunto) >= gradiOrdine.indexOf(grado) : false; }).length; return (

{meta.label}

{b.soglie[grado]}

{quanti}/{rosa.length}

); })}
); })}
), }, ]} /> ); }