diff --git a/src/components/pages/production/recording/form/RecordingForm.schema.ts b/src/components/pages/production/recording/form/RecordingForm.schema.ts index beffa26a..b1113ae2 100644 --- a/src/components/pages/production/recording/form/RecordingForm.schema.ts +++ b/src/components/pages/production/recording/form/RecordingForm.schema.ts @@ -39,6 +39,11 @@ export const RecordingFormSchema = Yup.object({ .min(1, 'Jumlah ayam minimal 1 ekor!') .typeError('Jumlah ayam harus berupa angka!') .default(1), + average_weight: Yup.number() + .optional() + .min(0, 'Rata-rata berat tidak boleh negatif!') + .typeError('Rata-rata berat harus berupa angka!') + .default(0), notes: Yup.string().optional(), }) ) @@ -123,12 +128,14 @@ export const getRecordingFormInitialValues = ( (bw: NonNullable[0]) => ({ weight: bw.weight, qty: bw.qty, + average_weight: bw.qty > 0 ? Math.round(bw.weight / bw.qty) : 0, notes: bw.notes || '', }) ) ?? [ { weight: 0, qty: 1, + average_weight: 0, notes: '', }, ], diff --git a/src/components/pages/production/recording/form/RecordingForm.tsx b/src/components/pages/production/recording/form/RecordingForm.tsx index 944b979a..f387d45e 100644 --- a/src/components/pages/production/recording/form/RecordingForm.tsx +++ b/src/components/pages/production/recording/form/RecordingForm.tsx @@ -7,6 +7,7 @@ import { Icon } from '@iconify/react'; import Button from '@/components/Button'; import TextInput from '@/components/input/TextInput'; +import NumberInput from '@/components/input/NumberInput'; import SelectInput, { OptionType } from '@/components/input/SelectInput'; import CheckboxInput from '@/components/input/CheckboxInput'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; @@ -135,6 +136,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ? bw.qty : parseFloat(String(bw.qty)) || 0, notes: bw.notes, + // average_weight is not included in payload as it's calculated field only })), stocks: (values.stocks ?? []).map((stock) => ({ product_warehouse_id: stock.product_warehouse_id, @@ -229,6 +231,33 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { } }, [formik.values.record_datetime]); + // Auto-calculate average weight when weight or qty changes + useEffect(() => { + if (formik.values.body_weights) { + const updatedBodyWeights = formik.values.body_weights.map((weight) => ({ + ...weight, + average_weight: + weight.qty > 0 && weight.weight > 0 + ? Math.round(weight.weight / weight.qty) + : 0, + })); + + // Only update if values are different to avoid infinite loops + const hasChanges = updatedBodyWeights.some( + (updated, idx) => + updated.average_weight !== + (formik.values.body_weights[idx]?.average_weight || 0) + ); + + if (hasChanges) { + formik.setFieldValue('body_weights', updatedBodyWeights, false); + } + } + }, [ + formik.values.body_weights?.map((w) => w.weight), + formik.values.body_weights?.map((w) => w.qty), + ]); + // EVENT HANDLERS - Body Weights const addBodyWeight = () => { const newBodyWeights = [ @@ -237,11 +266,76 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { weight: 0, qty: 1, notes: '', + average_weight: 0, }, ]; formik.setFieldValue('body_weights', newBodyWeights); }; + // Handle calculation when weight changes + const handleWeightChange = (idx: number, value: number) => { + formik.setFieldValue(`body_weights.${idx}.weight`, value); + + const currentWeight = formik.values.body_weights?.[idx]; + if (currentWeight) { + const qty = currentWeight.qty; + if (qty > 0 && value > 0) { + const averageWeight = Math.round(value / qty); + formik.setFieldValue(`body_weights.${idx}.average_weight`, averageWeight); + } else { + formik.setFieldValue(`body_weights.${idx}.average_weight`, 0); + } + } + }; + + // Handle calculation when qty changes + const handleQtyChange = (idx: number, value: number) => { + formik.setFieldValue(`body_weights.${idx}.qty`, value); + + const currentWeight = formik.values.body_weights?.[idx]; + if (currentWeight) { + const weight = currentWeight.weight; + if (value > 0 && weight > 0) { + const averageWeight = Math.round(weight / value); + formik.setFieldValue(`body_weights.${idx}.average_weight`, averageWeight); + } else { + formik.setFieldValue(`body_weights.${idx}.average_weight`, 0); + } + } + }; + + // Handle calculation when average_weight changes + const handleAverageWeightChange = (idx: number, value: number) => { + formik.setFieldValue(`body_weights.${idx}.average_weight`, value); + + const currentWeight = formik.values.body_weights?.[idx]; + if (currentWeight) { + const qty = currentWeight.qty; + if (qty > 0 && value > 0) { + const totalWeight = value * qty; + formik.setFieldValue(`body_weights.${idx}.weight`, totalWeight); + } else { + formik.setFieldValue(`body_weights.${idx}.weight`, 0); + } + } + }; + + // Create wrapper handlers that match NumberInput's onChange signature + const handleWeightChangeWrapper = (idx: number) => (e: React.ChangeEvent) => { + const value = parseFloat(e.target.value.replace(/[^\d,.-]/g, '').replace(/,/g, '')) || 0; + handleWeightChange(idx, value); + }; + + const handleQtyChangeWrapper = (idx: number) => (e: React.ChangeEvent) => { + const value = parseFloat(e.target.value.replace(/[^\d,.-]/g, '').replace(/,/g, '')) || 0; + handleQtyChange(idx, value); + }; + + const handleAverageWeightChangeWrapper = (idx: number) => (e: React.ChangeEvent) => { + const value = parseFloat(e.target.value.replace(/[^\d,.-]/g, '').replace(/,/g, '')) || 0; + handleAverageWeightChange(idx, value); + }; + const removeBodyWeight = (idx: number) => { const updatedBodyWeights = formik.values.body_weights?.filter( (_, i) => i !== idx @@ -353,6 +447,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { }; }; + return ( <>
@@ -514,6 +609,15 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { * + + Rata-rata Berat Ayam (gram) + + + + Catatan {type !== 'detail' && Action} @@ -546,17 +650,18 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { )} - { className={{ wrapper: 'w-full min-w-32', }} - placeholder='Berat ayam (gram)' /> - { className={{ wrapper: 'w-full min-w-24', }} - placeholder='Jumlah ayam' + /> + + +