'use client'; /** * Benutzerverwaltung (Client): Liste aller Benutzer mit Edit-Modal. * Im Modal laesst sich die Rolle aendern (PATCH /api/users/[id]); * Fehler werden inline angezeigt. Der eigene Account ist geschuetzt * (Server lehnt ab). */ import { appFetch } from '@/lib/client-fetch'; import { useCallback, useEffect, useState } from 'react'; import { Button, Card, ErrorMessage, Badge } from '@/components/ui/ui'; import { ModalShell } from '@/components/ui/ModalShell'; interface ManagedUser { id: string; email: string; username: string | null; role: 'ADMIN' | 'USER'; createdAt: string; memberships: { calendar: { id: string; title: string; isActive: boolean } }[]; ownedCalendars: { id: string; title: string; isActive: boolean }[]; } export function UserManagement({ currentUserId }: { currentUserId: string }) { const [users, setUsers] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(null); const [pendingId, setPendingId] = useState(null); /** Aktuell im Edit-Modal geoeffneter Benutzer (null = geschlossen). */ const [editingUser, setEditingUser] = useState(null); const loadUsers = useCallback(async () => { setIsLoading(true); setError(null); try { const response = await appFetch('/api/users', { cache: 'no-store' }); if (!response.ok) { const data = (await response.json().catch(() => null)) as | { error?: string } | null; throw new Error(data?.error ?? 'Benutzer konnten nicht geladen werden.'); } const data = (await response.json()) as { users: ManagedUser[] }; setUsers(data.users); } catch (loadError) { setError( loadError instanceof Error ? loadError.message : 'Benutzer konnten nicht geladen werden.', ); } finally { setIsLoading(false); } }, []); useEffect(() => { void loadUsers(); }, [loadUsers]); /** * Aktualisiert die Rolle eines Benutzers und schliesst bei Erfolg * das Modal. Fehler werden im Modal (falls offen) bzw. inline * angezeigt. */ async function changeRole(userId: string, nextRole: 'ADMIN' | 'USER') { setPendingId(userId); setError(null); try { const response = await appFetch(`/api/users/${userId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ role: nextRole }), }); if (!response.ok) { const data = (await response.json().catch(() => null)) as | { error?: string } | null; throw new Error(data?.error ?? 'Rolle konnte nicht geaendert werden.'); } const data = (await response.json()) as { user: ManagedUser }; setUsers((previous) => previous.map((user) => user.id === data.user.id ? { ...user, role: data.user.role } : user, ), ); setEditingUser((previous) => previous && previous.id === data.user.id ? { ...previous, role: data.user.role } : previous, ); } catch (changeError) { setError( changeError instanceof Error ? changeError.message : 'Rolle konnte nicht geaendert werden.', ); } finally { setPendingId(null); } } if (isLoading) { return (

Benutzer werden geladen...

); } return (
{error && } {users.length === 0 ? (

Noch keine Benutzer registriert.

) : (
    {users.map((user) => { const isSelf = user.id === currentUserId; return (
  • {user.username ?? user.email} {user.username && ( {user.email} )} {isSelf && ( Du )}

    Registriert am{' '} {new Date(user.createdAt).toLocaleDateString('de-DE')} {user.ownedCalendars.length > 0 && ` · ${user.ownedCalendars.length} Kalender`} {user.memberships.length > 0 && ` · Mitglied in ${user.memberships.length} Kalender(n)`}

  • ); })}
)} {editingUser && ( { setEditingUser(null); setError(null); }} onSave={(nextRole) => changeRole(editingUser.id, nextRole)} /> )}
); } /** * Modal zum Bearbeiten eines Benutzers (derzeit: Rolle). * Schliessen via Abbrechen, X-Button, ESC oder Klick auf den Hintergrund. */ function EditUserModal({ user, isSelf, isPending, error, onClose, onSave, }: { user: ManagedUser; isSelf: boolean; isPending: boolean; error: string | null; onClose: () => void; onSave: (nextRole: 'ADMIN' | 'USER') => void; }) { const [selectedRole, setSelectedRole] = useState<'ADMIN' | 'USER'>(user.role); return (

{user.username ?? user.email} {user.username && ( {user.email} )}

Registriert am{' '} {new Date(user.createdAt).toLocaleDateString('de-DE')}

{isSelf && (

Die eigene Rolle kann nicht geaendert werden.

)}
{error && }
); }