Files
lti-web-client/src/components/pages/expense/form/ExpenseKandangsTable.tsx
T

252 lines
7.4 KiB
TypeScript

'use client';
import { useCallback, useEffect, useState } from 'react';
import useSWR from 'swr';
import { Icon } from '@iconify/react';
import Collapse from '@/components/Collapse';
import Card from '@/components/Card';
import Table from '@/components/Table';
import CheckboxInput from '@/components/input/CheckboxInput';
import { ColumnDef, ColumnSort, SortingState } from '@tanstack/react-table';
import { cn, convertRowSelectionArrToObj } from '@/lib/helper';
import { Kandang } from '@/types/api/master-data/kandang';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { KandangApi } from '@/services/api/master-data';
import { isResponseSuccess } from '@/lib/api-helper';
interface ExpenseKandangsTableProps {
locationId?: number;
type: 'add' | 'edit' | 'detail';
formType?: 'request' | 'realization';
selectedKandangs: {
id?: number;
name?: string;
}[];
onChange: (kandangs: { id?: number; name?: string }[]) => void;
className?: {
wrapper?: string;
};
}
const ExpenseKandangsTable = ({
type,
formType = 'request',
locationId,
selectedKandangs,
onChange,
className,
}: ExpenseKandangsTableProps) => {
const {
state: tableFilterState,
updateFilter,
setPage,
toQueryString: getTableFilterQueryString,
} = useTableFilter({
initial: {
search: '',
nameSort: '',
picSort: '',
locationId,
},
paramMap: {
page: 'page',
pageSize: 'limit',
nameSort: 'sort_name',
picSort: 'sort_pic',
locationId: 'location_id',
},
});
const { data: kandangs, isLoading } = useSWR(
locationId ? `${KandangApi.basePath}${getTableFilterQueryString()}` : null,
KandangApi.getAllFetcher
);
const [open, setOpen] = useState(
isResponseSuccess(kandangs) ? kandangs.data.length > 0 : false
);
const [sorting, setSorting] = useState<SortingState>([]);
const [rowSelection, setRowSelection] = useState<Record<string, boolean>>(
convertRowSelectionArrToObj(
selectedKandangs
.map((item) => item.id)
.filter((id): id is number => id !== undefined)
)
);
const kandangsColumns: ColumnDef<Kandang>[] = [
{
id: 'select',
header: ({ table }) => (
<div className='w-full flex flex-row justify-center'>
<CheckboxInput
name='allRow'
checked={table.getIsAllPageRowsSelected()}
indeterminate={table.getIsSomePageRowsSelected()}
onChange={table.getToggleAllPageRowsSelectedHandler()}
disabled={type === 'detail'}
/>
</div>
),
cell: ({ row }) => (
<div>
<CheckboxInput
name='row'
checked={row.getIsSelected()}
disabled={!row.getCanSelect() || type === 'detail'}
indeterminate={row.getIsSomeSelected()}
onChange={row.getToggleSelectedHandler()}
/>
</div>
),
},
{
accessorKey: 'name',
header: 'Nama',
},
{
accessorKey: 'pic',
header: 'PIC',
cell: (props) => props.row.original.pic.name,
},
];
const updateSortingFilter = useCallback(
(
sortName: Exclude<keyof typeof tableFilterState, 'page' | 'pageSize'>,
sortFilter: ColumnSort | undefined
) => {
if (!sortFilter) {
updateFilter(sortName, '');
} else {
updateFilter(sortName, sortFilter.desc ? 'desc' : 'asc');
}
},
[updateFilter]
);
useEffect(() => {
if (locationId) updateFilter('locationId', locationId);
}, [locationId, updateFilter]);
useEffect(() => {
setOpen(isResponseSuccess(kandangs) ? kandangs.data.length > 0 : false);
}, [kandangs, isResponseSuccess]);
useEffect(() => {
if (Object.keys(rowSelection).length !== 0 && isResponseSuccess(kandangs)) {
const formattedSelectedKandangs = Object.keys(rowSelection).map(
(item) => {
const selectedKandang = kandangs.data.find(
(kandang) => kandang.id === parseInt(item)
);
return {
id: parseInt(item),
name: selectedKandang?.name ?? 'Kandang tidak ditemukan!',
};
}
);
onChange(formattedSelectedKandangs);
} else {
onChange([]);
}
}, [rowSelection]);
useEffect(() => {
if (
selectedKandangs.length === 0 &&
Object.keys(rowSelection).length !== 0
) {
setRowSelection({});
}
}, [selectedKandangs]);
// track sorting
useEffect(() => {
const nameSortFilter = sorting.find((sortItem) => sortItem.id === 'name');
const picSortFilter = sorting.find((sortItem) => sortItem.id === 'pic');
updateSortingFilter('nameSort', nameSortFilter);
updateSortingFilter('picSort', picSortFilter);
}, [sorting, updateSortingFilter]);
return (
<>
{selectedKandangs.length > 0 && selectedKandangs.some((k) => k.id) && (
<Card
className={{
wrapper: className?.wrapper,
body: 'p-4 shadow',
}}
>
<Collapse
open={open}
onOpenChange={setOpen}
title={
<div className='card-actions p-4 justify-between items-center w-full'>
<div className='card-title'>
{formType === 'realization'
? 'Kandang yang Direalisasikan'
: 'Pilih Kandang'}
</div>
<Icon
icon='material-symbols:keyboard-arrow-down'
width={24}
height={24}
className={cn('text-primary transition-transform', {
'-rotate-180': open,
})}
/>
</div>
}
className='w-full!'
titleClassName='w-full p-0!'
>
<Table<Kandang>
data={isResponseSuccess(kandangs) ? kandangs?.data : []}
columns={kandangsColumns}
pageSize={tableFilterState.pageSize}
page={isResponseSuccess(kandangs) ? kandangs?.meta?.page : 0}
totalItems={
isResponseSuccess(kandangs) ? kandangs?.meta?.total_results : 0
}
onPageChange={setPage}
isLoading={isLoading}
sorting={sorting}
setSorting={setSorting}
rowSelection={rowSelection}
setRowSelection={setRowSelection}
className={{
containerClassName: cn({
'mb-20':
isResponseSuccess(kandangs) && kandangs?.data?.length === 0,
}),
tableWrapperClassName: 'overflow-x-auto min-h-full!',
tableClassName: 'font-inter w-full table-auto min-h-full!',
headerRowClassName: 'border-b border-b-gray-200',
headerColumnClassName:
'px-6 py-3 text-xs font-semibold text-gray-500 first:flex first:flex-row first:justify-start',
bodyRowClassName: 'border-b border-b-gray-200',
bodyColumnClassName:
'px-6 py-3 first:flex first:flex-row first:justify-start',
paginationClassName: cn({
hidden:
isResponseSuccess(kandangs) &&
kandangs?.meta?.total_pages === 1,
}),
}}
/>
</Collapse>
</Card>
)}
</>
);
};
export default ExpenseKandangsTable;