refactor(FE): Allow null for select fields and track id fields

This commit is contained in:
rstubryan
2026-01-12 14:12:12 +07:00
parent 8516929056
commit bf834cf79b
3 changed files with 90 additions and 38 deletions
@@ -7,18 +7,19 @@ type ExpenseFormSchemaType = {
category?: {
value: 'BOP' | 'NON-BOP';
label: 'BOP' | 'NON-BOP';
};
} | null;
location?: {
value: number;
label: string;
};
} | null;
location_id: number;
transaction_date?: string;
kandangs?: { id?: number; name?: string }[];
supplier?: {
value: number;
label: string;
};
} | null;
supplier_id: number;
existing_documents?: { id: number; name: string; url: string }[];
deleted_documents?: number[];
documents?: File[];
@@ -28,7 +29,8 @@ type ExpenseFormSchemaType = {
nonstock?: {
value: number;
label: string;
};
} | null;
nonstock_id?: number;
quantity?: number;
price?: number;
notes?: string;
@@ -41,16 +43,24 @@ export const ExpenseRequestFormSchema: Yup.ObjectSchema<ExpenseFormSchemaType> =
category: Yup.object({
value: Yup.string().oneOf(['BOP', 'NON-BOP']).required(),
label: Yup.string().oneOf(['BOP', 'NON-BOP']).required(),
}).required('Kategori wajib diisi!'),
})
.nullable()
.optional(),
location: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).required('Lokasi wajib diisi!'),
})
.nullable()
.optional(),
location_id: Yup.number().min(1).required('Lokasi wajib diisi!'),
location_id: Yup.number()
.required('Lokasi wajib diisi!')
.min(1, 'Lokasi wajib diisi!')
.typeError('Lokasi wajib diisi!'),
transaction_date: Yup.string().required('Tanggal transaksi wajib diisi!'),
kandangs: Yup.array()
.of(
Yup.object({
@@ -63,28 +73,28 @@ export const ExpenseRequestFormSchema: Yup.ObjectSchema<ExpenseFormSchemaType> =
supplier: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).required('Vendor wajib diisi!'),
})
.nullable()
.optional(),
existing_documents: Yup.array().of(
Yup.object({
id: Yup.number().required(),
name: Yup.string().required(),
url: Yup.string().required(),
})
),
supplier_id: Yup.number()
.required('Vendor wajib diisi!')
.min(1, 'Vendor wajib diisi!')
.typeError('Vendor wajib diisi!'),
existing_documents: Yup.array()
.of(
Yup.object({
id: Yup.number().required(),
name: Yup.string().required(),
url: Yup.string().required(),
})
)
.optional(),
deleted_documents: Yup.array().of(Yup.number().required()).optional(),
documents: Yup.array()
.of(
Yup.mixed<File>()
.required()
.test('fileSize', 'Ukuran dokumen maksimal 5 MB', (value) => {
if (!value || !(value instanceof File)) return true;
return value.size <= 5 * 1024 * 1024;
})
)
.optional(),
documents: Yup.array().of(Yup.mixed<File>().required()).optional(),
expense_nonstocks: Yup.array()
.of(
@@ -96,9 +106,17 @@ export const ExpenseRequestFormSchema: Yup.ObjectSchema<ExpenseFormSchemaType> =
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!'),
price: Yup.number().required('Harga satuan wajib diisi!'),
}).nullable(),
nonstock_id: Yup.number()
.required('Nonstock wajib diisi!')
.min(1, 'Nonstock wajib diisi!')
.typeError('Nonstock wajib diisi!'),
quantity: Yup.number()
.required('Total kuantitas wajib diisi!')
.typeError('Total kuantitas wajib diisi!'),
price: Yup.number()
.required('Harga satuan wajib diisi!')
.typeError('Harga satuan wajib diisi!'),
notes: Yup.string(),
})
)
@@ -142,13 +160,13 @@ export const getExpenseFormInitialValues = (
value: initialValues.category,
label: initialValues.category,
}
: undefined,
: null,
location: initialValues?.location
? {
value: initialValues.location.id,
label: initialValues.location.name,
}
: undefined,
: null,
location_id: Number(initialValues?.location.id || 0),
transaction_date: initialValues?.transaction_date
? formatDate(initialValues.transaction_date, 'YYYY-MM-DD')
@@ -162,7 +180,8 @@ export const getExpenseFormInitialValues = (
value: initialValues.supplier.id,
label: initialValues.supplier.name,
}
: undefined,
: null,
supplier_id: initialValues?.supplier?.id ?? 0,
existing_documents: initialValues?.documents?.map((doc) => {
const path = doc.path.startsWith('/') ? doc.path.slice(1) : doc.path;
return {
@@ -182,12 +201,25 @@ export const getExpenseFormInitialValues = (
value: expenseItem.nonstock.id,
label: expenseItem.nonstock.name,
},
nonstock_id: expenseItem.nonstock.id,
quantity: expenseItem.qty,
price: expenseItem.price,
notes: expenseItem.note,
}))
: [],
}))
: [],
: [
{
cost_items: [
{
nonstock: null,
nonstock_id: 0,
quantity: undefined,
price: undefined,
notes: '',
},
],
},
],
};
};
@@ -204,7 +204,8 @@ const ExpenseRequestForm = ({
{
cost_items: [
{
nonstock: undefined,
nonstock: null,
nonstock_id: 0,
quantity: undefined,
price: undefined,
notes: '',
@@ -226,7 +227,8 @@ const ExpenseRequestForm = ({
{
cost_items: [
{
nonstock: undefined,
nonstock: null,
nonstock_id: 0,
quantity: undefined,
price: undefined,
notes: '',
@@ -251,7 +253,8 @@ const ExpenseRequestForm = ({
kandang_id: kandangItem.id,
cost_items: existingExpenseNonstock?.cost_items || [
{
nonstock: undefined,
nonstock: null,
nonstock_id: 0,
quantity: undefined,
price: undefined,
notes: '',
@@ -266,10 +269,20 @@ const ExpenseRequestForm = ({
const supplierChangeHandler = (val: OptionType | OptionType[] | null) => {
formik.setFieldTouched('supplier', true);
formik.setFieldValue('supplier', val);
const supplierId = Array.isArray(val) ? val[0]?.value : val?.value;
formik.setFieldValue('supplier_id', supplierId ?? 0);
};
const requestDocumentsChangeHandler = (val: File[]) => {
formik.setFieldTouched('documents', true);
const invalidFiles = val.filter((file) => file.size > 5 * 1024 * 1024);
if (invalidFiles.length > 0) {
toast.error('Ukuran dokumen maksimal 5 MB!');
return;
}
formik.setFieldValue('documents', val);
};
@@ -585,7 +598,7 @@ const ExpenseRequestForm = ({
type='submit'
color='primary'
isLoading={formik.isSubmitting}
disabled={!formik.isValid || formik.isSubmitting}
disabled={formik.isSubmitting}
className='px-4'
>
Submit
@@ -25,7 +25,7 @@ interface ExpenseRequestKandangDetailExpenseProps {
location?: {
value: number;
label: string;
};
} | null;
className?: {
wrapper?: string;
};
@@ -59,13 +59,20 @@ const ExpenseRequestKandangDetailExpense: React.FC<
`expense_nonstocks[${kandangExpenseIdx}].cost_items[${expenseIdx}].nonstock`,
val
);
const nonstockId = Array.isArray(val) ? val[0]?.value : val?.value;
formik.setFieldValue(
`expense_nonstocks[${kandangExpenseIdx}].cost_items[${expenseIdx}].nonstock_id`,
nonstockId ?? 0
);
};
const addExpenseItemHandler = (kandangExpenseIdx: number) => {
const newExpensesValue = [
...formik.values.expense_nonstocks[kandangExpenseIdx].cost_items,
{
nonstock: undefined,
nonstock: null,
nonstock_id: 0,
price: undefined,
quantity: undefined,
notes: '',