mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-63,63,65): enhance MovementForm to fetch and display product details from ProductWarehouse
This commit is contained in:
@@ -119,43 +119,61 @@ export type MovementFormValues = Yup.InferType<typeof MovementFormSchema>;
|
||||
|
||||
export const getMovementFormInitialValues = (
|
||||
initialValues?: Movement
|
||||
): MovementFormValues => ({
|
||||
transfer_reason: initialValues?.transfer_reason ?? '',
|
||||
transfer_date: initialValues?.transfer_date ?? '',
|
||||
source_warehouse: initialValues?.source_warehouse
|
||||
? {
|
||||
value: initialValues.source_warehouse.id,
|
||||
label: initialValues.source_warehouse.name,
|
||||
}
|
||||
: null,
|
||||
source_warehouse_id: initialValues?.source_warehouse?.id ?? 0,
|
||||
destination_warehouse: initialValues?.destination_warehouse
|
||||
? {
|
||||
value: initialValues.destination_warehouse.id,
|
||||
label: initialValues.destination_warehouse.name,
|
||||
}
|
||||
: null,
|
||||
destination_warehouse_id: initialValues?.destination_warehouse?.id ?? 0,
|
||||
products:
|
||||
initialValues?.details?.map((p) => ({
|
||||
product: { value: p.product_id, label: '' },
|
||||
product_id: p.product_id,
|
||||
product_qty: p.quantity,
|
||||
})) ?? [],
|
||||
deliveries:
|
||||
initialValues?.deliveries?.map((d) => ({
|
||||
delivery_cost: d.shipping_cost_total,
|
||||
delivery_cost_per_item: d.shipping_cost_item,
|
||||
document_index: 0,
|
||||
document: d.document_path || null,
|
||||
driver_name: d.driver_name,
|
||||
vehicle_plate: d.vehicle_plate,
|
||||
supplier: { value: d.supplier.id, label: d.supplier.name },
|
||||
supplier_id: d.supplier_id,
|
||||
products: d.items.map((p) => ({
|
||||
product: { value: 0, label: '' },
|
||||
product_id: 0,
|
||||
): MovementFormValues => {
|
||||
const detailIdToProductId = new Map<number, number>();
|
||||
initialValues?.details?.forEach((detail) => {
|
||||
detailIdToProductId.set(detail.id, detail.product_id);
|
||||
});
|
||||
|
||||
return {
|
||||
transfer_reason: initialValues?.transfer_reason ?? '',
|
||||
transfer_date: initialValues?.transfer_date ?? '',
|
||||
source_warehouse: initialValues?.source_warehouse
|
||||
? {
|
||||
value: initialValues.source_warehouse.id,
|
||||
label: initialValues.source_warehouse.name,
|
||||
}
|
||||
: null,
|
||||
source_warehouse_id: initialValues?.source_warehouse?.id ?? 0,
|
||||
destination_warehouse: initialValues?.destination_warehouse
|
||||
? {
|
||||
value: initialValues.destination_warehouse.id,
|
||||
label: initialValues.destination_warehouse.name,
|
||||
}
|
||||
: null,
|
||||
destination_warehouse_id: initialValues?.destination_warehouse?.id ?? 0,
|
||||
products:
|
||||
initialValues?.details?.map((p) => ({
|
||||
product: { value: p.product_id, label: `Product ID: ${p.product_id}` },
|
||||
product_id: p.product_id,
|
||||
product_qty: p.quantity,
|
||||
})),
|
||||
})) ?? [],
|
||||
});
|
||||
})) ?? [],
|
||||
deliveries:
|
||||
initialValues?.deliveries?.map((d) => {
|
||||
return {
|
||||
delivery_cost: d.shipping_cost_total,
|
||||
delivery_cost_per_item: d.shipping_cost_item,
|
||||
document_index: 0,
|
||||
document: d.document_path || null,
|
||||
driver_name: d.driver_name,
|
||||
vehicle_plate: d.vehicle_plate,
|
||||
supplier: d.supplier
|
||||
? { value: d.supplier.id, label: d.supplier.name }
|
||||
: null,
|
||||
supplier_id: d.supplier_id,
|
||||
products: d.items.map((item) => {
|
||||
const productId =
|
||||
detailIdToProductId.get(item.stock_transfer_detail_id) ?? 0;
|
||||
return {
|
||||
product:
|
||||
productId > 0
|
||||
? { value: productId, label: `Product ID: ${productId}` }
|
||||
: null,
|
||||
product_id: productId,
|
||||
product_qty: item.quantity,
|
||||
};
|
||||
}),
|
||||
};
|
||||
}) ?? [],
|
||||
};
|
||||
};
|
||||
|
||||
@@ -25,7 +25,11 @@ import {
|
||||
DeliverySchema,
|
||||
} from '@/components/pages/inventory/movement/form/MovementForm.schema';
|
||||
import { useMovementFormHandlers } from './useMovementFormHandlers';
|
||||
import { SupplierApi, WarehouseApi } from '@/services/api/master-data';
|
||||
import {
|
||||
SupplierApi,
|
||||
WarehouseApi,
|
||||
ProductApi,
|
||||
} from '@/services/api/master-data';
|
||||
import { ProductWarehouseApi } from '@/services/api/inventory';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import FileInput from '@/components/input/FileInput';
|
||||
@@ -43,6 +47,9 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
] = useState('');
|
||||
const [selectedProducts, setSelectedProducts] = useState<number[]>([]);
|
||||
const [selectedDeliveries, setSelectedDeliveries] = useState<number[]>([]);
|
||||
const [fetchedProductIds, setFetchedProductIds] = useState<Set<number>>(
|
||||
new Set()
|
||||
);
|
||||
|
||||
const {
|
||||
deleteModal,
|
||||
@@ -338,12 +345,183 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
}, [formik.values.deliveries]);
|
||||
|
||||
useEffect(() => {
|
||||
if (formik.values.source_warehouse_id && type !== 'edit') {
|
||||
if (
|
||||
formik.values.source_warehouse_id &&
|
||||
type !== 'edit' &&
|
||||
type !== 'detail'
|
||||
) {
|
||||
formik.setFieldValue('products', []);
|
||||
formik.setFieldValue('deliveries', []);
|
||||
}
|
||||
}, [formik.values.source_warehouse_id]);
|
||||
|
||||
// Effect to populate product labels from ProductWarehouse data
|
||||
useEffect(() => {
|
||||
if (!productWarehouses || !isResponseSuccess(productWarehouses)) return;
|
||||
if (type !== 'edit' && type !== 'detail') return;
|
||||
|
||||
let hasUpdates = false;
|
||||
const updatedProducts = formik.values.products?.map((product) => {
|
||||
if (product.product && product.product.label.startsWith('Product ID:')) {
|
||||
const productWarehouse = productWarehouses.data.find(
|
||||
(pw) => pw.product.id === product.product_id
|
||||
);
|
||||
if (productWarehouse) {
|
||||
hasUpdates = true;
|
||||
return {
|
||||
...product,
|
||||
product: {
|
||||
value: productWarehouse.product.id,
|
||||
label: productWarehouse.product.name,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
return product;
|
||||
});
|
||||
|
||||
if (hasUpdates && updatedProducts) {
|
||||
formik.setFieldValue('products', updatedProducts);
|
||||
|
||||
const updatedDeliveries = formik.values.deliveries?.map((delivery) => {
|
||||
const updatedDeliveryProducts = delivery.products.map(
|
||||
(deliveryProduct) => {
|
||||
if (
|
||||
deliveryProduct.product &&
|
||||
deliveryProduct.product.label.startsWith('Product ID:')
|
||||
) {
|
||||
const productWarehouse = productWarehouses.data.find(
|
||||
(pw) => pw.product.id === deliveryProduct.product_id
|
||||
);
|
||||
if (productWarehouse) {
|
||||
return {
|
||||
...deliveryProduct,
|
||||
product: {
|
||||
value: productWarehouse.product.id,
|
||||
label: productWarehouse.product.name,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
return deliveryProduct;
|
||||
}
|
||||
);
|
||||
return {
|
||||
...delivery,
|
||||
products: updatedDeliveryProducts,
|
||||
};
|
||||
});
|
||||
formik.setFieldValue('deliveries', updatedDeliveries);
|
||||
}
|
||||
}, [productWarehouses, type]);
|
||||
|
||||
useEffect(() => {
|
||||
if (type !== 'edit' && type !== 'detail') return;
|
||||
|
||||
const productIdsToFetch: number[] = [];
|
||||
|
||||
formik.values.products?.forEach((product) => {
|
||||
if (
|
||||
product.product &&
|
||||
product.product.label.startsWith('Product ID:') &&
|
||||
product.product_id > 0 &&
|
||||
!fetchedProductIds.has(product.product_id)
|
||||
) {
|
||||
productIdsToFetch.push(product.product_id);
|
||||
}
|
||||
});
|
||||
|
||||
formik.values.deliveries?.forEach((delivery) => {
|
||||
delivery.products.forEach((deliveryProduct) => {
|
||||
if (
|
||||
deliveryProduct.product &&
|
||||
deliveryProduct.product.label.startsWith('Product ID:') &&
|
||||
deliveryProduct.product_id > 0 &&
|
||||
!fetchedProductIds.has(deliveryProduct.product_id)
|
||||
) {
|
||||
if (!productIdsToFetch.includes(deliveryProduct.product_id)) {
|
||||
productIdsToFetch.push(deliveryProduct.product_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (productIdsToFetch.length === 0) return;
|
||||
|
||||
const fetchProducts = async () => {
|
||||
const productMap = new Map<number, { id: number; name: string }>();
|
||||
const newFetchedIds = new Set(fetchedProductIds);
|
||||
|
||||
for (const productId of productIdsToFetch) {
|
||||
try {
|
||||
const response = await ProductApi.getSingle(productId);
|
||||
if (isResponseSuccess(response)) {
|
||||
const product = response.data;
|
||||
productMap.set(product.id, { id: product.id, name: product.name });
|
||||
newFetchedIds.add(productId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch product ${productId}:`, error);
|
||||
newFetchedIds.add(productId); // Mark as fetched to avoid retry loops
|
||||
}
|
||||
}
|
||||
|
||||
if (productMap.size > 0) {
|
||||
const updatedProducts = formik.values.products?.map((p) => {
|
||||
const productData = productMap.get(p.product_id);
|
||||
if (productData) {
|
||||
return {
|
||||
...p,
|
||||
product: {
|
||||
value: productData.id,
|
||||
label: productData.name,
|
||||
},
|
||||
};
|
||||
}
|
||||
return p;
|
||||
});
|
||||
|
||||
const updatedDeliveries = formik.values.deliveries?.map((delivery) => {
|
||||
const updatedDeliveryProducts = delivery.products.map(
|
||||
(deliveryProduct) => {
|
||||
const productData = productMap.get(deliveryProduct.product_id);
|
||||
if (productData) {
|
||||
return {
|
||||
...deliveryProduct,
|
||||
product: {
|
||||
value: productData.id,
|
||||
label: productData.name,
|
||||
},
|
||||
};
|
||||
}
|
||||
return deliveryProduct;
|
||||
}
|
||||
);
|
||||
return {
|
||||
...delivery,
|
||||
products: updatedDeliveryProducts,
|
||||
};
|
||||
});
|
||||
|
||||
if (updatedProducts) {
|
||||
formik.setFieldValue('products', updatedProducts);
|
||||
}
|
||||
if (updatedDeliveries) {
|
||||
formik.setFieldValue('deliveries', updatedDeliveries);
|
||||
}
|
||||
}
|
||||
|
||||
setFetchedProductIds(newFetchedIds);
|
||||
};
|
||||
|
||||
fetchProducts();
|
||||
}, [
|
||||
formik.values.products,
|
||||
formik.values.deliveries,
|
||||
type,
|
||||
fetchedProductIds,
|
||||
]);
|
||||
|
||||
const getFilteredProductWarehouseOptions = useCallback(() => {
|
||||
return (
|
||||
formik.values.products
|
||||
@@ -484,7 +662,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className='w-full max-w-5xl'>
|
||||
<section className='w-full'>
|
||||
<FormHeader
|
||||
type={type}
|
||||
title='Movement'
|
||||
|
||||
Reference in New Issue
Block a user