fosrl.pangolin/src/app/admin/users/AdminUsersTable.tsx

204 lines
6.5 KiB
TypeScript
Raw Normal View History

2025-03-21 18:04:14 -04:00
"use client";
import { ColumnDef } from "@tanstack/react-table";
import { UsersDataTable } from "./AdminUsersDataTable";
import { Button } from "@app/components/ui/button";
import { ArrowRight, ArrowUpDown } from "lucide-react";
import { useRouter } from "next/navigation";
import { useState } from "react";
import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog";
import { toast } from "@app/hooks/useToast";
import { formatAxiosError } from "@app/lib/api";
import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
2025-05-06 06:49:47 +00:00
import { useTranslations } from 'next-intl';
2025-03-21 18:04:14 -04:00
export type GlobalUserRow = {
id: string;
2025-04-13 17:57:27 -04:00
name: string | null;
username: string;
email: string | null;
type: string;
idpId: number | null;
idpName: string;
2025-03-21 18:04:14 -04:00
dateCreated: string;
};
type Props = {
users: GlobalUserRow[];
};
export default function UsersTable({ users }: Props) {
const router = useRouter();
2025-05-06 06:49:47 +00:00
const t = useTranslations();
2025-03-21 18:04:14 -04:00
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [selected, setSelected] = useState<GlobalUserRow | null>(null);
const [rows, setRows] = useState<GlobalUserRow[]>(users);
const api = createApiClient(useEnvContext());
const deleteUser = (id: string) => {
api.delete(`/user/${id}`)
.catch((e) => {
console.error("Error deleting user", e);
toast({
variant: "destructive",
2025-05-06 06:49:47 +00:00
title: t('userErrorDelete'),
description: formatAxiosError(e, t('userErrorDelete'))
2025-03-21 18:04:14 -04:00
});
})
.then(() => {
router.refresh();
setIsDeleteModalOpen(false);
const newRows = rows.filter((row) => row.id !== id);
setRows(newRows);
});
};
const columns: ColumnDef<GlobalUserRow>[] = [
{
accessorKey: "id",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() =>
column.toggleSorting(column.getIsSorted() === "asc")
}
>
ID
</Button>
);
}
},
2025-04-13 17:57:27 -04:00
{
accessorKey: "username",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() =>
column.toggleSorting(column.getIsSorted() === "asc")
}
>
2025-05-06 06:49:47 +00:00
{t('username')}
2025-04-13 17:57:27 -04:00
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
);
}
},
2025-03-21 18:04:14 -04:00
{
accessorKey: "email",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() =>
column.toggleSorting(column.getIsSorted() === "asc")
}
>
2025-05-06 06:49:47 +00:00
{t('email')}
2025-03-21 18:04:14 -04:00
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
);
}
},
2025-04-13 17:57:27 -04:00
{
accessorKey: "name",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() =>
column.toggleSorting(column.getIsSorted() === "asc")
}
>
2025-05-06 06:49:47 +00:00
{t('name')}
2025-04-13 17:57:27 -04:00
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
);
}
},
{
accessorKey: "idpName",
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() =>
column.toggleSorting(column.getIsSorted() === "asc")
}
>
2025-05-06 06:49:47 +00:00
{t('identityProvider')}
2025-04-13 17:57:27 -04:00
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
);
}
},
2025-03-21 18:04:14 -04:00
{
id: "actions",
cell: ({ row }) => {
const r = row.original;
return (
<>
<div className="flex items-center justify-end">
<Button
variant={"outlinePrimary"}
className="ml-2"
onClick={() => {
setSelected(r);
setIsDeleteModalOpen(true);
}}
>
2025-05-06 06:49:47 +00:00
{t('delete')}
2025-03-21 18:04:14 -04:00
</Button>
</div>
</>
);
}
}
];
return (
<>
{selected && (
<ConfirmDeleteDialog
open={isDeleteModalOpen}
setOpen={(val) => {
setIsDeleteModalOpen(val);
setSelected(null);
}}
dialog={
<div className="space-y-4">
<p>
2025-05-06 06:49:47 +00:00
{t('userQuestionRemove', {selectedUser: selected?.email || selected?.name || selected?.username})}
2025-03-21 18:04:14 -04:00
</p>
<p>
<b>
2025-05-06 06:49:47 +00:00
{t('userMessageRemove')}
2025-03-21 18:04:14 -04:00
</b>
</p>
<p>
2025-05-06 06:49:47 +00:00
{t('userMessageConfirm')}
2025-03-21 18:04:14 -04:00
</p>
</div>
}
2025-05-06 06:49:47 +00:00
buttonText={t('userDeleteConfirm')}
2025-03-21 18:04:14 -04:00
onConfirm={async () => deleteUser(selected!.id)}
2025-04-13 17:57:27 -04:00
string={
selected.email || selected.name || selected.username
}
2025-05-06 06:49:47 +00:00
title={t('userDeleteServer')}
2025-03-21 18:04:14 -04:00
/>
)}
<UsersDataTable columns={columns} data={rows} />
</>
);
}