Files
CRAPP/src/components/crapp/AdminLogin.tsx
T
davideandClaude Sonnet 5 c2667b3bfe Sostituisco l'admin per nome con un login vero (account Strapi)
Le azioni da referente (/scout, /eventi, sollecito presenze, export CSV
scout) non dipendono più da quale giocatore hai scelto di essere in
/benvenuto (chiunque poteva scegliere "Ivan Cacciari" senza password), ma
da un login reale contro l'account admin di Strapi (già usato per gestire
rosa/classifica/storico), verificato via /admin/login.

Nuovi src/lib/admin-auth.ts (loginAdmin/logoutAdmin/useAdminSession, sessione
locale di 8h) e src/components/crapp/AdminLogin.tsx (form riutilizzabile),
raggiungibile da /profilo e dalle schermate riservate. Rimossi adminNomi/
isAdmin da crapp-data.ts.

Resta un limite noto: questo protegge solo la UI dell'app, le tabelle
Supabase coinvolte hanno ancora RLS aperta e restano scrivibili in diretto
con la chiave anon — un fix più ampio (Supabase Auth + RLS reale) è
documentato ma non ancora fatto.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-28 16:17:05 +02:00

80 lines
2.9 KiB
TypeScript

import { useState } from "react";
import { Loader2, Lock } from "lucide-react";
import { toast } from "sonner";
import { loginAdmin, logoutAdmin, useAdminSession } from "@/lib/admin-auth";
/** Sblocca le funzioni admin (scout, gestione eventi, sollecito presenze) con la password
* dell'account Strapi dei referenti — non più scegliendo semplicemente il proprio nome. */
export function AdminLogin() {
const { attivo, email } = useAdminSession();
const [inputEmail, setInputEmail] = useState("");
const [password, setPassword] = useState("");
const [inCorso, setInCorso] = useState(false);
if (attivo) {
return (
<div className="flex items-center justify-between gap-3 rounded-2xl bg-secondary/60 p-3">
<span className="min-w-0 text-sm">
<span className="block font-semibold">Admin attivo</span>
<span className="block truncate text-[11px] text-muted-foreground">{email}</span>
</span>
<button
type="button"
onClick={() => {
logoutAdmin();
toast.success("Uscito dalla modalità admin");
}}
className="shrink-0 rounded-full bg-card px-3 py-1.5 text-[11px] font-bold uppercase text-foreground shadow-card"
>
Esci
</button>
</div>
);
}
async function accedi(e: React.FormEvent) {
e.preventDefault();
if (!inputEmail || !password || inCorso) return;
setInCorso(true);
const risultato = await loginAdmin(inputEmail, password);
setInCorso(false);
if (risultato.ok) {
setPassword("");
toast.success("Modalità admin attiva");
} else {
toast.error(risultato.errore);
}
}
return (
<form onSubmit={accedi} className="space-y-2 rounded-2xl bg-secondary/60 p-3">
<p className="inline-flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-wide text-muted-foreground">
<Lock className="h-3.5 w-3.5" /> Accedi come admin (account Strapi)
</p>
<input
type="email"
value={inputEmail}
onChange={(e) => setInputEmail(e.target.value)}
placeholder="Email"
autoComplete="username"
className="w-full rounded-xl border border-border bg-background px-3 py-2 text-sm"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
autoComplete="current-password"
className="w-full rounded-xl border border-border bg-background px-3 py-2 text-sm"
/>
<button
type="submit"
disabled={inCorso}
className="flex w-full items-center justify-center gap-2 rounded-xl bg-accent-grad py-2.5 text-sm font-bold uppercase text-accent-foreground shadow-pop disabled:opacity-50"
>
{inCorso ? <Loader2 className="h-4 w-4 animate-spin" /> : null} Accedi
</button>
</form>
);
}