diff --git a/src/app/us-284/page.tsx b/src/app/us-284/page.tsx new file mode 100644 index 00000000..49764069 --- /dev/null +++ b/src/app/us-284/page.tsx @@ -0,0 +1,11 @@ +import SapronakCalculationTable from '@/components/pages/us-284/SapronakCalculationTable'; + +const PerhitunganSapronak = () => { + return ( +
+ +
+ ); +}; + +export default PerhitunganSapronak; diff --git a/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx b/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx index e2d8018f..5b54b10e 100644 --- a/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx +++ b/src/components/pages/production/project-flock/detail/ProjectFlockDetail.tsx @@ -20,6 +20,10 @@ import ConfirmationModal from '@/components/modal/ConfirmationModal'; import { ProjectFlockApi } from '@/services/api/production/project-flock'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import toast from 'react-hot-toast'; +import ApprovalSteps, { + useApprovalSteps, +} from '@/components/pages/ApprovalSteps'; +import { PROJECT_FLOCK_APPROVAL_LINE } from '@/config/approval-line'; const ProjectFlockDetail = ({ projectFlock, @@ -38,6 +42,17 @@ const ProjectFlockDetail = ({ (kandang) => kandang.id === Number(selectedKandangId) ); + const { + approvals, + isLoading: approvalsLoading, + refresh: refreshApprovals, + } = useApprovalSteps({ + latestApproval: projectFlock?.approval, + approvalLines: PROJECT_FLOCK_APPROVAL_LINE, + moduleName: 'PROJECT_FLOCKS', + moduleId: projectFlock?.id.toString() ?? '', + }); + const confirmationModalDeleteClickHandler = async () => { setIsDeleteLoading(true); const deleteProjectFlockRes = await ProjectFlockApi.delete( @@ -90,6 +105,12 @@ const ProjectFlockDetail = ({

Informasi Umum

+ {/* Status Approval */} + {approvals && !approvalsLoading && ( +
+ +
+ )} {/* Badge Row */}
-
+ {/*
History
@@ -163,7 +184,7 @@ const ProjectFlockDetail = ({ height={11} /> -
+
*/} {/* BARIS 1 */}
{ + constructor(basePath: string = '') { + super(basePath); + } + + async getPerhitunganSapronak( + projectFlockId: number + ): Promise | undefined> { + // Dummy implementation - simulate API call with delay + return new Promise((resolve) => { + setTimeout(() => { + resolve({ + code: 200, + status: 'success', + message: 'Retrieved sapronak calculation successfully', + data: DUMMY_SAPRONAK_CALCULATION, + }); + }, 500); // Simulate 500ms network delay + }); + + /* + // Real API implementation - uncomment when backend is ready + try { + const path = `${this.basePath}/project-flock/${projectFlockId}/sapronak-calculation`; + + return await httpClient>(path, { + method: 'GET', + }); + } catch (error: unknown) { + if (axios.isAxiosError>(error)) { + return error.response?.data; + } + return undefined; + } + */ + } +} + +export const ClosingApi = new ClosingService(`/closing`); diff --git a/src/components/pages/us-284/SapronakCalculationTable.tsx b/src/components/pages/us-284/SapronakCalculationTable.tsx new file mode 100644 index 00000000..dea01068 --- /dev/null +++ b/src/components/pages/us-284/SapronakCalculationTable.tsx @@ -0,0 +1,204 @@ +'use client'; + +import Card from '@/components/Card'; +import { + ClosingApi, + RowSapronakCalculation, +} from '@/components/pages/us-284/DummyDataSapronakCalculation'; +import Table from '@/components/Table'; +import { isResponseSuccess } from '@/lib/api-helper'; +import { cn, formatCurrency, formatNumber } from '@/lib/helper'; +import { ColumnDef } from '@tanstack/react-table'; +import { useMemo } from 'react'; +import useSWR from 'swr'; + +const SapronakCalculationTable = ({ + projectFlockId, +}: { + projectFlockId: number; +}) => { + const { data: sapronakCalculation, isLoading } = useSWR( + `/sapronak-calculation`, + () => ClosingApi.getPerhitunganSapronak(projectFlockId) + ); + + const columns: ColumnDef[] = useMemo( + () => [ + { + header: 'Tanggal', + accessorKey: 'tanggal', + cell: (props) => { + const value = props.getValue() as string; + // Data already in DD-MMM-YYYY format, just display it + return value || '-'; + }, + }, + { + header: 'No. Referensi', + accessorKey: 'no_referensi', + }, + { + header: 'QTY Masuk', + accessorKey: 'qty_masuk', + cell: (props) => { + const value = props.getValue() as number; + return formatNumber(value); + }, + }, + { + header: 'QTY Keluar', + accessorKey: 'qty_keluar', + cell: (props) => { + const value = props.getValue() as number; + return formatNumber(value); + }, + }, + { + header: 'QTY Pakai', + accessorKey: 'qty_pakai', + cell: (props) => { + const value = props.getValue() as number; + return formatNumber(value); + }, + }, + { + header: 'Uraian', + accessorKey: 'uraian', + }, + { + header: 'Kategori Produk', + accessorKey: 'kategori_produk', + }, + { + header: 'Harga Beli/Qty (Rp)', + accessorKey: 'harga_beli_per_qty', + cell: (props) => { + const value = props.getValue() as number; + return formatCurrency(value); + }, + }, + { + header: 'Total Harga (Rp)', + accessorKey: 'total_harga', + cell: (props) => { + const value = props.getValue() as number; + return formatCurrency(value); + }, + }, + { + header: 'Keterangan', + accessorKey: 'keterangan', + cell: (props) => { + const value = props.getValue() as string; + return value || '-'; + }, + }, + ], + [] + ); + + return ( +
+ {isLoading && ( +
+ +
+ )} + {isResponseSuccess(sapronakCalculation) && ( + <> + + + data={sapronakCalculation.data.doc_broiler.rows} + columns={columns} + className={{ + containerClassName: cn({ + 'mb-20': + isResponseSuccess(sapronakCalculation) && + sapronakCalculation?.data.doc_broiler.rows.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 last:flex last:flex-row last:justify-end', + bodyRowClassName: 'border-b border-b-gray-200', + bodyColumnClassName: + 'px-6 py-3 last:flex last:flex-row last:justify-end', + }} + /> + + + + + data={sapronakCalculation.data.ovk.rows} + columns={columns} + className={{ + containerClassName: cn({ + 'mb-20': + isResponseSuccess(sapronakCalculation) && + sapronakCalculation?.data.ovk.rows.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 last:flex last:flex-row last:justify-end', + bodyRowClassName: 'border-b border-b-gray-200', + bodyColumnClassName: + 'px-6 py-3 last:flex last:flex-row last:justify-end', + }} + /> + + + + + data={sapronakCalculation.data.pakan.rows} + columns={columns} + className={{ + containerClassName: cn({ + 'mb-20': + isResponseSuccess(sapronakCalculation) && + sapronakCalculation?.data.pakan.rows.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 last:flex last:flex-row last:justify-end', + bodyRowClassName: 'border-b border-b-gray-200', + bodyColumnClassName: + 'px-6 py-3 last:flex last:flex-row last:justify-end', + }} + /> + + + )} +
+ ); +}; + +export default SapronakCalculationTable; diff --git a/src/config/constant.ts b/src/config/constant.ts index 8af85bc1..4611bb90 100644 --- a/src/config/constant.ts +++ b/src/config/constant.ts @@ -58,6 +58,12 @@ export const MAIN_DRAWER_LINKS: MAIN_DRAWER_MENU[] = [ icon: 'uil:wallet', }, + { + title: 'Perhitungan Sapronak', + link: '/us-284', + icon: 'uil:calculator', + }, + { title: 'Persediaan', link: '/inventory',