chore(FE-188,193): adjust ExpenseRequestKandangDetailExpense component

This commit is contained in:
ValdiANS
2025-11-25 09:17:02 +07:00
parent e4a6b22357
commit b868a37485
@@ -41,28 +41,28 @@ const ExpenseRequestKandangDetailExpense: React.FC<
val: OptionType | OptionType[] | null val: OptionType | OptionType[] | null
) => { ) => {
formik.setFieldTouched( formik.setFieldTouched(
`kandangExpenses[${kandangExpenseIdx}].expenses[${expenseIdx}].nonstock`, `cost_per_kandangs[${kandangExpenseIdx}].cost_items[${expenseIdx}].nonstock`,
true true
); );
formik.setFieldValue( formik.setFieldValue(
`kandangExpenses[${kandangExpenseIdx}].expenses[${expenseIdx}].nonstock`, `cost_per_kandangs[${kandangExpenseIdx}].cost_items[${expenseIdx}].nonstock`,
val val
); );
}; };
const addExpenseItemHandler = (kandangExpenseIdx: number) => { const addExpenseItemHandler = (kandangExpenseIdx: number) => {
const newExpensesValue = [ const newExpensesValue = [
...formik.values.kandangExpenses[kandangExpenseIdx].expenses, ...formik.values.cost_per_kandangs[kandangExpenseIdx].cost_items,
{ {
nonstock: undefined, nonstock: undefined,
totalExpense: undefined, total_cost: undefined,
totalQuantity: undefined, quantity: undefined,
notes: '', notes: '',
}, },
]; ];
formik.setFieldValue( formik.setFieldValue(
`kandangExpenses[${kandangExpenseIdx}].expenses`, `cost_per_kandangs[${kandangExpenseIdx}].cost_items`,
newExpensesValue newExpensesValue
); );
}; };
@@ -71,27 +71,28 @@ const ExpenseRequestKandangDetailExpense: React.FC<
kandangExpenseIdx: number, kandangExpenseIdx: number,
expenseIdx: number expenseIdx: number
) => { ) => {
const path = `kandangExpenses[${kandangExpenseIdx}].expenses`; const path = `cost_per_kandangs[${kandangExpenseIdx}].cost_items`;
// trims values, errors, and touched at expenseIdx // trims values, errors, and touched at expenseIdx
removeArrayItemAndSync(formik, path, expenseIdx); removeArrayItemAndSync(formik, path, expenseIdx);
}; };
const isExpenseRepeaterInputError = ( const isExpenseRepeaterInputError = (
column: 'nonstock' | 'totalQuantity' | 'totalExpense' | 'notes', column: 'nonstock' | 'quantity' | 'total_cost' | 'notes',
kandangExpenseIdx: number, kandangExpenseIdx: number,
expenseIdx: number expenseIdx: number
) => { ) => {
return ( return (
formik.touched.kandangExpenses?.[kandangExpenseIdx]?.expenses?.[ formik.touched.cost_per_kandangs?.[kandangExpenseIdx]?.cost_items?.[
expenseIdx expenseIdx
]?.[column] && ]?.[column] &&
Boolean( Boolean(
formik.errors.kandangExpenses?.[kandangExpenseIdx] instanceof Object && formik.errors.cost_per_kandangs?.[kandangExpenseIdx] instanceof
formik.errors.kandangExpenses?.[kandangExpenseIdx].expenses?.[ Object &&
formik.errors.cost_per_kandangs?.[kandangExpenseIdx].cost_items?.[
expenseIdx expenseIdx
] instanceof Object && ] instanceof Object &&
formik.errors.kandangExpenses?.[kandangExpenseIdx].expenses?.[ formik.errors.cost_per_kandangs?.[kandangExpenseIdx].cost_items?.[
expenseIdx expenseIdx
]?.[column] ]?.[column]
) )
@@ -112,7 +113,8 @@ const ExpenseRequestKandangDetailExpense: React.FC<
</div> </div>
<div className='w-full flex flex-col gap-6'> <div className='w-full flex flex-col gap-6'>
{formik.values.kandangExpenses.length === 0 && ( {(formik.values.cost_per_kandangs.length === 0 ||
!formik.values.supplier?.value) && (
<div> <div>
<p className='text-sm text-gray-400 text-center'> <p className='text-sm text-gray-400 text-center'>
Pilih kandang terlebih dahulu! Pilih kandang terlebih dahulu!
@@ -120,168 +122,171 @@ const ExpenseRequestKandangDetailExpense: React.FC<
</div> </div>
)} )}
{formik.values.kandangExpenses.map( {formik.values.cost_per_kandangs.length > 0 &&
(kandangExpense, kandangExpenseIdx) => { formik.values.supplier?.value &&
const kandangName = formik.values.kandangs?.find( formik.values.cost_per_kandangs.map(
(kandang) => kandang.id === kandangExpense.kandangId (kandangExpense, kandangExpenseIdx) => {
); const kandangName = formik.values.kandangs?.find(
(kandang) => kandang.id === kandangExpense.kandang_id
);
return ( return (
kandangName?.name && ( kandangName?.name && (
<div <div
key={`kandangExpense-${kandangExpenseIdx}`} key={`kandangExpense-${kandangExpenseIdx}`}
className='w-full flex flex-col gap-4' className='w-full flex flex-col gap-4'
> >
<div> <div>
<h5 className='mb-2 text-lg font-bold text-center'> <h5 className='mb-2 text-lg font-bold text-center'>
Biaya {kandangName?.name} Biaya {kandangName?.name}
</h5> </h5>
<div className='overflow-x-auto'> <div className='overflow-x-auto'>
<table className='table'> <table className='table'>
<thead> <thead>
<tr> <tr>
<th>Nonstock</th> <th>Nonstock</th>
<th>Total Kuantitas</th> <th>Total Kuantitas</th>
<th>Total Biaya</th> <th>Total Biaya</th>
<th>Catatan</th> <th>Catatan</th>
{type !== 'detail' && <th>Aksi</th>} {type !== 'detail' && <th>Aksi</th>}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{kandangExpense.expenses.map( {kandangExpense.cost_items.map(
(expenseItem, expenseIdx) => ( (expenseItem, expenseIdx) => (
<tr key={`expense-${expenseIdx}`}> <tr key={`expense-${expenseIdx}`}>
<td className='p-2'> <td className='p-2'>
<SelectInput <SelectInput
placeholder='Pilih Nonstock' placeholder='Pilih Nonstock'
value={expenseItem.nonstock} value={expenseItem.nonstock}
onChange={(val) => { onChange={(val) => {
nonstockChangeHandler( nonstockChangeHandler(
kandangExpenseIdx,
expenseIdx,
val
);
}}
options={nonstockOptions}
isLoading={isLoadingNonstockOptions}
onInputChange={setNonstockInputValue}
className={{ wrapper: 'min-w-48' }}
/>
</td>
<td className='p-2'>
<NumberInput
required
name={`kandangExpenses[${kandangExpenseIdx}].expenses[${expenseIdx}].totalQuantity`}
placeholder='Masukkan Total Kuantitas'
value={
formik.values.kandangExpenses[
kandangExpenseIdx
].expenses[expenseIdx].totalQuantity ?? ''
}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
isError={isExpenseRepeaterInputError(
'totalQuantity',
kandangExpenseIdx,
expenseIdx
)}
className={{ wrapper: 'min-w-24' }}
/>
</td>
<td className='p-2'>
<NumberInput
name={`kandangExpenses[${kandangExpenseIdx}].expenses[${expenseIdx}].totalExpense`}
placeholder='Masukkan Total Biaya'
value={
formik.values.kandangExpenses[
kandangExpenseIdx
].expenses[expenseIdx].totalExpense ?? ''
}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
isError={isExpenseRepeaterInputError(
'totalExpense',
kandangExpenseIdx,
expenseIdx
)}
inputPrefix={
<span className='text-gray-600 font-medium'>
Rp
</span>
}
className={{ wrapper: 'min-w-24' }}
/>
</td>
<td className='p-2'>
<TextInput
name={`kandangExpenses[${kandangExpenseIdx}].expenses[${expenseIdx}].notes`}
placeholder='Tuliskan catatan'
value={
formik.values.kandangExpenses[
kandangExpenseIdx
].expenses[expenseIdx].notes ?? ''
}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
isError={isExpenseRepeaterInputError(
'notes',
kandangExpenseIdx,
expenseIdx
)}
className={{ wrapper: 'min-w-24' }}
/>
</td>
{type !== 'detail' && (
<td>
<Button
type='button'
color='error'
onClick={() =>
deleteExpenseItemHandler(
kandangExpenseIdx, kandangExpenseIdx,
expenseIdx expenseIdx,
) val
} );
> }}
<Icon options={nonstockOptions}
icon='material-symbols:delete-outline-rounded' isLoading={isLoadingNonstockOptions}
width={24} onInputChange={setNonstockInputValue}
height={24} className={{ wrapper: 'min-w-48' }}
/> />
</Button>
</td> </td>
)}
</tr>
)
)}
</tbody>
</table>
</div>
</div>
{type !== 'detail' && ( <td className='p-2'>
<Button <NumberInput
type='button' required
variant='outline' name={`cost_per_kandangs[${kandangExpenseIdx}].cost_items[${expenseIdx}].quantity`}
color='success' placeholder='Masukkan Total Kuantitas'
onClick={() => addExpenseItemHandler(kandangExpenseIdx)} value={
className='w-fit mx-auto' formik.values.cost_per_kandangs[
> kandangExpenseIdx
<Icon icon='ic:round-plus' width={24} height={24} />{' '} ].cost_items[expenseIdx].quantity ?? ''
Tambah }
</Button> onChange={formik.handleChange}
)} onBlur={formik.handleBlur}
</div> isError={isExpenseRepeaterInputError(
) 'quantity',
); kandangExpenseIdx,
} expenseIdx
)} )}
className={{ wrapper: 'min-w-24' }}
/>
</td>
<td className='p-2'>
<NumberInput
name={`cost_per_kandangs[${kandangExpenseIdx}].cost_items[${expenseIdx}].total_cost`}
placeholder='Masukkan Total Biaya'
value={
formik.values.cost_per_kandangs[
kandangExpenseIdx
].cost_items[expenseIdx].total_cost ??
''
}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
isError={isExpenseRepeaterInputError(
'total_cost',
kandangExpenseIdx,
expenseIdx
)}
inputPrefix={
<span className='text-gray-600 font-medium'>
Rp
</span>
}
className={{ wrapper: 'min-w-24' }}
/>
</td>
<td className='p-2'>
<TextInput
name={`cost_per_kandangs[${kandangExpenseIdx}].cost_items[${expenseIdx}].notes`}
placeholder='Tuliskan catatan'
value={
formik.values.cost_per_kandangs[
kandangExpenseIdx
].cost_items[expenseIdx].notes ?? ''
}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
isError={isExpenseRepeaterInputError(
'notes',
kandangExpenseIdx,
expenseIdx
)}
className={{ wrapper: 'min-w-24' }}
/>
</td>
{type !== 'detail' && (
<td>
<Button
type='button'
color='error'
onClick={() =>
deleteExpenseItemHandler(
kandangExpenseIdx,
expenseIdx
)
}
>
<Icon
icon='material-symbols:delete-outline-rounded'
width={24}
height={24}
/>
</Button>
</td>
)}
</tr>
)
)}
</tbody>
</table>
</div>
</div>
{type !== 'detail' && (
<Button
type='button'
variant='outline'
color='success'
onClick={() => addExpenseItemHandler(kandangExpenseIdx)}
className='w-fit mx-auto'
>
<Icon icon='ic:round-plus' width={24} height={24} />{' '}
Tambah
</Button>
)}
</div>
)
);
}
)}
</div> </div>
</Card> </Card>
); );