refactor(FE-114): enhance form UI by adding required field indicators for multiple inputs

This commit is contained in:
rstubryan
2025-10-22 13:55:12 +07:00
parent 9c114628c7
commit c249585bc2
2 changed files with 254 additions and 55 deletions
@@ -864,8 +864,24 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
</div>
</th>
)}
<th>Produk</th>
<th>Qty</th>
<th>
Produk
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Qty
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
{type !== 'detail' && <th>Aksi</th>}
</tr>
</thead>
@@ -1032,7 +1048,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
{/* Deliveries table */}
<div className='card bg-base-100 shadow mb-4'>
<div className='card-body'>
<h2 className='card-title mb-4'>Pengiriman</h2>
<h2 className='card-title mb-8'>Pengiriman</h2>
<div className='overflow-x-auto'>
<table className='table'>
<thead>
@@ -1064,14 +1080,70 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
</div>
</th>
)}
<th>Produk</th>
<th>Qty</th>
<th>Supplier</th>
<th>Plat Nomor</th>
<th>
Produk
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Qty
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Supplier
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Plat Nomor
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>Dokumen</th>
<th>Biaya Pengiriman (Rp.)</th>
<th>Biaya Per Item (Rp.)</th>
<th>Nama Sopir</th>
<th>
Biaya Pengiriman (Rp.)
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Biaya Per Item (Rp.)
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Nama Sopir
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
{type !== 'detail' && <th>Aksi</th>}
</tr>
</thead>
@@ -418,27 +418,96 @@ 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;
// Handle calculation when chicken_weight changes
const handleChickenWeightChange = useCallback(
(idx: number, value: number) => {
formik.setFieldValue(`body_weight.${idx}.chicken_weight`, value);
const currentWeight = formik.values.body_weight?.[idx];
if (currentWeight) {
const chickenCount = currentWeight.chicken_count;
if (chickenCount > 0 && value > 0) {
const averageWeight = Math.round(value / chickenCount);
formik.setFieldValue(
`body_weight.${idx}.average_chicken_weight`,
newAverage
averageWeight
);
} else {
formik.setFieldValue(`body_weight.${idx}.average_chicken_weight`, '');
}
}, 0);
};
}
},
[formik]
);
// Handle calculation when chicken_count changes
const handleChickenCountChange = useCallback(
(idx: number, value: number) => {
formik.setFieldValue(`body_weight.${idx}.chicken_count`, value);
const currentWeight = formik.values.body_weight?.[idx];
if (currentWeight) {
const chickenWeight = currentWeight.chicken_weight;
if (chickenWeight > 0 && value > 0) {
const averageWeight = Math.round(chickenWeight / value);
formik.setFieldValue(
`body_weight.${idx}.average_chicken_weight`,
averageWeight
);
} else {
formik.setFieldValue(`body_weight.${idx}.average_chicken_weight`, '');
}
}
},
[formik]
);
// Handle calculation when average_weight changes
const handleAverageWeightChange = useCallback(
(idx: number, value: number) => {
formik.setFieldValue(`body_weight.${idx}.average_chicken_weight`, value);
const currentWeight = formik.values.body_weight?.[idx];
if (currentWeight) {
const chickenCount = currentWeight.chicken_count;
if (chickenCount > 0 && value > 0) {
const totalWeight = value * chickenCount;
formik.setFieldValue(
`body_weight.${idx}.chicken_weight`,
totalWeight
);
} else if (value === 0) {
formik.setFieldValue(`body_weight.${idx}.chicken_weight`, '');
}
}
},
[formik]
);
// Create wrapper handlers that match NumberInput's onChange signature
const handleChickenWeightChangeWrapper = useCallback(
(idx: number) => (e: React.ChangeEvent<HTMLInputElement>) => {
const value = parseFloat(e.target.value) || 0;
handleChickenWeightChange(idx, value);
},
[handleChickenWeightChange]
);
const handleChickenCountChangeWrapper = useCallback(
(idx: number) => (e: React.ChangeEvent<HTMLInputElement>) => {
const value = parseFloat(e.target.value) || 0;
handleChickenCountChange(idx, value);
},
[handleChickenCountChange]
);
const handleAverageWeightChangeWrapper = useCallback(
(idx: number) => (e: React.ChangeEvent<HTMLInputElement>) => {
const value = parseFloat(e.target.value) || 0;
handleAverageWeightChange(idx, value);
},
[handleAverageWeightChange]
);
const removeBodyWeight = (idx: number) => {
const updatedBodyWeight = formik.values.body_weight?.filter(
@@ -712,9 +781,25 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
</div>
</th>
)}
<th>Nama Pakan</th>
<th>
Nama Pakan
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>Total Stock pada saat ini</th>
<th>Jumlah Stock yang digunakan</th>
<th>
Jumlah Stock yang digunakan
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
{type !== 'detail' && <th>Action</th>}
</tr>
</thead>
@@ -945,9 +1030,33 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
</div>
</th>
)}
<th>Berat (Gram)</th>
<th>Jumlah Ayam</th>
<th>Rata-rata berat Ayam</th>
<th>
Berat (Gram)
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Jumlah Ayam
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Rata-rata berat Ayam
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
{type !== 'detail' && <th>Action</th>}
</tr>
</thead>
@@ -981,10 +1090,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
required
name={`body_weight.${idx}.chicken_weight`}
value={weight.chicken_weight}
onChange={handleBodyWeightChange(
'chicken_weight',
idx
)}
onChange={handleChickenWeightChangeWrapper(idx)}
onBlur={formik.handleBlur}
maskType='weight'
weightUnit='gram'
@@ -1015,10 +1121,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
required
name={`body_weight.${idx}.chicken_count`}
value={weight.chicken_count}
onChange={handleBodyWeightChange(
'chicken_count',
idx
)}
onChange={handleChickenCountChangeWrapper(idx)}
onBlur={formik.handleBlur}
maskType='number'
decimals={0}
@@ -1048,15 +1151,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
<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}
value={weight.average_chicken_weight || ''}
onChange={handleAverageWeightChangeWrapper(idx)}
onBlur={formik.handleBlur}
maskType='weight'
weightUnit='gram'
@@ -1076,12 +1172,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
idx
).errorMessage
}
readOnly={true}
disabled={true}
readOnly={type === 'detail'}
className={{
wrapper: 'w-full min-w-24',
}}
placeholder='0'
placeholder=''
/>
</div>
</td>
@@ -1175,9 +1270,25 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
</div>
</th>
)}
<th>Name Vaksin</th>
<th>
Name Vaksin
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>Total Stock pada saat ini</th>
<th>Jumlah Stock yang digunakan</th>
<th>
Jumlah Stock yang digunakan
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
{type !== 'detail' && <th>Action</th>}
</tr>
</thead>
@@ -1418,8 +1529,24 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
</div>
</th>
)}
<th>Kondisi/Alasan Mortalitas</th>
<th>Jumlah</th>
<th>
Kondisi/Alasan Mortalitas
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
<th>
Jumlah
<span
className='tooltip tooltip-error tooltip-bottom z-[9999]'
data-tip='required'
>
<span className='text-error'>*</span>
</span>
</th>
{type !== 'detail' && <th>Action</th>}
</tr>
</thead>