refactor(FE-438): Add Project Flock selection and lookup

This commit is contained in:
rstubryan
2025-12-26 17:12:40 +07:00
parent 97c5917401
commit 517e8c758c
2 changed files with 215 additions and 41 deletions
@@ -8,7 +8,12 @@ type UniformityFormSchemaType = {
label: string;
} | null;
location_id: number;
project_flock_kandang_id: number;
project_flock?: {
value: number;
label: string;
} | null;
project_flock_id: number;
project_flock_kandang_id: number | null;
kandang?: {
value: number;
label: string;
@@ -46,9 +51,14 @@ export const UniformityFormSchema: Yup.ObjectSchema<UniformityFormSchemaType> =
location_id: Yup.number()
.required('Location wajib diisi!')
.typeError('Location wajib diisi!'),
project_flock_kandang_id: Yup.number()
.required('Project flock kandang wajib diisi!')
.typeError('Project flock kandang wajib diisi!'),
project_flock: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
project_flock_id: Yup.number()
.required('Project flock wajib diisi!')
.typeError('Project flock wajib diisi!'),
project_flock_kandang_id: Yup.number().optional().nullable().default(null),
kandang: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
@@ -73,6 +83,13 @@ export const getUniformityFormInitialValues = (
}
: null,
location_id: initialValues?.location?.id ?? 0,
project_flock: initialValues?.project_flock
? {
value: initialValues.project_flock.id,
label: initialValues.project_flock.flock_name,
}
: null,
project_flock_id: initialValues?.project_flock?.id ?? 0,
project_flock_kandang_id: initialValues?.project_flock_kandang_id ?? 0,
kandang: initialValues?.kandang
? {
@@ -21,14 +21,22 @@ import {
UniformityFormValues,
getUniformityFormInitialValues,
} from '@/components/pages/uniformity/form/UniformityForm.schema';
import { LocationApi, KandangApi } from '@/services/api/master-data';
import { LocationApi } from '@/services/api/master-data';
import {
ProjectFlockApi,
ProjectFlockKandangApi,
} from '@/services/api/production';
import { UniformityApi } from '@/services/api/uniformity';
import { isResponseError } from '@/lib/api-helper';
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
import {
Uniformity,
CreateUniformityPayload,
} from '@/types/api/uniformity/uniformity';
import { type BaseApiResponse } from '@/types/api/api-general';
import { ProjectFlockKandangLookup } from '@/types/api/production/project-flock';
import { Kandang } from '@/types/api/master-data/kandang';
import ExpandedDrawerForm from '@/components/pages/uniformity/form/ExpandedDrawerForm';
import useSWR from 'swr';
interface UniformityFormProps {
formType?: 'add' | 'edit';
@@ -50,17 +58,142 @@ const UniformityForm = ({
useState('');
// ===== SELECT INPUT DATA =====
const [selectedLocation, setSelectedLocation] = useState<OptionType | null>(
null
);
const [projectFlockSearchValue, setProjectFlockSearchValue] = useState('');
const [selectedProjectFlock, setSelectedProjectFlock] =
useState<OptionType | null>(null);
const [selectedKandang, setSelectedKandang] = useState<OptionType | null>(
null
);
const {
setInputValue: setLocationSelectInputValue,
options: locationOptions,
isLoadingOptions: isLoadingLocations,
} = useSelect(LocationApi.basePath, 'id', 'name', 'search');
const {
setInputValue: setKandangSelectInputValue,
options: kandangOptions,
isLoadingOptions: isLoadingKandangs,
} = useSelect(KandangApi.basePath, 'id', 'name', 'search');
// ===== FETCH PROJECT FLOCKS DATA =====
const projectFlocksUrl = useMemo(() => {
const params = new URLSearchParams({
search: projectFlockSearchValue || '',
limit: '100',
});
if (selectedLocation) {
params.append('location_id', selectedLocation.value.toString());
}
return `${ProjectFlockApi.basePath}?${params.toString()}`;
}, [projectFlockSearchValue, selectedLocation]);
const { data: projectFlocksData, isLoading: isLoadingProjectFlocks } = useSWR(
projectFlocksUrl,
ProjectFlockApi.getAllFetcher
);
const projectFlocksDataList =
projectFlocksData?.status === 'success'
? projectFlocksData.data
: undefined;
// ===== PROJECT FLOCK OPTIONS =====
const projectFlockOptions = useMemo(() => {
let options: OptionType[] = [];
if (isResponseSuccess(projectFlocksData)) {
const flockOptions =
projectFlocksData?.data.map((projectFlock) => ({
value: projectFlock.id,
label: projectFlock.flock_name || '',
})) || [];
options = options.concat(flockOptions);
}
return options;
}, [projectFlocksData]);
// ===== APPROVED PROJECT FLOCK KANDANGS =====
const approvedProjectFlockKandangsUrl = useMemo(() => {
const params = new URLSearchParams({
step_name: 'Disetujui',
limit: '100',
});
return `${ProjectFlockKandangApi.basePath}?${params.toString()}`;
}, []);
const { data: approvedProjectFlockKandangsData } = useSWR(
approvedProjectFlockKandangsUrl,
ProjectFlockKandangApi.getAllFetcher
);
const approvedProjectFlockKandangs = useMemo(() => {
if (!isResponseSuccess(approvedProjectFlockKandangsData)) return [];
return approvedProjectFlockKandangsData.data;
}, [approvedProjectFlockKandangsData]);
// ===== KANDANG OPTIONS (FILTERED BY SELECTED PROJECT FLOCK) =====
const kandangOptions = useMemo(() => {
let options: OptionType[] = [];
if (selectedProjectFlock && projectFlocksDataList) {
const selectedProjectFlockData = projectFlocksDataList.find(
(pf) => pf.id === selectedProjectFlock.value
);
if (selectedProjectFlockData?.kandangs) {
const approvedKandangIds = approvedProjectFlockKandangs
.filter((pfk) => pfk.project_flock_id === selectedProjectFlock.value)
.map((pfk) => pfk.kandang_id);
const kandangOpts = selectedProjectFlockData.kandangs
.filter((kandang: Kandang) => {
if (formType === 'add') {
return approvedKandangIds.includes(kandang.id);
}
return true;
})
.map((kandang: Kandang) => ({
value: kandang.id,
label: kandang.name || '',
}));
options = options.concat(kandangOpts);
}
}
return options;
}, [
selectedProjectFlock,
projectFlocksDataList,
approvedProjectFlockKandangs,
formType,
]);
// ===== PROJECT FLOCK KANDANG LOOKUP =====
const projectFlockKandangLookupUrl = useMemo(() => {
if (!selectedProjectFlock || !selectedKandang) return null;
const params = new URLSearchParams({
project_flock_id: selectedProjectFlock.value.toString(),
kandang_id: selectedKandang.value.toString(),
});
return `${ProjectFlockApi.basePath}/kandangs/lookup?${params.toString()}`;
}, [selectedProjectFlock, selectedKandang]);
const { data: projectFlockKandangLookupData } = useSWR(
projectFlockKandangLookupUrl,
projectFlockKandangLookupUrl
? () =>
ProjectFlockApi.getAllFetcher(
projectFlockKandangLookupUrl
) as Promise<BaseApiResponse<ProjectFlockKandangLookup>>
: null
);
const projectFlockKandangLookup =
projectFlockKandangLookupData?.status === 'success'
? projectFlockKandangLookupData.data
: undefined;
// ===== FORM CONFIGURATION =====
const formikInitialValues = useMemo<UniformityFormValues>(
@@ -76,14 +209,22 @@ const UniformityForm = ({
validateOnMount: false,
enableReinitialize: true,
onSubmit: async (values) => {
const projectFlockKandangId = projectFlockKandangLookup?.id;
if (!projectFlockKandangId) {
setUniformityFormErrorMessage(
'Project Flock Kandang tidak ditemukan. Silakan pilih Project Flock dan Kandang yang valid.'
);
return;
}
const formData = new FormData();
formData.append('date', values.date);
formData.append('location_id', values.location_id.toString());
formData.append(
'project_flock_kandang_id',
values.project_flock_kandang_id.toString()
projectFlockKandangId.toString()
);
formData.append('kandang_id', values.kandang_id.toString());
if (values.files) {
formData.append('files[]', values.files);
@@ -111,6 +252,35 @@ const UniformityForm = ({
formik.setFieldValue('location', location);
formik.setFieldTouched('location_id', true);
formik.setFieldValue('location_id', (location as OptionType)?.value || 0);
setSelectedLocation(location);
setSelectedProjectFlock(null);
setSelectedKandang(null);
formik.setFieldValue('project_flock', null);
formik.setFieldValue('project_flock_id', 0);
formik.setFieldValue('kandang', null);
formik.setFieldValue('kandang_id', 0);
},
[formik]
);
const handleProjectFlockChange = useCallback(
(val: OptionType | OptionType[] | null) => {
const projectFlock = val as OptionType | null;
formik.setFieldTouched('project_flock', true);
formik.setFieldValue('project_flock', projectFlock);
formik.setFieldTouched('project_flock_id', true);
formik.setFieldValue(
'project_flock_id',
(projectFlock as OptionType)?.value || 0
);
setSelectedProjectFlock(projectFlock);
setSelectedKandang(null);
formik.setFieldValue('kandang', null);
formik.setFieldValue('kandang_id', 0);
},
[formik]
);
@@ -122,6 +292,8 @@ const UniformityForm = ({
formik.setFieldValue('kandang', kandang);
formik.setFieldTouched('kandang_id', true);
formik.setFieldValue('kandang_id', (kandang as OptionType)?.value || 0);
setSelectedKandang(kandang);
},
[formik]
);
@@ -225,7 +397,7 @@ const UniformityForm = ({
<SelectInput
required
label='Lokasi Farm'
label='Lokasi'
placeholder='Pilih Lokasi...'
value={formik.values.location}
onChange={handleLocationChange}
@@ -242,33 +414,19 @@ const UniformityForm = ({
<SelectInput
required
label='Project Flock Kandang'
placeholder='Pilih Project Flock Kandang...'
value={
formik.values.project_flock_kandang_id
? {
value: formik.values.project_flock_kandang_id,
label: formik.values.project_flock_kandang_id.toString(),
}
: null
}
onChange={(val) => {
const option = val as OptionType | null;
formik.setFieldValue(
'project_flock_kandang_id',
option?.value || 0
);
}}
options={[
{ value: 1, label: '1' },
{ value: 2, label: '2' },
{ value: 3, label: '3' },
]}
label='Project Flock'
placeholder='Pilih Project Flock...'
value={formik.values.project_flock}
onChange={handleProjectFlockChange}
options={projectFlockOptions}
onInputChange={setProjectFlockSearchValue}
isLoading={isLoadingProjectFlocks}
isDisabled={!formik.values.location_id}
isError={
formik.touched.project_flock_kandang_id &&
Boolean(formik.errors.project_flock_kandang_id)
formik.touched.project_flock_id &&
Boolean(formik.errors.project_flock_id)
}
errorMessage={formik.errors.project_flock_kandang_id as string}
errorMessage={formik.errors.project_flock_id as string}
isClearable
className={{ wrapper: 'w-full' }}
/>
@@ -280,8 +438,7 @@ const UniformityForm = ({
value={formik.values.kandang}
onChange={handleKandangChange}
options={kandangOptions}
onInputChange={setKandangSelectInputValue}
isLoading={isLoadingKandangs}
isDisabled={!formik.values.project_flock_id}
isError={
formik.touched.kandang_id && Boolean(formik.errors.kandang_id)
}