refactor(FE): Add depletion product handling in inventory adjustment

forms
This commit is contained in:
rstubryan
2026-03-06 10:52:59 +07:00
parent 667eb41eb2
commit 37bc7a85e5
3 changed files with 126 additions and 37 deletions
@@ -282,6 +282,9 @@ const InventoryAdjustmentTable = () => {
if (recordingOption) {
return recordingOption.label;
}
if (subtypeValue === 'RECORDING_DEPLETION_OUT') {
return 'Recording Depletion';
}
return subtypeValue || '-';
};
@@ -26,6 +26,11 @@ export type InventoryAdjustmentFormSchemaType = {
label: string;
} | null;
product_id: number;
depletion_product: {
value: number;
label: string;
} | null;
depletion_product_id: number;
transaction_type: string;
transaction_subtype: string;
qty: number | string;
@@ -80,6 +85,13 @@ export const InventoryAdjustmentFormSchema: Yup.ObjectSchema<InventoryAdjustment
.min(1, 'Produk wajib diisi!')
.required('Produk wajib diisi!')
.typeError('Produk wajib diisi!'),
depletion_product: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
depletion_product_id: Yup.number()
.default(0)
.typeError('Jenis deplesi harus berupa angka'),
transaction_type: Yup.string()
.min(1, 'Tipe transaksi wajib diisi!')
.oneOf(
@@ -74,6 +74,8 @@ const InventoryAdjustmentForm = ({
useState<OptionType | null>(null);
const [selectedTransactionSubtype, setSelectedTransactionSubtype] =
useState<OptionType | null>(null);
const [selectedDepletionProduct, setSelectedDepletionProduct] =
useState<OptionType | null>(null);
const [selectedProjectFlockLocationId, setSelectedProjectFlockLocationId] =
useState<string>('');
@@ -185,6 +187,15 @@ const InventoryAdjustmentForm = ({
rawData: products,
} = useSelect<Product>(ProductApi.basePath, 'id', 'name', 'search');
const {
setInputValue: setDepletionProductInputValue,
options: depletionProductOptions,
isLoadingOptions: isLoadingDepletionProductOptions,
loadMore: loadMoreDepletionProducts,
} = useSelect<Product>(ProductApi.basePath, 'id', 'name', 'search', {
is_depletion: 'true',
});
const productOptions = useMemo(() => {
if (!isResponseSuccess(products)) return [];
@@ -241,6 +252,8 @@ const InventoryAdjustmentForm = ({
project_flock_kandang_id: 0,
product: null,
product_id: 0,
depletion_product: null,
depletion_product_id: 0,
transaction_type: '',
transaction_subtype: '',
qty: '',
@@ -260,7 +273,10 @@ const InventoryAdjustmentForm = ({
setInventoryAdjustmentFormErrorMessage('');
const payload: CreateInventoryAdjustmentPayload = {
project_flock_kandang_id: values.project_flock_kandang_id,
product_id: values.product_id,
product_id:
values.depletion_product_id > 0
? values.depletion_product_id
: values.product_id,
transaction_subtype: values.transaction_subtype,
qty: Number(values.qty),
price: Number(values.price),
@@ -275,6 +291,8 @@ const InventoryAdjustmentForm = ({
},
});
const { setFieldValue, setFieldTouched, resetForm, setValues } = formik;
const transactionSubtypeOptions = useMemo(() => {
const transactionType = selectedTransactionType?.value;
@@ -321,19 +339,31 @@ const InventoryAdjustmentForm = ({
useEffect(() => {
if (selectedTransactionType?.value === 'RECORDING' && selectedProduct) {
setSelectedTransactionSubtype(null);
formik.setFieldValue('transaction_subtype', '');
setFieldValue('transaction_subtype', '');
}
}, [selectedProduct, selectedTransactionType]);
}, [setFieldValue, selectedProduct, selectedTransactionType]);
const isDepletionProductVisible = useMemo(() => {
return selectedTransactionSubtype?.value === 'RECORDING_DEPLETION_IN';
}, [selectedTransactionSubtype]);
useEffect(() => {
if (!isDepletionProductVisible) {
setSelectedDepletionProduct(null);
setFieldValue('depletion_product', null);
setFieldValue('depletion_product_id', 0);
}
}, [isDepletionProductVisible, setFieldValue]);
// ===== EVENT HANDLERS =====
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
const location = val as OptionType | null;
const locationId = location ? Number(location.value) : 0;
formik.setFieldTouched('location', true);
formik.setFieldValue('location', location);
formik.setFieldTouched('location_id', true);
formik.setFieldValue('location_id', locationId);
setFieldTouched('location', true);
setFieldValue('location', location);
setFieldTouched('location_id', true);
setFieldValue('location_id', locationId);
setSelectedLocation(location);
setSelectedProjectFlock(null);
@@ -348,10 +378,10 @@ const InventoryAdjustmentForm = ({
const projectFlock = val as OptionType | null;
const projectFlockId = Number(projectFlock?.value);
formik.setFieldTouched('project_flock', true);
formik.setFieldValue('project_flock', projectFlock);
formik.setFieldTouched('project_flock_id', true);
formik.setFieldValue('project_flock_id', projectFlockId);
setFieldTouched('project_flock', true);
setFieldValue('project_flock', projectFlock);
setFieldTouched('project_flock_id', true);
setFieldValue('project_flock_id', projectFlockId);
setSelectedProjectFlock(projectFlock);
setSelectedKandang(null);
@@ -362,44 +392,58 @@ const InventoryAdjustmentForm = ({
const kandang = val as OptionType | null;
const kandangId = Number(kandang?.value);
formik.setFieldTouched('kandang', true);
formik.setFieldValue('kandang', kandang);
formik.setFieldTouched('kandang_id', true);
formik.setFieldValue('kandang_id', kandangId);
setFieldTouched('kandang', true);
setFieldValue('kandang', kandang);
setFieldTouched('kandang_id', true);
setFieldValue('kandang_id', kandangId);
setSelectedKandang(kandang);
setSelectedProduct(null);
formik.setFieldTouched('project_flock_kandang', true);
formik.setFieldTouched('project_flock_kandang_id', true);
setFieldTouched('project_flock_kandang', true);
setFieldTouched('project_flock_kandang_id', true);
};
const productChangeHandler = (val: OptionType | OptionType[] | null) => {
const product = val as OptionType | null;
const productId = (product?.value as number) ?? 0;
formik.setFieldTouched('product', true);
formik.setFieldValue('product', product);
formik.setFieldTouched('product_id', true);
formik.setFieldValue('product_id', productId);
setFieldTouched('product', true);
setFieldValue('product', product);
setFieldTouched('product_id', true);
setFieldValue('product_id', productId);
setSelectedProduct(product);
};
const depletionProductChangeHandler = (
val: OptionType | OptionType[] | null
) => {
const depletionProduct = val as OptionType | null;
const depletionProductId = (depletionProduct?.value as number) ?? 0;
setFieldTouched('depletion_product', true);
setFieldValue('depletion_product', depletionProduct);
setFieldTouched('depletion_product_id', true);
setFieldValue('depletion_product_id', depletionProductId);
setSelectedDepletionProduct(depletionProduct);
};
useEffect(() => {
const transactionType = formik.values.transaction_type;
if (!transactionType) {
setSelectedTransactionSubtype(null);
formik.setFieldValue('transaction_subtype', '');
setFieldValue('transaction_subtype', '');
return;
}
setSelectedTransactionSubtype(null);
formik.setFieldValue('transaction_subtype', '');
formik.setFieldTouched('transaction_subtype', true);
setFieldValue('transaction_subtype', '');
setFieldTouched('transaction_subtype', true);
if (transactionType === 'PEMBELIAN') {
formik.setFieldValue(
setFieldValue(
'transaction_subtype',
TRANSACTION_SUBTYPE_OPTIONS.PEMBELIAN.value
);
@@ -408,7 +452,7 @@ const InventoryAdjustmentForm = ({
label: TRANSACTION_SUBTYPE_OPTIONS.PEMBELIAN.label,
});
} else if (transactionType === 'PENJUALAN') {
formik.setFieldValue(
setFieldValue(
'transaction_subtype',
TRANSACTION_SUBTYPE_OPTIONS.PENJUALAN.value
);
@@ -417,7 +461,7 @@ const InventoryAdjustmentForm = ({
label: TRANSACTION_SUBTYPE_OPTIONS.PENJUALAN.label,
});
}
}, [formik.values.transaction_type]);
}, [setFieldTouched, setFieldValue, formik.values.transaction_type]);
const transactionTypeChangeHandler = (
val: OptionType | OptionType[] | null
@@ -425,8 +469,8 @@ const InventoryAdjustmentForm = ({
const typeOption = val as OptionType | null;
const selectedType = typeOption?.value as string;
formik.setFieldValue('transaction_type', selectedType);
formik.setFieldTouched('transaction_type', true);
setFieldValue('transaction_type', selectedType);
setFieldTouched('transaction_type', true);
setSelectedTransactionType(typeOption);
};
@@ -437,20 +481,21 @@ const InventoryAdjustmentForm = ({
const subtypeOption = val as OptionType | null;
const selectedSubtype = subtypeOption?.value as string;
formik.setFieldTouched('transaction_subtype', true);
formik.setFieldValue('transaction_subtype', selectedSubtype);
setFieldTouched('transaction_subtype', true);
setFieldValue('transaction_subtype', selectedSubtype);
setSelectedTransactionSubtype(subtypeOption);
};
const resetHandler = () => {
formik.resetForm();
resetForm();
setSelectedLocation(null);
setSelectedProjectFlock(null);
setSelectedKandang(null);
setSelectedProduct(null);
setSelectedTransactionType(null);
setSelectedTransactionSubtype(null);
setSelectedDepletionProduct(null);
setSelectedProjectFlockLocationId('');
};
@@ -460,14 +505,18 @@ const InventoryAdjustmentForm = ({
projectFlockKandangLookup.project_flock_kandang_id;
if (formik.values.project_flock_kandang_id !== projectFlockKandangId) {
formik.setFieldValue('project_flock_kandang_id', projectFlockKandangId);
formik.setFieldValue('project_flock_kandang', {
setFieldValue('project_flock_kandang_id', projectFlockKandangId);
setFieldValue('project_flock_kandang', {
value: projectFlockKandangId,
label: `${projectFlockKandangLookup.project_flock.flock_name} - ${projectFlockKandangLookup.kandang.name}`,
});
}
}
}, [projectFlockKandangLookup, formik.values.project_flock_kandang_id]);
}, [
projectFlockKandangLookup,
formik.values.project_flock_kandang_id,
setFieldValue,
]);
useEffect(() => {
if (initialValues && type === 'detail') {
@@ -519,7 +568,7 @@ const InventoryAdjustmentForm = ({
});
}
formik.setValues({
setValues({
location: initialValues.location
? {
value: initialValues.location.id,
@@ -550,6 +599,8 @@ const InventoryAdjustmentForm = ({
}
: null,
product_id: initialValues.product_warehouse?.product?.id ?? 0,
depletion_product: null,
depletion_product_id: 0,
transaction_type: transactionType,
transaction_subtype: transactionSubtype,
qty: initialValues.qty ?? '',
@@ -557,7 +608,7 @@ const InventoryAdjustmentForm = ({
notes: initialValues.notes ?? '',
});
}
}, [formik.setValues, initialValues, type]);
}, [setValues, initialValues, type]);
// ===== Formik Error List =====
const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik);
@@ -729,6 +780,29 @@ const InventoryAdjustmentForm = ({
isSearchable
/>
{/* RECORDING_DEPLETION_IN */}
{isDepletionProductVisible && (
<SelectInput
required
label='Jenis Deplesi'
value={selectedDepletionProduct}
onChange={depletionProductChangeHandler}
onInputChange={setDepletionProductInputValue}
options={depletionProductOptions}
onMenuScrollToBottom={loadMoreDepletionProducts}
isLoading={isLoadingDepletionProductOptions}
isError={
formik.touched.depletion_product_id &&
Boolean(formik.errors.depletion_product_id)
}
errorMessage={formik.errors.depletion_product_id as string}
isDisabled={type === 'detail'}
placeholder='Pilih Jenis Deplesi'
isClearable
isSearchable
/>
)}
{/* Number Input Quantity */}
<NumberInput
className={{