import { createFileRoute, Link } from "@tanstack/react-router"; import { useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { Flame, Camera, Trash2, Bell, LogOut, ShieldCheck, Bug, Lightbulb } from "lucide-react"; import { cn } from "@/lib/utils"; import { PageHeader, Section, StatTile } from "@/components/crapp/ui-bits"; import { Avatar } from "@/components/crapp/Avatar"; import { caricaAvatar, rimuoviAvatar, useAvatarEsiste, useInvalidaAvatarEsiste, } from "@/lib/avatar-store"; import { SerieGriglia } from "@/components/crapp/SerieCard"; import { CollezioneBadge } from "@/components/crapp/CollezioneBadge"; import { ProfiloAmministrativo } from "@/components/crapp/ProfiloAmministrativo"; import { useVotiSocial } from "@/lib/badge-social"; import { useIo } from "@/lib/rosa"; import { usePresenzeUltimoMese } from "@/lib/presenze-mese"; import { attivaNotifiche, disattivaNotifiche, pushSupportato, statoNotifiche, } from "@/lib/push-client"; import { resetGiocatore } from "@/lib/user-store"; import { esci } from "@/lib/auth"; import { useIsAdmin } from "@/lib/ruoli"; import { Reveal } from "@/components/motion/Reveal"; export const Route = createFileRoute("/profilo")({ head: () => ({ meta: [ { title: "Profilo giocatore — CrAPP" }, { name: "description", content: "Foto, ruolo, statistiche personali, badge e obiettivi del giocatore CRAP Volley.", }, { property: "og:title", content: "Profilo giocatore — CrAPP" }, { property: "og:description", content: "Statistiche personali, badge e presenze della stagione.", }, ], }), component: Profilo, }); function Profilo() { const votiSocial = useVotiSocial(); const g = useIo(); const admin = useIsAdmin(); const ultimoMese = usePresenzeUltimoMese(g?.id); const inputRef = useRef(null); const fotoEsiste = useAvatarEsiste(g?.id); const invalidaAvatarEsiste = useInvalidaAvatarEsiste(); const [bust, setBust] = useState(0); const [notifiche, setNotifiche] = useState(false); const [inCorso, setInCorso] = useState(false); const [supportate, setSupportate] = useState(true); useEffect(() => { setSupportate(pushSupportato()); statoNotifiche() .then(setNotifiche) .catch(() => setNotifiche(false)); }, []); if (!g) return null; async function cambiaNotifiche() { if (!g || inCorso) return; setInCorso(true); try { if (notifiche) { await disattivaNotifiche(); setNotifiche(false); toast.success("Notifiche disattivate"); } else { await attivaNotifiche(g.id); setNotifiche(true); toast.success("Notifiche palloni attive"); } } catch (error) { toast.error(error instanceof Error ? error.message : "Notifiche non disponibili"); } finally { setInCorso(false); } } async function logout() { try { await esci(); resetGiocatore(); } catch (error) { toast.error(error instanceof Error ? error.message : "Uscita non riuscita"); } } const percPresenze = g.totaliEventi ? Math.round((g.presenze / g.totaliEventi) * 100) : 0; async function onFile(e: React.ChangeEvent) { const file = e.target.files?.[0]; e.target.value = ""; if (!file || !g) return; if (!confirm("Aggiornare l'immagine profilo?")) return; try { await caricaAvatar(g.id, file); setBust(Date.now()); invalidaAvatarEsiste(g.id); toast.success("Immagine profilo aggiornata"); } catch { toast.error("Non sono riuscito a caricare l'immagine"); } } return ( <>
{fotoEsiste.data ? ( ) : null}
{g.streak} } label="Presenze di fila" />
{[ "Notifiche convocazioni", "Promemoria allenamenti", "Cambi orario", "Bacheca squadra", ].map((v) => ( ))} {admin ? ( Dashboard amministratore ) : null} Segnala un bug Suggerisci una nuova funzionalità
); }