fix(FE): fixing closing overhead per kandang

This commit is contained in:
randy-ar
2026-02-03 11:33:58 +07:00
parent e123ca9b13
commit f01765d2f8
4 changed files with 141 additions and 44 deletions
@@ -66,7 +66,13 @@ const ClosingDetail: React.FC<ClosingDetailProps> = ({
{ {
id: 'overhead', id: 'overhead',
label: 'Overhead', label: 'Overhead',
content: <ClosingOverheadTabContent projectFlockId={id} />, content: (
<ClosingOverheadTabContent
projectFlockId={id}
generalInformation={initialValue}
kandangData={kandangData}
/>
),
}, },
{ {
id: 'hppEkspedisi', id: 'hppEkspedisi',
@@ -1,3 +1,4 @@
import { formatNumber } from '@/lib/helper';
import { ClosingGeneralInformation } from '@/types/api/closing'; import { ClosingGeneralInformation } from '@/types/api/closing';
import { ProjectFlock } from '@/types/api/production/project-flock'; import { ProjectFlock } from '@/types/api/production/project-flock';
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang'; import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
@@ -56,8 +57,8 @@ const ClosingGeneralInformationTable = ({
<td>:</td> <td>:</td>
<td> <td>
{!kandangData {!kandangData
? (initialValue?.population ?? 0) ? formatNumber(initialValue?.population || 0)
: (chickinPopulation ?? 0)}{' '} : formatNumber(chickinPopulation || 0)}{' '}
Ekor Ekor
</td> </td>
</tr> </tr>
@@ -1,16 +1,26 @@
import ClosingOverheadTable from '@/components/pages/closing/ClosingOverheadTable'; import ClosingOverheadTable from '@/components/pages/closing/ClosingOverheadTable';
import { ClosingGeneralInformation } from '@/types/api/closing';
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
interface ClosingOverheadTabContentProps { interface ClosingOverheadTabContentProps {
projectFlockId: number; projectFlockId: number;
generalInformation?: ClosingGeneralInformation;
kandangData?: ProjectFlockKandang;
} }
const ClosingOverheadTabContent = ({ const ClosingOverheadTabContent = ({
projectFlockId, projectFlockId,
generalInformation,
kandangData,
}: ClosingOverheadTabContentProps) => { }: ClosingOverheadTabContentProps) => {
return ( return (
<div className='flex flex-col gap-4'> <div className='flex flex-col gap-4'>
{projectFlockId && ( {projectFlockId && (
<ClosingOverheadTable projectFlockId={projectFlockId} /> <ClosingOverheadTable
projectFlockId={projectFlockId}
generalInformation={generalInformation}
kandangData={kandangData}
/>
)} )}
</div> </div>
); );
@@ -3,7 +3,13 @@ import Table, { TABLE_DEFAULT_STYLING } from '@/components/Table';
import { isResponseSuccess } from '@/lib/api-helper'; import { isResponseSuccess } from '@/lib/api-helper';
import { cn, formatCurrency, formatDate, formatNumber } from '@/lib/helper'; import { cn, formatCurrency, formatDate, formatNumber } from '@/lib/helper';
import { ClosingApi } from '@/services/api/closing'; import { ClosingApi } from '@/services/api/closing';
import { Overhead, OverheadTotal } from '@/types/api/closing'; import {
ClosingGeneralInformation,
Overhead,
OverheadTotal,
} from '@/types/api/closing';
import { ProjectFlockKandang } from '@/types/api/production/project-flock-kandang';
import { Icon } from '@iconify/react';
import { ColumnDef } from '@tanstack/react-table'; import { ColumnDef } from '@tanstack/react-table';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
import { useMemo } from 'react'; import { useMemo } from 'react';
@@ -11,16 +17,30 @@ import useSWR from 'swr';
interface ClosingOverheadTableProps { interface ClosingOverheadTableProps {
projectFlockId: number; projectFlockId: number;
generalInformation?: ClosingGeneralInformation;
kandangData?: ProjectFlockKandang;
} }
const ClosingOverheadTable = ({ const ClosingOverheadTable = ({
projectFlockId, projectFlockId,
generalInformation,
kandangData,
}: ClosingOverheadTableProps) => { }: ClosingOverheadTableProps) => {
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const kandangId = searchParams.get('kandangId'); const kandangId = searchParams.get('kandangId');
const { data: overhead, isLoading: isLoadingOverhead } = useSWR( const { data: overhead, isLoading: isLoadingOverhead } = useSWR(
`${ClosingApi.basePath}/${projectFlockId}${kandangId ? `/${kandangId}` : ''}/overhead`, `${ClosingApi.basePath}/${projectFlockId}/overhead`,
() => ClosingApi.getOverhead(projectFlockId),
{
keepPreviousData: true,
}
);
const { data: overheadKandang, isLoading: isLoadingOverheadKandang } = useSWR(
kandangId
? `${ClosingApi.basePath}/${projectFlockId}/${kandangId}/overhead`
: undefined,
() => () =>
ClosingApi.getOverhead( ClosingApi.getOverhead(
projectFlockId, projectFlockId,
@@ -31,6 +51,26 @@ const ClosingOverheadTable = ({
} }
); );
const chickinPopulation = useMemo(() => {
if (kandangData) {
return kandangData?.chickins?.reduce(
(acc, chickin) => acc + chickin.usage_qty,
0
);
}
return 0;
}, [kandangData]);
const kandangTotal = useMemo(() => {
if (!isResponseSuccess(overhead)) {
return 0;
}
const total =
((chickinPopulation ?? 0) * overhead.data.total.actual_total_amount) /
(generalInformation?.population ?? 0);
return total;
}, [overhead, chickinPopulation, generalInformation]);
// Helper function to create columns with footer support // Helper function to create columns with footer support
const createColumns = ( const createColumns = (
total?: OverheadTotal, total?: OverheadTotal,
@@ -44,17 +84,13 @@ const ClosingOverheadTable = ({
{ {
id: 'budget_quantity', id: 'budget_quantity',
header: 'Jumlah', header: 'Jumlah',
accessorFn: (props) => accessorFn: (props) => formatNumber(props.budget_quantity),
props.budget_quantity ? formatNumber(props.budget_quantity) : '-',
footer: total ? () => formatNumber(total.budget_quantity) : '', footer: total ? () => formatNumber(total.budget_quantity) : '',
}, },
{ {
id: 'budget_unit_price', id: 'budget_unit_price',
header: 'Harga Satuan', header: 'Harga Satuan',
accessorFn: (props) => accessorFn: (props) => formatCurrency(props.budget_unit_price),
props.budget_unit_price
? formatCurrency(props.budget_unit_price)
: '-',
footer: '', footer: '',
}, },
{ {
@@ -78,34 +114,25 @@ const ClosingOverheadTable = ({
id: 'actual_date', id: 'actual_date',
header: 'Tanggal', header: 'Tanggal',
accessorFn: (props) => accessorFn: (props) =>
props.actual_date formatDate(props.actual_date, 'DD MMM, YYYY'),
? formatDate(props.actual_date, 'DD MMM, YYYY')
: '-',
footer: '', footer: '',
}, },
{ {
id: 'actual_quantity', id: 'actual_quantity',
header: 'Jumlah', header: 'Jumlah',
accessorFn: (props) => accessorFn: (props) => formatNumber(props.actual_quantity),
props.actual_quantity ? formatNumber(props.actual_quantity) : '-',
footer: total ? () => formatNumber(total.actual_quantity) : '', footer: total ? () => formatNumber(total.actual_quantity) : '',
}, },
{ {
id: 'actual_unit_price', id: 'actual_unit_price',
header: 'Harga Satuan', header: 'Harga Satuan',
accessorFn: (props) => accessorFn: (props) => formatCurrency(props.actual_unit_price),
props.actual_unit_price
? formatCurrency(props.actual_unit_price)
: '-',
footer: '', footer: '',
}, },
{ {
id: 'actual_total_amount', id: 'actual_total_amount',
header: 'Total', header: 'Total',
accessorFn: (props) => accessorFn: (props) => formatCurrency(props.actual_total_amount),
props.actual_total_amount
? formatCurrency(props.actual_total_amount)
: '-',
footer: total footer: total
? () => formatCurrency(total.actual_total_amount) ? () => formatCurrency(total.actual_total_amount)
: '', : '',
@@ -118,35 +145,25 @@ const ClosingOverheadTable = ({
{ {
id: 'actual_date', id: 'actual_date',
header: 'Tanggal', header: 'Tanggal',
accessorFn: (props) => accessorFn: (props) => formatDate(props.actual_date, 'DD MMM, YYYY'),
props.actual_date
? formatDate(props.actual_date, 'DD MMM, YYYY')
: '-',
footer: '', footer: '',
}, },
{ {
id: 'actual_quantity', id: 'actual_quantity',
header: 'Jumlah', header: 'Jumlah',
accessorFn: (props) => accessorFn: (props) => formatNumber(props.actual_quantity),
props.actual_quantity ? formatNumber(props.actual_quantity) : '-',
footer: total ? () => formatNumber(total.actual_quantity) : '', footer: total ? () => formatNumber(total.actual_quantity) : '',
}, },
{ {
id: 'actual_unit_price', id: 'actual_unit_price',
header: 'Harga Satuan', header: 'Harga Satuan',
accessorFn: (props) => accessorFn: (props) => formatCurrency(props.actual_unit_price),
props.actual_unit_price
? formatCurrency(props.actual_unit_price)
: '-',
footer: '', footer: '',
}, },
{ {
id: 'actual_total_amount', id: 'actual_total_amount',
header: 'Total', header: 'Total',
accessorFn: (props) => accessorFn: (props) => formatCurrency(props.actual_total_amount),
props.actual_total_amount
? formatCurrency(props.actual_total_amount)
: '-',
footer: total ? () => formatCurrency(total.actual_total_amount) : '', footer: total ? () => formatCurrency(total.actual_total_amount) : '',
}, },
]; ];
@@ -171,8 +188,7 @@ const ClosingOverheadTable = ({
{ {
id: 'cost_per_bird', id: 'cost_per_bird',
header: 'Rp/Ekor', header: 'Rp/Ekor',
accessorFn: (props) => accessorFn: (props) => formatCurrency(props.cost_per_bird),
props.cost_per_bird ? formatCurrency(props.cost_per_bird) : '-',
footer: total ? () => formatCurrency(total.cost_per_bird) : '', footer: total ? () => formatCurrency(total.cost_per_bird) : '',
}, },
]; ];
@@ -183,11 +199,15 @@ const ClosingOverheadTable = ({
() => () =>
isResponseSuccess(overhead) isResponseSuccess(overhead)
? createColumns( ? createColumns(
overhead.data?.total, kandangId
? isResponseSuccess(overheadKandang)
? overheadKandang.data?.total
: undefined
: overhead.data?.total,
kandangId ? Number(kandangId) : undefined kandangId ? Number(kandangId) : undefined
) )
: createColumns(), : createColumns(),
[overhead] [overhead, kandangId, overheadKandang]
); );
return ( return (
@@ -203,7 +223,13 @@ const ClosingOverheadTable = ({
> >
<Table<Overhead> <Table<Overhead>
data={ data={
isResponseSuccess(overhead) ? (overhead.data?.overheads ?? []) : [] kandangId
? isResponseSuccess(overheadKandang)
? (overheadKandang.data?.overheads ?? [])
: []
: isResponseSuccess(overhead)
? (overhead.data?.overheads ?? [])
: []
} }
columns={columns} columns={columns}
className={{ className={{
@@ -220,6 +246,60 @@ const ClosingOverheadTable = ({
: false : false
} }
/> />
{kandangId && (
<Card
className={{
wrapper: 'w-full',
body: 'p-4 shadow-button-soft border border-base-content/10 rounded-lg',
}}
>
<div className='flex flex-row gap-4 w-full justify-center items-stretch'>
<div className='flex flex-row items-center justify-between'>
<h2 className='text-base font-bold'>Pembelian Kandang </h2>
</div>
<div className='flex flex-col items-center justify-center'>
<Icon icon='heroicons:equals' className='inline' />
</div>
<div className='flex flex-col flex-1'>
<div className='flex flex-row items-center justify-center font-medium'>
Populasi Akhir KANDANG{' '}
<Icon icon='heroicons:x-mark' className='inline' /> Pemakaian
Di FARM
</div>
<hr className='w-full h-1' />
<div className='flex flex-row items-center justify-center font-medium'>
Populasi Akhir Proyek
</div>
</div>
<div className='flex flex-col items-center justify-center'>
<Icon icon='heroicons:equals' className='inline' />
</div>
<div className='flex flex-col flex-1'>
<div className='flex flex-row items-center justify-center font-medium'>
{formatNumber(chickinPopulation ?? 0)}
<Icon icon='heroicons:x-mark' className='inline' />
{formatCurrency(
isResponseSuccess(overhead)
? overhead.data?.total.actual_total_amount
: 0
)}
</div>
<hr className='w-full h-1' />
<div className='flex flex-row items-center justify-center font-medium'>
{formatNumber(generalInformation?.population ?? 0)}
</div>
</div>
<div className='flex flex-col items-center justify-center'>
<Icon icon='heroicons:equals' className='inline' />
</div>
<div className='flex flex-row items-center justify-between'>
<h2 className='text-base font-bold'>
{formatNumber(kandangTotal || 0)}
</h2>
</div>
</div>
</Card>
)}
</Card> </Card>
</> </>
); );