diff --git a/src/components/pages/production/recording/form/RecordingForm.tsx b/src/components/pages/production/recording/form/RecordingForm.tsx index 39226f82..4502800f 100644 --- a/src/components/pages/production/recording/form/RecordingForm.tsx +++ b/src/components/pages/production/recording/form/RecordingForm.tsx @@ -29,12 +29,16 @@ import { ProjectFlockApi } from '@/services/api/production'; import { LocationApi } from '@/services/api/master-data'; import { ProductWarehouseApi } from '@/services/api/inventory'; import { isResponseSuccess } from '@/lib/api-helper'; -import { PeriodFlock } from '@/types/api/production/project-flock'; +import { + PeriodFlock, + ProjectFlockKandangLookup, +} from '@/types/api/production/project-flock'; import { useModal } from '@/components/Modal'; import toast from 'react-hot-toast'; import Card from '@/components/Card'; import Badge from '@/components/Badge'; +import { Kandang } from '@/types/api/master-data/kandang'; interface RecordingFormProps { type?: 'add' | 'edit' | 'detail'; @@ -46,9 +50,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { const [selectedStocks, setSelectedStocks] = useState([]); const [selectedDepletions, setSelectedDepletions] = useState([]); - const [editingAverageIndex, setEditingAverageIndex] = useState( - null - ); + const [editingAverageIndex] = useState(null); const [manuallyEditedRows, setManuallyEditedRows] = useState>( new Set() ); @@ -58,6 +60,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { null ); const [projectFlockSearchValue, setProjectFlockSearchValue] = useState(''); + const [selectedProjectFlock, setSelectedProjectFlock] = + useState(null); + const [selectedKandang, setSelectedKandang] = useState( + null + ); const [isApproveLoading, setIsApproveLoading] = useState(false); const [isRejectLoading, setIsRejectLoading] = useState(false); @@ -85,6 +92,30 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ProjectFlockApi.getAllFetcher ); + 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> + : null + ); + + const projectFlockKandangLookup = + projectFlockKandangLookupData?.status === 'success' + ? projectFlockKandangLookupData.data + : undefined; + const stockProductsUrl = useMemo(() => { if (!selectedLocation) return null; const params = new URLSearchParams({ @@ -199,25 +230,47 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ); }, [locations]); - const projectFlockKandangOptions = useMemo(() => { + const projectFlockOptions = useMemo(() => { if (!isResponseSuccess(projectFlocks)) return []; + return ( + projectFlocks?.data.map((projectFlock) => ({ + value: projectFlock.id, + label: projectFlock.flock.name, + })) || [] + ); + }, [projectFlocks]); - const options: OptionType[] = []; - projectFlocks?.data.forEach((projectFlock) => { - projectFlock.kandangs.forEach((kandang) => { - const isAlreadyRecorded = recordedProjectFlockIds.has(projectFlock.id); - const label = isAlreadyRecorded - ? `${projectFlock.flock.name} - ${kandang.name} (Sudah Direcord)` - : `${projectFlock.flock.name} - ${kandang.name}`; + const kandangOptions = useMemo(() => { + if (!selectedProjectFlock || !isResponseSuccess(projectFlocks)) return []; - options.push({ - value: projectFlock.id, - label: label, - }); - }); + const selectedProjectFlockData = projectFlocks.data.find( + (pf) => pf.id === selectedProjectFlock.value + ); + + if (!selectedProjectFlockData || !selectedProjectFlockData.kandangs) + return []; + + return selectedProjectFlockData.kandangs.map((kandang: Kandang) => ({ + value: kandang.id, + label: kandang.name, + })); + }, [selectedProjectFlock, projectFlocks]); + + const recordedProjectFlockKandangIds = useMemo(() => { + if (!isResponseSuccess(existingRecordings)) return new Set(); + + const todayRecordings = existingRecordings?.data || []; + const recordedIds = new Set(); + + todayRecordings.forEach((recording) => { + const recordingDate = recording.record_datetime?.split('T')[0]; + if (recordingDate === today) { + recordedIds.add(recording.project_flock_kandangs_id); + } }); - return options; - }, [projectFlocks, recordedProjectFlockIds, type]); + + return recordedIds; + }, [existingRecordings, today]); const unifiedStockProducts = useMemo(() => { const options: OptionType[] = []; @@ -432,39 +485,38 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { [formik.values.stocks, getAvailableStock, type] ); - const getProjectFlockBadgeAdornment = useCallback( - (projectFlockId: number) => { - if (!isResponseSuccess(projectFlocks)) return null; + const getProjectFlockBadgeAdornment = useCallback(() => { + if (!isResponseSuccess(projectFlocks) || !projectFlockKandangLookup) + return null; - const projectFlock = projectFlocks.data.find( - (pf) => pf.id === projectFlockId - ); - if (!projectFlock) return null; + const isAlreadyRecorded = recordedProjectFlockKandangIds.has( + projectFlockKandangLookup.id + ); + let color: 'neutral' | 'success' | 'warning' | 'error' = 'neutral'; - const isAlreadyRecorded = recordedProjectFlockIds.has(projectFlockId); - let color: 'neutral' | 'success' | 'warning' | 'error' = 'neutral'; + if (isAlreadyRecorded) { + color = 'warning'; + } else { + color = 'success'; + } - if (isAlreadyRecorded) { - color = 'warning'; - } else { - color = 'success'; - } - - return ( - - Periode {projectFlock.period} - - ); - }, - [projectFlocks, recordedProjectFlockIds] - ); + return ( + + Periode {projectFlockKandangLookup.project_flock?.period} + + ); + }, [ + projectFlocks, + recordedProjectFlockKandangIds, + projectFlockKandangLookup, + ]); const getProductFlagBadgeAdornment = useCallback( (productWarehouseId: number) => { @@ -563,31 +615,53 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { // ===== EVENT HANDLERS ===== const locationChangeHandler = (val: OptionType | OptionType[] | null) => { setSelectedLocation(val as OptionType); + setSelectedProjectFlock(null); + setSelectedKandang(null); formik.setFieldValue('project_flock_kandang', null); formik.setFieldValue('project_flock_kandangs_id', 0); }; - const projectFlockKandangChangeHandler = ( - val: OptionType | OptionType[] | null - ) => { - if ( - type === 'add' && - val && - recordedProjectFlockIds.has((val as OptionType).value as number) - ) { - toast.error('Project Flock ini sudah direcord hari ini!'); - return; - } - - formik.setFieldTouched('project_flock_kandang', true); - formik.setFieldValue('project_flock_kandang', val); - formik.setFieldTouched('project_flock_kandangs_id', true); - formik.setFieldValue( - 'project_flock_kandangs_id', - (val as OptionType)?.value || 0 - ); + const projectFlockChangeHandler = (val: OptionType | OptionType[] | null) => { + setSelectedProjectFlock(val as OptionType); + setSelectedKandang(null); + formik.setFieldValue('project_flock_kandang', null); + formik.setFieldValue('project_flock_kandangs_id', 0); }; + const kandangChangeHandler = (val: OptionType | OptionType[] | null) => { + setSelectedKandang(val as OptionType); + formik.setFieldTouched('project_flock_kandang', true); + formik.setFieldTouched('project_flock_kandangs_id', true); + }; + + useEffect(() => { + if (projectFlockKandangLookup?.project_flock_kandang_id) { + const projectFlockKandangId = + projectFlockKandangLookup.project_flock_kandang_id; + + if ( + type === 'add' && + recordedProjectFlockKandangIds.has(projectFlockKandangId) + ) { + toast.error('Project Flock Kandang ini sudah direcord hari ini!'); + return; + } + + formik.setFieldValue('project_flock_kandangs_id', projectFlockKandangId); + + formik.setFieldValue('project_flock_kandang', { + value: projectFlockKandangId, + label: `${selectedProjectFlock?.label || ''} - ${selectedKandang?.label || ''}`, + }); + } + }, [ + projectFlockKandangLookup, + selectedProjectFlock, + selectedKandang, + type, + recordedProjectFlockKandangIds, + ]); + const approveHandler = async () => { setIsApproveLoading(true); @@ -868,6 +942,21 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { title='Recording' backUrl='/production/recording' /> + + {/* Project Flock Info Card */} + {projectFlockKandangLookup && ( + + {projectFlockKandangLookup.project_flock.category} + + )} +
{ className={ type === 'detail' ? 'flex flex-col gap-6' - : 'grid grid-cols-1 md:grid-cols-2 gap-6' + : 'grid grid-cols-3 gap-4' } > {type === 'detail' ? null : ( - + <> + + + + + + )} -
- -
+ {type === 'detail' && formik.values.project_flock_kandang && ( +
+ +
+ {formik.values.project_flock_kandang.label} +
+
+ )} diff --git a/src/types/api/production/project-flock.d.ts b/src/types/api/production/project-flock.d.ts index be14302d..cedfca38 100644 --- a/src/types/api/production/project-flock.d.ts +++ b/src/types/api/production/project-flock.d.ts @@ -47,3 +47,13 @@ export type ProjectFlockApprovalPayload = { action: 'APPROVED' | 'REJECTED'; approvable_ids: number[]; }; + +export type ProjectFlockKandangLookup = { + id: number; + project_flock_kandang_id: number; + project_flock_id: number; + kandang_id: number; + kandang: Kandang; + project_flock: ProjectFlock; + quantity: number; +};