Rollen-Fix
All checks were successful
CI / Build (push) Successful in 1m21s
CI / Deploy (push) Successful in 53s

This commit is contained in:
Jan
2026-04-13 23:44:46 +02:00
parent 6acc2852d8
commit dfdff6bf99
3 changed files with 146 additions and 15 deletions

View File

@@ -127,6 +127,23 @@ function toggleApprovalPermission(
? currentValue.filter((entry) => entry !== approvalType)
: sortApprovalPermissions([...currentValue, approvalType]);
}
function sortManagedUsersList(users: DashboardManagedUser[]) {
const roleOrder: Record<DashboardManagedUser["role"], number> = {
ADMIN: 0,
FINANCE: 1,
MEMBER: 2
};
return [...users].sort((left, right) => {
const roleDifference = roleOrder[left.role] - roleOrder[right.role];
if (roleDifference !== 0) {
return roleDifference;
}
return left.username.localeCompare(right.username, "de-DE");
});
}
type MobileSection = "overview" | "actions";
type DesktopSection = "overview" | "budgetGroups" | "periods" | "users" | "logs";
@@ -276,6 +293,7 @@ export function DashboardShell({
const [editingPasswordUserId, setEditingPasswordUserId] = useState<string | null>(null);
const [editingUserId, setEditingUserId] = useState<string | null>(null);
const [passwordDrafts, setPasswordDrafts] = useState<Record<string, string>>({});
const [managedUsersState, setManagedUsersState] = useState(() => sortManagedUsersList(managedUsers));
const [userDrafts, setUserDrafts] = useState<Record<string, ManagedUserDraft>>({});
const [approvalThresholdDraft, setApprovalThresholdDraft] = useState(approvalThreshold.toFixed(2));
const [periodForm, setPeriodForm] = useState<PeriodFormState>(getSuggestedPeriodDraft(currentPeriod));
@@ -422,10 +440,14 @@ export function DashboardShell({
}, [approvalThreshold]);
useEffect(() => {
if (editingUserId && !managedUsers.some((user) => user.id === editingUserId)) {
setManagedUsersState(sortManagedUsersList(managedUsers));
}, [managedUsers]);
useEffect(() => {
if (editingUserId && !managedUsersState.some((user) => user.id === editingUserId)) {
setEditingUserId(null);
}
}, [editingUserId, managedUsers]);
}, [editingUserId, managedUsersState]);
const selectedExpenseGroup =
editableExpenseGroups.find((group) => group.id === expenseForm.agId) ?? defaultEditableGroup;
const selectedBudgetOptions = selectedExpenseGroup?.budgets ?? [];
@@ -859,7 +881,7 @@ export function DashboardShell({
const createdPassword = userForm.password;
const createdUsername = userForm.username.trim().toLowerCase();
await parseResponse(
const result = (await parseResponse(
await fetch("/api/users", {
method: "POST",
headers: {
@@ -873,7 +895,13 @@ export function DashboardShell({
approvalPermissions: sortApprovalPermissions(userForm.approvalPermissions)
})
})
);
)) as { user?: DashboardManagedUser };
if (result.user) {
setManagedUsersState((current) =>
sortManagedUsersList([...current.filter((user) => user.id !== result.user!.id), result.user!])
);
}
setUserForm({
username: "",
@@ -897,7 +925,7 @@ export function DashboardShell({
const draft = getManagedUserDraft(user);
await runAction(async () => {
await parseResponse(
const result = (await parseResponse(
await fetch(`/api/users/${user.id}`, {
method: "PATCH",
headers: {
@@ -909,7 +937,13 @@ export function DashboardShell({
approvalPermissions: sortApprovalPermissions(draft.approvalPermissions)
})
})
);
)) as { user?: DashboardManagedUser };
if (result.user) {
setManagedUsersState((current) =>
sortManagedUsersList([...current.filter((entry) => entry.id !== result.user!.id), result.user!])
);
}
setEditingUserId(null);
}, `Nutzer ${user.username} wurde aktualisiert.`);
@@ -947,6 +981,18 @@ export function DashboardShell({
method: "DELETE"
})
);
setManagedUsersState((current) => current.filter((user) => user.id !== userId));
setUserDrafts((current) => {
const next = { ...current };
delete next[userId];
return next;
});
setPasswordDrafts((current) => {
const next = { ...current };
delete next[userId];
return next;
});
}, "Nutzer wurde gel\u00f6scht.");
}
@@ -1786,7 +1832,7 @@ export function DashboardShell({
</Typography>
</Box>
<Stack spacing={1.4}>
{managedUsers.map((user) => {
{managedUsersState.map((user) => {
const canDelete = user.id !== viewer.id && user.createdExpensesCount === 0 && user.approvalsCount === 0;
const isResetOpen = editingPasswordUserId === user.id;
const isEditingUser = editingUserId === user.id;