diff --git a/src/components/pages/production/uniformity/UniformityTable.tsx b/src/components/pages/production/uniformity/UniformityTable.tsx index fafa3d77..5b6bf892 100644 --- a/src/components/pages/production/uniformity/UniformityTable.tsx +++ b/src/components/pages/production/uniformity/UniformityTable.tsx @@ -51,6 +51,13 @@ import { generateUniformityExcel } from '@/components/pages/production/uniformit import Dropdown from '@/components/Dropdown'; import Menu from '@/components/menu/Menu'; import MenuItem from '@/components/menu/MenuItem'; +import { useFormik } from 'formik'; +import { + UniformityTableFilterSchema, + type UniformityTableFilterValues, +} from '@/components/pages/production/uniformity/UniformityTableFilter.schema'; +import AlertErrorList from '@/components/helper/form/FormErrors'; +import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; const UniformityConfirmationPreview = ({ uniformity, @@ -314,6 +321,37 @@ const UniformityTable = () => { } }, [projectFlockKandangLookup]); + // ===== FORMIK FILTER ===== + const filterFormik = useFormik({ + initialValues: { + start_date: filterStartDate, + end_date: filterEndDate, + location: filterLocation, + location_id: Number(filterLocation?.value) || 0, + project_flock: filterProjectFlock, + project_flock_id: Number(filterProjectFlock?.value) || 0, + project_flock_kandang_id: filterProjectFlockKandangId, + kandang: filterKandang, + kandang_id: Number(filterKandang?.value) || 0, + }, + validationSchema: UniformityTableFilterSchema, + enableReinitialize: true, + onSubmit: async (values) => { + setFilterStartDate(values.start_date); + setFilterEndDate(values.end_date); + setFilterLocation(values.location ?? null); + setFilterProjectFlock(values.project_flock ?? null); + setFilterKandang(values.kandang ?? null); + + setIsSubmitted(true); + filterModal.closeModal(); + }, + }); + + // ===== FORMIK ERROR LIST ===== + const { formErrorList, close, handleFormSubmit } = + useFormikErrorList(filterFormik); + // ===== BUILD SWR KEY WITH FILTERS ===== const uniformitySwrKey = useMemo(() => { const basePath = UniformityApi.basePath; @@ -370,29 +408,54 @@ const UniformityTable = () => { const handleFilterLocationChange = useCallback( (val: OptionType | OptionType[] | null) => { const location = val as OptionType | null; + const locationId = Number(location?.value) || 0; + + filterFormik.setFieldValue('location', location); + filterFormik.setFieldValue('location_id', locationId); + setFilterLocation(location); setFilterProjectFlock(null); setFilterKandang(null); setFilterProjectFlockLocationId( location ? location.value.toString() : '' ); + + filterFormik.setFieldValue('project_flock', null); + filterFormik.setFieldValue('project_flock_id', 0); + filterFormik.setFieldValue('kandang', null); + filterFormik.setFieldValue('kandang_id', 0); }, - [] + [filterFormik] ); const handleFilterProjectFlockChange = useCallback( (val: OptionType | OptionType[] | null) => { - setFilterProjectFlock(val as OptionType | null); + const projectFlock = val as OptionType | null; + const projectFlockId = Number(projectFlock?.value) || 0; + + filterFormik.setFieldValue('project_flock', projectFlock); + filterFormik.setFieldValue('project_flock_id', projectFlockId); + + setFilterProjectFlock(projectFlock); setFilterKandang(null); + + filterFormik.setFieldValue('kandang', null); + filterFormik.setFieldValue('kandang_id', 0); }, - [] + [filterFormik] ); const handleFilterKandangChange = useCallback( (val: OptionType | OptionType[] | null) => { - setFilterKandang(val as OptionType | null); + const kandang = val as OptionType | null; + const kandangId = Number(kandang?.value) || 0; + + filterFormik.setFieldValue('kandang', kandang); + filterFormik.setFieldValue('kandang_id', kandangId); + + setFilterKandang(kandang); }, - [] + [filterFormik] ); const handleResetFilters = useCallback(() => { @@ -403,41 +466,34 @@ const UniformityTable = () => { setFilterProjectFlockKandangId(undefined); setFilterStartDate(''); setFilterEndDate(''); - }, []); + setFilterErrors({}); + + filterFormik.resetForm(); + }, [filterFormik]); + + const handleFilterStartDateChange = useCallback( + (e: React.ChangeEvent) => { + const value = e.target.value; + setFilterStartDate(value); + filterFormik.setFieldValue('start_date', value); + }, + [filterFormik] + ); + + const handleFilterEndDateChange = useCallback( + (e: React.ChangeEvent) => { + const value = e.target.value; + setFilterEndDate(value); + filterFormik.setFieldValue('end_date', value); + }, + [filterFormik] + ); const handleApplyFilters = useCallback(() => { - const errors: Record = {}; - - if (!filterStartDate) { - errors.start_date = 'Tanggal mulai wajib diisi'; - } - if (!filterEndDate) { - errors.end_date = 'Tanggal akhir wajib diisi'; - } - if (!filterLocation) { - errors.location = 'Lokasi wajib dipilih'; - } - if (!filterProjectFlock) { - errors.project_flock = 'Project Flock wajib dipilih'; - } - if (!filterKandang) { - errors.kandang = 'Kandang wajib dipilih'; - } - - setFilterErrors(errors); - - if (Object.keys(errors).length === 0) { - setIsSubmitted(true); - filterModal.closeModal(); - } - }, [ - filterModal, - filterStartDate, - filterEndDate, - filterLocation, - filterProjectFlock, - filterKandang, - ]); + handleFormSubmit( + new Event('submit') as unknown as React.FormEvent + ); + }, [handleFormSubmit]); const selectedRowIds = useMemo(() => { return Object.keys(rowSelection) @@ -1134,42 +1190,46 @@ const UniformityTable = () => { + + {/* Error List Alert */} + {formErrorList.length > 0 && ( +
+ +
+ )} +
{ - setFilterStartDate(e.target.value); - setFilterErrors((prev) => ({ ...prev, start_date: '' })); - }} + value={filterFormik.values.start_date} + onChange={handleFilterStartDateChange} + onBlur={filterFormik.handleBlur} + isError={ + filterFormik.touched.start_date && + Boolean(filterFormik.errors.start_date) + } + errorMessage={filterFormik.errors.start_date} className={{ wrapper: 'w-full' }} /> - {filterErrors.start_date && ( -

- {filterErrors.start_date} -

- )}
{ - setFilterEndDate(e.target.value); - setFilterErrors((prev) => ({ ...prev, end_date: '' })); - }} + value={filterFormik.values.end_date} + onChange={handleFilterEndDateChange} + onBlur={filterFormik.handleBlur} + isError={ + filterFormik.touched.end_date && + Boolean(filterFormik.errors.end_date) + } + errorMessage={filterFormik.errors.end_date} className={{ wrapper: 'w-full' }} /> - {filterErrors.end_date && ( -

- {filterErrors.end_date} -

- )}
@@ -1177,65 +1237,65 @@ const UniformityTable = () => { { handleFilterLocationChange(value); - setFilterErrors((prev) => ({ ...prev, location: '' })); }} options={filterLocationOptions} onInputChange={setFilterLocationInputValue} isLoading={isLoadingFilterLocations} onMenuScrollToBottom={loadMoreFilterLocations} + isError={ + filterFormik.touched.location && + Boolean(filterFormik.errors.location) + } + errorMessage={filterFormik.errors.location} + isClearable className={{ wrapper: 'w-full' }} /> - {filterErrors.location && ( -

- {filterErrors.location} -

- )}
{ handleFilterProjectFlockChange(value); - setFilterErrors((prev) => ({ ...prev, project_flock: '' })); }} options={filterProjectFlockOptions} onInputChange={setFilterProjectFlockSearchValue} isLoading={isLoadingFilterProjectFlocks} onMenuScrollToBottom={loadMoreFilterProjectFlocks} - isDisabled={!filterLocation} + isDisabled={!filterFormik.values.location} + isError={ + filterFormik.touched.project_flock && + Boolean(filterFormik.errors.project_flock) + } + errorMessage={filterFormik.errors.project_flock} + isClearable className={{ wrapper: 'w-full' }} /> - {filterErrors.project_flock && ( -

- {filterErrors.project_flock} -

- )}
{ handleFilterKandangChange(value); - setFilterErrors((prev) => ({ ...prev, kandang: '' })); }} options={filterKandangOptions} - isDisabled={!filterProjectFlock} + isDisabled={!filterFormik.values.project_flock} + isError={ + filterFormik.touched.kandang && + Boolean(filterFormik.errors.kandang) + } + errorMessage={filterFormik.errors.kandang} + isClearable className={{ wrapper: 'w-full' }} /> - {filterErrors.kandang && ( -

- {filterErrors.kandang} -

- )}
diff --git a/src/components/pages/production/uniformity/UniformityTableFilter.schema.ts b/src/components/pages/production/uniformity/UniformityTableFilter.schema.ts new file mode 100644 index 00000000..a95ea3e2 --- /dev/null +++ b/src/components/pages/production/uniformity/UniformityTableFilter.schema.ts @@ -0,0 +1,66 @@ +import { OptionType } from '@/components/input/SelectInput'; +import * as yup from 'yup'; + +export type UniformityTableFilterType = { + start_date: string; + end_date: string; + location: OptionType | null; + location_id: number; + project_flock: OptionType | null; + project_flock_id: number; + project_flock_kandang_id: number | undefined; + kandang: OptionType | null; + kandang_id: number; +}; + +export const UniformityTableFilterSchema = yup.object({ + start_date: yup.string().required('Tanggal mulai wajib diisi'), + end_date: yup.string().required('Tanggal akhir wajib diisi'), + location: yup + .mixed() + .required('Lokasi wajib dipilih') + .test('is-not-empty', 'Lokasi wajib dipilih', (value) => { + if (Array.isArray(value)) { + return value.length > 0; + } + return !!value; + }), + location_id: yup + .number() + .min(1, 'Location wajib diisi!') + .required('Location wajib diisi!') + .typeError('Location wajib diisi!'), + project_flock: yup + .mixed() + .required('Project Flock wajib dipilih') + .test('is-not-empty', 'Project Flock wajib dipilih', (value) => { + if (Array.isArray(value)) { + return value.length > 0; + } + return !!value; + }), + project_flock_id: yup + .number() + .min(1, 'Project flock wajib diisi!') + .required('Project flock wajib diisi!') + .typeError('Project flock wajib diisi!'), + project_flock_kandang_id: yup.number().optional(), + kandang: yup + .mixed() + .required('Kandang wajib dipilih') + .test('is-not-empty', 'Kandang wajib dipilih', (value) => { + if (Array.isArray(value)) { + return value.length > 0; + } + return !!value; + }), + kandang_id: yup + .number() + .min(1, 'Kandang wajib diisi!') + .required('Kandang wajib diisi!') + .typeError('Kandang wajib diisi!'), +}) as yup.ObjectSchema; + +export type UniformityTableFilterValues = yup.InferType< + typeof UniformityTableFilterSchema +>;