import { useState, useEffect } from 'react' import { Plus, Copy, Check, Loader2 } from 'lucide-react' import api from '@/services/api' import type { InvitationResponse, CreateInvitationPayload } from '@/types' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Skeleton } from '@/components/ui/skeleton' import { Alert, AlertDescription } from '@/components/ui/alert' import { Tooltip, TooltipContent, TooltipTrigger, } from '@/components/ui/tooltip' export function AdminInvitationsPage() { const [invitations, setInvitations] = useState([]) const [loading, setLoading] = useState(true) // Create dialog const [createOpen, setCreateOpen] = useState(false) const [createForm, setCreateForm] = useState({ email: '', role: 'dak_mitarbeiter', expires_in_days: 7, }) const [creating, setCreating] = useState(false) const [createError, setCreateError] = useState('') const [createdToken, setCreatedToken] = useState(null) // Copy feedback const [copiedId, setCopiedId] = useState(null) useEffect(() => { fetchInvitations() }, []) const fetchInvitations = () => { setLoading(true) api.get('/admin/invitations', { params: { skip: 0, limit: 200 } }) .then((res) => setInvitations(res.data)) .catch(() => setInvitations([])) .finally(() => setLoading(false)) } const handleCreate = async () => { setCreating(true) setCreateError('') setCreatedToken(null) try { const payload: Record = { role: createForm.role, expires_in_days: createForm.expires_in_days, } if (createForm.email && createForm.email.trim()) { payload.email = createForm.email.trim() } const res = await api.post('/admin/invitations', payload) setCreatedToken(res.data.token) fetchInvitations() } catch (err: unknown) { const msg = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail setCreateError(msg || 'Fehler beim Erstellen der Einladung.') } finally { setCreating(false) } } const copyToken = async (token: string, id: number) => { try { await navigator.clipboard.writeText(token) setCopiedId(id) setTimeout(() => setCopiedId(null), 2000) } catch { // Fallback const textarea = document.createElement('textarea') textarea.value = token document.body.appendChild(textarea) textarea.select() document.execCommand('copy') document.body.removeChild(textarea) setCopiedId(id) setTimeout(() => setCopiedId(null), 2000) } } const getStatus = (inv: InvitationResponse): { label: string; variant: 'default' | 'secondary' | 'destructive' } => { if (inv.used_at) return { label: 'Verwendet', variant: 'secondary' } if (new Date(inv.expires_at) < new Date()) return { label: 'Abgelaufen', variant: 'destructive' } return { label: 'Aktiv', variant: 'default' } } const resetCreateDialog = () => { setCreateForm({ email: '', role: 'dak_mitarbeiter', expires_in_days: 7 }) setCreateError('') setCreatedToken(null) setCreateOpen(false) } return (

Einladungen

{loading ? (
{Array.from({ length: 5 }).map((_, i) => ( ))}
) : invitations.length > 0 ? ( Token E-Mail Rolle Erstellt Gültig bis Status Aktion {invitations.map((inv) => { const status = getStatus(inv) return ( {inv.token.slice(0, 12)}... {inv.email || '-'} {inv.role === 'admin' ? 'Admin' : 'DAK Mitarbeiter'} {formatDateTime(inv.created_at)} {formatDateTime(inv.expires_at)} {status.label} {copiedId === inv.id ? 'Kopiert!' : 'Token kopieren'} ) })}
) : (

Keine Einladungen vorhanden.

)} {/* Create invitation dialog */} { if (!open) resetCreateDialog() }}> Einladung erstellen Erstellen Sie einen Einladungstoken für neue Benutzer. {createdToken ? (
Einladung erfolgreich erstellt! Kopieren Sie den Token:
{createdToken}
) : ( <>
setCreateForm((f) => ({ ...f, email: e.target.value }))} placeholder="Optional: E-Mail des Eingeladenen" />
setCreateForm((f) => ({ ...f, expires_in_days: Number(e.target.value) }))} min={1} max={90} className="w-28" />
{createError && ( {createError} )}
)}
) } function formatDateTime(dateStr: string): string { try { return new Date(dateStr).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', }) } catch { return dateStr } }