diff --git a/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema.ts b/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema.ts index 41284e0c..de9c9eaa 100644 --- a/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema.ts +++ b/src/components/pages/inventory/adjustment/form/InventoryAdjustmentForm.schema.ts @@ -81,11 +81,13 @@ export const InventoryAdjustmentFormSchema: Yup.ObjectSchema { - // State const router = useRouter(); const [ InventoryAdjustmentFormErrorMessage, @@ -60,7 +58,6 @@ const InventoryAdjustmentForm = ({ ] = useState(''); const [quantityLabel, setQuantityLabel] = useState('Kuantitas'); - // Selected States untuk cascading selects const [selectedLocation, setSelectedLocation] = useState( null ); @@ -69,10 +66,16 @@ const InventoryAdjustmentForm = ({ const [selectedKandang, setSelectedKandang] = useState( null ); + const [selectedProduct, setSelectedProduct] = useState( + null + ); + const [selectedTransactionType, setSelectedTransactionType] = + useState(null); + const [selectedTransactionSubtype, setSelectedTransactionSubtype] = + useState(null); const [selectedProjectFlockLocationId, setSelectedProjectFlockLocationId] = useState(''); - // Submit Handler const createInventoryAdjustmentHandler = useCallback( async (payload: CreateInventoryAdjustmentPayload) => { const createInventoryAdjustmentRes = @@ -91,7 +94,6 @@ const InventoryAdjustmentForm = ({ [router] ); - // API Data Fetching const { setInputValue: setLocationInputValue, options: locationOptions, @@ -115,7 +117,6 @@ const InventoryAdjustmentForm = ({ } ); - // Lookup URL untuk mendapatkan project_flock_kandang_id const projectFlockKandangLookupUrl = useMemo(() => { if (!selectedProjectFlock || !selectedKandang) return null; const params = new URLSearchParams({ @@ -140,7 +141,6 @@ const InventoryAdjustmentForm = ({ ? projectFlockKandangLookupData.data : undefined; - // Fetch project_flock_kandang detail untuk edit mode saja (tidak perlu untuk detail) const projectFlockKandangDetailUrl = useMemo(() => { if (type !== 'edit' || !initialValues?.project_flock_kandang_id) return null; @@ -162,7 +162,6 @@ const InventoryAdjustmentForm = ({ ? projectFlockKandangDetailData.data : undefined; - // Fetch approved project flock kandangs untuk filter kandang options const approvedProjectFlockKandangsUrl = useMemo(() => { const params = new URLSearchParams({ step_name: 'Disetujui', @@ -181,7 +180,6 @@ const InventoryAdjustmentForm = ({ return approvedProjectFlockKandangsData.data; }, [approvedProjectFlockKandangsData]); - // Product select dengan filter project_flock_kandang_id - hanya fetch jika project_flock_kandang_id ada const productUrl = useMemo(() => { if (!projectFlockKandangLookup?.project_flock_kandang_id) return null; const params = new URLSearchParams({ @@ -214,7 +212,6 @@ const InventoryAdjustmentForm = ({ // Implementasi load more jika diperlukan }, []); - // Kandang options dari project flock data (filtered by approved status untuk add mode) const kandangOptions = useMemo(() => { let options: OptionType[] = []; @@ -225,14 +222,12 @@ const InventoryAdjustmentForm = ({ ); if (selectedProjectFlockData?.kandangs) { - // Get approved kandang ids untuk project flock yang dipilih const approvedKandangIds = approvedProjectFlockKandangs .filter((pfk) => pfk.project_flock_id === selectedProjectFlock.value) .map((pfk) => pfk.kandang_id); const kandangOptions = selectedProjectFlockData.kandangs .filter((kandang: Kandang) => { - // Untuk add mode, hanya tampilkan kandang yang approved if (type === 'add') { return approvedKandangIds.includes(kandang.id); } @@ -268,7 +263,6 @@ const InventoryAdjustmentForm = ({ approvedProjectFlockKandangs, ]); - // Enhanced options untuk edit/detail const enhancedLocationOptions = useMemo(() => { const options = [...locationOptions]; @@ -307,7 +301,6 @@ const InventoryAdjustmentForm = ({ return options; }, [projectFlockOptions, projectFlockKandangDetail, type]); - // Formik Initial Values const formikInitialValues = useMemo>( () => ({ location: null, @@ -329,11 +322,12 @@ const InventoryAdjustmentForm = ({ [] ); - // Formik const formik = useFormik({ enableReinitialize: false, initialValues: formikInitialValues as InventoryAdjustmentFormValues, validationSchema: InventoryAdjustmentFormSchema, + validateOnChange: true, + validateOnBlur: true, onSubmit: async (values) => { setInventoryAdjustmentFormErrorMessage(''); const payload: CreateInventoryAdjustmentPayload = { @@ -353,26 +347,23 @@ const InventoryAdjustmentForm = ({ }, }); - // Transaction subtype options berdasarkan transaction_type const transactionSubtypeOptions = useMemo(() => { - const transactionType = formik.values.transaction_type; + const transactionType = selectedTransactionType?.value; if (transactionType === 'RECORDING') { return TRANSACTION_SUBTYPE_OPTIONS.RECORDING; } return []; - }, [formik.values.transaction_type]); + }, [selectedTransactionType]); - // Cek apakah subtype readonly (untuk PEMBELIAN/PENJUALAN) const isTransactionSubtypeReadonly = useMemo(() => { - const transactionType = formik.values.transaction_type; + const transactionType = selectedTransactionType?.value; return transactionType === 'PEMBELIAN' || transactionType === 'PENJUALAN'; - }, [formik.values.transaction_type]); + }, [selectedTransactionType]); - // Update quantity label berdasarkan transaction_subtype useEffect(() => { - const subtype = formik.values.transaction_subtype; + const subtype = selectedTransactionSubtype?.value; if ( subtype === 'RECORDING_STOCK_OUT' || subtype === 'RECORDING_DEPLETION_OUT' || @@ -389,9 +380,9 @@ const InventoryAdjustmentForm = ({ } else { setQuantityLabel('Kuantitas'); } - }, [formik.values.transaction_subtype]); + }, [selectedTransactionSubtype]); - // Event Handlers + // ===== EVENT HANDLERS ===== const locationChangeHandler = (val: OptionType | OptionType[] | null) => { const location = val as OptionType | null; const locationId = location ? Number(location.value) : 0; @@ -402,21 +393,12 @@ const InventoryAdjustmentForm = ({ formik.setFieldValue('location_id', locationId); setSelectedLocation(location); + setSelectedProjectFlock(null); + setSelectedKandang(null); + setSelectedProduct(null); setSelectedProjectFlockLocationId( location ? location.value.toString() : '' ); - - // Reset dependent fields - 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.setFieldValue('project_flock_kandang', null); - formik.setFieldValue('project_flock_kandang_id', 0); - formik.setFieldValue('product', null); - formik.setFieldValue('product_id', 0); }; const projectFlockChangeHandler = (val: OptionType | OptionType[] | null) => { @@ -430,14 +412,7 @@ const InventoryAdjustmentForm = ({ setSelectedProjectFlock(projectFlock); setSelectedKandang(null); - - // Reset dependent fields - formik.setFieldValue('kandang', null); - formik.setFieldValue('kandang_id', 0); - formik.setFieldValue('project_flock_kandang', null); - formik.setFieldValue('project_flock_kandang_id', 0); - formik.setFieldValue('product', null); - formik.setFieldValue('product_id', 0); + setSelectedProduct(null); }; const kandangChangeHandler = (val: OptionType | OptionType[] | null) => { @@ -450,52 +425,68 @@ const InventoryAdjustmentForm = ({ formik.setFieldValue('kandang_id', kandangId); setSelectedKandang(kandang); - - // Reset product karena kandang berubah - formik.setFieldValue('product', null); - formik.setFieldValue('product_id', 0); + setSelectedProduct(null); formik.setFieldTouched('project_flock_kandang', true); formik.setFieldTouched('project_flock_kandang_id', true); }; const productChangeHandler = (val: OptionType | OptionType[] | null) => { + const product = val as OptionType | null; + const productId = product?.value ?? 0; + formik.setFieldTouched('product', true); - formik.setFieldValue('product', val); + formik.setFieldValue('product', product); formik.setFieldTouched('product_id', true); - formik.setFieldValue('product_id', (val as OptionType)?.value ?? 0); + formik.setFieldValue('product_id', productId); + + setSelectedProduct(product); }; const transactionTypeChangeHandler = ( val: OptionType | OptionType[] | null ) => { - const selectedType = (val as OptionType)?.value as string; + const typeOption = val as OptionType | null; + const selectedType = typeOption?.value as string; - formik.setFieldTouched('transaction_type', true); formik.setFieldValue('transaction_type', selectedType); + formik.setFieldTouched('transaction_type', true); + + setSelectedTransactionType(typeOption); + setSelectedTransactionSubtype(null); - // Reset transaction_subtype formik.setFieldValue('transaction_subtype', ''); - // Auto-fill transaction_subtype untuk PEMBELIAN dan PENJUALAN if (selectedType === 'PEMBELIAN') { formik.setFieldValue( 'transaction_subtype', TRANSACTION_SUBTYPE_OPTIONS.PEMBELIAN.value ); + setSelectedTransactionSubtype({ + value: TRANSACTION_SUBTYPE_OPTIONS.PEMBELIAN.value, + label: TRANSACTION_SUBTYPE_OPTIONS.PEMBELIAN.label, + }); } else if (selectedType === 'PENJUALAN') { formik.setFieldValue( 'transaction_subtype', TRANSACTION_SUBTYPE_OPTIONS.PENJUALAN.value ); + setSelectedTransactionSubtype({ + value: TRANSACTION_SUBTYPE_OPTIONS.PENJUALAN.value, + label: TRANSACTION_SUBTYPE_OPTIONS.PENJUALAN.label, + }); } }; const transactionSubtypeChangeHandler = ( val: OptionType | OptionType[] | null ) => { - const selectedSubtype = (val as OptionType)?.value as string; - formik.setFieldTouched('transaction_subtype', true); + const subtypeOption = val as OptionType | null; + const selectedSubtype = subtypeOption?.value as string; + formik.setFieldValue('transaction_subtype', selectedSubtype); + formik.setFieldTouched('transaction_subtype', true); + + setSelectedTransactionSubtype(subtypeOption); }; const resetHandler = () => { @@ -504,10 +495,12 @@ const InventoryAdjustmentForm = ({ setSelectedLocation(null); setSelectedProjectFlock(null); setSelectedKandang(null); + setSelectedProduct(null); + setSelectedTransactionType(null); + setSelectedTransactionSubtype(null); setSelectedProjectFlockLocationId(''); }; - // Effect - Set project_flock_kandang_id dari lookup useEffect(() => { if (projectFlockKandangLookup?.project_flock_kandang_id) { const projectFlockKandangId = @@ -523,12 +516,10 @@ const InventoryAdjustmentForm = ({ } }, [projectFlockKandangLookup, formik.values.project_flock_kandang_id]); - // Effect - Set initial values untuk edit mode (dengan projectFlockKandangDetail) useEffect(() => { if (initialValues && type === 'edit') { const transactionSubtype = initialValues.transaction_subtype; - // Determine transaction_type dari transaction_subtype let transactionType = ''; if (transactionSubtype === 'PURCHASE_IN') { transactionType = 'PEMBELIAN'; @@ -538,7 +529,6 @@ const InventoryAdjustmentForm = ({ transactionType = 'RECORDING'; } - // Set lokasi if (initialValues.location) { const locationOption = { value: initialValues.location.id, @@ -548,7 +538,6 @@ const InventoryAdjustmentForm = ({ setSelectedProjectFlockLocationId(initialValues.location.id.toString()); } - // Set project flock if (initialValues.project_flock) { const projectFlockOption = { value: initialValues.project_flock.id, @@ -557,7 +546,6 @@ const InventoryAdjustmentForm = ({ setSelectedProjectFlock(projectFlockOption); } - // Set kandang dari project_flock_kandang jika ada (hanya untuk edit mode) if (projectFlockKandangDetail) { const kandangOption = { value: projectFlockKandangDetail.kandang.id, @@ -566,6 +554,43 @@ const InventoryAdjustmentForm = ({ setSelectedKandang(kandangOption); } + if (initialValues.product_warehouse?.product) { + const productOption = { + value: initialValues.product_warehouse.product.id, + label: initialValues.product_warehouse.product.name, + }; + setSelectedProduct(productOption); + } + + if (transactionType) { + const typeOption = { + value: transactionType, + label: + TRANSACTION_TYPE_OPTIONS.find( + (opt) => opt.value === transactionType + )?.label || '', + }; + setSelectedTransactionType(typeOption); + } + + if (transactionSubtype) { + let subtypeLabel = ''; + if (transactionSubtype === 'PURCHASE_IN') { + subtypeLabel = TRANSACTION_SUBTYPE_OPTIONS.PEMBELIAN.label; + } else if (transactionSubtype === 'MARKETING_OUT') { + subtypeLabel = TRANSACTION_SUBTYPE_OPTIONS.PENJUALAN.label; + } else { + subtypeLabel = + TRANSACTION_SUBTYPE_OPTIONS.RECORDING.find( + (opt) => opt.value === transactionSubtype + )?.label || ''; + } + setSelectedTransactionSubtype({ + value: transactionSubtype, + label: subtypeLabel, + }); + } + formik.setValues({ location: initialValues.location ? { @@ -611,12 +636,10 @@ const InventoryAdjustmentForm = ({ } }, [formik.setValues, initialValues, projectFlockKandangDetail, type]); - // Effect - Set initial values untuk detail mode (tanpa projectFlockKandangDetail) useEffect(() => { if (initialValues && type === 'detail') { const transactionSubtype = initialValues.transaction_subtype; - // Determine transaction_type dari transaction_subtype let transactionType = ''; if (transactionSubtype === 'PURCHASE_IN') { transactionType = 'PEMBELIAN'; @@ -626,6 +649,43 @@ const InventoryAdjustmentForm = ({ transactionType = 'RECORDING'; } + if (initialValues.product_warehouse?.product) { + const productOption = { + value: initialValues.product_warehouse.product.id, + label: initialValues.product_warehouse.product.name, + }; + setSelectedProduct(productOption); + } + + if (transactionType) { + const typeOption = { + value: transactionType, + label: + TRANSACTION_TYPE_OPTIONS.find( + (opt) => opt.value === transactionType + )?.label || '', + }; + setSelectedTransactionType(typeOption); + } + + if (transactionSubtype) { + let subtypeLabel = ''; + if (transactionSubtype === 'PURCHASE_IN') { + subtypeLabel = TRANSACTION_SUBTYPE_OPTIONS.PEMBELIAN.label; + } else if (transactionSubtype === 'MARKETING_OUT') { + subtypeLabel = TRANSACTION_SUBTYPE_OPTIONS.PENJUALAN.label; + } else { + subtypeLabel = + TRANSACTION_SUBTYPE_OPTIONS.RECORDING.find( + (opt) => opt.value === transactionSubtype + )?.label || ''; + } + setSelectedTransactionSubtype({ + value: transactionSubtype, + label: subtypeLabel, + }); + } + formik.setValues({ location: initialValues.location ? { @@ -641,7 +701,7 @@ const InventoryAdjustmentForm = ({ } : null, project_flock_id: initialValues.project_flock?.id ?? 0, - kandang: null, // Tidak perlu kandang untuk detail mode + kandang: null, kandang_id: 0, project_flock_kandang: initialValues.project_flock_kandang_id ? { @@ -699,7 +759,7 @@ const InventoryAdjustmentForm = ({ {/* Select Input Project Flock */} {/* Select Input Kandang */} {/* Select Input Product */} {/* Select Input Transaction Type */} opt.value === formik.values.transaction_type - )?.label || '', - } - : null - } + value={selectedTransactionType} onChange={transactionTypeChangeHandler} options={TRANSACTION_TYPE_OPTIONS} isError={ @@ -795,29 +860,14 @@ const InventoryAdjustmentForm = ({ isDisabled={type === 'detail'} placeholder='Pilih Tipe Transaksi' isClearable + isSearchable /> {/* Select Input Transaction Subtype */} - opt.value === - formik.values.transaction_subtype - )?.label || '', - } - : null - } + value={selectedTransactionSubtype} onChange={transactionSubtypeChangeHandler} options={transactionSubtypeOptions} isError={ @@ -828,22 +878,23 @@ const InventoryAdjustmentForm = ({ isDisabled={ type === 'detail' || isTransactionSubtypeReadonly || - formik.values.transaction_type === '' + !selectedTransactionType } placeholder={ - formik.values.transaction_type === '' + !selectedTransactionType ? 'Pilih Tipe Transaksi terlebih dahulu' : isTransactionSubtypeReadonly ? 'Otomatis terisi' : 'Pilih Sub Tipe Transaksi' } isClearable + isSearchable /> {/* Number Input Quantity */}