mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-208,212): enhance PurchaseRequestForm with location and warehouse handling, update validation and reset logic for dependent fields
This commit is contained in:
@@ -164,12 +164,7 @@ const PurchaseRequestForm = ({
|
|||||||
isLoadingOptions: isLoadingAreas,
|
isLoadingOptions: isLoadingAreas,
|
||||||
} = useSelect(AreaApi.basePath, 'id', 'name', 'search');
|
} = useSelect(AreaApi.basePath, 'id', 'name', 'search');
|
||||||
|
|
||||||
const {
|
const [locationSelectInputValue, setLocationSelectInputValue] = useState('');
|
||||||
inputValue: locationSelectInputValue,
|
|
||||||
setInputValue: setLocationSelectInputValue,
|
|
||||||
options: locationOptions,
|
|
||||||
isLoadingOptions: isLoadingLocations,
|
|
||||||
} = useSelect(LocationApi.basePath, 'id', 'name', 'search');
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
inputValue: warehouseSelectInputValue,
|
inputValue: warehouseSelectInputValue,
|
||||||
@@ -177,34 +172,12 @@ const PurchaseRequestForm = ({
|
|||||||
isLoadingOptions: isLoadingWarehouses,
|
isLoadingOptions: isLoadingWarehouses,
|
||||||
} = useSelect(WarehouseApi.basePath, 'id', 'name', 'search');
|
} = useSelect(WarehouseApi.basePath, 'id', 'name', 'search');
|
||||||
|
|
||||||
const warehousesUrl = `${WarehouseApi.basePath}?${new URLSearchParams({ search: warehouseSelectInputValue }).toString()}`;
|
|
||||||
const { data: warehouses } = useSWR(
|
|
||||||
warehousesUrl,
|
|
||||||
WarehouseApi.getAllFetcher
|
|
||||||
);
|
|
||||||
|
|
||||||
// ===== DATA PROCESSING =====
|
|
||||||
const warehouseOptions = useMemo(() => {
|
|
||||||
if (!isResponseSuccess(warehouses)) return [];
|
|
||||||
|
|
||||||
return (
|
|
||||||
warehouses?.data.map((w) => ({
|
|
||||||
value: w.id,
|
|
||||||
label: w.name,
|
|
||||||
area: w.area?.name,
|
|
||||||
location:
|
|
||||||
'type' in w && (w.type === 'LOKASI' || w.type === 'KANDANG')
|
|
||||||
? w.location?.name
|
|
||||||
: undefined,
|
|
||||||
})) || []
|
|
||||||
);
|
|
||||||
}, [warehouses]);
|
|
||||||
|
|
||||||
// ===== PRODUCT WAREHOUSE FETCHING =====
|
// ===== PRODUCT WAREHOUSE FETCHING =====
|
||||||
const getProductWarehousesUrl = useCallback(() => {
|
const getProductWarehousesUrl = useCallback(() => {
|
||||||
const productWarehouseParams = new URLSearchParams({
|
const productWarehouseParams = new URLSearchParams({
|
||||||
search: productWarehouseSelectInputValue,
|
search: productWarehouseSelectInputValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
return `${ProductWarehouseApi.basePath}?${productWarehouseParams.toString()}`;
|
return `${ProductWarehouseApi.basePath}?${productWarehouseParams.toString()}`;
|
||||||
}, [productWarehouseSelectInputValue]);
|
}, [productWarehouseSelectInputValue]);
|
||||||
|
|
||||||
@@ -212,6 +185,33 @@ const PurchaseRequestForm = ({
|
|||||||
const { data: productWarehouses, isLoading: isLoadingProductWarehouses } =
|
const { data: productWarehouses, isLoading: isLoadingProductWarehouses } =
|
||||||
useSWR(productWarehousesUrl, ProductWarehouseApi.getAllFetcher);
|
useSWR(productWarehousesUrl, ProductWarehouseApi.getAllFetcher);
|
||||||
|
|
||||||
|
// Filter product warehouses per item based on selected warehouse
|
||||||
|
const getProductWarehouseOptionsForItem = useCallback(
|
||||||
|
(warehouseId: number | string) => {
|
||||||
|
if (!isResponseSuccess(productWarehouses)) return [];
|
||||||
|
|
||||||
|
const warehouseIdNum =
|
||||||
|
typeof warehouseId === 'string'
|
||||||
|
? parseInt(warehouseId) || 0
|
||||||
|
: warehouseId;
|
||||||
|
if (warehouseIdNum === 0) return [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
productWarehouses?.data
|
||||||
|
.filter((pw) => pw.warehouse.id === warehouseIdNum)
|
||||||
|
.map((pw) => ({
|
||||||
|
value: pw.product.id,
|
||||||
|
label: pw.product.name,
|
||||||
|
product_id: pw.product.id,
|
||||||
|
warehouse_id: pw.warehouse.id,
|
||||||
|
warehouse_name: pw.warehouse.name,
|
||||||
|
quantity: pw.quantity,
|
||||||
|
})) || []
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[productWarehouses]
|
||||||
|
);
|
||||||
|
|
||||||
const productWarehouseOptions = isResponseSuccess(productWarehouses)
|
const productWarehouseOptions = isResponseSuccess(productWarehouses)
|
||||||
? productWarehouses?.data.map((pw) => ({
|
? productWarehouses?.data.map((pw) => ({
|
||||||
value: pw.product.id,
|
value: pw.product.id,
|
||||||
@@ -281,6 +281,71 @@ const PurchaseRequestForm = ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ===== API DATA FETCHING =====
|
||||||
|
const locationsUrl = useMemo(() => {
|
||||||
|
const params = new URLSearchParams({
|
||||||
|
search: locationSelectInputValue,
|
||||||
|
...(formik.values.area_id && formik.values.area_id > 0
|
||||||
|
? { area_id: formik.values.area_id.toString() }
|
||||||
|
: {}),
|
||||||
|
});
|
||||||
|
return `${LocationApi.basePath}?${params.toString()}`;
|
||||||
|
}, [locationSelectInputValue, formik.values.area_id]);
|
||||||
|
|
||||||
|
const { data: locations, isLoading: isLoadingLocations } = useSWR(
|
||||||
|
locationsUrl,
|
||||||
|
LocationApi.getAllFetcher
|
||||||
|
);
|
||||||
|
|
||||||
|
const locationOptions = useMemo(() => {
|
||||||
|
if (!isResponseSuccess(locations)) return [];
|
||||||
|
return (
|
||||||
|
locations?.data.map((location) => ({
|
||||||
|
value: location.id,
|
||||||
|
label: location.name,
|
||||||
|
})) || []
|
||||||
|
);
|
||||||
|
}, [locations]);
|
||||||
|
|
||||||
|
const warehousesUrl = useMemo(() => {
|
||||||
|
const params = new URLSearchParams({ search: warehouseSelectInputValue });
|
||||||
|
|
||||||
|
if (formik.values.area_id && formik.values.area_id > 0) {
|
||||||
|
params.append('area_id', formik.values.area_id.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formik.values.location_id && formik.values.location_id > 0) {
|
||||||
|
params.append('location_id', formik.values.location_id.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${WarehouseApi.basePath}?${params.toString()}`;
|
||||||
|
}, [
|
||||||
|
warehouseSelectInputValue,
|
||||||
|
formik.values.area_id,
|
||||||
|
formik.values.location_id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const { data: warehouses } = useSWR(
|
||||||
|
warehousesUrl,
|
||||||
|
WarehouseApi.getAllFetcher
|
||||||
|
);
|
||||||
|
|
||||||
|
const warehouseOptions = useMemo(() => {
|
||||||
|
if (!isResponseSuccess(warehouses)) return [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
warehouses?.data.map((w) => ({
|
||||||
|
value: w.id,
|
||||||
|
label: w.name,
|
||||||
|
area: w.area?.name,
|
||||||
|
location:
|
||||||
|
'type' in w && (w.type === 'LOKASI' || w.type === 'KANDANG')
|
||||||
|
? w.location?.name
|
||||||
|
: undefined,
|
||||||
|
})) || []
|
||||||
|
);
|
||||||
|
}, [warehouses]);
|
||||||
|
|
||||||
// ===== EVENT HANDLERS =====
|
// ===== EVENT HANDLERS =====
|
||||||
const supplierChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const supplierChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
const supplier = val as OptionType | null;
|
const supplier = val as OptionType | null;
|
||||||
@@ -296,6 +361,25 @@ const PurchaseRequestForm = ({
|
|||||||
formik.setFieldValue('area', area);
|
formik.setFieldValue('area', area);
|
||||||
formik.setFieldTouched('area_id', true);
|
formik.setFieldTouched('area_id', true);
|
||||||
formik.setFieldValue('area_id', (area as OptionType)?.value || 0);
|
formik.setFieldValue('area_id', (area as OptionType)?.value || 0);
|
||||||
|
|
||||||
|
// Reset area dependent fields
|
||||||
|
formik.setFieldValue('location', null);
|
||||||
|
formik.setFieldValue('location_id', 0);
|
||||||
|
setLocationSelectInputValue('');
|
||||||
|
|
||||||
|
// Reset area dependent fields in all purchase items
|
||||||
|
if (formik.values.purchase_items) {
|
||||||
|
formik.values.purchase_items.forEach((_, idx) => {
|
||||||
|
formik.setFieldValue(`purchase_items.${idx}.warehouse`, null);
|
||||||
|
formik.setFieldValue(`purchase_items.${idx}.warehouse_id`, '');
|
||||||
|
formik.setFieldValue(`purchase_items.${idx}.product_warehouse`, null);
|
||||||
|
formik.setFieldValue(
|
||||||
|
`purchase_items.${idx}.product_warehouse_id`,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
formik.setFieldValue(`purchase_items.${idx}.product_id`, '');
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||||
@@ -304,6 +388,20 @@ const PurchaseRequestForm = ({
|
|||||||
formik.setFieldValue('location', location);
|
formik.setFieldValue('location', location);
|
||||||
formik.setFieldTouched('location_id', true);
|
formik.setFieldTouched('location_id', true);
|
||||||
formik.setFieldValue('location_id', (location as OptionType)?.value || 0);
|
formik.setFieldValue('location_id', (location as OptionType)?.value || 0);
|
||||||
|
|
||||||
|
// Reset location dependent fields in all purchase items
|
||||||
|
if (formik.values.purchase_items) {
|
||||||
|
formik.values.purchase_items.forEach((_, idx) => {
|
||||||
|
formik.setFieldValue(`purchase_items.${idx}.warehouse`, null);
|
||||||
|
formik.setFieldValue(`purchase_items.${idx}.warehouse_id`, '');
|
||||||
|
formik.setFieldValue(`purchase_items.${idx}.product_warehouse`, null);
|
||||||
|
formik.setFieldValue(
|
||||||
|
`purchase_items.${idx}.product_warehouse_id`,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
formik.setFieldValue(`purchase_items.${idx}.product_id`, '');
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Purchase Items Handlers
|
// Purchase Items Handlers
|
||||||
@@ -455,7 +553,11 @@ const PurchaseRequestForm = ({
|
|||||||
<SelectInput
|
<SelectInput
|
||||||
required
|
required
|
||||||
label='Lokasi'
|
label='Lokasi'
|
||||||
placeholder='Pilih Lokasi...'
|
placeholder={
|
||||||
|
!formik.values.area_id
|
||||||
|
? 'Pilih Area terlebih dahulu'
|
||||||
|
: 'Pilih Lokasi...'
|
||||||
|
}
|
||||||
value={formik.values.location}
|
value={formik.values.location}
|
||||||
onChange={locationChangeHandler}
|
onChange={locationChangeHandler}
|
||||||
options={locationOptions}
|
options={locationOptions}
|
||||||
@@ -466,8 +568,8 @@ const PurchaseRequestForm = ({
|
|||||||
Boolean(formik.errors.location_id)
|
Boolean(formik.errors.location_id)
|
||||||
}
|
}
|
||||||
errorMessage={formik.errors.location_id as string}
|
errorMessage={formik.errors.location_id as string}
|
||||||
isDisabled={type === 'detail'}
|
isDisabled={type === 'detail' || !formik.values.area_id}
|
||||||
isClearable
|
isClearable={type !== 'detail' && !!formik.values.area_id}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={type === 'detail' ? 'col-span-1' : 'col-span-2'}>
|
<div className={type === 'detail' ? 'col-span-1' : 'col-span-2'}>
|
||||||
@@ -577,6 +679,18 @@ const PurchaseRequestForm = ({
|
|||||||
`purchase_items.${idx}.warehouse_id`,
|
`purchase_items.${idx}.warehouse_id`,
|
||||||
(warehouse as OptionType)?.value || 0
|
(warehouse as OptionType)?.value || 0
|
||||||
);
|
);
|
||||||
|
formik.setFieldValue(
|
||||||
|
`purchase_items.${idx}.product_warehouse`,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
formik.setFieldValue(
|
||||||
|
`purchase_items.${idx}.product_warehouse_id`,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
formik.setFieldValue(
|
||||||
|
`purchase_items.${idx}.product_id`,
|
||||||
|
''
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
options={warehouseOptions}
|
options={warehouseOptions}
|
||||||
onInputChange={setWarehouseSelectInputValue}
|
onInputChange={setWarehouseSelectInputValue}
|
||||||
@@ -618,7 +732,9 @@ const PurchaseRequestForm = ({
|
|||||||
?.product_id || 0
|
?.product_id || 0
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
options={productWarehouseOptions}
|
options={getProductWarehouseOptionsForItem(
|
||||||
|
item.warehouse_id
|
||||||
|
)}
|
||||||
onInputChange={setProductWarehouseSelectInputValue}
|
onInputChange={setProductWarehouseSelectInputValue}
|
||||||
isLoading={isLoadingProductWarehouses}
|
isLoading={isLoadingProductWarehouses}
|
||||||
isError={
|
isError={
|
||||||
@@ -629,9 +745,13 @@ const PurchaseRequestForm = ({
|
|||||||
getPurchaseItemError(idx, 'product_warehouse_id')
|
getPurchaseItemError(idx, 'product_warehouse_id')
|
||||||
.errorMessage
|
.errorMessage
|
||||||
}
|
}
|
||||||
isDisabled={type === 'detail'}
|
isDisabled={type === 'detail' || !item.warehouse_id}
|
||||||
isClearable
|
isClearable={type !== 'detail' && !!item.warehouse_id}
|
||||||
placeholder='Pilih Produk'
|
placeholder={
|
||||||
|
!item.warehouse_id
|
||||||
|
? 'Pilih Gudang terlebih dahulu'
|
||||||
|
: 'Pilih Produk'
|
||||||
|
}
|
||||||
className={{
|
className={{
|
||||||
wrapper: 'min-w-32',
|
wrapper: 'min-w-32',
|
||||||
}}
|
}}
|
||||||
|
|||||||
Reference in New Issue
Block a user