improved admin and events tables

This commit is contained in:
z1glr
2025-01-21 12:51:59 +00:00
parent 8fef9b5318
commit 7265a4e36a
17 changed files with 357 additions and 237 deletions

View File

@@ -1,7 +1,8 @@
import { apiCall } from "@/lib";
import { User } from "@/Zustand";
import zustand, { User } from "@/Zustand";
import {
Button,
ButtonGroup,
Checkbox,
Table,
TableBody,
@@ -12,14 +13,17 @@ import {
Tooltip,
} from "@heroui/react";
import { useAsyncList } from "@react-stately/data";
import { FormEvent, useState } from "react";
import { useState } from "react";
import AddUser from "./AddUser";
import { AddLarge, Edit } from "@carbon/icons-react";
import { AddLarge, Edit, TrashCan } from "@carbon/icons-react";
import EditUser from "./EditUser";
import DeleteConfirmation from "@/components/DeleteConfirmation";
export default function Users() {
const [showAddUser, setShowAddUser] = useState(false);
const [editUser, setEditUser] = useState<User | undefined>();
const [deleteUser, setDeleteUser] = useState<User | undefined>();
const loggedInUser = zustand((state) => state.user);
const users = useAsyncList<User>({
async load() {
@@ -64,23 +68,22 @@ export default function Users() {
},
});
// send an addUser request to the backend then reload the table
async function addUser(e: FormEvent<HTMLFormElement>) {
const data = Object.fromEntries(new FormData(e.currentTarget));
async function sendDeleteUser(userName: User["userName"] | undefined) {
if (!!userName) {
const result = await apiCall("DELETE", "users", {
userName,
});
const result = await apiCall("POST", "users", undefined, {
...data,
admin: data.admin === "admin",
});
if (result.ok) {
users.reload();
if (result.ok) {
users.reload();
setDeleteUser(undefined);
}
}
}
// content above the user-tabel
const topContent = (
<>
<div>
<Button
color="primary"
startContent={<AddLarge />}
@@ -88,7 +91,7 @@ export default function Users() {
>
Add User
</Button>
</>
</div>
);
return (
@@ -101,6 +104,13 @@ export default function Users() {
topContent={topContent}
sortDescriptor={users.sortDescriptor}
onSortChange={users.sort}
topContentPlacement="outside"
classNames={{
wrapper: "bg-accent-4",
tr: "even:bg-accent-5 ",
th: "font-subheadline text-xl text-accent-1 bg-transparent ",
thead: "[&>tr]:first:!shadow-border",
}}
>
<TableHeader>
<TableColumn allowsSorting key="userName">
@@ -119,16 +129,34 @@ export default function Users() {
<Checkbox isSelected={user.admin} />
</TableCell>
<TableCell>
<Button
isIconOnly
variant="light"
size="sm"
onPress={() => setEditUser(user)}
>
<Tooltip content="Edit user">
<Edit />
</Tooltip>
</Button>
<ButtonGroup>
<Button
isIconOnly
variant="light"
size="sm"
onPress={() => setEditUser(user)}
isDisabled={
user.userName === "admin" &&
loggedInUser?.userName !== "admin"
}
>
<Tooltip content="Edit user">
<Edit />
</Tooltip>
</Button>
<Button
isIconOnly
variant="light"
size="sm"
color="danger"
isDisabled={["admin", loggedInUser?.userName].includes(
user.userName,
)}
onPress={() => setDeleteUser(user)}
>
<TrashCan />
</Button>
</ButtonGroup>
</TableCell>
</TableRow>
)}
@@ -138,11 +166,14 @@ export default function Users() {
<AddUser
isOpen={showAddUser}
onOpenChange={setShowAddUser}
onSubmit={(e) => void addUser(e)}
onSuccess={() => {
setShowAddUser(false);
users.reload();
}}
/>
<EditUser
isOpen={editUser !== undefined}
user={editUser}
value={editUser}
onOpenChange={(isOpen) =>
!isOpen ? setEditUser(undefined) : undefined
}
@@ -151,6 +182,16 @@ export default function Users() {
setEditUser(undefined);
}}
/>
<DeleteConfirmation
isOpen={!!deleteUser}
onOpenChange={(isOpen) => (!isOpen ? setDeleteUser(undefined) : null)}
onDelete={() => sendDeleteUser(deleteUser?.userName)}
itemName="User"
>
{" "}
The user <span>{deleteUser?.userName}</span> will be deleted.
</DeleteConfirmation>
</div>
);
}