diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index bee92a57..0d5b9bc8 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -54,7 +54,8 @@ const Navbar = ({ title, toggleSidebar }: NavbarProps) => {
@@ -62,9 +63,11 @@ const Navbar = ({ title, toggleSidebar }: NavbarProps) => {
} - contentClassName='w-52 mt-3' + className={{ + content: 'w-52 mt-3', + }} > - + diff --git a/src/components/pages/closing/ClosingDetail.tsx b/src/components/pages/closing/ClosingDetail.tsx index fd88fa49..dc06eb22 100644 --- a/src/components/pages/closing/ClosingDetail.tsx +++ b/src/components/pages/closing/ClosingDetail.tsx @@ -6,12 +6,13 @@ import { Icon } from '@iconify/react'; import Button from '@/components/Button'; import Tabs from '@/components/Tabs'; import ClosingGeneralInformationTable from '@/components/pages/closing/ClosingGeneralInformationTable'; +import ClosingSapronakTabContent from '@/components/pages/closing/ClosingSapronakTabContent'; +import ClosingProductionDataTabContent from '@/components/pages/closing/ClosingProductionDataTabContent'; import { ClosingGeneralInformation, BaseClosingSales, } from '@/types/api/closing'; -import ClosingSapronakTabContent from './ClosingSapronakTabContent'; import ClosingSapronakCalculationTabContent from '@/components/pages/closing/ClosingSapronakCalculationTabContent'; import ClosingOverheadTabContent from '@/components/pages/closing/ClosingOverheadTabContent'; import SalesReportTable from './sale/SalesReportTable'; @@ -59,7 +60,7 @@ const ClosingDetail: React.FC = ({ { id: 'dataProduksi', label: 'Data Produksi', - content: 'Data Produksi', + content: , }, { id: 'keuangan', diff --git a/src/components/pages/closing/ClosingProductionDataTabContent.tsx b/src/components/pages/closing/ClosingProductionDataTabContent.tsx new file mode 100644 index 00000000..ba8a12ed --- /dev/null +++ b/src/components/pages/closing/ClosingProductionDataTabContent.tsx @@ -0,0 +1,268 @@ +'use client'; + +import useSWR from 'swr'; +import { ClosingApi } from '@/services/api/closing'; +import { isResponseSuccess } from '@/lib/api-helper'; +import { formatNumber } from '@/lib/helper'; + +interface ClosingProductionDataTabContentProps { + projectFlockId: number; +} + +const ClosingProductionDataTabContent = ({ + projectFlockId, +}: ClosingProductionDataTabContentProps) => { + const { data: productionData, isLoading } = useSWR( + `${ClosingApi.basePath}/${projectFlockId}/production-data`, + () => ClosingApi.getProductionData(projectFlockId) + ); + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (!productionData || !isResponseSuccess(productionData)) { + return ( +
+ Gagal memuat data produksi. +
+ ); + } + + const { purchase, sales, performance, variance } = productionData.data; + + // Helper for consistent row styling + const DataRow = ({ + label, + value, + unit = '', + valueClassName = 'font-bold text-gray-800', + unitClassName = 'text-gray-500 w-12 text-right', + }: { + label: string; + value: string | number; + unit?: string; + valueClassName?: string; + unitClassName?: string; + }) => ( +
+ {label} +
+ {value} + {unit && {unit}} +
+
+ ); + + // Helper for rows with two values (e.g., Deplesi: Ekor & %) + const DoubleDataRow = ({ + label, + value1, + unit1, + value2, + unit2, + value1ClassName = 'font-bold text-gray-800', + value2ClassName = 'font-bold text-blue-500', + }: { + label: string; + value1: string | number; + unit1: string; + value2: string | number; + unit2: string; + value1ClassName?: string; + value2ClassName?: string; + }) => ( +
+ {label} +
+
+ {value1} + {unit1} +
+
+ {value2} + {unit2} +
+
+
+ ); + + return ( +
+

Data Produksi

+ +
+ {/* Left Column */} +
+ {/* Purchase Section */} +
+

+ Pembelian +

+
+ + + + + + +
+
+ + {/* Sales Section */} +
+

+ Penjualan +

+
+ + + + +
+
+
+ + {/* Divider Line (Absolute centered) */} +
+ + {/* Right Column */} +
+ {/* Performance Section */} +
+

+ Performance +

+
+ + + + + + + + + + +
+
+ + {/* Variance Section (Pushed to bottom) */} +
+

Selisih

+
+ + + +
+
+
+
+
+ ); +}; + +export default ClosingProductionDataTabContent; diff --git a/src/services/api/closing.ts b/src/services/api/closing.ts index 0a6ef40c..2511a4f9 100644 --- a/src/services/api/closing.ts +++ b/src/services/api/closing.ts @@ -6,6 +6,7 @@ import { ClosingGeneralInformation, ClosingIncomingSapronak, ClosingOutgoingSapronak, + ClosingProductionData, ClosingOverhead, ClosingSapronakCalculation, } from '@/types/api/closing'; @@ -134,6 +135,22 @@ export class ClosingApiService extends BaseApiService { } } + async getProductionData(id: number) { + try { + const getProductionDataPath = `${this.basePath}/${id}/production-data`; + const getProductionDataRes = await httpClient< + BaseApiResponse + >(getProductionDataPath); + + return getProductionDataRes; + } catch (error) { + if (axios.isAxiosError>(error)) { + return error.response?.data; + } + return undefined; + } + } + async getPerhitunganSapronak( id: number ): Promise | undefined> { diff --git a/src/types/api/closing.d.ts b/src/types/api/closing.d.ts index baf4c7aa..44819613 100644 --- a/src/types/api/closing.d.ts +++ b/src/types/api/closing.d.ts @@ -79,6 +79,41 @@ export type ClosingIncomingSapronak = { export type ClosingOutgoingSapronak = ClosingIncomingSapronak; +export type ClosingProductionData = { + purchase: { + initial_population: number; + claim_culling: number; + final_population: number; + feed_in_kg: number; + feed_used_kg: number; + feed_used_per_head_kg: number; + }; + sales: { + sales_kg: number; + sales_head: number; + average_weight_kg: number; + average_price_per_kg: number; + }; + performance: { + depletion_head: number; + depletion_percentage: number; + age_days: number; + mortality_std: number; + mortality_act: number; + deff_mortality: number; + fcr_std: number; + fcr_act: number; + deff_fcr: number; + adg: number; + ip: number; + }; + variance: { + variance_head: number; + variance_head_percentage: number; + variance_feed_kg: number; + }; +}; + // ====== PERHITUNGAN SAPRONAK ====== export type RowSapronakCalculation = {