mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 21:41:57 +00:00
feat(FE-114): integrate location and project flock selection in RecordingForm
This commit is contained in:
@@ -2,10 +2,12 @@
|
||||
|
||||
import { useMemo, useState, useEffect } from 'react';
|
||||
import { useFormik } from 'formik';
|
||||
import useSWR from 'swr';
|
||||
import { Icon } from '@iconify/react';
|
||||
import Button from '@/components/Button';
|
||||
|
||||
import TextInput from '@/components/input/TextInput';
|
||||
import SelectInput, { OptionType } from '@/components/input/SelectInput';
|
||||
import CheckboxInput from '@/components/input/CheckboxInput';
|
||||
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||
import { FormHeader } from '@/components/helper/form/FormHeader';
|
||||
@@ -21,6 +23,9 @@ import {
|
||||
UpdateRecordingFormSchema,
|
||||
} from './RecordingForm.schema';
|
||||
import { useRecordingFormHandlers } from './useRecordingFormHandlers';
|
||||
import { ProjectFlockApi } from '@/services/api/production';
|
||||
import { LocationApi } from '@/services/api/master-data';
|
||||
import { isResponseSuccess } from '@/lib/api-helper';
|
||||
|
||||
import Card from '@/components/Card';
|
||||
|
||||
@@ -34,6 +39,62 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
const [selectedStocks, setSelectedStocks] = useState<number[]>([]);
|
||||
const [selectedDepletions, setSelectedDepletions] = useState<number[]>([]);
|
||||
|
||||
// State for Location search and selection
|
||||
const [locationSearchValue, setLocationSearchValue] = useState('');
|
||||
const [selectedLocation, setSelectedLocation] = useState<OptionType | null>(null);
|
||||
|
||||
// State for Project Flock search
|
||||
const [projectFlockSearchValue, setProjectFlockSearchValue] = useState('');
|
||||
|
||||
// Fetch Locations data
|
||||
const locationsUrl = `${LocationApi.basePath}?${new URLSearchParams({
|
||||
search: locationSearchValue || '',
|
||||
}).toString()}`;
|
||||
|
||||
const { data: locations, isLoading: isLoadingLocations } = useSWR(
|
||||
locationsUrl,
|
||||
LocationApi.getAllFetcher
|
||||
);
|
||||
|
||||
// Fetch Project Flocks data with location filter
|
||||
const projectFlocksUrl = `${ProjectFlockApi.basePath}?${new URLSearchParams({
|
||||
search: projectFlockSearchValue || '',
|
||||
...(selectedLocation ? { location_id: selectedLocation.value.toString() } : {}),
|
||||
}).toString()}`;
|
||||
|
||||
const { data: projectFlocks, isLoading: isLoadingProjectFlocks } = useSWR(
|
||||
projectFlocksUrl,
|
||||
ProjectFlockApi.getAllFetcher
|
||||
);
|
||||
|
||||
// Extract location options from locations data
|
||||
const locationOptions = useMemo(() => {
|
||||
if (!isResponseSuccess(locations)) return [];
|
||||
|
||||
return locations?.data.map((location) => ({
|
||||
value: location.id,
|
||||
label: location.name,
|
||||
})) || [];
|
||||
}, [locations]);
|
||||
|
||||
// Extract kandang options from project_flocks data
|
||||
const projectFlockKandangOptions = useMemo(() => {
|
||||
if (!isResponseSuccess(projectFlocks)) return [];
|
||||
|
||||
const options: OptionType[] = [];
|
||||
|
||||
projectFlocks?.data.forEach((projectFlock) => {
|
||||
projectFlock.kandangs.forEach((kandang) => {
|
||||
options.push({
|
||||
value: kandang.id,
|
||||
label: `${projectFlock.flock.name} - ${projectFlock.area.name} - ${kandang.name}`,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return options;
|
||||
}, [projectFlocks]);
|
||||
|
||||
const {
|
||||
deleteModal,
|
||||
recordingFormErrorMessage,
|
||||
@@ -114,9 +175,19 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
});
|
||||
|
||||
// EVENT HANDLERS - Select Inputs
|
||||
const projectFlockChangeHandler = (value: string) => {
|
||||
const projectFlockId = parseInt(value) || 0;
|
||||
formik.setFieldValue('project_flock_kandang_id', projectFlockId, false);
|
||||
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
setSelectedLocation(val as OptionType);
|
||||
|
||||
// Reset project flock selection when location changes
|
||||
formik.setFieldValue('project_flock_kandang', null);
|
||||
formik.setFieldValue('project_flock_kandang_id', 0);
|
||||
};
|
||||
|
||||
const projectFlockKandangChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
formik.setFieldTouched('project_flock_kandang', true);
|
||||
formik.setFieldValue('project_flock_kandang', val);
|
||||
formik.setFieldTouched('project_flock_kandang_id', true);
|
||||
formik.setFieldValue('project_flock_kandang_id', (val as OptionType)?.value || 0);
|
||||
};
|
||||
|
||||
// EVENT HANDLERS - Date Time
|
||||
@@ -303,28 +374,41 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
}}
|
||||
>
|
||||
<div className='grid grid-cols-1 md:grid-cols-2 gap-6'>
|
||||
<TextInput
|
||||
<SelectInput
|
||||
required
|
||||
label='Project Flock Kandang ID'
|
||||
type='number'
|
||||
name='project_flock_kandang_id'
|
||||
value={formik.values.project_flock_kandang_id?.toString() || ''}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
formik.setFieldValue(
|
||||
'project_flock_kandang_id',
|
||||
parseInt(value) || 0
|
||||
);
|
||||
projectFlockChangeHandler(value);
|
||||
}}
|
||||
onBlur={formik.handleBlur}
|
||||
label='Lokasi'
|
||||
value={selectedLocation}
|
||||
onChange={locationChangeHandler}
|
||||
options={locationOptions}
|
||||
onInputChange={setLocationSearchValue}
|
||||
isLoading={isLoadingLocations}
|
||||
isDisabled={type === 'detail'}
|
||||
placeholder='Pilih Lokasi'
|
||||
isClearable
|
||||
isSearchable
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
required
|
||||
label='Project Flock'
|
||||
value={formik.values.project_flock_kandang ?? undefined}
|
||||
onChange={projectFlockKandangChangeHandler}
|
||||
options={projectFlockKandangOptions}
|
||||
onInputChange={setProjectFlockSearchValue}
|
||||
isLoading={isLoadingProjectFlocks}
|
||||
isError={
|
||||
formik.touched.project_flock_kandang_id &&
|
||||
Boolean(formik.errors.project_flock_kandang_id)
|
||||
}
|
||||
errorMessage={formik.errors.project_flock_kandang_id as string}
|
||||
readOnly={type === 'detail'}
|
||||
placeholder='Masukkan project flock kandang ID'
|
||||
isDisabled={type === 'detail' || !selectedLocation}
|
||||
placeholder={
|
||||
selectedLocation
|
||||
? 'Pilih Project Flock - Kandang'
|
||||
: 'Pilih Lokasi terlebih dahulu'
|
||||
}
|
||||
isClearable
|
||||
isSearchable
|
||||
/>
|
||||
|
||||
<TextInput
|
||||
@@ -369,21 +453,13 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
readOnly={type === 'detail'}
|
||||
placeholder='Masukkan status (0-3)'
|
||||
/>
|
||||
|
||||
<CheckboxInput
|
||||
hidden={true}
|
||||
name='ontime'
|
||||
checked={formik.values.ontime || false}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
formik.setFieldValue('ontime', e.target.checked);
|
||||
}}
|
||||
disabled={type !== 'detail'}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
|
||||
{/* Body Weights Table */}
|
||||
<Card
|
||||
title='Data Bobot Badan'
|
||||
title='Bobot Badan'
|
||||
className={{
|
||||
wrapper: 'w-full mb-4 shadow',
|
||||
title: 'mb-4',
|
||||
@@ -583,7 +659,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
|
||||
{/* Stocks Table */}
|
||||
<Card
|
||||
title='Data Stok Pakan'
|
||||
title='Stok Persediaan'
|
||||
className={{
|
||||
wrapper: 'w-full mb-4 shadow',
|
||||
title: 'mb-4',
|
||||
@@ -620,7 +696,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
</th>
|
||||
)}
|
||||
<th>
|
||||
Product Warehouse ID
|
||||
Persediaan
|
||||
<span
|
||||
className='tooltip tooltip-error tooltip-bottom z-[9999]'
|
||||
data-tip='required'
|
||||
@@ -826,7 +902,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
|
||||
{/* Depletions Table */}
|
||||
<Card
|
||||
title='Data Depletions (Hilang/Mati)'
|
||||
title='Deplesi'
|
||||
className={{
|
||||
wrapper: 'w-full mb-4 shadow',
|
||||
title: 'mb-4',
|
||||
|
||||
Reference in New Issue
Block a user