diff --git a/src/components/pages/master-data/nonstock/form/NonstockForm.tsx b/src/components/pages/master-data/nonstock/form/NonstockForm.tsx index 33dcba54..7a67c9a7 100644 --- a/src/components/pages/master-data/nonstock/form/NonstockForm.tsx +++ b/src/components/pages/master-data/nonstock/form/NonstockForm.tsx @@ -3,26 +3,31 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { useRouter } from 'next/navigation'; import { useFormik } from 'formik'; +import { toast } from 'react-hot-toast'; +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 { useModal } from '@/components/Modal'; +import ConfirmationModal from '@/components/modal/ConfirmationModal'; import { NonstockFormSchema, NonstockFormValues, UpdateNonstockFormSchema, } from '@/components/pages/master-data/nonstock/form/NonstockForm.schema'; -import { isResponseError } from '@/lib/api-helper'; +import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { - CreateNonstockPayload, Nonstock, + CreateNonstockPayload, UpdateNonstockPayload, } from '@/types/api/master-data/nonstock'; -import { - createNonstock, - updateNonstock, -} from '@/services/api/master-data/nonstock'; +import { NonstockApi, SupplierApi, UomApi } from '@/services/api/master-data'; +import { cn } from '@/lib/helper'; +import { flags } from '@/types/api/api-general'; +import { SUPPLIER_FLAG_OPTIONS } from '@/config/constant'; interface NonstockFormProps { type?: 'add' | 'edit' | 'detail'; @@ -31,19 +36,21 @@ interface NonstockFormProps { const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { const router = useRouter(); + const deleteModal = useModal(); const [nonstockFormErrorMessage, setNonstockFormErrorMessage] = useState(''); + const [isDeleteLoading, setIsDeleteLoading] = useState(false); const createNonstockHandler = useCallback( async (payload: CreateNonstockPayload) => { - const createNonstockRes = await createNonstock(payload); + const createNonstockRes = await NonstockApi.create(payload); if (isResponseError(createNonstockRes)) { setNonstockFormErrorMessage(createNonstockRes.message); return; } - alert(createNonstockRes?.message); + toast.success(createNonstockRes?.message as string); router.push('/master-data/nonstock'); }, [router] @@ -51,14 +58,14 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { const updateNonstockHandler = useCallback( async (nonstockId: number, payload: UpdateNonstockPayload) => { - const updateNonstockRes = await updateNonstock(nonstockId, payload); + const updateNonstockRes = await NonstockApi.update(nonstockId, payload); if (updateNonstockRes?.status === 'error') { setNonstockFormErrorMessage(updateNonstockRes.message); return; } - alert(updateNonstockRes?.message); + toast.success(updateNonstockRes?.message as string); router.refresh(); router.push('/master-data/nonstock'); }, @@ -68,6 +75,22 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { const formikInitialValues = useMemo(() => { return { name: initialValues?.name ?? '', + uomId: initialValues?.uom_id ?? 0, + uom: initialValues?.uom + ? { + value: initialValues?.uom.id, + label: initialValues?.uom.name, + } + : null, + supplierIds: + initialValues?.suppliers.map((supplier) => supplier.id) ?? [], + suppliers: + initialValues?.suppliers.map((supplier) => ({ + value: supplier.id, + label: supplier.name, + })) ?? [], + + flags: initialValues?.flags ?? [], }; }, [initialValues]); @@ -80,6 +103,9 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { const nonstockPayload: CreateNonstockPayload = { name: values.name, + uom_id: values.uomId, + supplier_ids: values.supplierIds as number[], + flags: values.flags as flags[], }; switch (type) { @@ -97,81 +123,268 @@ const NonstockForm = ({ type = 'add', initialValues }: NonstockFormProps) => { }, }); + 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 uomChangeHandler = (val: OptionType | OptionType[] | null) => { + formik.setFieldTouched('uom', true); + formik.setFieldValue('uom', val); + + formik.setFieldTouched('uomId', true); + formik.setFieldValue('uomId', (val as OptionType)?.value); + }; + + // supplier + const [supplierSelectInputValue, setSupplierSelectInputValue] = useState(''); + + const suppliersUrl = `${SupplierApi.basePath}?${new URLSearchParams({ + search: supplierSelectInputValue ?? '', + }).toString()}`; + + const { data: suppliers, isLoading: isLoadingSuppliers } = useSWR( + suppliersUrl, + SupplierApi.getAllFetcher + ); + + const supplierOptions = isResponseSuccess(suppliers) + ? suppliers?.data + .filter((sup) => sup.category === 'BOP') + .map((supplier) => ({ + value: supplier.id, + label: supplier.name, + })) + : []; + + const supplierChangeHandler = (val: OptionType | OptionType[] | null) => { + formik.setFieldTouched('suppliers', true); + formik.setFieldValue('suppliers', val); + + const supplierIds = (val as OptionType[]).map( + (supplier) => supplier.value as number + ); + + formik.setFieldTouched('supplierIds', true); + formik.setFieldValue('supplierIds', supplierIds); + }; + + const deleteNonstockClickHandler = () => { + deleteModal.openModal(); + }; + + const confirmationModalDeleteClickHandler = async () => { + setIsDeleteLoading(true); + + await NonstockApi.delete(initialValues?.id as number); + + deleteModal.closeModal(); + toast.success('Successfully delete Nonstock!'); + setIsDeleteLoading(false); + router.push('/master-data/nonstock'); + }; + + const flagsChangeHandler = (val: OptionType | OptionType[] | null) => { + const formattedFlags = (val as OptionType[]).map( + (flag) => flag.value as string + ); + + formik.setFieldValue('flags', formattedFlags); + }; + useEffect(() => { - formik.setValues(formikInitialValues); - }, [formikInitialValues]); + formikSetValues(formikInitialValues); + }, [formikSetValues, formikInitialValues]); return ( -
-
- + +

+ {type === 'add' && 'Tambah Nonstock'} + {type === 'edit' && 'Edit Nonstock'} + {type === 'detail' && 'Detail Nonstock'} +

+
+ +
- - Kembali - +
+ -

- {type === 'add' && 'Tambah Non Stock'} - {type === 'edit' && 'Edit Non Stock'} - {type === 'detail' && 'Detail Non Stock'} -

- + - -
- -
+ - {type !== 'detail' && ( - <> -
- + + formik.values.flags?.includes(opt.value) + )} + onChange={flagsChangeHandler} + options={SUPPLIER_FLAG_OPTIONS} + isError={formik.touched.flags && Boolean(formik.errors.flags)} + errorMessage={formik.errors.flags as string} + isDisabled={type === 'detail'} + isClearable + /> +
- -
+
+ {type !== 'add' && ( +
+ - {nonstockFormErrorMessage && ( -
- - {nonstockFormErrorMessage} + {type !== 'edit' && ( + + )}
)} - - )} - -
+ + {type !== 'detail' && ( +
+ + + +
+ )} + + + {nonstockFormErrorMessage && ( +
+ + {nonstockFormErrorMessage} +
+ )} + + + + {type !== 'add' && ( + + )} + ); };