'use client'; import { useModal } from '@/components/Modal'; import { CATEGORY_OPTIONS, TYPE_OPTIONS } from '@/config/constant'; import { isResponseError } from '@/lib/api-helper'; import { SupplierApi } from '@/services/api/master-data'; import { CreateSupplierPayload, Supplier, } from '@/types/api/master-data/supplier'; import { useRouter } from 'next/navigation'; import { useCallback, useEffect, useMemo, useState } from 'react'; import toast from 'react-hot-toast'; import { SupplierFormSchema, SupplierFormValues, UpdateSupplierFormSchema, } from '@/components/pages/master-data/supplier/form/SupplierForm.schema'; import { useFormik } from 'formik'; import SelectInput, { OptionType } from '@/components/input/SelectInput'; import { Icon } from '@iconify/react'; import Button from '@/components/Button'; import TextInput from '@/components/input/TextInput'; import TextArea from '@/components/input/TextArea'; import { cn } from '@/lib/helper'; import ConfirmationModal from '@/components/modal/ConfirmationModal'; import RequirePermission from '@/components/helper/RequirePermission'; import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; import AlertErrorList from '@/components/helper/form/FormErrors'; interface SupplierCustomProps { formType?: 'add' | 'edit' | 'detail'; initialValues?: Supplier; } const SupplierForm = ({ formType = 'add', initialValues, }: SupplierCustomProps) => { // Setup Kebutuhan Form const router = useRouter(); const deleteModal = useModal(); // Setup State const [supplierFormErrorMessage, setSupplierFormErrorMessage] = useState(''); const [isDeleteLoading, setIsDeleteLoading] = useState(false); const [hatcheryOptionsValues, setHatcheryOptionValues] = useState< OptionType[] >([]); // -- Options data mapping const typeOptions = TYPE_OPTIONS; const categoryOptions = CATEGORY_OPTIONS; // Handler Event const createSupplierHandler = useCallback( async (payload: CreateSupplierPayload) => { const createSupplierRes = await SupplierApi.create(payload); if (isResponseError(createSupplierRes)) { setSupplierFormErrorMessage(createSupplierRes.message); return; } toast.success(createSupplierRes?.message as string); router.push('/master-data/supplier'); }, [router] ); const updateSupplierHandler = useCallback( async (supplierId: number, payload: CreateSupplierPayload) => { const updateSupplierRes = await SupplierApi.update(supplierId, payload); if (isResponseError(updateSupplierRes)) { setSupplierFormErrorMessage(updateSupplierRes.message); return; } toast.success(updateSupplierRes?.message as string); router.push('/master-data/supplier'); }, [router] ); const deleteSupplierHandler = () => { deleteModal.openModal(); }; const confirmationModalDeleteclickHandler = async () => { setIsDeleteLoading(true); await SupplierApi.delete(initialValues?.id as number); deleteModal.closeModal(); setIsDeleteLoading(false); router.push('/master-data/supplier'); }; // Utils Functions const normalizeOptionValue = ( type?: string | { value: string; label: string }, options?: OptionType[] ): { value: string; label: string } => { if (!type && !options) return { value: '', label: '' }; if (!type && options && options.length > 0) return options[0] as { value: string; label: string }; if (typeof type === 'string') return { value: type, label: type }; return type ?? { value: '', label: '' }; }; // Memo const formikInitialValues = useMemo(() => { return { name: initialValues?.name ?? '', alias: initialValues?.alias ?? '', pic: initialValues?.pic ?? '', type: normalizeOptionValue(initialValues?.type, typeOptions), category: normalizeOptionValue(initialValues?.category, categoryOptions), hatchery: initialValues?.hatchery ?? '', phone: initialValues?.phone ?? '', email: initialValues?.email ?? '', address: initialValues?.address ?? '', npwp: initialValues?.npwp ?? '', account_number: initialValues?.account_number ?? '', due_date: initialValues?.due_date ?? 1, }; }, [initialValues, typeOptions, categoryOptions]); // Formik const formik = useFormik({ initialValues: formikInitialValues, enableReinitialize: true, validationSchema: formType === 'edit' ? UpdateSupplierFormSchema : SupplierFormSchema, onSubmit: async (values) => { // reset error message setSupplierFormErrorMessage(''); // create payload const payload: CreateSupplierPayload = { name: values.name, alias: values.alias, pic: values.pic, type: values.type.value, category: values.category.value, hatchery: values.hatchery ?? '', phone: values.phone, email: values.email, address: values.address, npwp: values.npwp, account_number: values.account_number, due_date: parseInt(values.due_date.toString()), }; // cek type form yang disubmit switch (formType) { case 'add': await createSupplierHandler(payload); break; case 'edit': await updateSupplierHandler(initialValues?.id as number, payload); break; default: break; } }, }); const { setFieldValue } = formik; // Initialize Formik useEffect(() => { if (formType !== 'add' && initialValues?.hatchery) { const hatcheryArrays = initialValues.hatchery.split(','); const hatcheryCreatedOptions = hatcheryArrays.map((item) => ({ value: item, label: item, })); setHatcheryOptionValues(hatcheryCreatedOptions); } }, [formType, initialValues?.hatchery]); useEffect(() => { const commaSeparatedValues = hatcheryOptionsValues .map((item) => item.value) .join(','); setFieldValue('hatchery', commaSeparatedValues); }, [hatcheryOptionsValues, setFieldValue]); // Option Handler const typeChangeHandler = (val: OptionType | OptionType[] | null) => { formik.setFieldTouched('type', true); formik.setFieldValue('type', val); }; const categoryChangeHandler = (val: OptionType | OptionType[] | null) => { formik.setFieldTouched('category', true); formik.setFieldValue('category', val); }; // ===== Formik Error List ===== const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); // Render return ( <>

{formType === 'add' && 'Tambah Supplier'} {formType === 'edit' && 'Ubah Supplier'} {formType === 'detail' && 'Detail Supplier'}

{/* Fields Form */}
item.value === formik.values.type?.value ) ?? undefined } onChange={typeChangeHandler} options={typeOptions} isError={formik.touched.type && Boolean(formik.errors.type)} errorMessage={formik.errors.type as string} isDisabled={formType === 'detail'} isClearable isSearchable={true} /> item.value === formik.values.category?.value ) ?? undefined } onChange={categoryChangeHandler} options={categoryOptions} isError={ formik.touched.category && Boolean(formik.errors.category) } errorMessage={formik.errors.category as string} isDisabled={formType === 'detail'} isClearable isSearchable={true} /> { setHatcheryOptionValues(val as OptionType[]); }} isError={ formik.touched.hatchery && Boolean(formik.errors.hatchery) } errorMessage={formik.errors.hatchery as string} isDisabled={formType === 'detail'} isClearable isSearchable={true} options={[]} />