'use client'; import Button from '@/components/Button'; import AlertErrorList from '@/components/helper/form/FormErrors'; import { FormHeader } from '@/components/helper/form/FormHeader'; import DateInput from '@/components/input/DateInput'; import NumberInput from '@/components/input/NumberInput'; import SelectInput, { OptionType, useSelect, } from '@/components/input/SelectInput'; import TextArea from '@/components/input/TextArea'; import TextInput from '@/components/input/TextInput'; import { FinanceFormSchema, FinanceFormValues, } from '@/components/pages/finance/add/FormFinanceAdd.schema'; import { FINANCE_PARTY_TYPE_OPTIONS, FINANCE_PAYMENT_METHOD_OPTIONS, } from '@/config/constant'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { formatDate, formatTitleCase } from '@/lib/helper'; import { useFormikErrorList } from '@/services/hooks/useFormikErrorList'; import { FinanceApi } from '@/services/api/finance'; import { BankApi, CustomerApi, SupplierApi } from '@/services/api/master-data'; import { CreateFinancePayment, Finance, UpdateFinancePayment, } from '@/types/api/finance/finance'; import { Bank } from '@/types/api/master-data/bank'; import { useFormik } from 'formik'; import { useRouter } from 'next/navigation'; import { useCallback, useMemo, useState } from 'react'; import toast from 'react-hot-toast'; import Alert from '@/components/Alert'; import { Icon } from '@iconify/react'; interface FormFinanceAddProps { type?: 'add' | 'edit'; initialValues?: Finance; } interface PartyCommonProps { id: number; name: string; account_number: string; } const FormFinanceAdd = ({ type = 'add', initialValues, }: FormFinanceAddProps) => { const router = useRouter(); const [serverErrorMessage, setServerErrorMessage] = useState(''); // ===== Formik ===== const formikInitialValues = useMemo((): FinanceFormValues => { return { party_type_option: FINANCE_PARTY_TYPE_OPTIONS.find( (option) => option.value === initialValues?.party?.type ) || null, party_id_option: initialValues?.party ? { label: initialValues?.party?.name || '', value: initialValues?.party?.id || 0, } : null, payment_date: initialValues?.payment_date || '', payment_method_option: FINANCE_PAYMENT_METHOD_OPTIONS.find( (option) => option.value === initialValues?.payment_method ) || null, bank_id_option: initialValues?.bank ? { label: initialValues?.bank?.name, value: initialValues?.bank?.id, } : null, party_account_number: initialValues?.party?.account_number || '', reference_number: initialValues?.reference_number || '', nominal: initialValues?.nominal.toString() || '', notes: initialValues?.notes || '', }; }, [initialValues]); const formik = useFormik({ initialValues: formikInitialValues, validationSchema: FinanceFormSchema, validateOnChange: true, validateOnBlur: true, onSubmit: async (values) => { const payload = transformFormValuesToPayload(values); switch (type) { case 'add': await createFinance(payload); break; case 'edit': if (initialValues?.id) { await updateFinance(initialValues.id, payload); } break; } }, }); // ===== Formik Error List ===== const { formErrorList, close, handleFormSubmit } = useFormikErrorList(formik); // ===== Options ===== const { options: partyOptions, isLoadingOptions: isLoadingPartyOptions, rawData: partyRawData, setInputValue: setPartyInputValue, loadMore: loadMorePartyOptions, } = useSelect( formik.values.party_type_option?.value === 'CUSTOMER' ? CustomerApi.basePath : SupplierApi.basePath, 'id', 'name' ); const { options: bankOptions, rawData: bankRawData, isLoadingOptions: isLoadingBankOptions, setInputValue: setBankInputValue, loadMore: loadMoreBankOptions, } = useSelect(BankApi.basePath, 'id', 'name'); // ===== Helper Functions ===== const transformFormValuesToPayload = ( values: FinanceFormValues ): CreateFinancePayment => { return { party_id: Number(values.party_id_option?.value) || 0, party_type: (values.party_type_option?.value as string) || '', payment_date: formatDate(values.payment_date, 'YYYY-MM-DD'), payment_method: (values.payment_method_option?.value as string) || '', bank_id: Number(values.bank_id_option?.value) || 0, reference_number: values.reference_number, nominal: Number(values.nominal.replace(/\D/g, '')) || 0, notes: values.notes, }; }; // ===== Handler ===== const createFinance = useCallback( async (payload: CreateFinancePayment) => { const response = await FinanceApi.create(payload); if (isResponseError(response)) { toast.error(response.message); setServerErrorMessage(response.message); return; } toast.success('Data berhasil ditambahkan'); router.refresh(); router.push('/finance'); }, [router] ); const updateFinance = useCallback( async (financeId: number, payload: UpdateFinancePayment) => { const response = await FinanceApi.update(financeId, payload); if (isResponseError(response)) { toast.error(response.message); setServerErrorMessage(response.message); return; } toast.success('Data berhasil diperbarui'); router.refresh(); router.push('/finance'); }, [router] ); return ( <>
{ formik.setFieldValue('party_type_option', value); formik.setFieldValue('party_id_option', null); formik.setFieldValue('party_account_number', ''); }} isError={Boolean( formik.touched.party_type_option && formik.errors.party_type_option )} errorMessage={ formik.touched.party_type_option && formik.errors.party_type_option ? formik.errors.party_type_option : '' } isDisabled={type === 'edit'} required isClearable /> { formik.setFieldValue('party_id_option', value); if (isResponseSuccess(partyRawData) && value) { formik.setFieldValue( 'party_account_number', partyRawData.data?.find( (item) => item.id === (value as OptionType)?.value )?.account_number || '' ); } }} isLoading={isLoadingPartyOptions} isError={Boolean( formik.touched.party_id_option && formik.errors.party_id_option )} errorMessage={ formik.touched.party_id_option && formik.errors.party_id_option ? formik.errors.party_id_option : '' } required isClearable isDisabled={!formik.values.party_type_option?.value} /> { formik.setFieldValue('payment_method_option', value); }} isError={Boolean( formik.touched.payment_method_option && formik.errors.payment_method_option )} errorMessage={ formik.touched.payment_method_option && formik.errors.payment_method_option ? formik.errors.payment_method_option : '' } required isClearable /> ({ label: bankRawData.data?.find( (item) => item.id === option.value )?.alias + ' - ' + bankRawData.data?.find( (item) => item.id === option.value )?.account_number + ' - ' + bankRawData.data?.find( (item) => item.id === option.value )?.owner, value: option.value, })) : [] } value={formik.values.bank_id_option} onInputChange={setBankInputValue} onMenuScrollToBottom={loadMoreBankOptions} onChange={(value) => { formik.setFieldValue('bank_id_option', value); }} isLoading={isLoadingBankOptions} isError={Boolean( formik.touched.bank_id_option && formik.errors.bank_id_option )} errorMessage={ formik.touched.bank_id_option && formik.errors.bank_id_option ? formik.errors.bank_id_option : '' } required isClearable />