'use client'; import Button from '@/components/Button'; import { FormHeader } from '@/components/helper/form/FormHeader'; 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 { InitialBalanceFormSchema, InitialBalanceFormValues, } from '@/components/pages/finance/add/initial-balance/FormFinanceAddInitialBalance.schema'; import { FINANCE_INITIAL_BALANCE_TYPE_OPTIONS, FINANCE_PARTY_TYPE_OPTIONS, } from '@/config/constant'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; import { formatTitleCase } from '@/lib/helper'; import { FinanceApi } from '@/services/api/finance'; import { BankApi, CustomerApi, SupplierApi } from '@/services/api/master-data'; import { CreateInitialBalance, Finance, UpdateInitialBalance, } from '@/types/api/finance/finance'; import { Bank } from '@/types/api/master-data/bank'; import { Icon } from '@iconify/react'; import { useFormik } from 'formik'; import { useRouter } from 'next/navigation'; import { useCallback, useMemo } from 'react'; import toast from 'react-hot-toast'; interface FormFinanceAddInitialBalanceProps { type?: 'add' | 'edit'; initialValues?: Finance; } const FormFinanceAddInitialBalance = ({ type = 'add', initialValues, }: FormFinanceAddInitialBalanceProps) => { const router = useRouter(); // ===== Formik ===== const formikInitialValues = useMemo((): InitialBalanceFormValues => { // Type assertion to handle potential initial_balance_type field const extendedInitialValues = initialValues as Finance & { initial_balance_type?: string; }; 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, } : null, bank_id_option: initialValues?.bank ? { label: initialValues.bank.name, value: initialValues.bank.id, } : null, reference_number: initialValues?.reference_number || '', initial_balance_type_option: (initialValues?.nominal ?? 0) < 0 ? FINANCE_INITIAL_BALANCE_TYPE_OPTIONS.find( (option) => option.value === 'NEGATIVE' ) || null : FINANCE_INITIAL_BALANCE_TYPE_OPTIONS.find( (option) => option.value === 'POSITIVE' ) || null, nominal: initialValues?.nominal?.toString() || '', note: initialValues?.notes || '', }; }, [initialValues]); const formik = useFormik({ initialValues: formikInitialValues, validationSchema: InitialBalanceFormSchema, validateOnChange: true, validateOnBlur: true, onSubmit: async (values) => { const payload = transformFormValuesToPayload(values); switch (type) { case 'add': await createInitialBalance(payload); break; case 'edit': if (initialValues?.id) { await updateInitialBalance(initialValues.id, payload); } break; } }, }); // ===== Options ===== const { options: partyOptions, isLoadingOptions: isLoadingPartyOptions } = useSelect( formik.values.party_type_option?.value === 'CUSTOMER' ? CustomerApi.basePath : SupplierApi.basePath, 'id', 'name', '', { limit: 'limit' } ); const { options: bankOptions, rawData: bankRawData, isLoadingOptions: isLoadingBankOptions, } = useSelect(BankApi.basePath, 'id', 'name', '', { limit: 'limit' }); // ===== Helper Functions ===== const transformFormValuesToPayload = ( values: InitialBalanceFormValues ): CreateInitialBalance => { return { party_type: (values.party_type_option?.value as string) || '', party_id: Number(values.party_id_option?.value) || 0, bank_id: Number(values.bank_id_option?.value) || 0, reference_number: values.reference_number, initial_balance_type: (values.initial_balance_type_option?.value as string) || '', nominal: Number(values.nominal.replace(/\D/g, '')) || 0, note: values.note, }; }; // ===== Handler ===== const createInitialBalance = useCallback( async (payload: CreateInitialBalance) => { const response = await FinanceApi.createInitialBalances(payload); if (isResponseError(response)) { toast.error(response.message); return; } toast.success('Saldo awal berhasil ditambahkan'); router.refresh(); router.push('/finance'); }, [router] ); const updateInitialBalance = useCallback( async (financeId: number, payload: UpdateInitialBalance) => { const response = await FinanceApi.updateInitialBalances( financeId, payload ); if (isResponseError(response)) { toast.error(response.message); return; } toast.success('Saldo awal 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 : '' } required isClearable /> { formik.setFieldValue('party_id_option', value); }} 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} /> ({ 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} 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 /> { formik.setFieldValue('initial_balance_type_option', value); }} isError={Boolean( formik.touched.initial_balance_type_option && formik.errors.initial_balance_type_option )} errorMessage={ formik.touched.initial_balance_type_option && formik.errors.initial_balance_type_option ? formik.errors.initial_balance_type_option : '' } required isClearable /> ) : formik.values.initial_balance_type_option?.value === 'NEGATIVE' ? ( ) : ( '' ) } required />