feat(FE-442): create ProductionResultProjectFlockKandangTable component

This commit is contained in:
ValdiANS
2025-12-30 22:25:27 +07:00
parent 23ee8828f0
commit ea5ad20684
@@ -0,0 +1,364 @@
'use client';
import { useEffect, useState } from 'react';
import useSWR from 'swr';
import { ColumnDef, SortingState } from '@tanstack/react-table';
import { Icon } from '@iconify/react';
import Table from '@/components/Table';
import Card from '@/components/Card';
import Collapse from '@/components/Collapse';
import { cn, formatNumber } from '@/lib/helper';
import { isResponseSuccess } from '@/lib/api-helper';
import { ProductionResult } from '@/types/api/report/production-result';
import { useTableFilter } from '@/services/hooks/useTableFilter';
import { ProductionResultReportApi } from '@/services/api/report/production-result';
interface ProductionResultProjectFlockKandangTableProps {
projectFlockKandangId?: number;
kandangName?: string;
}
const ProductionResultProjectFlockKandangTable = ({
projectFlockKandangId,
kandangName,
}: ProductionResultProjectFlockKandangTableProps) => {
const {
state: tableFilterState,
updateFilter,
setPage,
setPageSize,
toQueryString: getTableFilterQueryString,
reset: resetFilter,
} = useTableFilter({
initial: {
filter_by: '',
sort_by: '',
},
paramMap: {
pageSize: 'limit',
},
});
const { data: productionResults, isLoading: isLoadingProductionResults } =
useSWR(
projectFlockKandangId
? `/reports/production-result/${projectFlockKandangId}${getTableFilterQueryString()}`
: null,
ProductionResultReportApi.getAllProductionResultFetcher,
{
keepPreviousData: true,
}
);
const [open, setOpen] = useState(false);
const [sorting, setSorting] = useState<SortingState>([]);
const productionResultColumns: ColumnDef<ProductionResult>[] = [
{
header: 'No',
cell: (props) => props.row.index + 1,
},
{
accessorKey: 'woa',
header: 'WOA',
},
{
accessorKey: 'bw',
header: 'BW',
cell: (props) => formatNumber(props.row.original.bw),
},
{
accessorKey: 'std_bw',
header: 'STD BW',
cell: (props) => formatNumber(props.row.original.std_bw),
},
{
accessorKey: 'uniformity',
header: 'Uniformity',
cell: (props) => formatNumber(props.row.original.uniformity),
},
{
accessorKey: 'std_uniformity',
header: 'STD Uniformity',
},
{
accessorKey: 'dep_kum',
header: 'Dep Kum',
cell: (props) => formatNumber(props.row.original.dep_kum),
},
{
accessorKey: 'dep_std',
header: 'Dep STD',
cell: (props) => formatNumber(props.row.original.dep_std),
},
// Butiran
{
header: 'Butiran',
columns: [
{
accessorKey: 'butiran_utuh',
header: 'Utuh',
cell: (props) => formatNumber(props.row.original.butiran_utuh),
},
{
accessorKey: 'butiran_putih',
header: 'Putih',
cell: (props) => formatNumber(props.row.original.butiran_putih),
},
{
accessorKey: 'butiran_retak',
header: 'Retak',
cell: (props) => formatNumber(props.row.original.butiran_retak),
},
{
accessorKey: 'butiran_pecah',
header: 'Pecah',
cell: (props) => formatNumber(props.row.original.butiran_pecah),
},
{
accessorKey: 'butiran_jumlah',
header: 'Jumlah (Butir)',
cell: (props) => formatNumber(props.row.original.butiran_jumlah),
},
{
accessorKey: 'total_butir',
header: 'Total Butir',
cell: (props) => formatNumber(props.row.original.total_butir),
},
],
},
// Kg
{
header: 'Kg',
columns: [
{
accessorKey: 'kg_utuh',
header: 'Utuh (Kg)',
cell: (props) => formatNumber(props.row.original.kg_utuh),
},
{
accessorKey: 'kg_putih',
header: 'Putih (Kg)',
cell: (props) => formatNumber(props.row.original.kg_putih),
},
{
accessorKey: 'kg_retak',
header: 'Retak (Kg)',
cell: (props) => formatNumber(props.row.original.kg_retak),
},
{
accessorKey: 'kg_pecah',
header: 'Pecah (Kg)',
cell: (props) => formatNumber(props.row.original.kg_pecah),
},
{
accessorKey: 'kg_jumlah',
header: 'Jumlah (Kg)',
cell: (props) => formatNumber(props.row.original.kg_jumlah),
},
{
accessorKey: 'total_kg',
header: 'Total Kg',
cell: (props) => formatNumber(props.row.original.total_kg),
},
],
},
// Persen
{
header: '%',
columns: [
{
accessorKey: 'persen_utuh',
header: 'Utuh',
cell: (props) => formatNumber(props.row.original.persen_utuh),
},
{
accessorKey: 'persen_putih',
header: 'Putih',
cell: (props) => formatNumber(props.row.original.persen_putih),
},
{
accessorKey: 'persen_retak',
header: 'Retak',
cell: (props) => formatNumber(props.row.original.persen_retak),
},
{
accessorKey: 'persen_pecah',
header: 'Pecah',
cell: (props) => formatNumber(props.row.original.persen_pecah),
},
],
},
// Produksi
{
header: 'Produksi',
columns: [
{
accessorKey: 'hd',
header: 'HD',
cell: (props) => formatNumber(props.row.original.hd),
},
{
accessorKey: 'hd_std',
header: 'HD STD',
cell: (props) => formatNumber(props.row.original.hd_std),
},
{
accessorKey: 'fi',
header: 'FI',
cell: (props) => formatNumber(props.row.original.fi),
},
{
accessorKey: 'fi_std',
header: 'FI STD',
cell: (props) => formatNumber(props.row.original.fi_std),
},
{
accessorKey: 'em',
header: 'EM',
cell: (props) => formatNumber(props.row.original.em),
},
{
accessorKey: 'em_std',
header: 'EM STD',
cell: (props) => formatNumber(props.row.original.em_std),
},
{
accessorKey: 'ew',
header: 'EW',
cell: (props) => formatNumber(props.row.original.ew),
},
{
accessorKey: 'ew_std',
header: 'EW STD',
cell: (props) => formatNumber(props.row.original.ew_std),
},
{
accessorKey: 'fcr',
header: 'FCR',
cell: (props) => formatNumber(props.row.original.fcr),
},
{
accessorKey: 'fcr_std',
header: 'FCR STD',
cell: (props) => formatNumber(props.row.original.fcr_std),
},
{
accessorKey: 'hh',
header: 'HH',
cell: (props) => formatNumber(props.row.original.hh),
},
{
accessorKey: 'hh_std',
header: 'HH STD',
cell: (props) => formatNumber(props.row.original.hh_std),
},
],
},
];
useEffect(() => {
if (sorting.length === 1) {
updateFilter('filter_by', sorting[0].id);
updateFilter('sort_by', sorting[0].desc ? 'desc' : 'asc');
} else {
updateFilter('filter_by', '');
updateFilter('sort_by', '');
}
}, [sorting]);
useEffect(() => {
if (!open) {
setOpen(
isResponseSuccess(productionResults)
? productionResults.data.length > 0
: false
);
}
}, [productionResults, isResponseSuccess]);
return (
<Card
className={{
wrapper: 'w-full',
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'>{kandangName}</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!'
>
<div className='w-full p-0'>
{/* <div className='flex flex-col gap-2 mb-4'>
<div className='w-full flex flex-col sm:flex-row justify-start items-end sm:items-center gap-4'>
<DebouncedTextInput
name='search'
placeholder='Cari Record'
value={tableFilterState.search}
onChange={searchChangeHandler}
className={{ wrapper: 'sm:max-w-3xs' }}
/>
</div>
</div> */}
<Table<ProductionResult>
data={
isResponseSuccess(productionResults)
? productionResults?.data
: []
}
columns={productionResultColumns}
pageSize={tableFilterState.pageSize}
onPageSizeChange={setPageSize}
rowOptions={[10, 20, 50, 100]}
page={
isResponseSuccess(productionResults)
? productionResults?.meta?.page
: 0
}
totalItems={
isResponseSuccess(productionResults)
? productionResults?.meta?.total_results
: 0
}
onPageChange={setPage}
isLoading={isLoadingProductionResults}
sorting={sorting}
setSorting={setSorting}
renderFooter={false}
className={{
containerClassName: cn({
'w-full mb-20':
isResponseSuccess(productionResults) &&
productionResults?.data?.length === 0,
}),
headerColumnClassName:
'px-4 py-3 border-base-content/10 text-base-content/50',
}}
/>
</div>
</Collapse>
</Card>
);
};
export default ProductionResultProjectFlockKandangTable;