2026-08-06 08:36:47 +02:00
|
|
|
import { useState } from "react";
|
|
|
|
|
import { Check, Crown, Sparkles } from "lucide-react";
|
|
|
|
|
import { toast } from "sonner";
|
|
|
|
|
import { cn } from "@/lib/utils";
|
2026-09-03 10:17:03 +02:00
|
|
|
import { nomeCompleto, useGiocatoriSquadra } from "@/lib/giocatori-squadra";
|
2026-09-08 10:00:52 +02:00
|
|
|
import { useGiocatoreBase } from "@/lib/user-store";
|
2026-08-06 08:36:47 +02:00
|
|
|
import {
|
|
|
|
|
categorieSocial,
|
|
|
|
|
conteggioCategoria,
|
|
|
|
|
mioVotoSocial,
|
|
|
|
|
useVotaSocial,
|
|
|
|
|
useVotiSocial,
|
|
|
|
|
vincitoreCategoria,
|
|
|
|
|
} from "@/lib/badge-social";
|
|
|
|
|
|
|
|
|
|
/** Voto social post-partita: un compagno per categoria, veloce da mobile. */
|
|
|
|
|
export function VotoSocial({ matchId }: { matchId: string }) {
|
2026-09-08 10:00:52 +02:00
|
|
|
// Solo `.id` serve qui: `useGiocatoreBase` basta, niente statistiche.
|
|
|
|
|
const io = useGiocatoreBase();
|
2026-08-06 08:36:47 +02:00
|
|
|
const voti = useVotiSocial();
|
|
|
|
|
const vota = useVotaSocial();
|
2026-09-03 10:17:03 +02:00
|
|
|
const { righe: squadra } = useGiocatoriSquadra();
|
|
|
|
|
const rosa = squadra.filter((g) => g.attivo);
|
2026-08-06 08:36:47 +02:00
|
|
|
const [aperta, setAperta] = useState<string | null>(null);
|
|
|
|
|
|
|
|
|
|
const tutti = voti.data ?? [];
|
|
|
|
|
const fatti = io
|
|
|
|
|
? categorieSocial.filter((c) => mioVotoSocial(tutti, matchId, c.id, io.id)).length
|
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
|
|
async function invia(categoria: string, id: string, nome: string) {
|
|
|
|
|
if (!io) return;
|
|
|
|
|
if (id === io.id) {
|
|
|
|
|
toast.error("Non puoi votare te stesso");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
await vota.mutateAsync({
|
|
|
|
|
match_id: matchId,
|
|
|
|
|
categoria,
|
|
|
|
|
votante_id: io.id,
|
|
|
|
|
votato_id: id,
|
|
|
|
|
votato_nome: nome,
|
|
|
|
|
});
|
|
|
|
|
setAperta(null);
|
|
|
|
|
toast.success(`Voto registrato: ${nome}`);
|
|
|
|
|
} catch {
|
|
|
|
|
toast.error("Voto non riuscito, riprova");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-2">
|
2026-09-05 12:42:24 +02:00
|
|
|
<div className="rounded-2xl bg-secondary/60 px-3 py-2 text-xs font-semibold text-muted-foreground">
|
2026-08-06 08:36:47 +02:00
|
|
|
<span className="inline-flex items-center gap-1.5">
|
|
|
|
|
<Sparkles className="h-3.5 w-3.5 text-accent" />
|
|
|
|
|
Hai votato {fatti}/{categorieSocial.length} categorie · un solo voto per categoria
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{categorieSocial.map((cat) => {
|
|
|
|
|
const Icon = cat.icon;
|
|
|
|
|
const mio = io ? mioVotoSocial(tutti, matchId, cat.id, io.id) : null;
|
|
|
|
|
const vincitore = vincitoreCategoria(tutti, matchId, cat.id);
|
|
|
|
|
const conteggio = conteggioCategoria(tutti, matchId, cat.id);
|
|
|
|
|
const totale = conteggio.reduce((s, c) => s + c.voti, 0);
|
|
|
|
|
const isOpen = aperta === cat.id;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div key={cat.id} className="overflow-hidden rounded-3xl bg-card shadow-card">
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => setAperta(isOpen ? null : cat.id)}
|
|
|
|
|
disabled={!io}
|
|
|
|
|
className="flex w-full items-center gap-3 p-3 text-left active:scale-[0.99] disabled:opacity-60"
|
|
|
|
|
aria-expanded={isOpen}
|
|
|
|
|
>
|
|
|
|
|
<span className="grid h-10 w-10 shrink-0 place-items-center rounded-2xl bg-secondary text-lg">
|
|
|
|
|
{cat.emoji}
|
|
|
|
|
</span>
|
|
|
|
|
<span className="min-w-0 flex-1">
|
|
|
|
|
<span className="block truncate text-sm font-bold leading-tight">{cat.nome}</span>
|
2026-09-05 12:42:24 +02:00
|
|
|
<span className="block truncate text-xs text-muted-foreground">
|
2026-08-06 08:36:47 +02:00
|
|
|
{mio ? `Hai votato ${mio.votato_nome}` : cat.descrizione}
|
|
|
|
|
</span>
|
|
|
|
|
</span>
|
|
|
|
|
<span
|
|
|
|
|
className={cn(
|
2026-09-05 12:42:24 +02:00
|
|
|
"shrink-0 rounded-full px-2.5 py-1 text-xs font-bold uppercase",
|
2026-08-06 08:36:47 +02:00
|
|
|
mio ? "bg-success text-success-foreground" : "bg-accent text-accent-foreground",
|
|
|
|
|
)}
|
|
|
|
|
>
|
|
|
|
|
{mio ? <Check className="h-3 w-3" /> : "Vota"}
|
|
|
|
|
</span>
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
{isOpen ? (
|
|
|
|
|
<div className="grid max-h-56 grid-cols-2 gap-1.5 overflow-y-auto border-t border-border p-3">
|
2026-09-03 10:17:03 +02:00
|
|
|
{rosa
|
2026-08-06 08:36:47 +02:00
|
|
|
.filter((g) => g.id !== io?.id)
|
|
|
|
|
.map((g) => (
|
|
|
|
|
<button
|
|
|
|
|
key={g.id}
|
|
|
|
|
type="button"
|
|
|
|
|
disabled={vota.isPending}
|
2026-09-03 10:17:03 +02:00
|
|
|
onClick={() => invia(cat.id, g.id, nomeCompleto(g))}
|
2026-08-06 08:36:47 +02:00
|
|
|
className={cn(
|
|
|
|
|
"truncate rounded-xl px-2.5 py-2 text-left text-xs font-semibold transition-colors",
|
|
|
|
|
mio?.votato_id === g.id
|
|
|
|
|
? "bg-accent text-accent-foreground"
|
|
|
|
|
: "bg-secondary text-foreground",
|
|
|
|
|
)}
|
|
|
|
|
>
|
2026-09-03 10:17:03 +02:00
|
|
|
{nomeCompleto(g)}
|
2026-08-06 08:36:47 +02:00
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="border-t border-border px-3 py-2">
|
|
|
|
|
{totale === 0 ? (
|
2026-09-05 12:42:24 +02:00
|
|
|
<p className="text-xs text-muted-foreground">
|
2026-08-06 08:36:47 +02:00
|
|
|
Nessun voto ancora: apri e scegli un compagno.
|
|
|
|
|
</p>
|
|
|
|
|
) : vincitore ? (
|
|
|
|
|
<p className="inline-flex items-center gap-1.5 text-xs font-bold">
|
|
|
|
|
<Crown className="h-3.5 w-3.5 text-oro" />
|
|
|
|
|
<Icon className="h-3.5 w-3.5 text-accent" />
|
2026-09-01 13:38:33 +02:00
|
|
|
{vincitore.nome} · {vincitore.voti} {vincitore.voti === 1 ? "voto" : "voti"}
|
2026-08-06 08:36:47 +02:00
|
|
|
</p>
|
|
|
|
|
) : (
|
2026-09-05 12:42:24 +02:00
|
|
|
<p className="text-xs text-muted-foreground">
|
2026-08-06 08:36:47 +02:00
|
|
|
Parità con {totale} voti: servono altri voti per assegnare il badge.
|
|
|
|
|
</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2026-09-01 13:38:33 +02:00
|
|
|
}
|