task-b
task-b.1 complere
This commit is contained in:
157
src/features/crm-demo/components/enquiries-table.tsx
Normal file
157
src/features/crm-demo/components/enquiries-table.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
'use client';
|
||||
|
||||
import Link from 'next/link';
|
||||
import { useMutation, useSuspenseQuery } from '@tanstack/react-query';
|
||||
import { type ColumnDef } from '@tanstack/react-table';
|
||||
import { parseAsInteger, parseAsString, useQueryStates } from 'nuqs';
|
||||
import { getSortingStateParser } from '@/lib/parsers';
|
||||
import { useDataTable } from '@/hooks/use-data-table';
|
||||
import { DataTable } from '@/components/ui/table/data-table';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { toast } from 'sonner';
|
||||
import { crmReferenceQueryOptions, enquiriesQueryOptions } from '../api/queries';
|
||||
import { convertEnquiryMutation } from '../api/mutations';
|
||||
import type { Enquiry } from '../api/types';
|
||||
import { ChancePill, EnquiryStatusBadge } from './shared';
|
||||
|
||||
const columns: ColumnDef<Enquiry>[] = [
|
||||
{ accessorKey: 'code', header: 'Code' },
|
||||
{ accessorKey: 'title', header: 'Enquiry' },
|
||||
{ accessorKey: 'productType', header: 'Product' },
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: 'Status',
|
||||
cell: ({ row }) => <EnquiryStatusBadge status={row.original.status} />
|
||||
},
|
||||
{
|
||||
accessorKey: 'chancePercent',
|
||||
header: 'Chance',
|
||||
cell: ({ row }) => <ChancePill value={row.original.chancePercent} />
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
header: '',
|
||||
cell: ({ row }) => <RowActions enquiry={row.original} />
|
||||
}
|
||||
];
|
||||
|
||||
const columnIds = ['code', 'title', 'productType', 'status', 'chancePercent', 'actions'];
|
||||
|
||||
function RowActions({ enquiry }: { enquiry: Enquiry }) {
|
||||
const mutation = useMutation({
|
||||
...convertEnquiryMutation,
|
||||
onSuccess: () => toast.success('สร้าง quotation mock จาก enquiry แล้ว')
|
||||
});
|
||||
|
||||
return (
|
||||
<div className='flex justify-end gap-2'>
|
||||
<Button variant='outline' size='sm' asChild>
|
||||
<Link href={`/dashboard/crm-demo/enquiries/${enquiry.id}`}>View</Link>
|
||||
</Button>
|
||||
<Button size='sm' isLoading={mutation.isPending} onClick={() => mutation.mutate(enquiry.id)}>
|
||||
Convert
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function EnquiriesTablePage() {
|
||||
const [params, setParams] = useQueryStates({
|
||||
page: parseAsInteger.withDefault(1),
|
||||
perPage: parseAsInteger.withDefault(10),
|
||||
name: parseAsString,
|
||||
status: parseAsString,
|
||||
productType: parseAsString,
|
||||
salesman: parseAsString,
|
||||
dateFrom: parseAsString,
|
||||
dateTo: parseAsString,
|
||||
sort: getSortingStateParser(columnIds).withDefault([])
|
||||
});
|
||||
const { data: reference } = useSuspenseQuery(crmReferenceQueryOptions());
|
||||
|
||||
const filters = {
|
||||
page: params.page,
|
||||
limit: params.perPage,
|
||||
...(params.name && { search: params.name }),
|
||||
...(params.status && { status: params.status }),
|
||||
...(params.productType && { productType: params.productType }),
|
||||
...(params.salesman && { salesman: params.salesman }),
|
||||
...(params.dateFrom && { dateFrom: params.dateFrom }),
|
||||
...(params.dateTo && { dateTo: params.dateTo }),
|
||||
...(params.sort.length ? { sort: JSON.stringify(params.sort) } : {})
|
||||
};
|
||||
|
||||
const { data } = useSuspenseQuery(enquiriesQueryOptions(filters));
|
||||
const pageCount = Math.ceil(data.totalItems / params.perPage);
|
||||
const { table } = useDataTable({
|
||||
data: data.items,
|
||||
columns,
|
||||
pageCount,
|
||||
initialState: {
|
||||
columnPinning: { right: ['actions'] }
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<div className='flex flex-1 flex-col space-y-4'>
|
||||
<div className='grid gap-3 md:grid-cols-2 xl:grid-cols-6'>
|
||||
<Input
|
||||
placeholder='ค้นหา enquiry หรือ code'
|
||||
value={params.name ?? ''}
|
||||
onChange={(event) => void setParams({ name: event.target.value || null, page: 1 })}
|
||||
/>
|
||||
<select
|
||||
className='border-input bg-background rounded-md border px-3 text-sm'
|
||||
value={params.status ?? ''}
|
||||
onChange={(event) => void setParams({ status: event.target.value || null, page: 1 })}
|
||||
>
|
||||
<option value=''>ทุกสถานะ</option>
|
||||
<option value='new'>New</option>
|
||||
<option value='qualifying'>Qualifying</option>
|
||||
<option value='requirement'>Requirement</option>
|
||||
<option value='follow_up'>Follow Up</option>
|
||||
<option value='converted'>Converted</option>
|
||||
</select>
|
||||
<select
|
||||
className='border-input bg-background rounded-md border px-3 text-sm'
|
||||
value={params.productType ?? ''}
|
||||
onChange={(event) => void setParams({ productType: event.target.value || null, page: 1 })}
|
||||
>
|
||||
<option value=''>ทุกสินค้า</option>
|
||||
<option value='crane'>Crane</option>
|
||||
<option value='dockdoor'>Dock Door</option>
|
||||
<option value='solarcell'>Solar Cell</option>
|
||||
</select>
|
||||
<select
|
||||
className='border-input bg-background rounded-md border px-3 text-sm'
|
||||
value={params.salesman ?? ''}
|
||||
onChange={(event) => void setParams({ salesman: event.target.value || null, page: 1 })}
|
||||
>
|
||||
<option value=''>ทุก salesperson</option>
|
||||
{reference.salespersons.map((sales) => (
|
||||
<option key={sales.id} value={sales.id}>
|
||||
{sales.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<Input
|
||||
type='date'
|
||||
value={params.dateFrom ?? ''}
|
||||
onChange={(event) => void setParams({ dateFrom: event.target.value || null, page: 1 })}
|
||||
/>
|
||||
<Input
|
||||
type='date'
|
||||
value={params.dateTo ?? ''}
|
||||
onChange={(event) => void setParams({ dateTo: event.target.value || null, page: 1 })}
|
||||
/>
|
||||
</div>
|
||||
<div className='flex justify-end'>
|
||||
<Button variant='outline' asChild>
|
||||
<Link href='/dashboard/crm-demo/customers'>Create Enquiry</Link>
|
||||
</Button>
|
||||
</div>
|
||||
<DataTable table={table} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user