mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 05:22:02 +00:00
refactor(FE-208,212): streamline PurchaseRequestForm structure, enhance state management, and improve field handling for purchase items
This commit is contained in:
@@ -52,19 +52,16 @@ const PurchaseRequestForm = ({
|
||||
}: PurchaseRequestFormProps) => {
|
||||
const router = useRouter();
|
||||
const deleteModal = useModal();
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
|
||||
const [locationSelectInputValue, setLocationSelectInputValue] = useState('');
|
||||
const [selectedPurchaseItems, setSelectedPurchaseItems] = useState<number[]>(
|
||||
[]
|
||||
);
|
||||
const [purchaseRequestFormErrorMessage, setPurchaseRequestFormErrorMessage] =
|
||||
useState('');
|
||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||
const [
|
||||
productWarehouseSelectInputValue,
|
||||
setProductWarehouseSelectInputValue,
|
||||
] = useState('');
|
||||
|
||||
// ===== INTERFACES =====
|
||||
// ===== TYPE DEFINITIONS =====
|
||||
interface ProductWarehouseOptionType extends OptionType {
|
||||
product_id: number;
|
||||
warehouse_id: number;
|
||||
@@ -72,7 +69,7 @@ const PurchaseRequestForm = ({
|
||||
quantity: number;
|
||||
}
|
||||
|
||||
// ===== HELPER FUNCTIONS =====
|
||||
// ===== UTILITY FUNCTIONS =====
|
||||
const getPurchaseItemError = (
|
||||
idx: number,
|
||||
field: 'warehouse_id' | 'product_warehouse_id' | 'product_id' | 'sub_qty'
|
||||
@@ -104,7 +101,7 @@ const PurchaseRequestForm = ({
|
||||
);
|
||||
};
|
||||
|
||||
// ===== FORM HANDLERS =====
|
||||
// ===== SUBMISSION HANDLERS =====
|
||||
const createPurchaseRequestHandler = useCallback(
|
||||
async (payload: CreatePurchaseRequestPayload) => {
|
||||
const res = await PurchaseApi.create(payload);
|
||||
@@ -150,14 +147,7 @@ const PurchaseRequestForm = ({
|
||||
router.push('/purchase');
|
||||
}, [deleteModal, initialValues?.id, router]);
|
||||
|
||||
// ===== API DATA FETCHING =====
|
||||
const allProductWarehousesUrl = `${ProductWarehouseApi.basePath}`;
|
||||
const { data: allProductWarehouses } = useSWR(
|
||||
allProductWarehousesUrl,
|
||||
ProductWarehouseApi.getAllFetcher
|
||||
);
|
||||
|
||||
// ===== USE SELECT HOOKS =====
|
||||
// ===== SELECT INPUT DATA =====
|
||||
const {
|
||||
inputValue: supplierSelectInputValue,
|
||||
setInputValue: setSupplierSelectInputValue,
|
||||
@@ -173,65 +163,13 @@ const PurchaseRequestForm = ({
|
||||
isLoadingOptions: isLoadingAreas,
|
||||
} = useSelect(AreaApi.basePath, 'id', 'name', 'search');
|
||||
|
||||
const [locationSelectInputValue, setLocationSelectInputValue] = useState('');
|
||||
|
||||
const {
|
||||
inputValue: warehouseSelectInputValue,
|
||||
setInputValue: setWarehouseSelectInputValue,
|
||||
isLoadingOptions: isLoadingWarehouses,
|
||||
} = useSelect(WarehouseApi.basePath, 'id', 'name', 'search');
|
||||
|
||||
// ===== PRODUCT WAREHOUSE FETCHING =====
|
||||
const getProductWarehousesUrl = useCallback(() => {
|
||||
const productWarehouseParams = new URLSearchParams({
|
||||
search: productWarehouseSelectInputValue,
|
||||
});
|
||||
|
||||
return `${ProductWarehouseApi.basePath}?${productWarehouseParams.toString()}`;
|
||||
}, [productWarehouseSelectInputValue]);
|
||||
|
||||
const productWarehousesUrl = getProductWarehousesUrl();
|
||||
const { data: productWarehouses, isLoading: isLoadingProductWarehouses } =
|
||||
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)
|
||||
? productWarehouses?.data.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,
|
||||
}))
|
||||
: [];
|
||||
|
||||
// ===== FORM CONFIGURATION =====
|
||||
const formikInitialValues = useMemo<PurchaseRequestFormValues>(
|
||||
() => getPurchaseRequestFormInitialValues(initialValues),
|
||||
[initialValues]
|
||||
@@ -290,7 +228,37 @@ const PurchaseRequestForm = ({
|
||||
},
|
||||
});
|
||||
|
||||
// ===== PRODUCT DATA FETCHING =====
|
||||
// ===== API DATA FETCHING =====
|
||||
const allProductWarehousesUrl = `${ProductWarehouseApi.basePath}`;
|
||||
const { data: productWarehouses, isLoading: isLoadingProductWarehouses } =
|
||||
useSWR(allProductWarehousesUrl, ProductWarehouseApi.getAllFetcher);
|
||||
|
||||
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 productUrl = useMemo(() => {
|
||||
const productIds =
|
||||
formik.values.purchase_items
|
||||
@@ -320,8 +288,6 @@ const PurchaseRequestForm = ({
|
||||
});
|
||||
return data;
|
||||
}, [productsResponse]);
|
||||
|
||||
// ===== API DATA FETCHING =====
|
||||
const locationsUrl = useMemo(() => {
|
||||
const params = new URLSearchParams({
|
||||
search: locationSelectInputValue,
|
||||
@@ -386,7 +352,7 @@ const PurchaseRequestForm = ({
|
||||
);
|
||||
}, [warehouses]);
|
||||
|
||||
// ===== EVENT HANDLERS =====
|
||||
// ===== FIELD CHANGE HANDLERS =====
|
||||
const supplierChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
const supplier = val as OptionType | null;
|
||||
formik.setFieldTouched('supplier', true);
|
||||
@@ -494,28 +460,19 @@ const PurchaseRequestForm = ({
|
||||
setSelectedPurchaseItems([]);
|
||||
};
|
||||
|
||||
// ===== PURCHASE ITEM OPERATIONS =====
|
||||
const handlePurchaseItemChange = (
|
||||
idx: number,
|
||||
field: string,
|
||||
field: 'sub_qty' | 'price',
|
||||
value: string | number
|
||||
) => {
|
||||
const integerFields = [
|
||||
'warehouse_id',
|
||||
'product_id',
|
||||
'product_warehouse_id',
|
||||
'total_qty',
|
||||
];
|
||||
const floatFields = ['price', 'sub_qty'];
|
||||
|
||||
if (integerFields.includes(field)) {
|
||||
if (field === 'sub_qty') {
|
||||
const numValue = typeof value === 'string' ? parseInt(value) || 0 : value;
|
||||
formik.setFieldValue(`purchase_items.${idx}.${field}`, numValue);
|
||||
} else if (floatFields.includes(field)) {
|
||||
formik.setFieldValue(`purchase_items.${idx}.sub_qty`, numValue);
|
||||
} else if (field === 'price') {
|
||||
const numValue =
|
||||
typeof value === 'string' ? parseFloat(value) || 0 : value;
|
||||
formik.setFieldValue(`purchase_items.${idx}.${field}`, numValue);
|
||||
} else {
|
||||
formik.setFieldValue(`purchase_items.${idx}.${field}`, value);
|
||||
formik.setFieldValue(`purchase_items.${idx}.price`, numValue);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -731,6 +688,7 @@ const PurchaseRequestForm = ({
|
||||
<SelectInput
|
||||
required
|
||||
value={item.warehouse}
|
||||
key={`warehouse-${idx}`}
|
||||
onChange={(val) => {
|
||||
const warehouse = val as OptionType | null;
|
||||
formik.setFieldValue(
|
||||
@@ -741,17 +699,29 @@ const PurchaseRequestForm = ({
|
||||
`purchase_items.${idx}.warehouse_id`,
|
||||
(warehouse as OptionType)?.value || 0
|
||||
);
|
||||
formik.setFieldTouched(
|
||||
`purchase_items.${idx}.product_warehouse`,
|
||||
false
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`purchase_items.${idx}.product_warehouse`,
|
||||
null
|
||||
);
|
||||
formik.setFieldTouched(
|
||||
`purchase_items.${idx}.product_warehouse_id`,
|
||||
false
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`purchase_items.${idx}.product_warehouse_id`,
|
||||
null
|
||||
0
|
||||
);
|
||||
formik.setFieldTouched(
|
||||
`purchase_items.${idx}.product_id`,
|
||||
false
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`purchase_items.${idx}.product_id`,
|
||||
''
|
||||
0
|
||||
);
|
||||
}}
|
||||
options={warehouseOptions}
|
||||
@@ -776,6 +746,7 @@ const PurchaseRequestForm = ({
|
||||
<SelectInput
|
||||
required
|
||||
value={item.product_warehouse}
|
||||
key={`product-warehouse-${idx}-${item.warehouse_id}`}
|
||||
onChange={(val) => {
|
||||
const productWarehouse =
|
||||
val as ProductWarehouseOptionType | null;
|
||||
@@ -799,7 +770,6 @@ const PurchaseRequestForm = ({
|
||||
options={getProductWarehouseOptionsForItem(
|
||||
item.warehouse_id
|
||||
)}
|
||||
onInputChange={setProductWarehouseSelectInputValue}
|
||||
isLoading={isLoadingProductWarehouses}
|
||||
isError={
|
||||
getPurchaseItemError(idx, 'product_warehouse_id')
|
||||
|
||||
Reference in New Issue
Block a user