diff --git a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx index a17b445f..97838e23 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx @@ -51,11 +51,19 @@ const PurchaseOrderStaffApprovalForm = ({ }, [initialValues?.approval]); const isRepeaterInputError = ( - idx: number, + purchaseItemId: number, field: 'price' | 'total_price' ): { isError: boolean; errorMessage: string } => { - const touchedItem = formik.touched.items?.[idx]; - const errorItem = formik.errors.items?.[idx] as + const formItemIndex = formik.values.items?.findIndex( + (item) => item.purchase_item_id === purchaseItemId + ); + + if (formItemIndex === -1) { + return { isError: false, errorMessage: '' }; + } + + const touchedItem = formik.touched.items?.[formItemIndex]; + const errorItem = formik.errors.items?.[formItemIndex] as | Record | undefined; @@ -200,10 +208,41 @@ const PurchaseOrderStaffApprovalForm = ({ return []; }, [initialValues?.items]); + const groupedPurchaseItems = useMemo(() => { + if (!purchaseItems.length) return []; + + const warehouseGroups = purchaseItems.reduce( + (acc, item) => { + const warehouseId = item.warehouse_id; + if (!acc[warehouseId]) { + acc[warehouseId] = { + warehouseId, + warehouseName: item.warehouse.name, + items: [], + }; + } + acc[warehouseId].items.push(item); + return acc; + }, + {} as Record< + number, + { + warehouseId: number; + warehouseName: string; + items: typeof purchaseItems; + } + > + ); + + return Object.values(warehouseGroups); + }, [purchaseItems]); + useEffect(() => { if (purchaseItems.length > 0 && initialValues?.items) { const updatedItems = purchaseItems.map((purchaseItem, idx) => { - const originalItem = initialValues.items?.[idx]; + const originalItem = initialValues.items?.find( + (item) => item.id === purchaseItem.id + ); return { purchase_item_id: type === 'edit' ? purchaseItem.value : undefined, product_id: purchaseItem.product_id || 0, @@ -219,17 +258,28 @@ const PurchaseOrderStaffApprovalForm = ({ }, [purchaseItems, type, initialValues]); // ===== PURCHASE ITEM OPERATIONS ===== + const findItemIndex = (purchaseItemId: number) => { + return purchaseItems.findIndex((item) => item.id === purchaseItemId); + }; + const handlePurchaseItemChange = ( - idx: number, + purchaseItemId: number, field: 'price' | 'total_price', value: string | number ) => { + const itemIndex = findItemIndex(purchaseItemId); + const formItemIndex = formik.values.items?.findIndex( + (item) => item.purchase_item_id === purchaseItemId + ); + + if (itemIndex === -1 || formItemIndex === -1) return; + if (field === 'price' || field === 'total_price') { const numValue = typeof value === 'string' ? parseFloat(value) || 0 : value; - formik.setFieldValue(`items.${idx}.${field}`, numValue); + formik.setFieldValue(`items.${formItemIndex}.${field}`, numValue); - const selectedItem = purchaseItems[idx]; + const selectedItem = purchaseItems[itemIndex]; if ( field === 'price' && @@ -238,7 +288,10 @@ const PurchaseOrderStaffApprovalForm = ({ numValue >= 0 ) { const calculatedTotal = numValue * selectedItem.quantity; - formik.setFieldValue(`items.${idx}.total_price`, calculatedTotal); + formik.setFieldValue( + `items.${formItemIndex}.total_price`, + calculatedTotal + ); } if ( @@ -248,7 +301,7 @@ const PurchaseOrderStaffApprovalForm = ({ numValue >= 0 ) { const calculatedPrice = numValue / selectedItem.quantity; - formik.setFieldValue(`items.${idx}.price`, calculatedPrice); + formik.setFieldValue(`items.${formItemIndex}.price`, calculatedPrice); } } }; @@ -266,163 +319,202 @@ const PurchaseOrderStaffApprovalForm = ({ : 'Edit Item Pembelian'}
- - - - - - - - - - - - - - {purchaseItems?.map((purchaseItem, idx) => { - const formItem = formik.values.items?.[idx]; - return ( - - - - - - - - - - ); - })} - -
GudangProdukJenis ProdukJumlahSatuan - Harga Satuan - * - - Total (Rp.) - * -
- - - - - - - - - - - - handlePurchaseItemChange( - idx, - 'price', - e.target.value - ) - } - onBlur={formik.handleBlur} - placeholder='Masukkan harga satuan' - allowNegative={false} - decimalScale={2} - thousandSeparator=',' - decimalSeparator='.' - inputPrefix={'Rp'} - isError={isRepeaterInputError(idx, 'price').isError} - errorMessage={ - isRepeaterInputError(idx, 'price').errorMessage - } - className={{ - wrapper: 'min-w-48 md:min-w-64 lg:min-w-72', - }} - /> - - - handlePurchaseItemChange( - idx, - 'total_price', - e.target.value - ) - } - onBlur={formik.handleBlur} - placeholder='Masukkan total harga' - allowNegative={false} - decimalScale={2} - thousandSeparator=',' - decimalSeparator='.' - inputPrefix={'Rp'} - isError={ - isRepeaterInputError(idx, 'total_price').isError - } - errorMessage={ - isRepeaterInputError(idx, 'total_price') - .errorMessage - } - className={{ - wrapper: 'min-w-48 md:min-w-64 lg:min-w-72', - }} - /> -
+ {groupedPurchaseItems.length > 0 ? ( +
+ {groupedPurchaseItems.map((warehouseData, index) => ( +
+
+ {/* Warehouse Header */} +
+ {index + 1}. {warehouseData.warehouseName.toUpperCase()} +
+ + {/* Items Table */} +
+ + + + + + + + + + + + + {warehouseData.items.map((purchaseItem) => { + const formItem = formik.values.items?.find( + (item) => + item.purchase_item_id === purchaseItem.id + ); + return ( + + + + + + + + + ); + })} + +
ProdukJenis ProdukJumlahSatuan + Harga Satuan + * + + Total (Rp.) + * +
+ + + + + + + + + + handlePurchaseItemChange( + purchaseItem.id, + 'price', + e.target.value + ) + } + onBlur={formik.handleBlur} + placeholder='Masukkan harga satuan' + allowNegative={false} + decimalScale={2} + thousandSeparator=',' + decimalSeparator='.' + inputPrefix={'Rp'} + isError={ + isRepeaterInputError( + purchaseItem.id, + 'price' + ).isError + } + errorMessage={ + isRepeaterInputError( + purchaseItem.id, + 'price' + ).errorMessage + } + className={{ + wrapper: + 'min-w-48 md:min-w-64 lg:min-w-72', + }} + /> + + + handlePurchaseItemChange( + purchaseItem.id, + 'total_price', + e.target.value + ) + } + onBlur={formik.handleBlur} + placeholder='Masukkan total harga' + allowNegative={false} + decimalScale={2} + thousandSeparator=',' + decimalSeparator='.' + inputPrefix={'Rp'} + isError={ + isRepeaterInputError( + purchaseItem.id, + 'total_price' + ).isError + } + errorMessage={ + isRepeaterInputError( + purchaseItem.id, + 'total_price' + ).errorMessage + } + className={{ + wrapper: + 'min-w-48 md:min-w-64 lg:min-w-72', + }} + /> +
+
+
+ + {/* Add divider after table except for last item */} + {index < groupedPurchaseItems.length - 1 && ( +
+ )} +
+ ))} +
+ ) : ( +
+ Tidak ada data item pembelian +
+ )}