From 1b90d657ff760090389d02e8c15cb33b0db7aff8 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Tue, 18 Nov 2025 20:43:57 +0700 Subject: [PATCH] refactor(FE-208,212): update PurchaseOrderForm and PurchaseOrderStaffApprovalForm for improved validation and dynamic item handling --- .../form/order/PurchaseOrderForm.schema.ts | 9 +- .../order/PurchaseOrderStaffApprovalForm.tsx | 169 +++++++----------- 2 files changed, 66 insertions(+), 112 deletions(-) diff --git a/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts b/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts index a24ff3ac..42db9d28 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts +++ b/src/components/pages/purchase/form/order/PurchaseOrderForm.schema.ts @@ -90,15 +90,16 @@ const PurchaseStaffApprovalItemObjectSchema: Yup.ObjectSchema 0); } ) diff --git a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx index f3c2ce36..4a9086a8 100644 --- a/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx +++ b/src/components/pages/purchase/form/order/PurchaseOrderStaffApprovalForm.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useCallback, useMemo, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useFormik } from 'formik'; import { Icon } from '@iconify/react'; import { toast } from 'react-hot-toast'; @@ -8,7 +8,7 @@ import { useSearchParams } from 'next/navigation'; import Button from '@/components/Button'; import TextInput from '@/components/input/TextInput'; import NumberInput from '@/components/input/NumberInput'; -import SelectInput, { OptionType } from '@/components/input/SelectInput'; +import { OptionType } from '@/components/input/SelectInput'; import { PurchaseRequestStaffApprovalFormDefaultValues, @@ -56,7 +56,7 @@ const PurchaseOrderStaffApprovalForm = ({ // ===== UTILITY FUNCTIONS ===== const getPurchaseItemError = ( idx: number, - field: 'purchase_item_id' | 'price' | 'total_price' + field: 'price' | 'total_price' ): { isError: boolean; errorMessage: string } => { const touchedItem = formik.touched.items?.[idx]; const errorItem = formik.errors.items?.[idx] as @@ -135,20 +135,20 @@ const PurchaseOrderStaffApprovalForm = ({ onSubmit: async (values) => { const payload: CreateStaffApprovalRequestPayload = { notes: values.notes || '', - items: (values.items || []).map((item) => ({ - purchase_item_id: - typeof item.purchase_item_id === 'string' - ? parseInt(item.purchase_item_id) || 0 - : item.purchase_item_id || 0, - price: - typeof item.price === 'string' - ? parseFloat(item.price) || 0 - : item.price || 0, - total_price: - typeof item.total_price === 'string' - ? parseFloat(item.total_price) || 0 - : item.total_price || 0, - })), + items: purchaseItems.map((purchaseItem, idx) => { + const formItem = values.items?.[idx]; + return { + purchase_item_id: purchaseItem.value, + price: + typeof formItem?.price === 'string' + ? parseFloat(formItem.price) || 0 + : formItem?.price || 0, + total_price: + typeof formItem?.total_price === 'string' + ? parseFloat(formItem.total_price) || 0 + : formItem?.total_price || 0, + }; + }), }; switch (type) { @@ -170,9 +170,9 @@ const PurchaseOrderStaffApprovalForm = ({ if (initialValues?.items) { return initialValues.items.map((item) => ({ value: item.id, - label: `${item.product.name} ${item.quantity}`, + label: `${item.product.name} ${item.sub_qty}`, id: item.id, - quantity: item.quantity, + quantity: item.sub_qty, product: { name: item.product.name, product_category: item.product.product_category, @@ -187,25 +187,18 @@ const PurchaseOrderStaffApprovalForm = ({ return []; }, [initialValues?.items]); - const getPurchaseItemOptions = useCallback(() => { - return purchaseItems; + // Ensure form values are properly set when purchaseItems change + useEffect(() => { + if (purchaseItems.length > 0) { + const updatedItems = purchaseItems.map((purchaseItem) => ({ + purchase_item_id: purchaseItem.value, + price: '', + total_price: '', + })); + formik.setFieldValue('items', updatedItems); + } }, [purchaseItems]); - // ===== FIELD CHANGE HANDLERS ===== - const purchaseItemChangeHandler = ( - idx: number, - val: OptionType | OptionType[] | null - ) => { - const purchaseItem = val as PurchaseItemOptionType | null; - formik.setFieldTouched(`items.${idx}.purchase_item`, true); - formik.setFieldValue(`items.${idx}.purchase_item`, purchaseItem); - formik.setFieldTouched(`items.${idx}.purchase_item_id`, true); - formik.setFieldValue( - `items.${idx}.purchase_item_id`, - (purchaseItem as OptionType)?.value || 0 - ); - }; - // ===== PURCHASE ITEM OPERATIONS ===== const handlePurchaseItemChange = ( idx: number, @@ -217,29 +210,26 @@ const PurchaseOrderStaffApprovalForm = ({ typeof value === 'string' ? parseFloat(value) || 0 : value; formik.setFieldValue(`items.${idx}.${field}`, numValue); - if (field === 'price') { - const selectedItem = purchaseItems.find( - (p) => p.value === formik.values.items?.[idx]?.purchase_item_id - ); - if (selectedItem && selectedItem.quantity && numValue > 0) { - const calculatedTotal = numValue * selectedItem.quantity; - formik.setFieldValue(`items.${idx}.total_price`, calculatedTotal); - } + const selectedItem = purchaseItems[idx]; + + if ( + field === 'price' && + selectedItem && + selectedItem.quantity > 0 && + numValue >= 0 + ) { + const calculatedTotal = numValue * selectedItem.quantity; + formik.setFieldValue(`items.${idx}.total_price`, calculatedTotal); } - if (field === 'total_price') { - const selectedItem = purchaseItems.find( - (p) => p.value === formik.values.items?.[idx]?.purchase_item_id - ); - if ( - selectedItem && - selectedItem.quantity && - selectedItem.quantity > 0 && - numValue > 0 - ) { - const calculatedPrice = numValue / selectedItem.quantity; - formik.setFieldValue(`items.${idx}.price`, calculatedPrice); - } + if ( + field === 'total_price' && + selectedItem && + selectedItem.quantity > 0 && + numValue >= 0 + ) { + const calculatedPrice = numValue / selectedItem.quantity; + formik.setFieldValue(`items.${idx}.price`, calculatedPrice); } } }; @@ -260,10 +250,6 @@ const PurchaseOrderStaffApprovalForm = ({ - @@ -280,43 +266,16 @@ const PurchaseOrderStaffApprovalForm = ({ - {formik.values.items?.map((item, idx) => { - const selectedPurchaseItem = purchaseItems.find( - (p) => p.value === item.purchase_item_id - ); + {purchaseItems?.map((purchaseItem, idx) => { + const formItem = formik.values.items?.[idx]; return ( -
- Item - * - Gudang Produk Jenis Produk
- - purchaseItemChangeHandler(idx, val) - } - options={getPurchaseItemOptions()} - isError={ - getPurchaseItemError(idx, 'purchase_item_id') - .isError - } - errorMessage={ - getPurchaseItemError(idx, 'purchase_item_id') - .errorMessage - } - placeholder='Pilih Item...' - className={{ - wrapper: 'min-w-52 md:min-w-72 lg:min-w-80', - }} - /> - handlePurchaseItemChange( idx, @@ -419,7 +372,7 @@ const PurchaseOrderStaffApprovalForm = ({ handlePurchaseItemChange( idx,