fix(web): Formularweg und Listenladen der Benutzerverwaltung melden Fehler sichtbar
WINDOWS #36, Aufgabe 2/3: handleSubmit und fetchUsers verschluckten abgewiesene Antworten und Verbindungsfehler ebenso wie der Loeschweg aus Aufgabe 1. formError zeigt jetzt den Servertext oder eine Ersatzmeldung im offenen Formulardialog; loadError verhindert die irrefuehrende Meldung "Keine Benutzer gefunden", wenn das Laden selbst gescheitert ist. Beide Zustaende werden beim Oeffnen eines neuen Dialogs zurueckgesetzt, damit eine alte Meldung nicht in den naechsten Aufruf hinueberwandert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
@@ -65,6 +65,8 @@ export default function AdminUsersPage() {
|
||||
const [editingUser, setEditingUser] = useState<User | null>(null);
|
||||
const [deleteConfirm, setDeleteConfirm] = useState<string | null>(null);
|
||||
const [deleteError, setDeleteError] = useState<string | null>(null);
|
||||
const [formError, setFormError] = useState<string | null>(null);
|
||||
const [loadError, setLoadError] = useState<string | null>(null);
|
||||
const [detailsUser, setDetailsUser] = useState<User | null>(null);
|
||||
const [formData, setFormData] = useState<UserFormData>({
|
||||
username: '',
|
||||
@@ -79,19 +81,22 @@ export default function AdminUsersPage() {
|
||||
currentUser?.role === 'ADMIN' || currentUser?.role === 'SUPER_ADMIN';
|
||||
|
||||
const fetchUsers = useCallback(async () => {
|
||||
setLoadError(null);
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/users`, {
|
||||
credentials: 'include',
|
||||
});
|
||||
if (res.ok) {
|
||||
setUsers(await res.json());
|
||||
} else {
|
||||
setLoadError(t('errors.loadFailed'));
|
||||
}
|
||||
} catch {
|
||||
// silently fail
|
||||
setLoadError(t('errors.loadFailed'));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, []);
|
||||
}, [t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasAccess) {
|
||||
@@ -110,6 +115,7 @@ export default function AdminUsersPage() {
|
||||
displayName: '',
|
||||
role: 'USER',
|
||||
});
|
||||
setFormError(null);
|
||||
setShowForm(true);
|
||||
};
|
||||
|
||||
@@ -122,11 +128,13 @@ export default function AdminUsersPage() {
|
||||
displayName: user.displayName ?? '',
|
||||
role: user.role,
|
||||
});
|
||||
setFormError(null);
|
||||
setShowForm(true);
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setFormError(null);
|
||||
|
||||
const url = editingUser
|
||||
? `${API_URL}/users/${editingUser.id}`
|
||||
@@ -156,9 +164,14 @@ export default function AdminUsersPage() {
|
||||
if (res.ok) {
|
||||
setShowForm(false);
|
||||
fetchUsers();
|
||||
} else {
|
||||
const detail = await readApiMessage(res);
|
||||
setFormError(
|
||||
detail ? t('errors.serverRejected', { detail }) : t('errors.generic'),
|
||||
);
|
||||
}
|
||||
} catch {
|
||||
// silently fail
|
||||
setFormError(t('errors.network'));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -215,10 +228,19 @@ export default function AdminUsersPage() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{loadError && (
|
||||
<div
|
||||
role="alert"
|
||||
className="rounded-md border border-destructive/50 bg-destructive/10 p-3 text-sm text-destructive"
|
||||
>
|
||||
{loadError}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Users table */}
|
||||
{loading ? (
|
||||
<p className="text-muted-foreground">{tCommon('loading')}</p>
|
||||
) : users.length === 0 ? (
|
||||
) : loadError ? null : users.length === 0 ? (
|
||||
<p className="text-muted-foreground">{t('noUsers')}</p>
|
||||
) : (
|
||||
<div className="overflow-x-auto rounded-md border border-border">
|
||||
@@ -400,6 +422,14 @@ export default function AdminUsersPage() {
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
{formError && (
|
||||
<div
|
||||
role="alert"
|
||||
className="rounded-md border border-destructive/50 bg-destructive/10 p-3 text-sm text-destructive"
|
||||
>
|
||||
{formError}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex justify-end gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user