From 9dc8f0553449ee5b789acebd28308f4bd5553668 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 10:55:38 +0700 Subject: [PATCH 01/19] feat: adjust penjualan calculation and delivery order logic --- .../pages/marketing/SalesOrderFormModal.tsx | 2 +- .../marketing/form/MarketingForm.schema.ts | 7 +---- .../DeliverOrderProduct.schema.ts | 28 +++++-------------- .../delivery-order/DeliverOrderProduct.tsx | 21 +++++++------- .../sales-order/SalesOrderProduct.schema.ts | 28 +++++-------------- .../sales-order/SalesOrderProductForm.tsx | 21 +++++++------- .../table-view/SalesOrderProductTable.tsx | 2 +- src/lib/marketing-calculation.ts | 4 +-- 8 files changed, 41 insertions(+), 72 deletions(-) diff --git a/src/components/pages/marketing/SalesOrderFormModal.tsx b/src/components/pages/marketing/SalesOrderFormModal.tsx index 66acc440..4f5d4b95 100644 --- a/src/components/pages/marketing/SalesOrderFormModal.tsx +++ b/src/components/pages/marketing/SalesOrderFormModal.tsx @@ -208,7 +208,7 @@ const SalesOrderFormModal = ({ convertion_unit: normalizedConvertionUnit, weight_per_convertion: product.weight_per_convertion ?? undefined, - week: product.week?.value ?? undefined, + week: product.week ?? undefined, } as CreateSalesOrderProductPayload; }), } as CreateSalesOrderPayload) diff --git a/src/components/pages/marketing/form/MarketingForm.schema.ts b/src/components/pages/marketing/form/MarketingForm.schema.ts index 0215217f..17b6d78c 100644 --- a/src/components/pages/marketing/form/MarketingForm.schema.ts +++ b/src/components/pages/marketing/form/MarketingForm.schema.ts @@ -128,12 +128,7 @@ export const SalesProductToFieldValues = ( label: formatTitleCase(product.convertion_unit), } : null, - week: product.week - ? { - value: product.week, - label: `Week ${product.week}`, - } - : null, + week: product.week ?? null, total_peti: product.total_peti, weight_per_convertion: product.weight_per_convertion, uom: product.product_warehouse.product.uom.name, diff --git a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.schema.ts b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.schema.ts index 4c20f05b..c7cb4e9f 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.schema.ts +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.schema.ts @@ -30,13 +30,7 @@ type DeliveryOrderProductSchemaType = { /** Harga per butir telur untuk TELUR + QTY */ price_per_qty?: number | null | undefined; /** Week untuk ayam pullet */ - week?: - | { - value?: number; - label?: string; - } - | null - | undefined; + week?: number | null | undefined; }; export const DeliveryOrderProductSchema: Yup.ObjectSchema = @@ -79,26 +73,18 @@ export const DeliveryOrderProductSchema: Yup.ObjectSchema marketingType?.value?.toLowerCase() === 'ayam_pullet', then: (schema) => schema - .shape({ - value: Yup.number().required( - 'Week wajib diisi untuk Ayam Pullet!' - ), - label: Yup.string().required( - 'Week wajib diisi untuk Ayam Pullet!' - ), - }) - .required('Week wajib diisi untuk Ayam Pullet!'), + .min(1, 'Week wajib diisi untuk Ayam Pullet!') + .required('Week wajib diisi untuk Ayam Pullet!') + .typeError('Week harus berupa angka!'), otherwise: (schema) => schema.optional().notRequired(), }), }); diff --git a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx index 850d88d2..d7b97d8e 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -511,19 +511,20 @@ const DeliveryOrderProductForm = ({ {/* Konversi Satuan Week Pullet */} {formik.values.marketing_type?.value.toLowerCase() === 'ayam_pullet' && ( - { - formik.setFieldValue('week', val); + name='week' + value={formik.values.week ?? undefined} + onChange={(e) => { + formik.setFieldValue('week', Number(e.target.value)); + setCurrentInput(e.target.name); }} - placeholder='Pilih Week' + onBlur={() => handleBlurField('week')} + isError={formik.touched.week && Boolean(formik.errors.week)} + errorMessage={formik.errors.week as string} + placeholder='Masukan Minggu' + decimalScale={0} /> )} diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema.ts b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema.ts index f17f6f8c..390756e7 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema.ts +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema.ts @@ -37,13 +37,7 @@ type SalesOrderProductSchemaType = { /** Harga per butir telur untuk TELUR + QTY */ price_per_qty?: number | null | undefined; /** Week untuk ayam pullet */ - week?: - | { - value?: number; - label?: string; - } - | null - | undefined; + week?: number | null | undefined; }; export const SalesOrderProductSchema: Yup.ObjectSchema = @@ -102,26 +96,18 @@ export const SalesOrderProductSchema: Yup.ObjectSchema marketingType?.value?.toLowerCase() === 'ayam_pullet', then: (schema) => schema - .shape({ - value: Yup.number().required( - 'Week wajib diisi untuk Ayam Pullet!' - ), - label: Yup.string().required( - 'Week wajib diisi untuk Ayam Pullet!' - ), - }) - .required('Week wajib diisi untuk Ayam Pullet!'), + .min(1, 'Week wajib diisi untuk Ayam Pullet!') + .required('Week wajib diisi untuk Ayam Pullet!') + .typeError('Week harus berupa angka!'), otherwise: (schema) => schema.optional().notRequired(), }), }); diff --git a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx index c718c40c..ac67cff4 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx @@ -467,19 +467,20 @@ const SalesOrderProductForm = ({ {/* Konversi Satuan Week Pullet */} {formik.values.marketing_type?.value.toLowerCase() === 'ayam_pullet' && ( - { - formik.setFieldValue('week', val); + name='week' + value={formik.values.week ?? undefined} + onChange={(e) => { + formik.setFieldValue('week', Number(e.target.value)); + setCurrentInput(e.target.name); }} - placeholder='Pilih Week' + onBlur={() => handleBlurField('week')} + isError={formik.touched.week && Boolean(formik.errors.week)} + errorMessage={formik.errors.week as string} + placeholder='Masukan Minggu' + decimalScale={0} /> )} diff --git a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx index 6f667f76..e900974b 100644 --- a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx @@ -234,7 +234,7 @@ const SalesOrderProductTable = ({ 'ayam_pullet' && ( Tipe Konversi - {item.week?.label} + Week {item.week} )} {item.convertion_unit?.value.toLowerCase() === 'peti' && ( diff --git a/src/lib/marketing-calculation.ts b/src/lib/marketing-calculation.ts index 5715ec88..5ad5a1e6 100644 --- a/src/lib/marketing-calculation.ts +++ b/src/lib/marketing-calculation.ts @@ -15,7 +15,7 @@ export type MarketingFormValues = { total_price?: string | number; marketing_type?: { value: string; label: string } | null; convertion_unit?: { value: string; label: string } | null; - week?: { value?: number; label?: string } | null; + week?: number | null; weight_per_convertion?: number | null; price_per_convertion?: number | null; total_peti?: number | null; @@ -100,7 +100,7 @@ export const calculateAyamPullet = ( ): void => { const { values, setFieldValue } = ctx; const unitPrice = Number(values.unit_price || 0); - const week = Number(values.week?.value || 0); + const week = Number(values.week || 0); const qty = Number(values.qty || 0); const avgWeight = Number(values.avg_weight || 0); const totalWeight = Number(values.total_weight || 0); From 42088e51a842beb408fdcc0c223c9e273a6fcdec Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 13:13:57 +0700 Subject: [PATCH 02/19] refactor(FE): Refactor marketing filter to use unique customer options --- .../pages/marketing/MarketingFilter.tsx | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/components/pages/marketing/MarketingFilter.tsx b/src/components/pages/marketing/MarketingFilter.tsx index 3c59e07e..eda3d9b2 100644 --- a/src/components/pages/marketing/MarketingFilter.tsx +++ b/src/components/pages/marketing/MarketingFilter.tsx @@ -1,6 +1,6 @@ 'use client'; -import { RefObject } from 'react'; +import { RefObject, useMemo } from 'react'; import { useFormik } from 'formik'; import { Icon } from '@iconify/react'; import Modal from '@/components/Modal'; @@ -9,10 +9,12 @@ import SelectInput, { OptionType, useSelect, } from '@/components/input/SelectInput'; -import { CustomerApi, ProductApi } from '@/services/api/master-data'; import { MARKETING_APPROVAL_LINE } from '@/config/approval-line'; import { MarketingFilter } from '@/types/api/marketing/marketing'; import SelectInputCheckbox from '@/components/input/SelectInputCheckbox'; +import { MarketingApi } from '@/services/api/marketing/marketing'; +import { isResponseSuccess } from '@/lib/api-helper'; +import { BaseMarketing, BaseSalesOrder } from '@/types/api/marketing/marketing'; interface MarketingFilterModal { ref: RefObject; @@ -31,21 +33,52 @@ const MarketingFilterModal = ({ // ===== OPTIONS ===== const { - options: productsOptions, + rawData: productsRawData, isLoadingOptions: isLoadingProductsOptions, setInputValue: setProductsInputValue, loadMore: loadMoreProducts, - } = useSelect(ProductApi.basePath, 'id', 'name', '', { + } = useSelect(MarketingApi.basePath, 'id', 'so_number', '', { limit: 'limit', }); + + const productsOptions = useMemo(() => { + if (!productsRawData || !isResponseSuccess(productsRawData)) return []; + + const productsMap = new Map(); + + productsRawData.data.forEach((deliveryOrder: BaseMarketing) => { + deliveryOrder.sales_order?.forEach((so: BaseSalesOrder) => { + const product = so.product_warehouse?.product; + if (product?.id && product?.name) { + productsMap.set(product.id, { + value: product.id, + label: product.name, + }); + } + }); + }); + + return Array.from(productsMap.values()); + }, [productsRawData]); + const { options: customersOptions, isLoadingOptions: isLoadingCustomersOptions, setInputValue: setCustomersInputValue, loadMore: loadMoreCustomers, - } = useSelect(CustomerApi.basePath, 'id', 'name', '', { + } = useSelect(MarketingApi.basePath, 'customer.id', 'customer.name', '', { limit: 'limit', }); + + const uniqueCustomersOptions = useMemo(() => { + const seen = new Set(); + return customersOptions.filter((customer) => { + if (seen.has(customer.value)) return false; + seen.add(customer.value); + return true; + }); + }, [customersOptions]); + const statusOptions = MARKETING_APPROVAL_LINE.map((item) => ({ value: item.step_name.split(' ').join('_').toUpperCase(), label: item.step_name, @@ -151,7 +184,7 @@ const MarketingFilterModal = ({ label='Customer' isClearable placeholder='Pilih customer' - options={customersOptions} + options={uniqueCustomersOptions} isLoading={isLoadingCustomersOptions} value={formik.values.customer_id} onChange={customerChangeHandler} From 5e9ce703209c97c342323fd1555ff805237fca46 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 13:21:33 +0700 Subject: [PATCH 03/19] feat(FE): Add "Ditolak" option to statusOptions in MarketingFilter --- src/components/pages/marketing/MarketingFilter.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/pages/marketing/MarketingFilter.tsx b/src/components/pages/marketing/MarketingFilter.tsx index eda3d9b2..3f56854e 100644 --- a/src/components/pages/marketing/MarketingFilter.tsx +++ b/src/components/pages/marketing/MarketingFilter.tsx @@ -79,10 +79,13 @@ const MarketingFilterModal = ({ }); }, [customersOptions]); - const statusOptions = MARKETING_APPROVAL_LINE.map((item) => ({ - value: item.step_name.split(' ').join('_').toUpperCase(), - label: item.step_name, - })); + const statusOptions = [ + ...MARKETING_APPROVAL_LINE.map((item) => ({ + value: item.step_name.split(' ').join('_').toUpperCase(), + label: item.step_name, + })), + { value: 'DITOLAK', label: 'Ditolak' }, + ]; const formik = useFormik<{ product_ids: OptionType[]; From 304be4f4325e25542c0ee2b94f163488e4a2afa0 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 13:29:38 +0700 Subject: [PATCH 04/19] feat(FE): Add support for displaying DO number in MarketingTable --- src/components/pages/marketing/MarketingTable.tsx | 9 +++++++-- src/types/api/marketing/marketing.d.ts | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/components/pages/marketing/MarketingTable.tsx b/src/components/pages/marketing/MarketingTable.tsx index 0a35a8bc..5f88c8b3 100644 --- a/src/components/pages/marketing/MarketingTable.tsx +++ b/src/components/pages/marketing/MarketingTable.tsx @@ -379,8 +379,13 @@ const MarketingTable = () => { }, }, { - accessorKey: 'so_number', + accessorKey: 'so_do_number', header: 'No. Order', + cell: (props) => { + return props.row.original.do_number + ? props.row.original.do_number + : props.row.original.so_number; + }, }, { accessorKey: 'so_date', @@ -408,7 +413,7 @@ const MarketingTable = () => { : approval?.step_number == 2 ? 'info' : approval?.step_number == 3 - ? 'warning' + ? 'success' : 'neutral' : 'neutral' } diff --git a/src/types/api/marketing/marketing.d.ts b/src/types/api/marketing/marketing.d.ts index 80a0b90b..12b0ee2c 100644 --- a/src/types/api/marketing/marketing.d.ts +++ b/src/types/api/marketing/marketing.d.ts @@ -17,6 +17,8 @@ export type BaseMarketing = { status?: string; so_number: string; so_date: string; + do_number?: string; + do_date?: string; customer: Customer; sales_person: CreatedUser; notes: string; From 08d1447d11672715665101a7513265db8380981c Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 13:41:17 +0700 Subject: [PATCH 05/19] refactor(FE): Update button label based on approval step number --- src/components/pages/marketing/MarketingTable.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/pages/marketing/MarketingTable.tsx b/src/components/pages/marketing/MarketingTable.tsx index 5f88c8b3..6368df11 100644 --- a/src/components/pages/marketing/MarketingTable.tsx +++ b/src/components/pages/marketing/MarketingTable.tsx @@ -109,7 +109,9 @@ const RowsOptionsMenu = ({ className='p-3 justify-start text-sm font-semibold w-full' > - Deliver Item + {props.row.original.latest_approval.step_number == 2 + ? 'Deliver Item' + : 'Edit Delivery'} From c9a5a91970c80404cab815013965aee18ae3bc5b Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 14:20:10 +0700 Subject: [PATCH 06/19] refactor(FE): Update order number display logic in DeliveryOrderFormModal --- src/components/pages/marketing/DeliveryOrderFormModal.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/pages/marketing/DeliveryOrderFormModal.tsx b/src/components/pages/marketing/DeliveryOrderFormModal.tsx index 7c953fe8..75f1bf1e 100644 --- a/src/components/pages/marketing/DeliveryOrderFormModal.tsx +++ b/src/components/pages/marketing/DeliveryOrderFormModal.tsx @@ -562,9 +562,11 @@ const DeliveryOrderFormModal = ({ - No. Sales Order + No. Order - {marketing.data.so_number} + {marketing.data.do_number + ? marketing.data.do_number + : marketing.data.so_number} From 4d23929924bd22beb6b64667073694f2f4f8f813 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 14:20:52 +0700 Subject: [PATCH 07/19] refactor(FE): Update approval logic and conditional rendering in delivery forms --- .../marketing/DeliveryOrderFormModal.tsx | 3 ++- .../table-view/DeliveryOrderProductTable.tsx | 26 ++++++++++++------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/components/pages/marketing/DeliveryOrderFormModal.tsx b/src/components/pages/marketing/DeliveryOrderFormModal.tsx index 75f1bf1e..a2feceac 100644 --- a/src/components/pages/marketing/DeliveryOrderFormModal.tsx +++ b/src/components/pages/marketing/DeliveryOrderFormModal.tsx @@ -430,7 +430,8 @@ const DeliveryOrderFormModal = ({ const isPending = useMemo(() => { return ( isResponseSuccess(marketing) && - marketing.data.latest_approval.step_number === 1 + marketing.data.latest_approval.step_number === 1 && + marketing.data.latest_approval.action === 'PENDING' ); }, [marketing]); diff --git a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx index 885cd8fc..93d4f658 100644 --- a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx @@ -39,6 +39,8 @@ const DeliveryOrderProductTable = ({ const onDeleteRef = useRef(onDelete); onDeleteRef.current = onDelete; + const approvalStepNumber = marketing?.latest_approval?.step_number; + return ( <>
@@ -105,16 +107,20 @@ const DeliveryOrderProductTable = ({ <> - - Tanggal Pengiriman - - {item.delivery_date ? ( - formatDate(item.delivery_date, 'DD MMM YYYY') - ) : ( - Belum diisi - )} - - + {approvalStepNumber !== 1 && ( + + + Tanggal Pengiriman + + + {item.delivery_date ? ( + formatDate(item.delivery_date, 'DD MMM YYYY') + ) : ( + Belum diisi + )} + + + )} {item.do_number && ( No. Pengiriman From 3bacc59dc610167e2601c56ce7faca1062822261 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 14:32:30 +0700 Subject: [PATCH 08/19] refactor(FE): Add condition to hide buttons when step number is 3 --- .../marketing/DeliveryOrderFormModal.tsx | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/components/pages/marketing/DeliveryOrderFormModal.tsx b/src/components/pages/marketing/DeliveryOrderFormModal.tsx index a2feceac..9027f63e 100644 --- a/src/components/pages/marketing/DeliveryOrderFormModal.tsx +++ b/src/components/pages/marketing/DeliveryOrderFormModal.tsx @@ -718,31 +718,33 @@ const DeliveryOrderFormModal = ({ />
)} - {step === 1 && ( -
- - -
- )} + {step === 1 && + marketing?.data?.latest_approval?.step_number !== 3 && ( +
+ + +
+ )} + {step === 3 && null} )} From 9ee5e95d0b0fd07a4e197df319bfd182a0deaa54 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 14:33:13 +0700 Subject: [PATCH 09/19] refactor(FE): Remove unused conditional rendering for step 3 --- src/components/pages/marketing/DeliveryOrderFormModal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/pages/marketing/DeliveryOrderFormModal.tsx b/src/components/pages/marketing/DeliveryOrderFormModal.tsx index 9027f63e..a1885709 100644 --- a/src/components/pages/marketing/DeliveryOrderFormModal.tsx +++ b/src/components/pages/marketing/DeliveryOrderFormModal.tsx @@ -744,7 +744,6 @@ const DeliveryOrderFormModal = ({ )} - {step === 3 && null} )} From 4e80c1a7037aac71d93c415764f1707f485fc683 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 6 Feb 2026 14:46:13 +0700 Subject: [PATCH 10/19] refactor(FE): Fix warehouse name display in DeliveryOrderProductTable --- .../marketing/form/table-view/DeliveryOrderProductTable.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx index 93d4f658..c77faba1 100644 --- a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx @@ -136,7 +136,9 @@ const DeliveryOrderProductTable = ({ Gudang - {item.marketing_product?.product_warehouse?.label} + {doItem?.warehouse?.name || + item.marketing_product?.product_warehouse_data + ?.warehouse?.name} From 54a6e7e2471fb64b50ca939df912d087649d12d3 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Sat, 7 Feb 2026 09:00:04 +0700 Subject: [PATCH 11/19] refactor(FE): Refactor RecordingForm to simplify egg product filtering --- .../recording/form/RecordingForm.tsx | 20 +++++-------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/components/pages/production/recording/form/RecordingForm.tsx b/src/components/pages/production/recording/form/RecordingForm.tsx index b8b6b1fc..e056663f 100644 --- a/src/components/pages/production/recording/form/RecordingForm.tsx +++ b/src/components/pages/production/recording/form/RecordingForm.tsx @@ -606,7 +606,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { isLoadingOptions: isLoadingEggProducts, loadMore: loadMoreEggProducts, } = useSelect(ProductWarehouseApi.basePath, 'id', 'product.name', 'search', { - search: 'telur', + type: 'TELUR', location_id: eggProductsLocationId, kandang_id: eggProductsKandangId, }); @@ -886,20 +886,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { if (isResponseSuccess(eggProductsData) && selectedKandang) { const data = eggProductsData.data as unknown as ProductWarehouse[]; data.forEach((product) => { - const productName = product.product.name; - - if ( - productName.toLowerCase().includes('telur') || - productName.toLowerCase().includes('egg') || - productName.toLowerCase().includes('pecah') || - productName.toLowerCase().includes('konsumsi') || - productName.toLowerCase().includes('baik') - ) { - options.push({ - value: product.id, - label: product.product.name, - }); - } + options.push({ + value: product.id, + label: product.product.name, + }); }); } From 5ac958231abcc13887f23a9dd75faa8aed37b598 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Sat, 7 Feb 2026 09:10:39 +0700 Subject: [PATCH 12/19] refactor(FE): Remove unused invoice download functionality from PurchaseTable --- .../pages/purchase/PurchaseTable.tsx | 64 +------------------ .../purchase/order/PurchaseOrderInvoice.tsx | 30 ++------- 2 files changed, 5 insertions(+), 89 deletions(-) diff --git a/src/components/pages/purchase/PurchaseTable.tsx b/src/components/pages/purchase/PurchaseTable.tsx index 2c08f726..b9ff2a56 100644 --- a/src/components/pages/purchase/PurchaseTable.tsx +++ b/src/components/pages/purchase/PurchaseTable.tsx @@ -17,7 +17,6 @@ import RowCollapseOptions from '@/components/table/RowCollapseOptions'; import RowOptionsMenuWrapper from '@/components/table/RowOptionsMenuWrapper'; import RequirePermission from '@/components/helper/RequirePermission'; import StatusBadge from '@/components/helper/StatusBadge'; -import PurchaseOrderInvoice from '@/components/pages/purchase/order/PurchaseOrderInvoice'; import { cn, formatDate } from '@/lib/helper'; import { isResponseSuccess } from '@/lib/api-helper'; @@ -159,27 +158,6 @@ const PurchaseTable = () => { PurchaseApi.getAllFetcher ); - const [isDownloadingInvoice, setIsDownloadingInvoice] = useState(false); - const [invoicePurchaseData, setInvoicePurchaseData] = - useState(null); - - const handleDownloadInvoice = async (purchaseId: number) => { - setIsDownloadingInvoice(true); - try { - const response = await PurchaseApi.getSingle(purchaseId); - if (isResponseSuccess(response) && response.data) { - setInvoicePurchaseData(response.data); - setTimeout(() => { - setInvoicePurchaseData(null); - }, 1000); - } - } catch { - toast.error('Gagal mengambil data purchase order.'); - } finally { - setIsDownloadingInvoice(false); - } - }; - // ===== TABLE COLUMNS DEFINITION ===== const purchaseColumns: ColumnDef[] = [ { @@ -190,38 +168,7 @@ const PurchaseTable = () => { }, }, { - accessorKey: 'po_expedition', - header: 'PO Ekspedisi', - cell: (props) => { - const purchase = props.row.original; - - if (!purchase.po_number || purchase.po_number === 'Belum dibuat') { - return -; - } - - return ( - - ); - }, - }, - { - accessorKey: 'supplier.name', + accessorKey: 'supplier', header: 'Vendor', cell: (props) => props.row.original.supplier.name, }, @@ -505,15 +452,6 @@ const PurchaseTable = () => { onClick: confirmationModalDeleteClickHandler, }} /> - - {invoicePurchaseData && ( -
- -
- )} ); }; diff --git a/src/components/pages/purchase/order/PurchaseOrderInvoice.tsx b/src/components/pages/purchase/order/PurchaseOrderInvoice.tsx index 4ad093e1..aed154d0 100644 --- a/src/components/pages/purchase/order/PurchaseOrderInvoice.tsx +++ b/src/components/pages/purchase/order/PurchaseOrderInvoice.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useMemo, useState, useEffect, useCallback, useRef } from 'react'; +import { useMemo, useState } from 'react'; import { Page, Text, @@ -235,16 +235,11 @@ const pdfStyles = StyleSheet.create({ interface PurchaseOrderInvoiceProps { data?: Purchase; className?: string; - triggerDownloadOnMount?: boolean; } -const PurchaseOrderInvoice = ({ - data, - triggerDownloadOnMount, -}: PurchaseOrderInvoiceProps) => { +const PurchaseOrderInvoice = ({ data }: PurchaseOrderInvoiceProps) => { const [, setIsGeneratingPDF] = useState(false); const purchaseData = data; - const hasDownloadedRef = useRef(false); const grandTotal = useMemo(() => { return ( @@ -255,7 +250,7 @@ const PurchaseOrderInvoice = ({ ); }, [purchaseData?.items]); - const handleDownloadPDF = useCallback(async () => { + const handleDownloadPDF = async () => { if (!purchaseData) { toast.error('No purchase order data available'); return; @@ -515,20 +510,7 @@ const PurchaseOrderInvoice = ({ } finally { setIsGeneratingPDF(false); } - }, [purchaseData]); - - useEffect(() => { - if (triggerDownloadOnMount && purchaseData && !hasDownloadedRef.current) { - hasDownloadedRef.current = true; - handleDownloadPDF(); - } - }, [triggerDownloadOnMount, purchaseData]); - - useEffect(() => { - if (!triggerDownloadOnMount) { - hasDownloadedRef.current = false; - } - }, [triggerDownloadOnMount]); + }; if (!purchaseData) { return ( @@ -538,10 +520,6 @@ const PurchaseOrderInvoice = ({ ); } - if (triggerDownloadOnMount) { - return null; - } - return purchaseData?.po_number && purchaseData.po_number !== 'Belum dibuat' ? ( @@ -753,8 +741,8 @@ const DeliveryOrderFormModal = ({ ref={successModal.ref} iconPosition='left' type='success' - text={`${modalAction === 'add' ? 'Data Berhasil Disimpan' : 'Data Berhasil Diubah'}`} - subtitleText={`${modalAction === 'add' ? 'Data delivery order telah berhasil disimpan.' : 'Data delivery order telah berhasil diubah.'}`} + text={`${currentModalAction === 'add' ? 'Data Berhasil Disimpan' : 'Data Berhasil Diubah'}`} + subtitleText={`${currentModalAction === 'add' ? 'Data delivery order telah berhasil disimpan.' : 'Data delivery order telah berhasil diubah.'}`} primaryButton={{ text: 'Oke', color: 'primary', @@ -764,14 +752,18 @@ const DeliveryOrderFormModal = ({ }, }} > - +
+ +
( + modalAction + ); + const isModalActionForForm = modalAction === 'add' || modalAction === 'edit' || @@ -412,6 +416,7 @@ const SalesOrderFormModal = ({ // ================== EFFECT ================== useEffect(() => { if (modalAction === 'add' || modalAction === 'edit') { + setCurrentModalAction(modalAction); formModal.openModal(); } }, [modalAction]); @@ -724,8 +729,8 @@ const SalesOrderFormModal = ({ ref={successModal.ref} iconPosition='left' type='success' - text={`${modalAction === 'add' ? 'Data Berhasil Ditambahkan' : 'Data Berhasil Diubah'}`} - subtitleText={`${modalAction === 'add' ? 'Data sales order telah berhasil disimpan.' : 'Data sales order telah berhasil diubah.'}`} + text={`${currentModalAction === 'add' ? 'Data Berhasil Ditambahkan' : 'Data Berhasil Diubah'}`} + subtitleText={`${currentModalAction === 'add' ? 'Data sales order telah berhasil disimpan.' : 'Data sales order telah berhasil diubah.'}`} primaryButton={{ text: 'Oke', color: 'primary', @@ -735,13 +740,15 @@ const SalesOrderFormModal = ({ }, }} > - +
+ +
Date: Sat, 7 Feb 2026 09:33:58 +0700 Subject: [PATCH 15/19] refactor(FE): Increase max height of order form modals to 50vh --- src/components/pages/marketing/DeliveryOrderFormModal.tsx | 2 +- src/components/pages/marketing/SalesOrderFormModal.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/marketing/DeliveryOrderFormModal.tsx b/src/components/pages/marketing/DeliveryOrderFormModal.tsx index a7f5be12..76c46ebf 100644 --- a/src/components/pages/marketing/DeliveryOrderFormModal.tsx +++ b/src/components/pages/marketing/DeliveryOrderFormModal.tsx @@ -752,7 +752,7 @@ const DeliveryOrderFormModal = ({ }, }} > -
+
-
+
Date: Sat, 7 Feb 2026 09:58:00 +0700 Subject: [PATCH 16/19] refactor(FE): Refactor tables to use Card component --- .../table-view/DeliveryOrderProductTable.tsx | 88 ++++++++++--------- .../table-view/SalesOrderProductTable.tsx | 82 ++++++++--------- 2 files changed, 88 insertions(+), 82 deletions(-) diff --git a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx index c77faba1..83ce01d3 100644 --- a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx @@ -1,5 +1,6 @@ import { DeliveryOrderProductFormValues } from '@/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.schema'; import Button from '@/components/Button'; +import Card from '@/components/Card'; import { Icon } from '@iconify/react'; import { useRef } from 'react'; import { formatCurrency, formatDate, formatNumber } from '@/lib/helper'; @@ -49,9 +50,50 @@ const DeliveryOrderProductTable = ({ (doItem) => doItem.do_number === item.do_number ); return ( -
+ + +
+ ) : undefined + } > <> @@ -199,7 +203,7 @@ const DeliveryOrderProductTable = ({
-
-
Value
- {(formType === 'add_delivery' || - formType === 'edit_delivery' || - formType === 'detail') && ( -
- - -
- )} -
+ Value
-
+ ); })}
diff --git a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx index e900974b..5cf8f9de 100644 --- a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx @@ -1,6 +1,7 @@ 'use client'; import Button from '@/components/Button'; +import Card from '@/components/Card'; import { SalesOrderProductFormValues } from '@/components/pages/marketing/form/repeater/sales-order/SalesOrderProduct.schema'; import { formatCurrency, @@ -146,9 +147,46 @@ const SalesOrderProductTable = ({ <>
{data.map((item) => ( -
+ + +
+ ) : undefined + } > <> @@ -294,7 +296,7 @@ const SalesOrderProductTable = ({
-
-
Value
- {formType !== 'success' && ( -
- - -
- )} -
+ Value
-
+ ))} {formType != 'add_deliver' && formType != 'edit_deliver' && From b85e47f60171d082b5160671219b4c0c0b7e936d Mon Sep 17 00:00:00 2001 From: rstubryan Date: Sat, 7 Feb 2026 10:00:02 +0700 Subject: [PATCH 17/19] refactor(FE): Add top border to table rows in product tables --- .../marketing/form/table-view/DeliveryOrderProductTable.tsx | 2 +- .../pages/marketing/form/table-view/SalesOrderProductTable.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx index 83ce01d3..80cd42fe 100644 --- a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx @@ -102,7 +102,7 @@ const DeliveryOrderProductTable = ({ className='border-none w-full' > - + Label diff --git a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx index 5cf8f9de..502e6c37 100644 --- a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx @@ -195,7 +195,7 @@ const SalesOrderProductTable = ({ className='border-none w-full' > - + Label From a8dce9da46509e2e24aa74b8aaecddffa3c69082 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Sat, 7 Feb 2026 10:04:15 +0700 Subject: [PATCH 18/19] refactor(FE): Refactor table actions to be part of the "Value" column --- .../table-view/DeliveryOrderProductTable.tsx | 70 +++++++++++-------- .../table-view/SalesOrderProductTable.tsx | 66 +++++++++-------- 2 files changed, 76 insertions(+), 60 deletions(-) diff --git a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx index 80cd42fe..af53685c 100644 --- a/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/DeliveryOrderProductTable.tsx @@ -64,36 +64,6 @@ const DeliveryOrderProductTable = ({ title: 'px-2 py-1.5 font-normal text-sm', collapsible: 'rounded-lg', }} - actions={ - formType === 'add_delivery' || - formType === 'edit_delivery' || - formType === 'detail' ? ( -
- - -
- ) : undefined - } > <> diff --git a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx index 502e6c37..a13a1117 100644 --- a/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx +++ b/src/components/pages/marketing/form/table-view/SalesOrderProductTable.tsx @@ -159,34 +159,6 @@ const SalesOrderProductTable = ({ title: 'px-2 py-1.5 font-normal text-sm', collapsible: 'rounded-lg', }} - actions={ - formType !== 'success' ? ( -
- - -
- ) : undefined - } >
- Value +
+
Value
+ {(formType === 'add_delivery' || + formType === 'edit_delivery' || + formType === 'detail') && ( +
+ + +
+ )} +
<> From 60ace68daea62d5f2b573e2e77c9741954f18b2c Mon Sep 17 00:00:00 2001 From: rstubryan Date: Mon, 9 Feb 2026 08:59:51 +0700 Subject: [PATCH 19/19] refactor(FE): Remove FCR-related fields and functionality --- .../project-flock/ProjectFlockTable.tsx | 4 - .../form/ProjectFlockForm.schema.ts | 14 -- .../project-flock/form/ProjectFlockForm.tsx | 35 ---- .../recording/form/RecordingForm.tsx | 166 +----------------- src/types/api/production/project-flock.d.ts | 4 - 5 files changed, 1 insertion(+), 222 deletions(-) diff --git a/src/components/pages/production/project-flock/ProjectFlockTable.tsx b/src/components/pages/production/project-flock/ProjectFlockTable.tsx index cad76310..7c4973eb 100644 --- a/src/components/pages/production/project-flock/ProjectFlockTable.tsx +++ b/src/components/pages/production/project-flock/ProjectFlockTable.tsx @@ -363,10 +363,6 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { accessorKey: 'location.name', header: 'Lokasi', }, - { - accessorKey: 'fcr.name', - header: 'FCR', - }, { accessorKey: 'category', header: 'Kategori', diff --git a/src/components/pages/production/project-flock/form/ProjectFlockForm.schema.ts b/src/components/pages/production/project-flock/form/ProjectFlockForm.schema.ts index dc972b14..eb6f236c 100644 --- a/src/components/pages/production/project-flock/form/ProjectFlockForm.schema.ts +++ b/src/components/pages/production/project-flock/form/ProjectFlockForm.schema.ts @@ -16,11 +16,6 @@ type ProjectFlockFormSchemaType = { label: string; } | null; category: string; - fcr: { - value: number | string; - label: string; - } | null; - fcr_id: number; production_standard: { value: number | string; label: string; @@ -96,15 +91,6 @@ export const ProjectFlockFormSchema: Yup.ObjectSchema, - fcr_id: initialValues?.fcr?.id ?? 0, production_standard_id: initialValues?.production_standard?.id ?? 0, location_id: initialValues?.location?.id ?? 0, kandang_ids: initialValues?.kandangs?.map( @@ -574,7 +559,6 @@ const ProjectFlockForm = ({ flock_name: values.flock_name as string, area_id: values.area_id as number, category: values.category as string, - fcr_id: values.fcr_id as number, production_standard_id: values.production_standard_id as number, location_id: values.location_id as number, kandang_ids: values.kandang_ids as number[], @@ -996,25 +980,6 @@ const ProjectFlockForm = ({ isClearable isDisabled={formType != 'add'} /> - { - optionChangeHandler(val, 'fcr'); - }} - onInputChange={setInputValueFcr} - onMenuScrollToBottom={loadMoreFcr} - options={optionsFcr} - isLoading={isLoadingFcrs} - isError={ - formik.touched.fcr_id && Boolean(formik.errors.fcr_id) - } - errorMessage={formik.errors.fcr_id as string} - isClearable - isDisabled={formType != 'add'} - /> [] = [ - { - accessorKey: 'weight', - header: 'Weight', - cell: (props) => formatNumber(props.getValue() as number), - }, - { - accessorKey: 'fcr_number', - header: 'FCR Number', - cell: (props) => formatNumber(props.getValue() as number), - }, - { - accessorKey: 'mortality', - header: 'Mortality', - cell: (props) => formatNumber(props.getValue() as number), - }, -]; - const productionStandardColumns: ColumnDef[] = [ { accessorKey: 'week', @@ -253,36 +234,14 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { const approveModal = useModal(); const rejectModal = useModal(); const deleteModal = useModal(); - const fcrStandardModal = useModal(); const productionStandardModal = useModal(); - const [fcrStandards, setFcrStandards] = useState([]); const [productionStandards, setProductionStandards] = useState(null); - const [isFcrModalOpen, setIsFcrModalOpen] = useState(false); const [isProductionStandardModalOpen, setIsProductionStandardModalOpen] = useState(false); - useEffect(() => { - const checkFcrModalOpen = () => { - const isOpen = fcrStandardModal.ref.current?.open || false; - setIsFcrModalOpen(isOpen); - }; - - checkFcrModalOpen(); - - const observer = new MutationObserver(checkFcrModalOpen); - if (fcrStandardModal.ref.current) { - observer.observe(fcrStandardModal.ref.current, { - attributes: true, - attributeFilter: ['open'], - }); - } - - return () => observer.disconnect(); - }, [fcrStandardModal.ref]); - useEffect(() => { const checkProductionStandardModalOpen = () => { const isOpen = productionStandardModal.ref.current?.open || false; @@ -460,24 +419,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ? projectFlockKandangLookupData.data : undefined; - const fcrId = useMemo(() => { - if (type === 'add') { - return projectFlockKandangLookup?.project_flock?.fcr?.id; - } - return initialValues?.project_flock?.fcr?.id; - }, [type, projectFlockKandangLookup, initialValues]); - - const { data: fcr, isLoading: isLoadingFcrStandards } = useSWR( - isFcrModalOpen && fcrId ? `fcr-detail-${fcrId}` : null, - () => FcrApi.getSingle(fcrId!) - ); - - useEffect(() => { - if (fcr?.status === 'success') { - setFcrStandards((fcr.data as FcrWithStandards).fcr_standards || []); - } - }, [fcr]); - const productionStandardId = useMemo(() => { if (type === 'add') { return projectFlockKandangLookup?.project_flock?.production_standard_id; @@ -1942,24 +1883,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { : '-'}

-
- Standard FCR -
- fcrStandardModal.openModal()} - > - {projectFlockKandangLookup?.project_flock?.fcr?.name || - initialValues?.project_flock?.fcr?.name || - '-'} - -
-
Standard Produksi @@ -2150,22 +2073,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
)} -
- Standard FCR -
- fcrStandardModal.openModal()} - > - {initialValues.project_flock?.fcr?.name || '-'} - -
-
Standard Produksi @@ -2217,21 +2124,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
- - - - -
- Value +
+
Value
+ {formType !== 'success' && ( +
+ + +
+ )} +
FCR (g) - - {initialValues.fcr_value != null - ? `${formatNumber(initialValues.fcr_value)} g` - : '-'} - - - {initialValues.project_flock?.fcr?.fcr_std != null - ? `${formatNumber(initialValues.project_flock?.fcr?.fcr_std)} g` - : '-'} -
Feed Intake (g) @@ -3273,62 +3165,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { )} - {/* FCR Standard Modal */} - -
- {/* Modal Header */} -
-
- -

Detail Standard FCR

-
- -
-
- {isLoadingFcrStandards ? ( -
- -
- ) : fcrStandards.length > 0 ? ( - - data={fcrStandards} - columns={fcrStandardColumns} - pageSize={100} - className={{ - tableWrapperClassName: 'overflow-x-auto', - tableClassName: 'w-full table-auto text-sm', - headerRowClassName: 'border-b border-b-gray-200', - headerColumnClassName: - 'px-4 py-3 text-xs font-semibold text-gray-500 whitespace-nowrap border-l border-l-gray-200 border-r border-r-gray-200 border-t border-t-gray-200 border-gray-200 border-b-0', - bodyRowClassName: - 'hover:bg-gray-50 transition-colors border-b border-gray-200 first:border-t first:border-t-gray-200 border-l border-l-gray-200 border-r border-r-gray-200', - bodyColumnClassName: - 'px-4 py-3 text-xs text-gray-900 whitespace-nowrap', - paginationClassName: 'hidden', - }} - /> - ) : ( -

- Tidak ada data FCR standards -

- )} -
-
-
- {/* Production Standard Modal */}