- «Rosa e presenze» (allenamento, partita, evento) elenca, conta e solleciti solo i convocati invece di tutta la rosa; il riquadro «La tua risposta» sparisce per i non convocati. - Calendario, Home e elenco eventi mostrano un evento con convocati solo a chi è convocato; admin e allenatori lo vedono sempre, `convocati` vuoto = tutti (eventoVisibile). - Filtro solo lato interfaccia: la RLS di eventi_app non cambia. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
101 lines
3.4 KiB
TypeScript
101 lines
3.4 KiB
TypeScript
import { createFileRoute } from "@tanstack/react-router";
|
|
import { MapPin, Clock, Users, PartyPopper } from "lucide-react";
|
|
import { PageHeader, Section } from "@/components/crapp/ui-bits";
|
|
import { formatData } from "@/lib/crapp-data";
|
|
import { convocatiEvento, useEvento } from "@/lib/eventi";
|
|
import { useRosa } from "@/lib/rosa";
|
|
import { RosaPresenze } from "@/components/crapp/RosaPresenze";
|
|
import { usePresenzeEvento } from "@/lib/presenze";
|
|
|
|
export const Route = createFileRoute("/evento/$id")({
|
|
head: () => {
|
|
const titolo = "Dettaglio evento";
|
|
return {
|
|
meta: [
|
|
{ title: `${titolo} — CrAPP` },
|
|
{
|
|
name: "description",
|
|
content: "Dettaglio evento extra-campo, orario, luogo e presenze del CRAP Volley.",
|
|
},
|
|
{ property: "og:title", content: `${titolo} — CrAPP` },
|
|
{
|
|
property: "og:description",
|
|
content: "Dettaglio evento extra-campo, orario, luogo e presenze del CRAP Volley.",
|
|
},
|
|
{ property: "og:type", content: "website" },
|
|
{ name: "twitter:card", content: "summary" },
|
|
],
|
|
};
|
|
},
|
|
component: EventoDetail,
|
|
});
|
|
|
|
function EventoDetail() {
|
|
const { id } = Route.useParams();
|
|
const { evento } = useEvento(id);
|
|
const { risposte } = usePresenzeEvento(id);
|
|
const rosa = useRosa();
|
|
const presentiVeri = rosa.filter(
|
|
(g) => risposte[g.id] === "presente" || risposte[g.id] === "ritardo",
|
|
).length;
|
|
|
|
if (!evento) {
|
|
return (
|
|
<div className="px-5 pt-8">
|
|
<p className="mt-8 text-center text-[15px] text-muted-foreground">Evento non trovato</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<PageHeader titolo="Evento" sottotitolo={formatData(evento.data)} />
|
|
|
|
<Section titolo={evento.titolo}>
|
|
<div className="rounded-3xl bg-card p-5 shadow-card">
|
|
<div className="flex items-center gap-3">
|
|
<div className="grid h-12 w-12 shrink-0 place-items-center rounded-2xl bg-warning/15 text-warning">
|
|
<PartyPopper className="h-6 w-6" />
|
|
</div>
|
|
<div className="min-w-0 flex-1">
|
|
<p className="text-[13px] font-bold uppercase tracking-wide text-muted-foreground">
|
|
Evento extra-campo
|
|
</p>
|
|
<p className="truncate text-lg font-bold leading-tight">{evento.titolo}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-4 space-y-2 text-[15px] text-muted-foreground">
|
|
<span className="inline-flex items-center gap-2">
|
|
<Clock className="h-4 w-4" /> {evento.ora}
|
|
</span>
|
|
<span className="ml-4 inline-flex items-center gap-2">
|
|
<MapPin className="h-4 w-4" /> {evento.luogo}
|
|
</span>
|
|
</div>
|
|
|
|
{evento.note ? (
|
|
<p className="mt-3 whitespace-pre-line rounded-2xl bg-secondary px-3 py-2 text-[15px]">
|
|
{evento.note}
|
|
</p>
|
|
) : null}
|
|
|
|
<div className="mt-4 inline-flex items-center gap-2 rounded-full bg-secondary px-3 py-1.5 text-[13px] font-semibold">
|
|
<Users className="h-4 w-4" />
|
|
Conferme: {presentiVeri}/{convocatiEvento(evento, rosa).length}
|
|
</div>
|
|
</div>
|
|
</Section>
|
|
|
|
<Section titolo="Rosa e presenze">
|
|
<RosaPresenze
|
|
eventoId={evento.id}
|
|
data={evento.data}
|
|
tipo={evento.tipo}
|
|
convocati={evento.convocati}
|
|
/>
|
|
</Section>
|
|
</>
|
|
);
|
|
}
|