refactor(FE): Refactor production result filter to use OptionType

This commit is contained in:
rstubryan
2026-02-13 09:29:37 +07:00
parent 5c00893ea3
commit d5962f94a1
2 changed files with 72 additions and 22 deletions
@@ -1,3 +1,4 @@
import { OptionType } from '@/components/input/SelectInput';
import * as yup from 'yup'; import * as yup from 'yup';
export type ProductionResultFilterProps = { export type ProductionResultFilterProps = {
@@ -7,12 +8,51 @@ export type ProductionResultFilterProps = {
kandang_id: string | null; kandang_id: string | null;
}; };
export type ProductionResultFilterFormType = {
area_id: OptionType | null;
location_id: OptionType | null;
project_flock_id: OptionType | null;
kandang_id: OptionType | null;
};
export const ProductionResultFilterSchema = yup.object({ export const ProductionResultFilterSchema = yup.object({
area_id: yup.string().required('Area wajib dipilih'), area_id: yup
location_id: yup.string().required('Lokasi wajib dipilih'), .mixed<OptionType>()
project_flock_id: yup.string().required('Project Flock wajib dipilih'), .required('Area wajib dipilih')
kandang_id: yup.string().required('Kandang wajib dipilih'), .test('is-not-empty', 'Area wajib dipilih', (value) => {
}); if (Array.isArray(value)) {
return value.length > 0;
}
return !!value;
}),
location_id: yup
.mixed<OptionType>()
.required('Lokasi wajib dipilih')
.test('is-not-empty', 'Lokasi wajib dipilih', (value) => {
if (Array.isArray(value)) {
return value.length > 0;
}
return !!value;
}),
project_flock_id: yup
.mixed<OptionType>()
.required('Project Flock wajib dipilih')
.test('is-not-empty', 'Project Flock wajib dipilih', (value) => {
if (Array.isArray(value)) {
return value.length > 0;
}
return !!value;
}),
kandang_id: yup
.mixed<OptionType>()
.required('Kandang wajib dipilih')
.test('is-not-empty', 'Kandang wajib dipilih', (value) => {
if (Array.isArray(value)) {
return value.length > 0;
}
return !!value;
}),
}) as yup.ObjectSchema<ProductionResultFilterFormType>;
export type ProductionResultFilterValues = yup.InferType< export type ProductionResultFilterValues = yup.InferType<
typeof ProductionResultFilterSchema typeof ProductionResultFilterSchema
@@ -8,15 +8,15 @@ import toast from 'react-hot-toast';
import { Icon } from '@iconify/react'; import { Icon } from '@iconify/react';
import Button from '@/components/Button'; import Button from '@/components/Button';
import Dropdown from '@/components/dropdown/Dropdown'; import Dropdown from '@/components/dropdown/Dropdown';
import SelectInput, { import SelectInput, { useSelect } from '@/components/input/SelectInput';
OptionType,
useSelect,
} from '@/components/input/SelectInput';
import Menu from '@/components/menu/Menu'; import Menu from '@/components/menu/Menu';
import MenuItem from '@/components/menu/MenuItem'; import MenuItem from '@/components/menu/MenuItem';
import ProductionResultProjectFlockKandangTable from '@/components/pages/report/production-result/ProductionResultProjectFlockKandangTable'; import ProductionResultProjectFlockKandangTable from '@/components/pages/report/production-result/ProductionResultProjectFlockKandangTable';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import { ProductionResultFilterSchema } from '@/components/pages/report/production-result/filter/ProductionResultFilter'; import {
ProductionResultFilterSchema,
type ProductionResultFilterValues,
} from '@/components/pages/report/production-result/filter/ProductionResultFilter';
import { BaseKandang } from '@/types/api/master-data/kandang'; import { BaseKandang } from '@/types/api/master-data/kandang';
import { AreaApi, LocationApi } from '@/services/api/master-data'; import { AreaApi, LocationApi } from '@/services/api/master-data';
@@ -53,13 +53,6 @@ interface FilterParams {
project_flock_kandang_id?: string; project_flock_kandang_id?: string;
} }
type ProductionResultFilterFormValues = {
area_id: OptionType | null;
location_id: OptionType | null;
project_flock_id: OptionType | null;
kandang_id: OptionType | null;
};
const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => { const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
// ===== STATE MANAGEMENT ===== // ===== STATE MANAGEMENT =====
const [isPdfExportLoading, setIsPdfExportLoading] = useState(false); const [isPdfExportLoading, setIsPdfExportLoading] = useState(false);
@@ -213,7 +206,7 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
]; ];
// ===== FORMIK SETUP ===== // ===== FORMIK SETUP =====
const formik = useFormik<ProductionResultFilterFormValues>({ const formik = useFormik<ProductionResultFilterValues>({
initialValues: { initialValues: {
area_id: null, area_id: null,
location_id: null, location_id: null,
@@ -221,6 +214,8 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
kandang_id: null, kandang_id: null,
}, },
validationSchema: ProductionResultFilterSchema, validationSchema: ProductionResultFilterSchema,
validateOnBlur: true,
validateOnChange: true,
onSubmit: (values) => { onSubmit: (values) => {
setFilterParams({ setFilterParams({
area_id: values.area_id?.value area_id: values.area_id?.value
@@ -723,7 +718,7 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
{/* Modal Body */} {/* Modal Body */}
<div className='p-4 flex flex-col gap-1.5'> <div className='p-4 flex flex-col gap-1.5'>
<SelectInput <SelectInput
required={true} required
label='Area' label='Area'
placeholder='Pilih Area' placeholder='Pilih Area'
options={areaOptions} options={areaOptions}
@@ -738,11 +733,13 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
onInputChange={setAreaInputValue} onInputChange={setAreaInputValue}
onMenuScrollToBottom={loadMoreAreas} onMenuScrollToBottom={loadMoreAreas}
isClearable isClearable
isError={formik.touched.area_id && Boolean(formik.errors.area_id)}
errorMessage={formik.errors.area_id}
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
/> />
<SelectInput <SelectInput
required={true} required
label='Lokasi' label='Lokasi'
placeholder='Pilih Lokasi' placeholder='Pilih Lokasi'
options={locationOptions} options={locationOptions}
@@ -757,11 +754,15 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
onMenuScrollToBottom={loadMoreLocations} onMenuScrollToBottom={loadMoreLocations}
isClearable isClearable
isDisabled={!formik.values.area_id} isDisabled={!formik.values.area_id}
isError={
formik.touched.location_id && Boolean(formik.errors.location_id)
}
errorMessage={formik.errors.location_id}
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
/> />
<SelectInput <SelectInput
required={true} required
label='Project Flock' label='Project Flock'
placeholder='Pilih Project Flock' placeholder='Pilih Project Flock'
options={projectFlockOptions} options={projectFlockOptions}
@@ -775,11 +776,16 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
onMenuScrollToBottom={loadMoreProjectFlocks} onMenuScrollToBottom={loadMoreProjectFlocks}
isClearable isClearable
isDisabled={!formik.values.location_id} isDisabled={!formik.values.location_id}
isError={
formik.touched.project_flock_id &&
Boolean(formik.errors.project_flock_id)
}
errorMessage={formik.errors.project_flock_id}
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
/> />
<SelectInput <SelectInput
required={true} required
label='Kandang' label='Kandang'
placeholder='Pilih Kandang' placeholder='Pilih Kandang'
options={projectFlockKandangOptions} options={projectFlockKandangOptions}
@@ -792,6 +798,10 @@ const ProductionResultContent = ({ tabId }: ProductionResultTabProps) => {
onMenuScrollToBottom={loadMoreProjectFlockKandangs} onMenuScrollToBottom={loadMoreProjectFlockKandangs}
isClearable isClearable
isDisabled={!formik.values.project_flock_id} isDisabled={!formik.values.project_flock_id}
isError={
formik.touched.kandang_id && Boolean(formik.errors.kandang_id)
}
errorMessage={formik.errors.kandang_id}
className={{ wrapper: 'w-full' }} className={{ wrapper: 'w-full' }}
/> />
</div> </div>