From e4f554bcd4d6c712d5f935b37f18610034aa2031 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Sat, 18 Oct 2025 12:25:04 +0700 Subject: [PATCH] refactor(FE-114,136): update RecordingForm validation and input handling for feed and vaccination data --- .../recording/form/RecordingForm.schema.ts | 52 ++++----- .../flock/recording/form/RecordingForm.tsx | 102 +++++++++--------- 2 files changed, 80 insertions(+), 74 deletions(-) diff --git a/src/components/pages/flock/recording/form/RecordingForm.schema.ts b/src/components/pages/flock/recording/form/RecordingForm.schema.ts index ed5507eb..16f7e690 100644 --- a/src/components/pages/flock/recording/form/RecordingForm.schema.ts +++ b/src/components/pages/flock/recording/form/RecordingForm.schema.ts @@ -49,20 +49,19 @@ export const RecordingFormSchema = Yup.object({ .of( Yup.object({ feed_id: Yup.string().required('Nama pakan wajib diisi!'), - feed_qty: Yup.number() - .required('Qty pakan wajib diisi!') - .min(1, 'Qty minimal 1!') - .typeError('Qty pakan wajib diisi!'), + feed_qty: Yup.mixed().notRequired(), feed_stock: Yup.number() - .required('Stock pakan wajib diisi!') - .min(1, 'Stock minimal 1!') - .typeError('Stock pakan wajib diisi!') + .required('Jumlah pakan yang digunakan wajib diisi!') + .min(1, 'Jumlah pakan minimal 1 kg!') + .typeError('Jumlah pakan yang digunakan harus berupa angka!') .test( 'is-not-exceed-qty', - 'Feed stock tidak boleh melebihi feed qty yang tersedia!', + 'Jumlah pakan yang digunakan tidak boleh melebihi stok tersedia!', function (value) { const { feed_qty } = this.parent; - return value === undefined || value <= feed_qty; + if (value === undefined) return true; + if (feed_qty === undefined || feed_qty === '' || typeof feed_qty !== 'number') return true; + return value <= feed_qty; } ), }) @@ -74,13 +73,16 @@ export const RecordingFormSchema = Yup.object({ Yup.object({ chicken_weight: Yup.number() .required('Berat ayam wajib diisi!') - .min(1, 'Berat minimal 1!'), + .min(1, 'Berat ayam minimal 1 gram!') + .typeError('Berat ayam harus berupa angka!'), chicken_count: Yup.number() .required('Jumlah ayam wajib diisi!') - .min(1, 'Jumlah minimal 1!'), + .min(1, 'Jumlah ayam minimal 1 ekor!') + .typeError('Jumlah ayam harus berupa angka!'), average_chicken_weight: Yup.number() .required('Rata-rata berat ayam wajib diisi!') - .min(1, 'Rata-rata minimal 1!'), + .min(1, 'Rata-rata berat ayam minimal 1 gram!') + .typeError('Rata-rata berat ayam harus berupa angka!'), }) ) .min(1, 'Minimal harus ada 1 data bobot badan!') @@ -89,20 +91,19 @@ export const RecordingFormSchema = Yup.object({ .of( Yup.object({ vaccine_id: Yup.string().required('Nama vaksin wajib diisi!'), - total_stock: Yup.number() - .required('Total stock wajib diisi!') - .min(1, 'Total stock minimal 1!') - .typeError('Total stock wajib diisi!'), + total_stock: Yup.mixed().notRequired(), used_stock: Yup.number() - .required('Jumlah stock wajib diisi!') - .min(1, 'Jumlah stock minimal 1!') - .typeError('Jumlah stock wajib diisi!') + .required('Jumlah vaksin yang digunakan wajib diisi!') + .min(1, 'Jumlah vaksin minimal 1!') + .typeError('Jumlah vaksin yang digunakan harus berupa angka!') .test( 'is-not-exceed-total', - 'Used stock tidak boleh melebihi total stock yang tersedia!', + 'Jumlah vaksin yang digunakan tidak boleh melebihi stok tersedia!', function (value) { const { total_stock } = this.parent; - return value === undefined || value <= total_stock; + if (value === undefined) return true; + if (total_stock === undefined || total_stock === '' || typeof total_stock !== 'number') return true; + return value <= total_stock; } ), }) @@ -119,8 +120,9 @@ export const RecordingFormSchema = Yup.object({ ) .required('Kondisi wajib diisi!'), count: Yup.number() - .required('Jumlah wajib diisi!') - .min(1, 'Jumlah minimal 1!'), + .required('Jumlah mortalitas wajib diisi!') + .min(1, 'Jumlah mortalitas minimal 1 ekor!') + .typeError('Jumlah mortalitas harus berupa angka!'), }) ) .min(1, 'Minimal harus ada 1 data mortalitas!') @@ -167,7 +169,7 @@ export const getRecordingFormInitialValues = ( : [ { feed_id: '', - feed_qty: 0, + feed_qty: '', feed_stock: 0, }, ], @@ -187,7 +189,7 @@ export const getRecordingFormInitialValues = ( : [ { vaccine_id: '', - total_stock: 0, + total_stock: '', used_stock: 0, }, ], diff --git a/src/components/pages/flock/recording/form/RecordingForm.tsx b/src/components/pages/flock/recording/form/RecordingForm.tsx index 773baab6..95600120 100644 --- a/src/components/pages/flock/recording/form/RecordingForm.tsx +++ b/src/components/pages/flock/recording/form/RecordingForm.tsx @@ -74,7 +74,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { : '', feed_data: (values.feed_data ?? []).map((p) => ({ feed_id: p.feed_id, - feed_qty: p.feed_qty, + feed_qty: typeof p.feed_qty === 'number' ? p.feed_qty : 0, feed_stock: p.feed_stock, })), body_weight: (values.body_weight ?? []).map((b) => ({ @@ -84,7 +84,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { })), vaccination: (values.vaccination ?? []).map((v) => ({ vaccine_id: v.vaccine_id, - total_stock: v.total_stock, + total_stock: typeof v.total_stock === 'number' ? v.total_stock : 0, used_stock: v.used_stock, })), mortality: (values.mortality ?? []).map((m) => ({ @@ -132,8 +132,9 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { // Create stock mapping for pakan (Feed) const pakanStockMap = useMemo(() => { - if (!isResponseSuccess(pakanProducts)) return new Map(); - const map = new Map(); + if (!isResponseSuccess(pakanProducts)) + return new Map(); + const map = new Map(); pakanProducts.data.forEach((product) => { map.set(product.id, product.quantity); }); @@ -155,8 +156,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { // Create stock mapping for OVK (Vaccination) const ovkStockMap = useMemo(() => { - if (!isResponseSuccess(ovkProducts)) return new Map(); - const map = new Map(); + if (!isResponseSuccess(ovkProducts)) return new Map(); + const map = new Map(); ovkProducts.data.forEach((product) => { map.set(product.id, product.quantity); }); @@ -256,8 +257,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ...(formik.values.feed_data || []), { feed: null, - feed_id: 0, - feed_qty: 0, + feed_id: '', + feed_qty: '', feed_stock: 0, }, ]; @@ -311,8 +312,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ...(formik.values.vaccination || []), { vaccine: null, - vaccine_id: 0, - total_stock: 0, + vaccine_id: '', + total_stock: '', used_stock: 0, }, ]; @@ -532,10 +533,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { onChange={(val) => { const productWarehouseId = (val as OptionType)?.value ?? 0; - const stock = - pakanStockMap.get( - productWarehouseId as number - ) ?? 0; + const stock = productWarehouseId + ? (pakanStockMap.get( + productWarehouseId as number + ) ?? '') + : ''; formik.setFieldValue( `feed_data.${idx}.feed`, @@ -543,12 +545,17 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ); formik.setFieldValue( `feed_data.${idx}.feed_id`, - productWarehouseId + productWarehouseId || '' ); formik.setFieldValue( `feed_data.${idx}.feed_qty`, stock ); + // Reset feed_stock when changing feed + formik.setFieldValue( + `feed_data.${idx}.feed_stock`, + 0 + ); }} options={pakanOptions} isLoading={false} @@ -569,21 +576,18 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { { onChange={(val) => { const productWarehouseId = (val as OptionType)?.value ?? 0; - const stock = - ovkStockMap.get(productWarehouseId as number) ?? - 0; + const stock = productWarehouseId + ? (ovkStockMap.get( + productWarehouseId as number + ) ?? '') + : ''; formik.setFieldValue( `vaccination.${idx}.vaccine`, @@ -956,12 +962,17 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ); formik.setFieldValue( `vaccination.${idx}.vaccine_id`, - productWarehouseId + productWarehouseId || '' ); formik.setFieldValue( `vaccination.${idx}.total_stock`, stock ); + // Reset used_stock when changing vaccine + formik.setFieldValue( + `vaccination.${idx}.used_stock`, + 0 + ); }} options={ovkOptions} isLoading={false} @@ -988,27 +999,18 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { { /> -