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