refactor(FE-114): enhance body weight calculations in RecordingForm with auto-update for average weight

This commit is contained in:
rstubryan
2025-10-21 09:54:28 +07:00
parent 1ecdff855e
commit 645668e1f9
@@ -77,22 +77,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 +307,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 +414,28 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
formik.setFieldValue('body_weight', newBodyWeight);
};
const handleBodyWeightChange =
(fieldName: string, idx: number) =>
(e: React.ChangeEvent<HTMLInputElement>) => {
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 +938,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 +972,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 +1001,46 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
/>
</td>
<td>
<NumberInput
required
name={`body_weight.${idx}.average_chicken_weight`}
value={weight.average_chicken_weight}
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={type === 'detail'}
className={{
wrapper: 'w-full min-w-24',
}}
/>
<div className='relative'>
<NumberInput
required
name={`body_weight.${idx}.average_chicken_weight`}
value={
weight.chicken_count > 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'
/>
</div>
</td>
{type !== 'detail' && (
<td>