feat: add client management module

This commit is contained in:
2026-06-16 18:25:01 +05:30
parent 964b177ae1
commit d8587a43d4
19 changed files with 879 additions and 1 deletions

View File

@@ -0,0 +1,130 @@
'use client';
import { useCallback, useMemo, useState } from 'react';
import { Building2, Plus } from 'lucide-react';
import { PageHeader } from '@/components/page-header';
import { PoweredBy } from '@/components/powered-by';
import { Button } from '@/components/ui/button';
import { PERMISSIONS } from '@/constants/permissions';
import { PermissionGuard } from '@/guards';
import type { Client } from '@/types';
import { useClientColumns } from './components/ClientColumns';
import { ClientFilters } from './components/ClientFilters';
import { ClientSheet } from './components/ClientSheet';
import { ClientTable } from './components/ClientTable';
import { useClientFilters } from './hooks/useClientFilters';
import { useClientForm } from './hooks/useClientForm';
import { useClientStatusMutation } from './hooks/useClientMutations';
import { useClientsQuery } from './hooks/useClientQueries';
export default function ClientsPage() {
const [isSheetOpen, setIsSheetOpen] = useState(false);
const {
skip,
setSkip,
limit,
searchTerm,
debouncedSearchTerm,
setSearchTerm,
statusFilter,
setStatusFilter,
} = useClientFilters();
const clientsQuery = useClientsQuery({
skip,
limit,
searchTerm: debouncedSearchTerm,
statusFilter,
});
const clientForm = useClientForm({
onSaved: () => setIsSheetOpen(false),
});
const { openCreate: prepareCreateClient, openEdit: prepareEditClient } = clientForm;
const { register, handleSubmit, clientId, isSaving } = clientForm;
const statusMutation = useClientStatusMutation();
const { mutate: updateClientStatus, pendingClientId } = statusMutation;
const openCreate = useCallback(() => {
prepareCreateClient();
setIsSheetOpen(true);
}, [prepareCreateClient]);
const openEdit = useCallback(
(client: Client) => {
prepareEditClient(client);
setIsSheetOpen(true);
},
[prepareEditClient],
);
const toggleStatus = useCallback(
(client: Client) => {
updateClientStatus(client);
},
[updateClientStatus],
);
const columns = useClientColumns({
onEdit: openEdit,
onToggleStatus: toggleStatus,
pendingClientId,
});
const total = clientsQuery.data?.total ?? 0;
const clients = clientsQuery.data?.items ?? [];
const toolbar = useMemo(
() => (
<ClientFilters
searchTerm={searchTerm}
statusFilter={statusFilter}
onSearchChange={setSearchTerm}
onStatusChange={setStatusFilter}
/>
),
[searchTerm, setSearchTerm, setStatusFilter, statusFilter],
);
return (
<>
<main className="relative z-10 space-y-5">
<PageHeader
title="Client Management"
description="Manage client company and contact details"
icon={Building2}
actions={
<PermissionGuard permissions={PERMISSIONS.CLIENT.CREATE}>
<Button onClick={openCreate}>
<Plus className="mr-2 size-4" />
Add Client
</Button>
</PermissionGuard>
}
/>
<ClientTable
columns={columns}
clients={clients}
isLoading={clientsQuery.isLoading}
toolbar={toolbar}
skip={skip}
limit={limit}
total={total}
onPageChange={setSkip}
/>
<PoweredBy />
</main>
<ClientSheet
open={isSheetOpen}
onOpenChange={setIsSheetOpen}
clientId={clientId}
register={register}
onSubmit={handleSubmit}
isSaving={isSaving}
/>
</>
);
}