mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 21:41:57 +00:00
275 lines
8.2 KiB
TypeScript
275 lines
8.2 KiB
TypeScript
'use client';
|
|
|
|
import { useCallback, useEffect, useRef, 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 rowSelectionRef = useRef(rowSelection);
|
|
const prevRowSelectionRef = useRef<Record<string, boolean>>({});
|
|
|
|
useEffect(() => {
|
|
rowSelectionRef.current = rowSelection;
|
|
}, [rowSelection]);
|
|
|
|
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]);
|
|
|
|
useEffect(() => {
|
|
const currentKeys = Object.keys(rowSelection).sort().join(',');
|
|
const prevKeys = Object.keys(prevRowSelectionRef.current).sort().join(',');
|
|
|
|
if (currentKeys !== prevKeys) {
|
|
prevRowSelectionRef.current = { ...rowSelection };
|
|
|
|
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 if (Object.keys(rowSelection).length === 0) {
|
|
onChange([]);
|
|
}
|
|
}
|
|
}, [rowSelection, kandangs, onChange]);
|
|
|
|
useEffect(() => {
|
|
if (
|
|
selectedKandangs.length === 0 &&
|
|
Object.keys(rowSelectionRef.current).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]);
|
|
|
|
// Tampilkan tabel jika:
|
|
// 1. Mode request pertama kali (type='add' dan formType='request')
|
|
// 2. Atau sudah ada kandang yang dipilih
|
|
const shouldShowTable =
|
|
(type === 'add' && formType === 'request') ||
|
|
(selectedKandangs.length > 0 && selectedKandangs.some((k) => k.id));
|
|
|
|
return (
|
|
<>
|
|
{shouldShowTable && (
|
|
<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;
|