From e4a6b223574ca30d06d077b2c353a958c11bf2eb Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 24 Nov 2025 09:54:28 +0700 Subject: [PATCH] chore(FE-188,193,199): adjust Expense Request Form and integrate to API --- .../pages/expense/form/ExpenseRequestForm.tsx | 246 ++++++++++++------ 1 file changed, 169 insertions(+), 77 deletions(-) diff --git a/src/components/pages/expense/form/ExpenseRequestForm.tsx b/src/components/pages/expense/form/ExpenseRequestForm.tsx index 0fd68c88..e47f2f76 100644 --- a/src/components/pages/expense/form/ExpenseRequestForm.tsx +++ b/src/components/pages/expense/form/ExpenseRequestForm.tsx @@ -42,7 +42,6 @@ interface ExpenseFormProps { initialValues?: Expense; } -// TODO: integrate this with real API const ExpenseRequestForm = ({ type = 'add', initialValues, @@ -59,7 +58,7 @@ const ExpenseRequestForm = ({ const createExpenseHandler = useCallback( async (payload: CreateExpensePayload) => { const createExpenseRes = await ExpenseApi.create( - ExpenseApi.convertPayloadToFormData(payload) + ExpenseApi.convertExpenseRequestPayloadToFormData(payload) ); if (isResponseError(createExpenseRes)) { @@ -74,10 +73,15 @@ const ExpenseRequestForm = ({ ); const updateExpenseHandler = useCallback( - async (expenseId: number, payload: UpdateExpensePayload) => { + async ( + expenseId: number, + payload: UpdateExpensePayload, + deletedDocumentIds: number[] + ) => { const updateExpenseRes = await ExpenseApi.update( expenseId, - ExpenseApi.convertPayloadToFormData(payload) + ExpenseApi.convertExpenseRequestUpdatePayloadToFormData(payload), + deletedDocumentIds ); if (updateExpenseRes?.status === 'error') { @@ -102,20 +106,17 @@ const ExpenseRequestForm = ({ setExpenseFormErrorMessage(''); const expensePayload: CreateExpensePayload = { - 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, + category: formik.values.category?.value as 'BOP' | 'NON-BOP', + transaction_date: values?.transaction_date as string, + supplier_id: values.supplier?.value as number, + documents: values.documents as File[], + cost_per_kandangs: values.cost_per_kandangs.map((costPerKandang) => ({ + kandang_id: costPerKandang.kandang_id, + cost_items: costPerKandang.cost_items.map((costItem) => ({ + nonstock_id: costItem.nonstock?.value as number, + quantity: parseFloat(String(costItem.quantity)) as number, + total_cost: parseFloat(String(costItem.total_cost)) as number, + notes: costItem.notes ?? '', })), })), }; @@ -126,9 +127,28 @@ const ExpenseRequestForm = ({ break; case 'edit': + const expenseUpdatePayload: UpdateExpensePayload = { + category: formik.values.category?.value as 'BOP' | 'NON-BOP', + transaction_date: values?.transaction_date as string, + supplier_id: values.supplier?.value as number, + documents: values.documents as File[], + cost_per_kandang: values.cost_per_kandangs.map( + (costPerKandang) => ({ + kandang_id: costPerKandang.kandang_id, + cost_items: costPerKandang.cost_items.map((costItem) => ({ + nonstock_id: costItem.nonstock?.value as number, + quantity: parseFloat(String(costItem.quantity)) as number, + total_cost: parseFloat(String(costItem.total_cost)) as number, + notes: costItem.notes ?? '', + })), + }) + ), + }; + await updateExpenseHandler( initialValues?.id as number, - expensePayload + expenseUpdatePayload, + formik.values.deleted_documents ?? [] ); break; } @@ -145,72 +165,103 @@ const ExpenseRequestForm = ({ const { setInputValue: setVendorInputValue, - options: vendorOptions, + options: supplierOptions, isLoadingOptions: isLoadingVendorOptions, } = useSelect(SupplierApi.basePath, 'id', 'name'); + const categoryChangeHandler = (val: OptionType | OptionType[] | null) => { + formik.setFieldTouched('category', true); + formik.setFieldValue('category', val); + }; + const locationChangeHandler = (val: OptionType | OptionType[] | null) => { formik.setFieldTouched('location', true); formik.setFieldValue('location', val); formik.setFieldValue('kandangs', []); - formik.setFieldValue('kandangExpenses', []); + formik.setFieldValue('cost_per_kandangs', []); }; const kandangsChangeHandler = (kandangs: { id: number; name: string }[]) => { formik.setFieldTouched('kandangs', true); formik.setFieldValue('kandangs', kandangs); - const newKandangExpenses = [...(formik.values.kandangExpenses ?? [])]; + const newCostPerKandangs = [...(formik.values.cost_per_kandangs ?? [])]; - // add new kandangExpenses + // add new cost_per_kandangs kandangs.forEach((kandangItem) => { - const isKandangExistInKandangExpense = newKandangExpenses.find( - (kandangExpenseItem) => kandangExpenseItem.kandangId === kandangItem.id + const isKandangExistInCostPerKandangs = newCostPerKandangs.find( + (costPerKandangItem) => costPerKandangItem.kandang_id === kandangItem.id ); - if (isKandangExistInKandangExpense) return; + if (isKandangExistInCostPerKandangs) return; - newKandangExpenses.push({ - kandangId: kandangItem.id, - expenses: [ + newCostPerKandangs.push({ + kandang_id: kandangItem.id, + cost_items: [ { nonstock: undefined, - totalExpense: undefined, - totalQuantity: undefined, + quantity: undefined, + total_cost: undefined, notes: '', }, ], }); }); - // prune kandangExpenses + // prune cost_per_kandangs const kandangIds = new Set(kandangs.map((kandang) => kandang.id)); - const deletedKandangExpensesIdx: number[] = []; + const deletedCostPerKandangsIdx: number[] = []; - newKandangExpenses.forEach((kandangExpense, idx) => { - const isKandangExpenseValid = kandangIds.has(kandangExpense.kandangId); + newCostPerKandangs.forEach((costPerKandang, idx) => { + const isCostPerKandangValid = kandangIds.has(costPerKandang.kandang_id); - if (!isKandangExpenseValid) { - deletedKandangExpensesIdx.push(idx); + if (!isCostPerKandangValid) { + deletedCostPerKandangsIdx.push(idx); } }); - deletedKandangExpensesIdx.forEach((deletedKandangExpenseIdx) => { - newKandangExpenses.splice(deletedKandangExpenseIdx, 1); + deletedCostPerKandangsIdx.forEach((deletedCostPerKandangIdx) => { + newCostPerKandangs.splice(deletedCostPerKandangIdx, 1); }); - formik.setFieldValue('kandangExpenses', newKandangExpenses); + formik.setFieldValue('cost_per_kandangs', newCostPerKandangs); }; - const vendorChangeHandler = (val: OptionType | OptionType[] | null) => { - formik.setFieldTouched('vendor', true); - formik.setFieldValue('vendor', val); + const supplierChangeHandler = (val: OptionType | OptionType[] | null) => { + formik.setFieldTouched('supplier', true); + formik.setFieldValue('supplier', val); }; const requestDocumentsChangeHandler = (val: File[]) => { - formik.setFieldTouched('request_documents', true); - formik.setFieldValue('request_documents', val); + formik.setFieldTouched('documents', true); + formik.setFieldValue('documents', val); + }; + + const requestDocumentsDeleteHandler = (deletedFileIdx: number) => { + const newRequestDocuments = formik.values.documents; + + newRequestDocuments?.splice(deletedFileIdx, 1); + + formik.setFieldValue('documents', newRequestDocuments); + }; + + const deleteDocumentClickHandler = ( + deletedDocumentIdx: number, + deletedDocumentId: number + ) => { + const newDeletedDocumentIds = [...(formik.values.deleted_documents ?? [])]; + const newExistingDocuments = [ + ...(formik.values.existing_documents ?? []), + ].filter((_, idx) => idx !== deletedDocumentIdx); + + newDeletedDocumentIds.push(deletedDocumentId); + + formik.setFieldTouched('deleted_documents', true); + formik.setFieldValue('deleted_documents', newDeletedDocumentIds); + + formik.setFieldTouched('existing_documents', true); + formik.setFieldValue('existing_documents', newExistingDocuments); }; const deleteExpenseClickHandler = () => { @@ -269,6 +320,25 @@ const ExpenseRequestForm = ({ className='w-full mt-8 flex flex-col gap-6' >
+ + @@ -306,9 +376,9 @@ const ExpenseRequestForm = ({ label='Vendor' required placeholder='Pilih Vendor' - value={formik.values.vendor} - onChange={vendorChangeHandler} - options={vendorOptions} + value={formik.values.supplier} + onChange={supplierChangeHandler} + options={supplierOptions} isLoading={isLoadingVendorOptions} onInputChange={setVendorInputValue} className={{ wrapper: 'col-span-12' }} @@ -316,9 +386,10 @@ const ExpenseRequestForm = ({ (
  • - - {existingDocument.name}{' '} - - +
    + + {existingDocument.name}{' '} + + + + +
  • ) )} @@ -402,6 +494,17 @@ const ExpenseRequestForm = ({
    )} + {expenseFormErrorMessage && ( +
    + + {expenseFormErrorMessage} +
    + )} + {type !== 'detail' && (
    )}
    - - {expenseFormErrorMessage && ( -
    - - {expenseFormErrorMessage} -
    - )}