"use client"; // Gestione della whitelist email che apre il portale di un cliente (gate OTP v2.3). // Scritto a token semantici anche se la pagina che lo ospita è ancora a palette // vecchia: quando /admin/clients/[id] verrà rifatta, questa sezione non si tocca. import { useRef, useState, useTransition } from "react"; import { useRouter } from "next/navigation"; import { addClientEmail, removeClientEmail, revokeClientSessions, } from "@/app/admin/clients/[id]/actions"; import type { ClientAccessEmail } from "@/lib/admin-queries"; import { Button } from "@/components/ui/button"; export function ClientAccessSection({ clientId, emails, }: { clientId: string; emails: ClientAccessEmail[]; }) { const [error, setError] = useState(null); const [revokeArmed, setRevokeArmed] = useState(false); const [revokedAt, setRevokedAt] = useState(null); const [isPending, startTransition] = useTransition(); const formRef = useRef(null); const router = useRouter(); function handleAdd(formData: FormData) { setError(null); startTransition(async () => { const res = await addClientEmail(clientId, formData); if (!res.ok) { setError(res.error); return; } formRef.current?.reset(); router.refresh(); }); } function handleRemove(emailId: string) { startTransition(async () => { await removeClientEmail(clientId, emailId); router.refresh(); }); } function handleRevoke() { if (!revokeArmed) { setRevokeArmed(true); return; } startTransition(async () => { await revokeClientSessions(clientId); setRevokeArmed(false); setRevokedAt(new Date().toLocaleString("it-IT")); router.refresh(); }); } return (

Accessi al portale

Solo queste email possono richiedere il codice di accesso. Chi ha il link ma non è in elenco non entra.

{revokeArmed ? (
Tutti dovranno rifare l'accesso. Confermi?
) : ( )}
{revokedAt && (

Sessioni revocate il {revokedAt}.

)}
{emails.length === 0 ? (

Nessuna email autorizzata — il cliente non può ancora accedere al portale.

) : (
    {emails.map((e) => (
  • {e.email}
  • ))}
)}
{error &&

{error}

}
); }