From ea7f8a68f439245372135f196036c5005ab7004a Mon Sep 17 00:00:00 2001 From: randy-ar Date: Mon, 29 Dec 2025 13:19:16 +0700 Subject: [PATCH 1/6] fix(FE): change select option warehouse marketing to correct data warehouses --- .../FormFinanceAddInitialBalance.schema.ts | 13 ------------- .../repeater/delivery-order/DeliverOrderProduct.tsx | 13 ------------- .../repeater/sales-order/SalesOrderProductForm.tsx | 4 ++-- 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/src/components/pages/finance/add/initial-balance/FormFinanceAddInitialBalance.schema.ts b/src/components/pages/finance/add/initial-balance/FormFinanceAddInitialBalance.schema.ts index c700f973..776028c6 100644 --- a/src/components/pages/finance/add/initial-balance/FormFinanceAddInitialBalance.schema.ts +++ b/src/components/pages/finance/add/initial-balance/FormFinanceAddInitialBalance.schema.ts @@ -1,19 +1,6 @@ import * as Yup from 'yup'; import { OptionType } from '@/components/input/SelectInput'; -/** - * API Payload format for Initial Balance: - * { - "party_type": "CUSTOMER", - "party_id": 1, - "bank_id": 1, - "reference_number": "IB.MBU.001", - "initial_balance_type": "DEBIT", - "nominal": 5000000, - "note": "Saldo awal piutang customer" - } - */ - // Type for form values (includes option objects for SelectInput) export type InitialBalanceFormValues = { party_type_option: OptionType | null; 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 f169eb3c..a0eed811 100644 --- a/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx +++ b/src/components/pages/marketing/form/repeater/delivery-order/DeliverOrderProduct.tsx @@ -174,19 +174,6 @@ const DeliveryOrderProductForm = ({ }} onReset={handleResetForm} > - {/* - {JSON.stringify(exisitingValues)} - - - {JSON.stringify(formik.values)} - */} - {/* - {JSON.stringify(formik.errors)} - -
- {JSON.stringify(formik.values.marketing_product)} -
*/} - {formikErrorMessage && (
setFormErrorMessage('')} className='my-3 w-full'> {formikErrorMessage} 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 ad50a927..75aa3ba6 100644 --- a/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx +++ b/src/components/pages/marketing/form/repeater/sales-order/SalesOrderProductForm.tsx @@ -11,7 +11,7 @@ import SelectInput, { useSelect, } from '@/components/input/SelectInput'; import { Kandang } from '@/types/api/master-data/kandang'; -import { KandangApi } from '@/services/api/master-data'; +import { KandangApi, WarehouseApi } from '@/services/api/master-data'; import { ProductWarehouse } from '@/types/api/inventory/product-warehouse'; import { ProductWarehouseApi } from '@/services/api/inventory'; import NumberInput from '@/components/input/NumberInput'; @@ -61,7 +61,7 @@ const SalesOrderProductForm = ({ const { options: kandangSourceOptions, isLoadingOptions: isLoadingKandangSourceOptions, - } = useSelect(KandangApi.basePath, 'id', 'name'); + } = useSelect(WarehouseApi.basePath, 'id', 'name'); const { options: warehouseSourceOptions, From cd42bd6bc08bf3c891c644bf358499160159af5d Mon Sep 17 00:00:00 2001 From: randy-ar Date: Mon, 29 Dec 2025 13:26:39 +0700 Subject: [PATCH 2/6] fix(FE): change hatchery to optional in master data supplier --- .../pages/master-data/nonstock/form/NonstockForm.tsx | 8 ++++---- .../master-data/supplier/form/SupplierForm.schema.ts | 2 +- .../pages/master-data/supplier/form/SupplierForm.tsx | 9 ++++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/components/pages/master-data/nonstock/form/NonstockForm.tsx b/src/components/pages/master-data/nonstock/form/NonstockForm.tsx index 47875902..af72f22f 100644 --- a/src/components/pages/master-data/nonstock/form/NonstockForm.tsx +++ b/src/components/pages/master-data/nonstock/form/NonstockForm.tsx @@ -79,14 +79,14 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { uomId: initialValues?.uom_id ?? 0, uom: initialValues?.uom ? { - value: initialValues?.uom.id, - label: initialValues?.uom.name, + value: initialValues?.uom?.id, + label: initialValues?.uom?.name, } : null, supplierIds: - initialValues?.suppliers.map((supplier) => supplier.id) ?? [], + initialValues?.suppliers?.map((supplier) => supplier.id) ?? [], suppliers: - initialValues?.suppliers.map((supplier) => ({ + initialValues?.suppliers?.map((supplier) => ({ value: supplier.id, label: supplier.name, })) ?? [], diff --git a/src/components/pages/master-data/supplier/form/SupplierForm.schema.ts b/src/components/pages/master-data/supplier/form/SupplierForm.schema.ts index 12c70b1c..9ec3890a 100644 --- a/src/components/pages/master-data/supplier/form/SupplierForm.schema.ts +++ b/src/components/pages/master-data/supplier/form/SupplierForm.schema.ts @@ -18,7 +18,7 @@ export const SupplierFormSchema = Yup.object({ value: Yup.string().required(), label: Yup.string().required(), }).required('Tipe wajib diisi!'), - hatchery: Yup.string().required('Hatchery wajib diisi!'), + hatchery: Yup.string().optional(), phone: Yup.string() .matches(/^[0-9]+$/, 'Nomor telepon hanya boleh berisi angka!') .min(10, 'Nomor telepon minimal 10 digit!') diff --git a/src/components/pages/master-data/supplier/form/SupplierForm.tsx b/src/components/pages/master-data/supplier/form/SupplierForm.tsx index d410ac11..2cacea89 100644 --- a/src/components/pages/master-data/supplier/form/SupplierForm.tsx +++ b/src/components/pages/master-data/supplier/form/SupplierForm.tsx @@ -142,7 +142,7 @@ const SupplierForm = ({ pic: values.pic, type: values.type.value, category: values.category.value, - hatchery: values.hatchery, + hatchery: values.hatchery ?? '', phone: values.phone, email: values.email, address: values.address, @@ -171,12 +171,12 @@ const SupplierForm = ({ useEffect(() => { formikSetValues(formikInitialValues); if (formType != 'add') { - const hatcheryArrays = formikInitialValues.hatchery.split(','); - const hatcheryCreatedOptions = hatcheryArrays.map((item) => ({ + const hatcheryArrays = formikInitialValues.hatchery?.split(','); + const hatcheryCreatedOptions = hatcheryArrays?.map((item) => ({ value: item, label: item, })); - setHatcheryOptionValues(hatcheryCreatedOptions); + setHatcheryOptionValues(hatcheryCreatedOptions ?? []); } }, [formikSetValues, formikInitialValues, setHatcheryOptionValues]); useEffect(() => { @@ -302,7 +302,6 @@ const SupplierForm = ({ Date: Mon, 29 Dec 2025 13:50:23 +0700 Subject: [PATCH 3/6] feat(FE): adding production standard select options for project flock --- .../project-flock/ProjectFlockTable.tsx | 4 +-- .../form/ProjectFlockForm.schema.ts | 14 +++++++++ .../project-flock/form/ProjectFlockForm.tsx | 31 +++++++++++++++++++ src/types/api/production/project-flock.d.ts | 3 ++ 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/components/pages/production/project-flock/ProjectFlockTable.tsx b/src/components/pages/production/project-flock/ProjectFlockTable.tsx index 233c43d7..025e7186 100644 --- a/src/components/pages/production/project-flock/ProjectFlockTable.tsx +++ b/src/components/pages/production/project-flock/ProjectFlockTable.tsx @@ -618,7 +618,7 @@ const ProjectFlockTable = ({ refresh }: { refresh?: () => void }) => { void }) => { , 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( (k: Kandang) => k.id @@ -400,6 +413,7 @@ const ProjectFlockForm = ({ 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[], project_budgets: values.project_budgets.flatMap((budget) => { @@ -858,6 +872,23 @@ const ProjectFlockForm = ({ isClearable isDisabled={formType != 'add'} /> + { + optionChangeHandler(val, 'production_standard'); + }} + options={optionsProductionStandards} + isLoading={isLoadingProductionStandards} + isError={ + formik.touched.production_standard && + Boolean(formik.errors.production_standard) + } + errorMessage={formik.errors.production_standard as string} + isClearable + isDisabled={formType != 'add'} + /> Date: Mon, 29 Dec 2025 15:01:42 +0700 Subject: [PATCH 4/6] fix(FE): fix delete and update button row in master data production standards --- .../form/ProductionStandardForm.schema.ts | 4 +- .../form/ProductionStandardForm.tsx | 91 +++++++++++-------- 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts index 6fc3799b..55e68039 100644 --- a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts +++ b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.schema.ts @@ -68,7 +68,9 @@ export const createProductionStandardRepeaterFormSchema = ( export const createProductionStandardFormSchema = (category: string) => { return Yup.object({ name: Yup.string().required('Nama wajib diisi!'), - project_category: Yup.string().required('Kategori proyek wajib diisi!'), + project_category: Yup.string() + .min(1, 'Kategori proyek wajib diisi!') + .required('Kategori proyek wajib diisi!'), details: Yup.array().of( createProductionStandardRepeaterFormSchema(category) ), diff --git a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx index 99edb852..fe424838 100644 --- a/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx +++ b/src/components/pages/master-data/production-standard/form/ProductionStandardForm.tsx @@ -29,6 +29,7 @@ import toast from 'react-hot-toast'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import { useModal } from '@/components/Modal'; import RequirePermission from '@/components/helper/RequirePermission'; +import Tooltip from '@/components/Tooltip'; type TableRowsType = { customRow: boolean; @@ -175,13 +176,15 @@ const ProductionStandardForm = ({ } = useFormStore(); // ===== Formik ===== + // Initial values - only recalculate when initialValue changes (for edit/detail mode) + // For add mode, we load from cache via useEffect instead to avoid race conditions const formikInitialValues = useMemo(() => { - // For add mode, merge cached data with initial values - if (formType === 'add' && formData) { + if (formType === 'add') { + // Don't use formData here - will be loaded via useEffect return { - name: formData.name || '', - project_category: formData.project_category || '', - details: formData.details || [], + name: '', + project_category: '', + details: [], } as ProductionStandardFormValues; } @@ -190,10 +193,11 @@ const ProductionStandardForm = ({ project_category: initialValue?.project_category || '', details: convertStandardValueToFormValues(initialValue?.details || []), } as ProductionStandardFormValues; - }, [initialValue, formData, formType]); + }, [initialValue, formType]); const formik = useFormik({ initialValues: formikInitialValues as ProductionStandardFormValues, - enableReinitialize: true, + // Only enable reinitialize for edit/detail mode, not add mode + enableReinitialize: formType !== 'add', onSubmit: (values) => { switch (formType) { case 'add': @@ -255,36 +259,38 @@ const ProductionStandardForm = ({ const { setValues: repeaterFormikSetValues } = repeaterFormik; // ===== Effect ===== - // Load initial values only when component mounts or when initialValue changes (for edit mode) - // This allows: - // 1. Add mode: Load cached data from formData store - // 2. Edit mode: Load existing data from initialValue - // We use initialValue?.id as dependency to avoid infinite loops + // Load cached data only once on mount for add mode + const [isInitialized, setIsInitialized] = useState(false); + useEffect(() => { - if (formType === 'add' && formData) { - // For add mode, load from cache + if (formType === 'add' && formData && !isInitialized) { + // For add mode, load from cache only on initial mount formikSetValues({ name: formData.name || '', project_category: formData.project_category || '', details: formData.details || [], } as ProductionStandardFormValues); - } else if (formType === 'detail' && initialValue) { - // For detail mode, load from initialValue and convert the details + setIsInitialized(true); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); // Only run once on mount + + // For edit/detail mode, update when initialValue changes + useEffect(() => { + if (formType === 'detail' && initialValue) { formikSetValues({ name: initialValue.name || '', project_category: initialValue.project_category || '', details: convertStandardValueToFormValues(initialValue.details || []), } as ProductionStandardFormValues); } else if (formType === 'edit' && initialValue) { - // For edit mode, load from initialValue and convert the details formikSetValues({ name: initialValue.name || '', project_category: initialValue.project_category || '', details: convertStandardValueToFormValues(initialValue.details || []), } as ProductionStandardFormValues); } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [formData, initialValue?.id]); // Trigger when formData or initialValue.id changes + }, [initialValue?.id, formType]); // ===== Data Table ===== const tableRows = useMemo(() => { @@ -323,11 +329,6 @@ const ProductionStandardForm = ({ }, [formik.values.details]); const columns = useMemo[]>(() => { const baseColumns: ColumnDef[] = [ - { - header: 'No', - accessorFn: (row, index) => index + 1, - enableSorting: false, - }, { header: 'Minggu', accessorKey: 'week', @@ -407,6 +408,7 @@ const ProductionStandardForm = ({ variant='outline' color='warning' className='p-2' + type='button' onClick={() => handleEditClick(row.row.original.week)} > @@ -415,6 +417,7 @@ const ProductionStandardForm = ({ variant='outline' color='error' className='p-2' + type='button' onClick={() => handleRemoveRow(row.row.original.week)} > @@ -430,7 +433,7 @@ const ProductionStandardForm = ({ ...uniformityColumns, ...(formType !== 'detail' ? [actionColumn] : []), ]; - }, [formik.values.project_category, formType]); + }, [formik.values, formType]); // ===== Handler ===== const handleAddRow = async ( @@ -488,9 +491,11 @@ const ProductionStandardForm = ({ setIsAddingRow(false); }; - const handleRemoveRow = (week: number) => { - const newValues = (formik.values.details || []).filter( - (detail) => detail.week !== week + const handleRemoveRow = async (week: number) => { + // Access formik.values directly to get the latest values + const currentDetails = formik.values.details || []; + const newValues = currentDetails.filter( + (detail) => Number(detail.week) !== Number(week) ); const updatedFormValues = { @@ -745,6 +750,7 @@ const ProductionStandardForm = ({ } required isDisabled={formType === 'detail'} + isClearable />
@@ -1105,16 +1111,27 @@ const ProductionStandardForm = ({ Batal )} - + + {/* Should not be absolute */}