mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-24 07:15:44 +00:00
refactor(FE-114): enhance body weight calculations in RecordingForm with auto-update for average weight
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { ChangeEvent } from 'react';
|
||||||
import { useFormik } from 'formik';
|
import { useFormik } from 'formik';
|
||||||
import { Icon } from '@iconify/react';
|
import { Icon } from '@iconify/react';
|
||||||
import Button from '@/components/Button';
|
import Button from '@/components/Button';
|
||||||
@@ -77,22 +78,46 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
: '',
|
: '',
|
||||||
feed_data: (values.feed_data ?? []).map((p) => ({
|
feed_data: (values.feed_data ?? []).map((p) => ({
|
||||||
feed_id: p.feed_id,
|
feed_id: p.feed_id,
|
||||||
feed_qty: typeof p.feed_qty === 'number' ? p.feed_qty : parseFloat(String(p.feed_qty)) || 0,
|
feed_qty:
|
||||||
feed_stock: typeof p.feed_stock === 'number' ? p.feed_stock : parseFloat(String(p.feed_stock)) || 0,
|
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) => ({
|
body_weight: (values.body_weight ?? []).map((b) => ({
|
||||||
chicken_weight: typeof b.chicken_weight === 'number' ? b.chicken_weight : parseFloat(String(b.chicken_weight)) || 0,
|
chicken_weight:
|
||||||
chicken_count: typeof b.chicken_count === 'number' ? b.chicken_count : parseFloat(String(b.chicken_count)) || 0,
|
typeof b.chicken_weight === 'number'
|
||||||
average_chicken_weight: typeof b.average_chicken_weight === 'number' ? b.average_chicken_weight : parseFloat(String(b.average_chicken_weight)) || 0,
|
? 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) => ({
|
vaccination: (values.vaccination ?? []).map((v) => ({
|
||||||
vaccine_id: v.vaccine_id,
|
vaccine_id: v.vaccine_id,
|
||||||
total_stock: typeof v.total_stock === 'number' ? v.total_stock : parseFloat(String(v.total_stock)) || 0,
|
total_stock:
|
||||||
used_stock: typeof v.used_stock === 'number' ? v.used_stock : parseFloat(String(v.used_stock)) || 0,
|
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) => ({
|
mortality: (values.mortality ?? []).map((m) => ({
|
||||||
condition: m.condition,
|
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]);
|
}, [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
|
// EVENT HANDLERS - Select Inputs
|
||||||
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
const locationValue = (val as OptionType)?.value;
|
const locationValue = (val as OptionType)?.value;
|
||||||
@@ -363,6 +415,28 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
formik.setFieldValue('body_weight', newBodyWeight);
|
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 removeBodyWeight = (idx: number) => {
|
||||||
const updatedBodyWeight = formik.values.body_weight?.filter(
|
const updatedBodyWeight = formik.values.body_weight?.filter(
|
||||||
(_, i) => i !== idx
|
(_, i) => i !== idx
|
||||||
@@ -865,7 +939,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
required
|
required
|
||||||
name={`body_weight.${idx}.chicken_weight`}
|
name={`body_weight.${idx}.chicken_weight`}
|
||||||
value={weight.chicken_weight}
|
value={weight.chicken_weight}
|
||||||
onChange={formik.handleChange}
|
onChange={handleBodyWeightChange(
|
||||||
|
'chicken_weight',
|
||||||
|
idx
|
||||||
|
)}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
maskType='weight'
|
maskType='weight'
|
||||||
weightUnit='gram'
|
weightUnit='gram'
|
||||||
@@ -896,7 +973,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
required
|
required
|
||||||
name={`body_weight.${idx}.chicken_count`}
|
name={`body_weight.${idx}.chicken_count`}
|
||||||
value={weight.chicken_count}
|
value={weight.chicken_count}
|
||||||
onChange={formik.handleChange}
|
onChange={handleBodyWeightChange(
|
||||||
|
'chicken_count',
|
||||||
|
idx
|
||||||
|
)}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
maskType='number'
|
maskType='number'
|
||||||
decimals={0}
|
decimals={0}
|
||||||
@@ -922,35 +1002,46 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
|||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<NumberInput
|
<div className='relative'>
|
||||||
required
|
<NumberInput
|
||||||
name={`body_weight.${idx}.average_chicken_weight`}
|
required
|
||||||
value={weight.average_chicken_weight}
|
name={`body_weight.${idx}.average_chicken_weight`}
|
||||||
onChange={formik.handleChange}
|
value={
|
||||||
onBlur={formik.handleBlur}
|
weight.chicken_count > 0
|
||||||
maskType='weight'
|
? Math.round(
|
||||||
weightUnit='gram'
|
weight.chicken_weight /
|
||||||
decimals={0}
|
weight.chicken_count
|
||||||
min={0}
|
)
|
||||||
isError={
|
: 0
|
||||||
isRepeaterInputError(
|
}
|
||||||
'body_weight',
|
onChange={formik.handleChange}
|
||||||
'average_chicken_weight',
|
onBlur={formik.handleBlur}
|
||||||
idx
|
maskType='weight'
|
||||||
).isError
|
weightUnit='gram'
|
||||||
}
|
decimals={0}
|
||||||
errorMessage={
|
min={0}
|
||||||
isRepeaterInputError(
|
isError={
|
||||||
'body_weight',
|
isRepeaterInputError(
|
||||||
'average_chicken_weight',
|
'body_weight',
|
||||||
idx
|
'average_chicken_weight',
|
||||||
).errorMessage
|
idx
|
||||||
}
|
).isError
|
||||||
readOnly={type === 'detail'}
|
}
|
||||||
className={{
|
errorMessage={
|
||||||
wrapper: 'w-full min-w-24',
|
isRepeaterInputError(
|
||||||
}}
|
'body_weight',
|
||||||
/>
|
'average_chicken_weight',
|
||||||
|
idx
|
||||||
|
).errorMessage
|
||||||
|
}
|
||||||
|
readOnly={true}
|
||||||
|
disabled={true}
|
||||||
|
className={{
|
||||||
|
wrapper: 'w-full min-w-24',
|
||||||
|
}}
|
||||||
|
placeholder='0'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
{type !== 'detail' && (
|
{type !== 'detail' && (
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
Reference in New Issue
Block a user