From fb29cea8d28eafe235dd1fa29f0ad5310fee1e60 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 21 Oct 2025 09:54:28 +0700 Subject: [PATCH] refactor(FE-114): enhance body weight calculations in RecordingForm with auto-update for average weight --- .../flock/recording/form/RecordingForm.tsx | 169 ++++++++++++++---- 1 file changed, 130 insertions(+), 39 deletions(-) diff --git a/src/components/pages/flock/recording/form/RecordingForm.tsx b/src/components/pages/flock/recording/form/RecordingForm.tsx index 40247d3a..7f013538 100644 --- a/src/components/pages/flock/recording/form/RecordingForm.tsx +++ b/src/components/pages/flock/recording/form/RecordingForm.tsx @@ -1,6 +1,7 @@ 'use client'; import { useCallback, useEffect, useMemo, useState } from 'react'; +import { ChangeEvent } from 'react'; import { useFormik } from 'formik'; import { Icon } from '@iconify/react'; import Button from '@/components/Button'; @@ -77,22 +78,46 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { : '', feed_data: (values.feed_data ?? []).map((p) => ({ feed_id: p.feed_id, - feed_qty: typeof p.feed_qty === 'number' ? p.feed_qty : parseFloat(String(p.feed_qty)) || 0, - feed_stock: typeof p.feed_stock === 'number' ? p.feed_stock : parseFloat(String(p.feed_stock)) || 0, + feed_qty: + typeof p.feed_qty === 'number' + ? p.feed_qty + : parseFloat(String(p.feed_qty)) || 0, + feed_stock: + typeof p.feed_stock === 'number' + ? p.feed_stock + : parseFloat(String(p.feed_stock)) || 0, })), body_weight: (values.body_weight ?? []).map((b) => ({ - chicken_weight: typeof b.chicken_weight === 'number' ? b.chicken_weight : parseFloat(String(b.chicken_weight)) || 0, - chicken_count: typeof b.chicken_count === 'number' ? b.chicken_count : parseFloat(String(b.chicken_count)) || 0, - average_chicken_weight: typeof b.average_chicken_weight === 'number' ? b.average_chicken_weight : parseFloat(String(b.average_chicken_weight)) || 0, + chicken_weight: + typeof b.chicken_weight === 'number' + ? b.chicken_weight + : parseFloat(String(b.chicken_weight)) || 0, + chicken_count: + typeof b.chicken_count === 'number' + ? b.chicken_count + : parseFloat(String(b.chicken_count)) || 0, + average_chicken_weight: + typeof b.average_chicken_weight === 'number' + ? b.average_chicken_weight + : parseFloat(String(b.average_chicken_weight)) || 0, })), vaccination: (values.vaccination ?? []).map((v) => ({ vaccine_id: v.vaccine_id, - total_stock: typeof v.total_stock === 'number' ? v.total_stock : parseFloat(String(v.total_stock)) || 0, - used_stock: typeof v.used_stock === 'number' ? v.used_stock : parseFloat(String(v.used_stock)) || 0, + total_stock: + typeof v.total_stock === 'number' + ? v.total_stock + : parseFloat(String(v.total_stock)) || 0, + used_stock: + typeof v.used_stock === 'number' + ? v.used_stock + : parseFloat(String(v.used_stock)) || 0, })), mortality: (values.mortality ?? []).map((m) => ({ condition: m.condition, - count: typeof m.count === 'number' ? m.count : parseFloat(String(m.count)) || 0, + count: + typeof m.count === 'number' + ? m.count + : parseFloat(String(m.count)) || 0, })), }; @@ -283,6 +308,33 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { } }, [initialValues, projectFlocks]); + // Auto-calculate average weight when chicken weight or count changes + useEffect(() => { + if (formik.values.body_weight) { + const updatedBodyWeight = formik.values.body_weight.map((weight) => ({ + ...weight, + average_chicken_weight: + weight.chicken_count > 0 + ? Math.round(weight.chicken_weight / weight.chicken_count) + : 0, + })); + + // Only update if values are different to avoid infinite loops + const hasChanges = updatedBodyWeight.some( + (updated, idx) => + updated.average_chicken_weight !== + formik.values.body_weight[idx]?.average_chicken_weight + ); + + if (hasChanges) { + formik.setFieldValue('body_weight', updatedBodyWeight); + } + } + }, [ + formik.values.body_weight?.map((w) => w.chicken_weight), + formik.values.body_weight?.map((w) => w.chicken_count), + ]); + // EVENT HANDLERS - Select Inputs const locationChangeHandler = (val: OptionType | OptionType[] | null) => { const locationValue = (val as OptionType)?.value; @@ -363,6 +415,28 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { formik.setFieldValue('body_weight', newBodyWeight); }; + const handleBodyWeightChange = + (fieldName: string, idx: number) => + (e: React.ChangeEvent) => { + formik.handleChange(e); + setTimeout(() => { + const currentWeight = formik.values.body_weight?.[idx]; + if (currentWeight) { + const newAverage = + currentWeight.chicken_count > 0 + ? Math.round( + currentWeight.chicken_weight / currentWeight.chicken_count + ) + : 0; + + formik.setFieldValue( + `body_weight.${idx}.average_chicken_weight`, + newAverage + ); + } + }, 0); + }; + const removeBodyWeight = (idx: number) => { const updatedBodyWeight = formik.values.body_weight?.filter( (_, i) => i !== idx @@ -865,7 +939,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { required name={`body_weight.${idx}.chicken_weight`} value={weight.chicken_weight} - onChange={formik.handleChange} + onChange={handleBodyWeightChange( + 'chicken_weight', + idx + )} onBlur={formik.handleBlur} maskType='weight' weightUnit='gram' @@ -896,7 +973,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { required name={`body_weight.${idx}.chicken_count`} value={weight.chicken_count} - onChange={formik.handleChange} + onChange={handleBodyWeightChange( + 'chicken_count', + idx + )} onBlur={formik.handleBlur} maskType='number' decimals={0} @@ -922,35 +1002,46 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { /> - +
+ 0 + ? Math.round( + weight.chicken_weight / + weight.chicken_count + ) + : 0 + } + onChange={formik.handleChange} + onBlur={formik.handleBlur} + maskType='weight' + weightUnit='gram' + decimals={0} + min={0} + isError={ + isRepeaterInputError( + 'body_weight', + 'average_chicken_weight', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'body_weight', + 'average_chicken_weight', + idx + ).errorMessage + } + readOnly={true} + disabled={true} + className={{ + wrapper: 'w-full min-w-24', + }} + placeholder='0' + /> +
{type !== 'detail' && (