refactor(FE-114,136): improve form validation handling and set touched state asynchronously

This commit is contained in:
rstubryan
2025-10-22 10:54:20 +07:00
parent b35d513e44
commit 9c114628c7
@@ -512,44 +512,43 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
}; };
// HELPER FUNCTIONS // HELPER FUNCTIONS
const isRepeaterInputError = <T extends keyof CreateRecordingPayload>( const isRepeaterInputError = <
T extends 'feed_data' | 'body_weight' | 'vaccination' | 'mortality',
>(
arrayName: T, arrayName: T,
field: T extends 'feed_data' column: T extends 'feed_data'
? keyof CreateRecordingPayload['feed_data'][0] ? keyof RecordingFormValues['feed_data'][0]
: T extends 'body_weight' : T extends 'body_weight'
? keyof CreateRecordingPayload['body_weight'][0] ? keyof RecordingFormValues['body_weight'][0]
: T extends 'vaccination' : T extends 'vaccination'
? keyof CreateRecordingPayload['vaccination'][0] ? keyof RecordingFormValues['vaccination'][0]
: T extends 'mortality' : T extends 'mortality'
? keyof CreateRecordingPayload['mortality'][0] ? keyof RecordingFormValues['mortality'][0]
: never, : never,
idx: number idx: number
) => { ) => {
const touched = formik.touched[arrayName] as if (
| { !formik.touched[arrayName] ||
[key: string]: boolean | undefined; !Array.isArray(formik.touched[arrayName])
}[] ) {
| undefined;
const errors = formik.errors[arrayName] as
| {
[key: string]: string | undefined;
}[]
| undefined;
if (!touched || !Array.isArray(touched)) {
return { return {
isError: false, isError: false,
errorMessage: undefined, errorMessage: '',
}; };
} }
const touchedField = touched[idx]?.[field as string]; const touchedField = formik.touched[arrayName]?.[idx]?.[column as string];
const errorField = errors?.[idx]?.[field as string]; const errorField = formik.errors[arrayName]?.[idx] as Record<
string,
string
>;
return { return {
isError: touchedField && Boolean(errorField), isError: touchedField && Boolean(errorField?.[column as string]),
errorMessage: touchedField ? errorField : undefined, errorMessage:
touchedField && errorField?.[column as string]
? errorField[column as string]
: '',
}; };
}; };
@@ -576,9 +575,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
label='Lokasi' label='Lokasi'
value={formik.values.location ?? undefined} value={formik.values.location ?? undefined}
onChange={(val) => { onChange={(val) => {
formik.setFieldTouched('location', true);
formik.setFieldTouched('location_id', true);
locationChangeHandler(val); locationChangeHandler(val);
setTimeout(() => {
formik.setFieldTouched('location', true);
formik.setFieldTouched('location_id', true);
}, 0);
}} }}
options={locationOptions} options={locationOptions}
onInputChange={setLocationSelectInputValue} onInputChange={setLocationSelectInputValue}
@@ -625,9 +626,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
label='Flock' label='Flock'
value={formik.values.flock ?? undefined} value={formik.values.flock ?? undefined}
onChange={(val) => { onChange={(val) => {
formik.setFieldTouched('flock', true);
formik.setFieldTouched('flock_id', true);
flockChangeHandler(val); flockChangeHandler(val);
setTimeout(() => {
formik.setFieldTouched('flock', true);
formik.setFieldTouched('flock_id', true);
}, 0);
}} }}
options={flockOptions} options={flockOptions}
onInputChange={setFlockSelectInputValue} onInputChange={setFlockSelectInputValue}
@@ -651,9 +654,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
label='Kandang' label='Kandang'
value={formik.values.coop ?? undefined} value={formik.values.coop ?? undefined}
onChange={(val) => { onChange={(val) => {
formik.setFieldTouched('coop', true);
formik.setFieldTouched('coop_id', true);
coopChangeHandler(val); coopChangeHandler(val);
setTimeout(() => {
formik.setFieldTouched('coop', true);
formik.setFieldTouched('coop_id', true);
}, 0);
}} }}
options={coopOptions} options={coopOptions}
isError={ isError={
@@ -756,14 +761,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
) ?? '') ) ?? '')
: ''; : '';
formik.setFieldTouched(
`feed_data.${idx}.feed`,
true
);
formik.setFieldTouched(
`feed_data.${idx}.feed_id`,
true
);
formik.setFieldValue( formik.setFieldValue(
`feed_data.${idx}.feed`, `feed_data.${idx}.feed`,
val val
@@ -780,6 +777,16 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
`feed_data.${idx}.feed_stock`, `feed_data.${idx}.feed_stock`,
0 0
); );
setTimeout(() => {
formik.setFieldTouched(
`feed_data.${idx}.feed`,
true
);
formik.setFieldTouched(
`feed_data.${idx}.feed_id`,
true
);
}, 0);
}} }}
options={pakanOptions} options={pakanOptions}
isLoading={isLoadingPakan} isLoading={isLoadingPakan}
@@ -1220,14 +1227,6 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
productWarehouseId as number productWarehouseId as number
) ?? '') ) ?? '')
: ''; : '';
formik.setFieldTouched(
`vaccination.${idx}.vaccine`,
true
);
formik.setFieldTouched(
`vaccination.${idx}.vaccine_id`,
true
);
formik.setFieldValue( formik.setFieldValue(
`vaccination.${idx}.vaccine`, `vaccination.${idx}.vaccine`,
val val
@@ -1244,6 +1243,17 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
`vaccination.${idx}.used_stock`, `vaccination.${idx}.used_stock`,
0 0
); );
// Set touched after setting values to trigger validation
setTimeout(() => {
formik.setFieldTouched(
`vaccination.${idx}.vaccine`,
true
);
formik.setFieldTouched(
`vaccination.${idx}.vaccine_id`,
true
);
}, 0);
}} }}
options={ovkOptions} options={ovkOptions}
isLoading={isLoadingOvk} isLoading={isLoadingOvk}