mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 21:41:57 +00:00
feat(FE-188,193): add Vendor, Request Documents, and Kandang Detail Expense input
This commit is contained in:
@@ -1,22 +1,27 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useFormik } from 'formik';
|
||||
import { toast } from 'react-hot-toast';
|
||||
|
||||
import { Icon } from '@iconify/react';
|
||||
import Button from '@/components/Button';
|
||||
import TextInput from '@/components/input/TextInput';
|
||||
import { useModal } from '@/components/Modal';
|
||||
import ConfirmationModal from '@/components/modal/ConfirmationModal';
|
||||
import SelectInput from '@/components/input/SelectInput';
|
||||
import SelectInput, {
|
||||
OptionType,
|
||||
useSelect,
|
||||
} from '@/components/input/SelectInput';
|
||||
import DateInput from '@/components/input/DateInput';
|
||||
import ExpenseKandangsTable from '@/components/pages/expense/form/ExpenseKandangsTable';
|
||||
import DropFileInput from '@/components/input/DropFileInput';
|
||||
import ExpenseRequestKandangDetailExpense from '@/components/pages/expense/form/ExpenseRequestKandangDetailExpense';
|
||||
|
||||
import {
|
||||
ExpenseRequestFormSchema,
|
||||
ExpenseRequestFormValues,
|
||||
getExpenseFormInitialValues,
|
||||
UpdateExpenseRequestFormSchema,
|
||||
} from '@/components/pages/expense/form/ExpenseRequestForm.schema';
|
||||
import { isResponseError } from '@/lib/api-helper';
|
||||
@@ -27,6 +32,9 @@ import {
|
||||
} from '@/types/api/expense';
|
||||
import { ExpenseApi } from '@/services/api/expense';
|
||||
import { cn, sleep } from '@/lib/helper';
|
||||
import { LocationApi, SupplierApi } from '@/services/api/master-data';
|
||||
import { ACCEPTED_FILE_TYPE } from '@/config/constant';
|
||||
import { Supplier } from '@/types/api/master-data/supplier';
|
||||
|
||||
interface ExpenseFormProps {
|
||||
type?: 'add' | 'edit' | 'detail';
|
||||
@@ -49,7 +57,9 @@ const ExpenseRequestForm = ({
|
||||
|
||||
const createExpenseHandler = useCallback(
|
||||
async (payload: CreateExpensePayload) => {
|
||||
const createExpenseRes = await ExpenseApi.create(payload);
|
||||
const createExpenseRes = await ExpenseApi.create(
|
||||
ExpenseApi.convertPayloadToFormData(payload)
|
||||
);
|
||||
|
||||
if (isResponseError(createExpenseRes)) {
|
||||
setExpenseFormErrorMessage(createExpenseRes.message);
|
||||
@@ -64,7 +74,10 @@ const ExpenseRequestForm = ({
|
||||
|
||||
const updateExpenseHandler = useCallback(
|
||||
async (expenseId: number, payload: UpdateExpensePayload) => {
|
||||
const updateExpenseRes = await ExpenseApi.update(expenseId, payload);
|
||||
const updateExpenseRes = await ExpenseApi.update(
|
||||
expenseId,
|
||||
ExpenseApi.convertPayloadToFormData(payload)
|
||||
);
|
||||
|
||||
if (updateExpenseRes?.status === 'error') {
|
||||
setExpenseFormErrorMessage(updateExpenseRes.message);
|
||||
@@ -78,14 +91,8 @@ const ExpenseRequestForm = ({
|
||||
[router]
|
||||
);
|
||||
|
||||
const formikInitialValues = useMemo<ExpenseRequestFormValues>(() => {
|
||||
return {
|
||||
name: initialValues?.name ?? '',
|
||||
};
|
||||
}, [initialValues]);
|
||||
|
||||
const formik = useFormik<ExpenseRequestFormValues>({
|
||||
initialValues: formikInitialValues,
|
||||
initialValues: getExpenseFormInitialValues(initialValues),
|
||||
validationSchema:
|
||||
type === 'edit'
|
||||
? UpdateExpenseRequestFormSchema
|
||||
@@ -94,7 +101,22 @@ const ExpenseRequestForm = ({
|
||||
setExpenseFormErrorMessage('');
|
||||
|
||||
const expensePayload: CreateExpensePayload = {
|
||||
name: values.name,
|
||||
locationId: values.location?.value as number,
|
||||
kandangIds: values.kandangs
|
||||
? values.kandangs.map((item) => item.id)
|
||||
: [],
|
||||
transaction_date: values.transaction_date as string,
|
||||
vendorId: values.vendor?.value as number,
|
||||
request_documents: values.request_documents as File[],
|
||||
kandang_expenses: values.kandangExpenses.map((kandangExpense) => ({
|
||||
kandangId: kandangExpense.kandangId,
|
||||
expenses: kandangExpense.expenses.map((expenseItem) => ({
|
||||
nonstockId: expenseItem.nonstock?.value as number,
|
||||
total_quantity: expenseItem.totalQuantity as number,
|
||||
total_expense: expenseItem.totalExpense as number,
|
||||
notes: expenseItem.notes,
|
||||
})),
|
||||
})),
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
@@ -114,6 +136,58 @@ const ExpenseRequestForm = ({
|
||||
|
||||
const { setValues: formikSetValues } = formik;
|
||||
|
||||
const {
|
||||
setInputValue: setLocationInputValue,
|
||||
options: locationOptions,
|
||||
isLoadingOptions: isLoadingLocationOptions,
|
||||
} = useSelect<Location>(LocationApi.basePath, 'id', 'name');
|
||||
|
||||
const {
|
||||
setInputValue: setVendorInputValue,
|
||||
options: vendorOptions,
|
||||
isLoadingOptions: isLoadingVendorOptions,
|
||||
} = useSelect<Supplier>(SupplierApi.basePath, 'id', 'name');
|
||||
|
||||
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
formik.setFieldTouched('location', true);
|
||||
formik.setFieldValue('location', val);
|
||||
};
|
||||
|
||||
const kandangsChangeHandler = (kandangs: { id: number; name: string }[]) => {
|
||||
formik.setFieldTouched('kandangs', true);
|
||||
formik.setFieldValue('kandangs', kandangs);
|
||||
|
||||
kandangs.forEach((kandangItem) => {
|
||||
const isKandangExistInKandangExpense = formik.values.kandangExpenses.find(
|
||||
(kandangExpenseItem) => kandangExpenseItem.kandangId === kandangItem.id
|
||||
);
|
||||
|
||||
if (isKandangExistInKandangExpense) return;
|
||||
|
||||
formik.values.kandangExpenses.push({
|
||||
kandangId: kandangItem.id,
|
||||
expenses: [
|
||||
{
|
||||
nonstock: undefined,
|
||||
totalExpense: undefined,
|
||||
totalQuantity: undefined,
|
||||
notes: '',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const vendorChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
formik.setFieldTouched('vendor', true);
|
||||
formik.setFieldValue('vendor', val);
|
||||
};
|
||||
|
||||
const requestDocumentsChangeHandler = (val: File[]) => {
|
||||
formik.setFieldTouched('request_documents', true);
|
||||
formik.setFieldValue('request_documents', val);
|
||||
};
|
||||
|
||||
const deleteExpenseClickHandler = () => {
|
||||
deleteModal.openModal();
|
||||
};
|
||||
@@ -141,8 +215,12 @@ const ExpenseRequestForm = ({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
formikSetValues(formikInitialValues);
|
||||
}, [formikSetValues, formikInitialValues]);
|
||||
formikSetValues(getExpenseFormInitialValues(initialValues));
|
||||
}, [formikSetValues, getExpenseFormInitialValues, initialValues]);
|
||||
|
||||
useEffect(() => {
|
||||
formik.setFieldValue('kandangs', undefined);
|
||||
}, [formik.values.location]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -172,30 +250,22 @@ const ExpenseRequestForm = ({
|
||||
<div className='grid grid-cols-12 gap-4'>
|
||||
<SelectInput
|
||||
label='Lokasi'
|
||||
required
|
||||
placeholder='Pilih Lokasi'
|
||||
options={[]}
|
||||
value={formik.values.location}
|
||||
onChange={locationChangeHandler}
|
||||
options={locationOptions}
|
||||
isLoading={isLoadingLocationOptions}
|
||||
onInputChange={setLocationInputValue}
|
||||
className={{ wrapper: 'col-span-12 sm:col-span-6' }}
|
||||
/>
|
||||
|
||||
{/* <TextInput
|
||||
required
|
||||
label='Nama'
|
||||
name='name'
|
||||
placeholder='Masukkan nama expense'
|
||||
value={formik.values.name}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
isError={formik.touched.name && Boolean(formik.errors.name)}
|
||||
errorMessage={formik.errors.name}
|
||||
readOnly={type === 'detail'}
|
||||
className={{
|
||||
wrapper: 'col-span-12 sm:col-span-6',
|
||||
}}
|
||||
/> */}
|
||||
|
||||
<DateInput
|
||||
name='transaction_date'
|
||||
label='Tanggal Transaksi'
|
||||
required
|
||||
value={formik.values.transaction_date}
|
||||
onChange={formik.handleChange}
|
||||
className={{
|
||||
wrapper: 'col-span-12 sm:col-span-6',
|
||||
}}
|
||||
@@ -203,11 +273,47 @@ const ExpenseRequestForm = ({
|
||||
|
||||
<ExpenseKandangsTable
|
||||
type={type}
|
||||
locationId={2}
|
||||
locationId={formik.values.location?.value}
|
||||
selectedKandangs={formik.values.kandangs ?? []}
|
||||
onChange={kandangsChangeHandler}
|
||||
className={{
|
||||
wrapper: 'w-full col-span-12',
|
||||
}}
|
||||
/>
|
||||
|
||||
<SelectInput
|
||||
label='Vendor'
|
||||
required
|
||||
placeholder='Pilih Vendor'
|
||||
value={formik.values.vendor}
|
||||
onChange={vendorChangeHandler}
|
||||
options={vendorOptions}
|
||||
isLoading={isLoadingVendorOptions}
|
||||
onInputChange={setVendorInputValue}
|
||||
className={{ wrapper: 'col-span-12' }}
|
||||
/>
|
||||
|
||||
<DropFileInput
|
||||
label='Dokumen Pengajuan'
|
||||
name='request_documents'
|
||||
values={formik.values.request_documents}
|
||||
onChange={requestDocumentsChangeHandler}
|
||||
accept={{
|
||||
...ACCEPTED_FILE_TYPE.PDF,
|
||||
...ACCEPTED_FILE_TYPE.IMAGE,
|
||||
}}
|
||||
className={{
|
||||
wrapper: 'col-span-12',
|
||||
inputWrapper: 'h-12 flex items-center',
|
||||
}}
|
||||
/>
|
||||
|
||||
<ExpenseRequestKandangDetailExpense
|
||||
formik={formik}
|
||||
className={{
|
||||
wrapper: 'col-span-12',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='flex flex-row justify-between gap-2 flex-wrap'>
|
||||
@@ -287,7 +393,7 @@ const ExpenseRequestForm = ({
|
||||
<ConfirmationModal
|
||||
ref={deleteModal.ref}
|
||||
type='error'
|
||||
text={`Apakah anda yakin ingin menghapus data Expense ini (${initialValues?.name})?`}
|
||||
text='Apakah anda yakin ingin menghapus data Expense ini?'
|
||||
secondaryButton={{
|
||||
text: 'Tidak',
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user