diff --git a/src/components/pages/master-data/product/form/ProductForm.tsx b/src/components/pages/master-data/product/form/ProductForm.tsx index 02afbfc9..f118e52a 100644 --- a/src/components/pages/master-data/product/form/ProductForm.tsx +++ b/src/components/pages/master-data/product/form/ProductForm.tsx @@ -9,7 +9,11 @@ import useSWR from 'swr'; import { Icon } from '@iconify/react'; import Button from '@/components/Button'; import TextInput from '@/components/input/TextInput'; -import SelectInput, { OptionType } from '@/components/input/SelectInput'; +import NumberInput from '@/components/input/NumberInput'; +import SelectInput, { + OptionType, + useSelect, +} from '@/components/input/SelectInput'; import { useModal } from '@/components/Modal'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; @@ -24,7 +28,12 @@ import { CreateProductPayload, UpdateProductPayload, } from '@/types/api/master-data/product'; -import { UomApi, ProductCategoryApi, SupplierApi, ProductApi } from '@/services/api/master-data'; +import { + UomApi, + ProductCategoryApi, + SupplierApi, + ProductApi, +} from '@/services/api/master-data'; import { cn } from '@/lib/helper'; import { PRODUCT_FLAG_OPTIONS } from '@/config/constant'; @@ -67,30 +76,37 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { [router] ); - const formikInitialValues = useMemo(() => ({ - name: initialValues?.name ?? '', - brand: initialValues?.brand ?? '', - sku: initialValues?.sku ?? '', - uom: initialValues?.uom - ? { value: initialValues.uom.id, label: initialValues.uom.name } - : null, - uom_id: initialValues?.uom?.id ?? 0, - product_category: initialValues?.product_category - ? { value: initialValues.product_category.id, label: initialValues.product_category.name } - : null, - product_category_id: initialValues?.product_category?.id ?? 0, - product_price: initialValues?.product_price ?? 0, - selling_price: initialValues?.selling_price ?? 0, - tax: initialValues?.tax ?? 0, - expiry_period: initialValues?.expiry_period ?? 0, - supplier: null, // not used for payload, just for UI - supplier_ids: initialValues?.suppliers?.map(s => s.id) ?? [], - flags: initialValues?.flags ?? [], - }), [initialValues]); + const formikInitialValues = useMemo( + () => ({ + name: initialValues?.name ?? '', + brand: initialValues?.brand ?? '', + sku: initialValues?.sku ?? '', + uom: initialValues?.uom + ? { value: initialValues.uom.id, label: initialValues.uom.name } + : null, + uom_id: initialValues?.uom?.id ?? 0, + product_category: initialValues?.product_category + ? { + value: initialValues.product_category.id, + label: initialValues.product_category.name, + } + : null, + product_category_id: initialValues?.product_category?.id ?? 0, + product_price: initialValues?.product_price ?? 0, + selling_price: initialValues?.selling_price ?? 0, + tax: initialValues?.tax ?? 0, + expiry_period: initialValues?.expiry_period ?? 0, + supplier: null, // not used for payload, just for UI + supplier_ids: initialValues?.suppliers?.map((s) => s.id) ?? [], + flags: initialValues?.flags ?? [], + }), + [initialValues] + ); const formik = useFormik({ initialValues: formikInitialValues, - validationSchema: type === 'edit' ? UpdateProductFormSchema : ProductFormSchema, + validationSchema: + type === 'edit' ? UpdateProductFormSchema : ProductFormSchema, onSubmit: async (values) => { setProductFormErrorMessage(''); const payload: CreateProductPayload = { @@ -99,12 +115,16 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { sku: values.sku, uom_id: values.uom_id, product_category_id: values.product_category_id, - product_price: values.product_price, - selling_price: values.selling_price, - tax: values.tax, - expiry_period: values.expiry_period, - supplier_ids: (values.supplier_ids ?? []).filter((id): id is number => typeof id === 'number'), - flags: (values.flags ?? []).filter((f): f is string => typeof f === 'string'), + product_price: parseInt(values.product_price.toString()) || 0, + selling_price: parseInt(values.selling_price.toString()) || 0, + tax: parseInt(values.tax.toString()) || 0, + expiry_period: parseInt(values.expiry_period.toString()) || 0, + supplier_ids: (values.supplier_ids ?? []).filter( + (id): id is number => typeof id === 'number' + ), + flags: (values.flags ?? []).filter( + (f): f is string => typeof f === 'string' + ), }; switch (type) { case 'add': @@ -120,12 +140,11 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { const { setValues: formikSetValues } = formik; // UOM - const [uomSelectInputValue, setUomSelectInputValue] = useState(''); - const uomsUrl = `${UomApi.basePath}?${new URLSearchParams({ search: uomSelectInputValue ?? '' }).toString()}`; - const { data: uoms, isLoading: isLoadingUoms } = useSWR(uomsUrl, UomApi.getAllFetcher); - const uomOptions = isResponseSuccess(uoms) - ? uoms?.data.map((uom) => ({ value: uom.id, label: uom.name })) - : []; + const { + setInputValue: setUomSelectInputValue, + options: uomOptions, + isLoadingOptions: isLoadingUoms, + } = useSelect(UomApi.basePath, 'id', 'name'); const uomChangeHandler = (val: OptionType | OptionType[] | null) => { formik.setFieldTouched('uom', true); formik.setFieldValue('uom', val); @@ -134,12 +153,11 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { }; // Product Category - const [categorySelectInputValue, setCategorySelectInputValue] = useState(''); - const categoriesUrl = `${ProductCategoryApi.basePath}?${new URLSearchParams({ search: categorySelectInputValue ?? '' }).toString()}`; - const { data: categories, isLoading: isLoadingCategories } = useSWR(categoriesUrl, ProductCategoryApi.getAllFetcher); - const categoryOptions = isResponseSuccess(categories) - ? categories?.data.map((cat) => ({ value: cat.id, label: cat.name })) - : []; + const { + setInputValue: setCategorySelectInputValue, + options: categoryOptions, + isLoadingOptions: isLoadingCategories, + } = useSelect(ProductCategoryApi.basePath, 'id', 'name'); const categoryChangeHandler = (val: OptionType | OptionType[] | null) => { formik.setFieldTouched('product_category', true); formik.setFieldValue('product_category', val); @@ -147,19 +165,25 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { formik.setFieldValue('product_category_id', (val as OptionType)?.value); }; - // Supplier (multi select) + // Supplier (multi select) - using SWR to filter by category const [supplierSelectInputValue, setSupplierSelectInputValue] = useState(''); const suppliersUrl = `${SupplierApi.basePath}?${new URLSearchParams({ search: supplierSelectInputValue ?? '' }).toString()}`; - const { data: suppliers, isLoading: isLoadingSuppliers } = useSWR(suppliersUrl, SupplierApi.getAllFetcher); + const { data: suppliers, isLoading: isLoadingSuppliers } = useSWR( + suppliersUrl, + SupplierApi.getAllFetcher + ); const supplierOptions = isResponseSuccess(suppliers) - ? suppliers?.data - .filter((sup) => sup.category === 'SAPRONAK') - .map((sup) => ({ value: sup.id, label: sup.name })) - : []; + ? suppliers?.data + .filter((sup) => sup.category === 'SAPRONAK') + .map((sup) => ({ value: sup.id, label: sup.name })) + : []; const supplierChangeHandler = (val: OptionType | OptionType[] | null) => { const arr = Array.isArray(val) ? val : val ? [val] : []; formik.setFieldTouched('supplier_ids', true); - formik.setFieldValue('supplier_ids', arr.map((v) => (v as OptionType).value)); + formik.setFieldValue( + 'supplier_ids', + arr.map((v) => (v as OptionType).value) + ); }; const deleteProductClickHandler = () => { @@ -181,7 +205,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => { return ( <> -
+