import React, { useState, useEffect } from 'react'; import { useAuth } from '../context/AuthContext'; import userService from '../services/userService'; import LoadingSpinner from '../components/common/LoadingSpinner'; import { toast } from 'react-toastify'; const UsersPage = () => { const { isSuperAdmin } = useAuth(); const [users, setUsers] = useState([]); const [roles, setRoles] = useState([]); const [loading, setLoading] = useState(true); const [showModal, setShowModal] = useState(false); const [editingUser, setEditingUser] = useState(null); const [showImportModal, setShowImportModal] = useState(false); const [azureGroups, setAzureGroups] = useState([]); const [azureGroupsLoading, setAzureGroupsLoading] = useState(false); const [importGroupId, setImportGroupId] = useState(''); const [importRoleId, setImportRoleId] = useState(''); const [importing, setImporting] = useState(false); const [groupSearch, setGroupSearch] = useState(''); const [search, setSearch] = useState(''); const [formData, setFormData] = useState({ username: '', email: '', password: '', role_id: '', first_name: '', last_name: '', is_active: true, }); useEffect(() => { loadData(); }, []); const loadData = async () => { try { const [usersData, rolesData] = await Promise.all([ userService.getAll(), userService.getRoles(), ]); setUsers(usersData); setRoles(rolesData); } catch (error) { toast.error('Fehler beim Laden der Daten'); } finally { setLoading(false); } }; const handleCreate = () => { setEditingUser(null); setFormData({ username: '', email: '', password: '', role_id: roles[0]?.id || '', first_name: '', last_name: '', is_active: true, }); setShowModal(true); }; const handleEdit = (user) => { setEditingUser(user); setFormData({ username: user.username, email: user.email, password: '', role_id: user.role_id, first_name: user.first_name || '', last_name: user.last_name || '', is_active: user.is_active, }); setShowModal(true); }; const handleSubmit = async (e) => { e.preventDefault(); try { const submitData = { ...formData }; // Remove password if empty (for edit) if (editingUser && !submitData.password) { delete submitData.password; } if (editingUser) { await userService.update(editingUser.id, submitData); toast.success('Benutzer erfolgreich aktualisiert'); } else { await userService.create(submitData); toast.success('Benutzer erfolgreich erstellt'); } setShowModal(false); loadData(); } catch (error) { toast.error(error.message || 'Fehler beim Speichern'); } }; const handleDelete = async (id) => { if (!window.confirm('Möchten Sie diesen Benutzer wirklich löschen?')) { return; } try { await userService.delete(id); toast.success('Benutzer erfolgreich gelöscht'); loadData(); } catch (error) { toast.error(error.message || 'Fehler beim Löschen'); } }; const handleToggleStatus = async (user) => { try { await userService.toggleStatus(user.id, !user.is_active); toast.success('Status erfolgreich geändert'); loadData(); } catch (error) { toast.error(error.message || 'Fehler beim Ändern des Status'); } }; const handleOpenImportModal = async () => { setImportGroupId(''); setImportRoleId(roles[0]?.id || ''); setGroupSearch(''); setShowImportModal(true); setAzureGroupsLoading(true); try { const groups = await userService.getAzureGroups(); setAzureGroups(groups); } catch (error) { toast.error(error.message || 'Fehler beim Laden der Azure-Gruppen'); setShowImportModal(false); } finally { setAzureGroupsLoading(false); } }; const handleImport = async () => { if (!importGroupId || !importRoleId) return; setImporting(true); try { const result = await userService.importFromAzure(importGroupId, importRoleId); toast.success( `Import abgeschlossen: ${result.imported} importiert, ${result.skipped} übersprungen` + (result.errors.length > 0 ? `, ${result.errors.length} Fehler` : '') ); setShowImportModal(false); if (result.imported > 0) loadData(); } catch (error) { toast.error(error.message || 'Fehler beim Importieren'); } finally { setImporting(false); } }; const handleRoleChange = async (userId, roleId) => { try { await userService.assignRole(userId, roleId); toast.success('Rolle erfolgreich zugewiesen'); loadData(); } catch (error) { toast.error(error.message || 'Fehler beim Zuweisen der Rolle'); } }; if (loading) { return (
); } return (

Benutzerverwaltung

{isSuperAdmin() && (
)}
{/* Search */}
setSearch(e.target.value)} style={{ maxWidth: 420 }} />
{/* Table */}
{(() => { const q = search.toLowerCase(); const filtered = q ? users.filter(u => u.username?.toLowerCase().includes(q) || u.email?.toLowerCase().includes(q) || u.first_name?.toLowerCase().includes(q) || u.last_name?.toLowerCase().includes(q) || u.role_name?.toLowerCase().includes(q) ) : users; if (filtered.length === 0) return ( ); return filtered.map((user) => ( )); })()}
Benutzername E-Mail Name Rolle Status Letzter Login Aktionen
Keine Benutzer gefunden
{user.username} {user.email} {user.first_name || user.last_name ? `${user.first_name || ''} ${ user.last_name || '' }`.trim() : '-'} {user.role_name} {user.is_active ? 'Aktiv' : 'Inaktiv'} {user.last_login ? new Date(user.last_login).toLocaleString('de-DE') : 'Nie'} {isSuperAdmin() && (
)}
{/* Azure Import Modal */} {showImportModal && (
setShowImportModal(false)}>
e.stopPropagation()}>

Benutzer aus Azure AD importieren

{azureGroupsLoading ? (

Gruppen werden geladen...

) : ( <>
setGroupSearch(e.target.value)} style={{ marginBottom: '0.4rem' }} />
{azureGroups .filter(g => g.displayName.toLowerCase().includes(groupSearch.toLowerCase())) .map((g) => (
setImportGroupId(g.id)} style={{ padding: '8px 12px', cursor: 'pointer', borderBottom: '1px solid var(--border-color)', background: importGroupId === g.id ? 'var(--primary)' : 'transparent', color: importGroupId === g.id ? '#fff' : 'var(--text-primary)', }} >
{g.displayName}
{g.description && (
{g.description}
)}
)) } {azureGroups.filter(g => g.displayName.toLowerCase().includes(groupSearch.toLowerCase())).length === 0 && (
Keine Gruppen gefunden
)}
{importGroupId && (
✓ Ausgewählt: {azureGroups.find(g => g.id === importGroupId)?.displayName}
)}
{(() => { const ROLE_META = { super_admin: { icon: '👑', color: '#ef4444', bg: '#fef2f2', label: 'Super Admin' }, admin: { icon: '🛡️', color: '#f97316', bg: '#fff7ed', label: 'Admin' }, support: { icon: '🎧', color: '#3b82f6', bg: '#eff6ff', label: 'IT-Support' }, bearbeiter: { icon: '🔧', color: '#8b5cf6', bg: '#f5f3ff', label: 'Bearbeiter' }, benutzer: { icon: '👤', color: '#6b7280', bg: '#f9fafb', label: 'Benutzer' }, hr_personal: { icon: '🧑‍💼', color: '#10b981', bg: '#f0fdf4', label: 'HR / Personal' }, buchhaltung: { icon: '💶', color: '#a78bfa', bg: '#faf5ff', label: 'Buchhaltung' }, }; return (
{roles.map(role => { const meta = ROLE_META[role.name] || { icon: '🔵', color: '#6b7280', bg: '#f9fafb', label: role.name }; const selected = String(importRoleId) === String(role.id); return ( ); })}
); })()}

Bereits vorhandene Benutzer (gleiche E-Mail oder Azure ID) werden übersprungen.

)}
)} {/* Modal */} {showModal && (
setShowModal(false)}>
e.stopPropagation()}>

