From f24ae992e622fedfe15c1d097c080ff4f7a1b8d3 Mon Sep 17 00:00:00 2001 From: ValdiANS Date: Mon, 24 Nov 2025 09:43:58 +0700 Subject: [PATCH] feat(FE-206): create Expense Realization Form validation --- .../form/ExpenseRealizationForm.schema.ts | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 src/components/pages/expense/form/ExpenseRealizationForm.schema.ts diff --git a/src/components/pages/expense/form/ExpenseRealizationForm.schema.ts b/src/components/pages/expense/form/ExpenseRealizationForm.schema.ts new file mode 100644 index 00000000..863238b9 --- /dev/null +++ b/src/components/pages/expense/form/ExpenseRealizationForm.schema.ts @@ -0,0 +1,181 @@ +import * as Yup from 'yup'; +import { Expense } from '@/types/api/expense'; +import { formatDate } from '@/lib/helper'; + +type ExpenseRealizationFormSchemaType = { + category?: { + value: 'BOP' | 'NON-BOP'; + label: 'BOP' | 'NON-BOP'; + }; + location?: { + value: number; + label: string; + }; + realization_date?: string; + kandangs?: { id: number; name: string }[]; + supplier?: { + value: number; + label: string; + }; + existing_documents?: { name: string; url: string }[]; + documents?: File[]; + realizations: { + kandang_id: number; + cost_items: { + nonstock?: { + value: number; + label: string; + }; + quantity?: number; + total_cost?: number; + notes?: string; + }[]; + }[]; +}; + +export const ExpenseRealizationFormSchema: Yup.ObjectSchema = + Yup.object({ + category: Yup.object({ + value: Yup.string().oneOf(['BOP', 'NON-BOP']).required(), + label: Yup.string().oneOf(['BOP', 'NON-BOP']).required(), + }).required('Kategori wajib diisi!'), + + location: Yup.object({ + value: Yup.number().min(1).required(), + label: Yup.string().required(), + }).required('Lokasi wajib diisi!'), + + realization_date: Yup.string().required('Tanggal transaksi wajib diisi!'), + kandangs: Yup.array() + .of( + Yup.object({ + id: Yup.number().required('Kandang wajib dipilih!'), + name: Yup.string().required('Kandang wajib dipilih!'), + }) + ) + .min(1, 'Kandang wajib dipilih!') + .required('Kandang wajib dipilih!'), + + supplier: Yup.object({ + value: Yup.number().min(1).required(), + label: Yup.string().required(), + }).required('Vendor wajib diisi!'), + + existing_documents: Yup.array().of( + Yup.object({ + name: Yup.string().required(), + url: Yup.string().required(), + }) + ), + + documents: Yup.array().of(Yup.mixed().required()).optional(), + + realizations: Yup.array() + .of( + Yup.object({ + kandang_id: Yup.number().min(1, 'Wajib memilih kandang!').required(), + cost_items: Yup.array() + .of( + Yup.object({ + nonstock: Yup.object({ + value: Yup.number().min(1).required(), + label: Yup.string().required(), + }).required('Nonstock wajib diisi!'), + quantity: Yup.number().required('Total kuantitas wajib diisi!'), + total_cost: Yup.number().required('Total biaya wajib diisi!'), + notes: Yup.string(), + }) + ) + .min(1, 'Kandang harus memiliki setidaknya 1 biaya!') + .required('Biaya kandang wajib diisi!'), + }) + ) + .min(1, 'Biaya kandang wajib diisi!') + .required('Biaya kandang wajib diisi!'), + }); + +export const UpdateExpenseRealizationFormSchema = ExpenseRealizationFormSchema; + +export const UploadRealizationDocumentsFormSchema = Yup.object({ + realization_documents: Yup.array() + .of(Yup.mixed().required()) + .required(), +}); + +export type ExpenseRealizationFormValues = Yup.InferType< + typeof ExpenseRealizationFormSchema +>; + +export type UploadRealizationDocumentsFormValues = Yup.InferType< + typeof UploadRealizationDocumentsFormSchema +>; + +export const getExpenseRealizationFormInitialValues = ( + initialValues?: Expense +): ExpenseRealizationFormValues => { + return { + category: initialValues?.category + ? { + value: initialValues.category, + label: initialValues.category, + } + : undefined, + location: initialValues?.location + ? { + value: initialValues.location.id, + label: initialValues.location.name, + } + : undefined, + realization_date: initialValues?.realization_date + ? formatDate(initialValues?.realization_date, 'YYYY-MM-DD') + : undefined, + kandangs: initialValues?.kandangs.map((kandang) => ({ + id: kandang.kandang_id, + name: kandang.name, + })), + supplier: initialValues?.supplier + ? { + value: initialValues.supplier.id, + label: initialValues.supplier.name, + } + : undefined, + existing_documents: initialValues?.realization_docs?.map((doc) => ({ + name: doc.path, + url: doc.path, + })), + documents: [], + realizations: initialValues?.kandangs + ? initialValues.kandangs.map((kandangExpense) => { + const costItemsInitialValue = kandangExpense.realisasi + ? kandangExpense.realisasi.map((realisasiItem, realisasiIdx) => { + return { + nonstock: { + value: kandangExpense.pengajuans?.[realisasiIdx] + .id as number, + label: realisasiItem.nonstock.name, + }, + quantity: realisasiItem.qty, + total_cost: realisasiItem.total_price, + notes: realisasiItem.note, + }; + }) + : kandangExpense.pengajuans + ? kandangExpense.pengajuans.map((expenseItem) => ({ + nonstock: { + value: expenseItem.id, + label: expenseItem.nonstock.name, + }, + quantity: expenseItem.qty, + total_cost: expenseItem.total_price, + notes: expenseItem.note, + })) + : []; + + return { + kandang_id: kandangExpense.kandang_id, + cost_items: costItemsInitialValue, + }; + }) + : [], + }; +};