From 2ee88a274249f47cf0edd34f1a99645ab3930dd0 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Wed, 15 Oct 2025 13:45:48 +0700 Subject: [PATCH] refactor(FE-114): enhance tanggal_recording handling and improve error messaging in RecordingForm --- .../flock/recording/form/RecordingForm.tsx | 247 +++++++++++++----- 1 file changed, 179 insertions(+), 68 deletions(-) diff --git a/src/components/pages/flock/recording/form/RecordingForm.tsx b/src/components/pages/flock/recording/form/RecordingForm.tsx index c0efe1fa..f53123f1 100644 --- a/src/components/pages/flock/recording/form/RecordingForm.tsx +++ b/src/components/pages/flock/recording/form/RecordingForm.tsx @@ -67,7 +67,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { setRecordingFormErrorMessage(''); const payload: CreateRecordingPayload = { flock_id: values.flock_id, - tanggal_recording: values.tanggal_recording.toISOString(), + tanggal_recording: + values.tanggal_recording instanceof Date + ? values.tanggal_recording.toISOString() + : new Date().toISOString(), data_pakan: (values.data_pakan ?? []).map((p) => ({ nama_pakan: p.nama_pakan, qty_pakan: p.qty_pakan, @@ -126,16 +129,31 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { idx: number ) => { const touched = formik.touched[arrayName] as - | Record[] - | undefined; - const errors = formik.errors[arrayName] as - | Record[] + | { + [key: string]: boolean | undefined; + }[] | undefined; - return ( - touched?.[idx]?.[field as string] && - Boolean(errors?.[idx]?.[field as string]) - ); + const errors = formik.errors[arrayName] as + | { + [key: string]: string | undefined; + }[] + | undefined; + + if (!touched || !Array.isArray(touched)) { + return { + isError: false, + errorMessage: undefined, + }; + } + + const touchedField = touched[idx]?.[field as string]; + const errorField = errors?.[idx]?.[field as string]; + + return { + isError: touchedField && Boolean(errorField), + errorMessage: touchedField ? errorField : undefined, + }; }; const addDataPakan = () => { @@ -312,11 +330,17 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { label='Tanggal Recording' type='date' name='tanggal_recording' - value={formik.values.tanggal_recording - .toISOString() - .substring(0, 10)} + value={ + formik.values.tanggal_recording instanceof Date + ? formik.values.tanggal_recording + .toISOString() + .substring(0, 10) + : '' + } onChange={(e) => { - const date = new Date(e.target.value); + const date = e.target.value + ? new Date(e.target.value) + : new Date(); formik.setFieldValue('tanggal_recording', date); }} onBlur={formik.handleBlur} @@ -397,11 +421,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={pakan.nama_pakan} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'data_pakan', - 'nama_pakan', - idx - )} + isError={ + isRepeaterInputError( + 'data_pakan', + 'nama_pakan', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'data_pakan', + 'nama_pakan', + idx + ).errorMessage + } readOnly={type === 'detail'} className={{ wrapper: 'w-full min-w-24', @@ -416,11 +449,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={pakan.qty_pakan} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'data_pakan', - 'qty_pakan', - idx - )} + isError={ + isRepeaterInputError( + 'data_pakan', + 'qty_pakan', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'data_pakan', + 'qty_pakan', + idx + ).errorMessage + } readOnly={type === 'detail'} className={{ wrapper: 'w-full min-w-24', @@ -435,11 +477,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={pakan.stock_pakan} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'data_pakan', - 'stock_pakan', - idx - )} + isError={ + isRepeaterInputError( + 'data_pakan', + 'stock_pakan', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'data_pakan', + 'stock_pakan', + idx + ).errorMessage + } readOnly={type === 'detail'} className={{ wrapper: 'w-full min-w-24', @@ -565,11 +616,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={bobot.berat_ayam} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'bobot_badan', - 'berat_ayam', - idx - )} + isError={ + isRepeaterInputError( + 'bobot_badan', + 'berat_ayam', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'bobot_badan', + 'berat_ayam', + idx + ).errorMessage + } readOnly={type === 'detail'} /> @@ -581,11 +641,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={bobot.jumlah_ayam} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'bobot_badan', - 'jumlah_ayam', - idx - )} + isError={ + isRepeaterInputError( + 'bobot_badan', + 'jumlah_ayam', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'bobot_badan', + 'jumlah_ayam', + idx + ).errorMessage + } readOnly={type === 'detail'} /> @@ -597,11 +666,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={bobot.rata_rata_berat_ayam} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'bobot_badan', - 'rata_rata_berat_ayam', - idx - )} + isError={ + isRepeaterInputError( + 'bobot_badan', + 'rata_rata_berat_ayam', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'bobot_badan', + 'rata_rata_berat_ayam', + idx + ).errorMessage + } readOnly={type === 'detail'} /> @@ -723,11 +801,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={vaksin.nama_vaksin} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'vaksinasi', - 'nama_vaksin', - idx - )} + isError={ + isRepeaterInputError( + 'vaksinasi', + 'nama_vaksin', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'vaksinasi', + 'nama_vaksin', + idx + ).errorMessage + } readOnly={type === 'detail'} className={{ wrapper: 'w-full min-w-24', @@ -742,11 +829,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={vaksin.total_stock} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'vaksinasi', - 'total_stock', - idx - )} + isError={ + isRepeaterInputError( + 'vaksinasi', + 'total_stock', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'vaksinasi', + 'total_stock', + idx + ).errorMessage + } readOnly={type === 'detail'} className={{ wrapper: 'w-full min-w-24', @@ -761,11 +857,20 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={vaksin.jumlah_stock} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'vaksinasi', - 'jumlah_stock', - idx - )} + isError={ + isRepeaterInputError( + 'vaksinasi', + 'jumlah_stock', + idx + ).isError + } + errorMessage={ + isRepeaterInputError( + 'vaksinasi', + 'jumlah_stock', + idx + ).errorMessage + } readOnly={type === 'detail'} className={{ wrapper: 'w-full min-w-24', @@ -894,11 +999,14 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { (val as OptionType)?.value ); }} - isError={isRepeaterInputError( - 'mortalitas', - 'kondisi', - idx - )} + isError={ + isRepeaterInputError('mortalitas', 'kondisi', idx) + .isError + } + errorMessage={ + isRepeaterInputError('mortalitas', 'kondisi', idx) + .errorMessage + } options={RECORDING_FLAG_OPTIONS} isDisabled={type === 'detail'} /> @@ -911,11 +1019,14 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { value={mortal.jumlah} onChange={formik.handleChange} onBlur={formik.handleBlur} - isError={isRepeaterInputError( - 'mortalitas', - 'jumlah', - idx - )} + isError={ + isRepeaterInputError('mortalitas', 'jumlah', idx) + .isError + } + errorMessage={ + isRepeaterInputError('mortalitas', 'jumlah', idx) + .errorMessage + } readOnly={type === 'detail'} className={{ wrapper: 'w-full min-w-24',