{editingUser ? 'Benutzer bearbeiten' : 'Neuer Benutzer'}

setFormData({ ...formData, username: e.target.value }) } required />
setFormData({ ...formData, email: e.target.value }) } required />
setFormData({ ...formData, password: e.target.value }) } required={!editingUser} placeholder={ editingUser ? 'Leer lassen, um nicht zu ändern' : '' } />
setFormData({ ...formData, first_name: e.target.value, }) } />
setFormData({ ...formData, last_name: e.target.value }) } />
{(() => { const ROLE_META = { super_admin: { icon: '👑', color: '#ef4444', bg: '#fef2f2', label: 'Super Admin' }, admin: { icon: '🛡️', color: '#f97316', bg: '#fff7ed', label: 'Admin' }, support: { icon: '🎧', color: '#3b82f6', bg: '#eff6ff', label: 'IT-Support' }, bearbeiter: { icon: '🔧', color: '#8b5cf6', bg: '#f5f3ff', label: 'Bearbeiter' }, benutzer: { icon: '👤', color: '#6b7280', bg: '#f9fafb', label: 'Benutzer' }, hr_personal: { icon: '🧑‍💼', color: '#10b981', bg: '#f0fdf4', label: 'HR / Personal' }, buchhaltung: { icon: '💶', color: '#a78bfa', bg: '#faf5ff', label: 'Buchhaltung' }, }; return (
{roles.map(role => { const meta = ROLE_META[role.name] || { icon: '🔵', color: '#6b7280', bg: '#f9fafb', label: role.name }; const selected = formData.role_id === role.id; return ( ); })}
); })()} {!formData.role_id && (
Bitte eine Rolle auswählen
)}
)}
); }; export default UsersPage;