158 lines
4.0 KiB
TypeScript
158 lines
4.0 KiB
TypeScript
'use client';
|
|
|
|
import { useCallback, useMemo, useState } from 'react';
|
|
import { Plus, Users } from 'lucide-react';
|
|
|
|
import { PageHeader } from '@/components/page-header';
|
|
import { Button } from '@/components/ui/button';
|
|
import { PERMISSIONS } from '@/constants/permissions';
|
|
import { PermissionGuard } from '@/guards';
|
|
import type { AdministrationUser } from '@/types';
|
|
|
|
import { useUserColumns } from './components/UserColumns';
|
|
import { UserFilters } from './components/UserFilters';
|
|
import { UserSheet } from './components/UserSheet';
|
|
import { UserStats } from './components/UserStats';
|
|
import { UserTable } from './components/UserTable';
|
|
import { useUserFilters } from './hooks/useUserFilters';
|
|
import { useUserForm } from './hooks/useUserForm';
|
|
import { useUserStatusMutation } from './hooks/useUserMutations';
|
|
import { useUsersQuery } from './hooks/useUserQueries';
|
|
|
|
export default function UsersPage() {
|
|
const [isSheetOpen, setIsSheetOpen] = useState(false);
|
|
const {
|
|
skip,
|
|
setSkip,
|
|
limit,
|
|
setLimit,
|
|
sorting,
|
|
setSorting,
|
|
searchTerm,
|
|
debouncedSearchTerm,
|
|
setSearchTerm,
|
|
statusFilter,
|
|
setStatusFilter,
|
|
} = useUserFilters();
|
|
|
|
const usersQuery = useUsersQuery({
|
|
skip,
|
|
limit,
|
|
searchTerm: debouncedSearchTerm,
|
|
statusFilter,
|
|
sorting,
|
|
});
|
|
const userForm = useUserForm({
|
|
onSaved: () => setIsSheetOpen(false),
|
|
});
|
|
const {
|
|
openCreate: prepareCreateUser,
|
|
openEdit: prepareEditUser,
|
|
register,
|
|
handleSubmit,
|
|
userId,
|
|
roleId,
|
|
setRoleId,
|
|
errors,
|
|
isSubmitted,
|
|
canSubmit,
|
|
isSaving,
|
|
} = userForm;
|
|
const statusMutation = useUserStatusMutation();
|
|
const { mutate: updateUserStatus, pendingUserId } = statusMutation;
|
|
|
|
const openCreate = useCallback(() => {
|
|
prepareCreateUser();
|
|
setIsSheetOpen(true);
|
|
}, [prepareCreateUser]);
|
|
|
|
const openEdit = useCallback(
|
|
(user: AdministrationUser) => {
|
|
prepareEditUser(user);
|
|
setIsSheetOpen(true);
|
|
},
|
|
[prepareEditUser],
|
|
);
|
|
|
|
const toggleStatus = useCallback(
|
|
(user: AdministrationUser) => {
|
|
updateUserStatus(user);
|
|
},
|
|
[updateUserStatus],
|
|
);
|
|
|
|
const columns = useUserColumns();
|
|
|
|
const total = usersQuery.data?.total ?? 0;
|
|
const users = usersQuery.data?.items ?? [];
|
|
const toolbar = useMemo(
|
|
() => (
|
|
<UserFilters
|
|
searchTerm={searchTerm}
|
|
statusFilter={statusFilter}
|
|
onSearchChange={setSearchTerm}
|
|
onStatusChange={setStatusFilter}
|
|
/>
|
|
),
|
|
[searchTerm, setSearchTerm, setStatusFilter, statusFilter],
|
|
);
|
|
|
|
return (
|
|
<>
|
|
<main className="relative z-10 space-y-5">
|
|
<PageHeader
|
|
title="User Management"
|
|
description="Manage users and role assignment"
|
|
icon={Users}
|
|
actions={
|
|
<PermissionGuard permissions={PERMISSIONS.USER.CREATE}>
|
|
<Button onClick={openCreate} size="sm">
|
|
<Plus />
|
|
Add User
|
|
</Button>
|
|
</PermissionGuard>
|
|
}
|
|
/>
|
|
|
|
<UserStats
|
|
total={total}
|
|
activeCount={usersQuery.data?.active_count ?? 0}
|
|
inactiveCount={usersQuery.data?.inactive_count ?? 0}
|
|
pendingCount={usersQuery.data?.pending_count ?? 0}
|
|
/>
|
|
|
|
<UserTable
|
|
columns={columns}
|
|
users={users}
|
|
isLoading={usersQuery.isLoading}
|
|
toolbar={toolbar}
|
|
skip={skip}
|
|
limit={limit}
|
|
total={total}
|
|
sorting={sorting}
|
|
onPageChange={setSkip}
|
|
onLimitChange={setLimit}
|
|
onSortingChange={setSorting}
|
|
onEdit={openEdit}
|
|
onToggleStatus={toggleStatus}
|
|
pendingUserId={pendingUserId}
|
|
/>
|
|
</main>
|
|
|
|
<UserSheet
|
|
open={isSheetOpen}
|
|
onOpenChange={setIsSheetOpen}
|
|
userId={userId}
|
|
register={register}
|
|
errors={errors}
|
|
isSubmitted={isSubmitted}
|
|
onSubmit={handleSubmit}
|
|
roleId={roleId}
|
|
onRoleChange={setRoleId}
|
|
canSubmit={canSubmit}
|
|
isSaving={isSaving}
|
|
/>
|
|
</>
|
|
);
|
|
}
|