diff --git a/src/components/pages/production/recording/form/RecordingForm.tsx b/src/components/pages/production/recording/form/RecordingForm.tsx index 9d90cdf2..f307b686 100644 --- a/src/components/pages/production/recording/form/RecordingForm.tsx +++ b/src/components/pages/production/recording/form/RecordingForm.tsx @@ -79,6 +79,7 @@ import { GROWING_RECORDING_APPROVAL_LINE, LAYING_RECORDING_APPROVAL_LINE, } from '@/config/approval-line'; +import { PROJECT_FLOCK_STATUS } from '@/config/constant'; import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; import { getRecordingRestriction } from '../recording-utils'; @@ -360,6 +361,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { loadMore: loadMoreProjectFlocks, } = useSelect(ProjectFlockApi.basePath, 'id', 'flock_name', 'search', { location_id: selectedProjectFlockLocationId, + status: PROJECT_FLOCK_STATUS.AKTIF, }); const projectFlockKandangLookupUrl = useMemo(() => { @@ -446,6 +448,23 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ? projectFlockKandangDetailData.data : undefined; + const selectedProjectFlockKandangId = useMemo(() => { + if (type === 'add') { + return projectFlockKandangLookup?.project_flock_kandang_id ?? null; + } + + return ( + projectFlockKandangDetail?.id ?? + initialValues?.project_flock?.project_flock_kandang_id ?? + null + ); + }, [ + type, + projectFlockKandangLookup, + projectFlockKandangDetail, + initialValues, + ]); + // ===== TRANSITION RESTRICTION LOGIC ===== const isTransitionPeriod = useMemo(() => { return ( @@ -756,8 +775,36 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { return options; }, [locationOptions, projectFlockKandangDetail, type]); + const isProjectFlockActive = useCallback((projectFlock: ProjectFlock) => { + const approvalStepName = projectFlock.approval?.step_name + ?.trim() + .toLowerCase(); + if (approvalStepName) { + return approvalStepName === PROJECT_FLOCK_STATUS.AKTIF.toLowerCase(); + } + + return ( + projectFlock.status?.trim().toLowerCase() === + PROJECT_FLOCK_STATUS.AKTIF.toLowerCase() + ); + }, []); + + const activeProjectFlockIDs = useMemo(() => { + if (!isResponseSuccess(projectFlocksRawData)) return new Set(); + + const data = projectFlocksRawData.data as ProjectFlock[]; + return new Set( + data + .filter((projectFlock) => isProjectFlockActive(projectFlock)) + .map((projectFlock) => projectFlock.id) + ); + }, [projectFlocksRawData, isProjectFlockActive]); + const enhancedProjectFlockOptions = useMemo(() => { - const options = [...projectFlockOptions]; + const options = projectFlockOptions.filter((option) => { + if (type !== 'add') return true; + return activeProjectFlockIDs.has(Number(option.value)); + }); if (projectFlockKandangDetail && (type === 'edit' || type === 'detail')) { const currentProjectFlock = projectFlockKandangDetail.project_flock; @@ -773,7 +820,12 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { } return options; - }, [projectFlockOptions, projectFlockKandangDetail, type]); + }, [ + projectFlockOptions, + projectFlockKandangDetail, + type, + activeProjectFlockIDs, + ]); const kandangOptions = useMemo(() => { let options: OptionType[] = []; @@ -881,8 +933,41 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { projectFlockKandangDetail, ]); + const isProductWarehouseBelongsToSelectedProjectFlockKandang = useCallback( + (productWarehouse: ProductWarehouse) => { + if (!selectedProjectFlockKandangId) return false; + + return ( + productWarehouse.project_flock_kandang?.id === + selectedProjectFlockKandangId + ); + }, + [selectedProjectFlockKandangId] + ); + + const scopedStockProductIds = useMemo(() => { + if (!isResponseSuccess(stockProducts) || !selectedProjectFlockKandangId) { + return new Set(); + } + + const data = stockProducts.data as unknown as ProductWarehouse[]; + return new Set( + data + .filter(isProductWarehouseBelongsToSelectedProjectFlockKandang) + .map((product) => product.id) + ); + }, [ + stockProducts, + selectedProjectFlockKandangId, + isProductWarehouseBelongsToSelectedProjectFlockKandang, + ]); + const unifiedStockProducts = useMemo(() => { - const options = [...stockProductOptions]; + const options = selectedProjectFlockKandangId + ? stockProductOptions.filter((option) => + scopedStockProductIds.has(Number(option.value)) + ) + : []; if ( initialValues && @@ -906,19 +991,30 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { } return options; - }, [stockProductOptions, initialValues, type]); + }, [ + stockProductOptions, + initialValues, + type, + selectedProjectFlockKandangId, + scopedStockProductIds, + ]); const depletionProducts = useMemo(() => { const options: OptionType[] = []; - if (isResponseSuccess(depletionProductsData) && selectedKandang) { + if ( + isResponseSuccess(depletionProductsData) && + selectedProjectFlockKandangId + ) { const data = depletionProductsData.data as unknown as ProductWarehouse[]; - data.forEach((product) => { - options.push({ - value: product.id, - label: product.product.name, + data + .filter(isProductWarehouseBelongsToSelectedProjectFlockKandang) + .forEach((product) => { + options.push({ + value: product.id, + label: product.product.name, + }); }); - }); } if (initialValues && initialValues.depletions && type !== 'add') { @@ -941,19 +1037,27 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { } return options; - }, [depletionProductsData, initialValues, type, selectedKandang]); + }, [ + depletionProductsData, + initialValues, + type, + selectedProjectFlockKandangId, + isProductWarehouseBelongsToSelectedProjectFlockKandang, + ]); const eggProducts = useMemo(() => { const options: OptionType[] = []; - if (isResponseSuccess(eggProductsData) && selectedKandang) { + if (isResponseSuccess(eggProductsData) && selectedProjectFlockKandangId) { const data = eggProductsData.data as unknown as ProductWarehouse[]; - data.forEach((product) => { - options.push({ - value: product.id, - label: product.product.name, + data + .filter(isProductWarehouseBelongsToSelectedProjectFlockKandang) + .forEach((product) => { + options.push({ + value: product.id, + label: product.product.name, + }); }); - }); } if (initialValues && initialValues.eggs && type !== 'add') { @@ -973,7 +1077,13 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { } return options; - }, [eggProductsData, initialValues, type, selectedKandang]); + }, [ + eggProductsData, + initialValues, + type, + selectedProjectFlockKandangId, + isProductWarehouseBelongsToSelectedProjectFlockKandang, + ]); // ===== FORMIK SETUP ===== const formikInitialValues = useMemo(() => { @@ -2699,7 +2809,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { color='success' onClick={addStock} className='w-fit' - disabled={!recordingRestriction.canEditStock} + disabled={ + !formik.values.project_flock_kandang_id || + !recordingRestriction.canEditStock + } > Tambah Stok @@ -2841,7 +2954,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ); }} options={getAvailableDepletionProductOptions(idx)} - placeholder='Pilih Kondisi' + placeholder={ + !formik.values.project_flock_kandang_id + ? 'Pilih kandang terlebih dahulu' + : 'Pilih Kondisi' + } isLoading={isLoadingDepletionProducts} onMenuScrollToBottom={loadMoreDepletionProducts} isError={ @@ -2860,6 +2977,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { } isDisabled={ type === 'detail' || + !formik.values.project_flock_kandang_id || !recordingRestriction.canEditDepletion } className={{ @@ -2959,7 +3077,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { color='success' onClick={addDepletion} className='w-fit' - disabled={!recordingRestriction.canEditDepletion} + disabled={ + !formik.values.project_flock_kandang_id || + !recordingRestriction.canEditDepletion + } > Tambah Depletion @@ -3085,7 +3206,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { ); }} options={getAvailableEggProductOptions(idx)} - placeholder='Pilih Kondisi Telur' + placeholder={ + !formik.values.project_flock_kandang_id + ? 'Pilih kandang terlebih dahulu' + : 'Pilih Kondisi Telur' + } isLoading={isLoadingEggProducts} onMenuScrollToBottom={loadMoreEggProducts} isError={ @@ -3102,7 +3227,10 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { idx ).errorMessage } - isDisabled={type === 'detail'} + isDisabled={ + type === 'detail' || + !formik.values.project_flock_kandang_id + } className={{ wrapper: 'w-full min-w-48', }} @@ -3207,6 +3335,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => { color='success' onClick={addEgg} className='w-fit' + disabled={!formik.values.project_flock_kandang_id} > Tambah Telur diff --git a/src/config/constant.ts b/src/config/constant.ts index ca0682b4..99594b65 100644 --- a/src/config/constant.ts +++ b/src/config/constant.ts @@ -555,6 +555,12 @@ export const APPROVAL_WORKFLOWS = { ], }; +export const PROJECT_FLOCK_STATUS = { + PENGAJUAN: APPROVAL_WORKFLOWS.PROJECT_FLOCKS[0].step_name, + AKTIF: APPROVAL_WORKFLOWS.PROJECT_FLOCKS[1].step_name, + SELESAI: APPROVAL_WORKFLOWS.PROJECT_FLOCKS[2].step_name, +} as const; + export const ACCEPTED_FILE_TYPE = { PDF: { 'application/pdf': ['.pdf'], diff --git a/src/types/api/inventory/product-warehouse.d.ts b/src/types/api/inventory/product-warehouse.d.ts index 060be2ab..4fc286c1 100644 --- a/src/types/api/inventory/product-warehouse.d.ts +++ b/src/types/api/inventory/product-warehouse.d.ts @@ -11,6 +11,16 @@ export type BaseProductWarehouse = { quantity: number; product: Product; warehouse: Warehouse; + project_flock_kandang?: { + id: number; + project_flock_id: number; + kandang_id: number; + period: number; + project_flock?: { + id: number; + flock_name: string; + }; + }; week?: number | null; };