mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 21:41:57 +00:00
255 lines
9.9 KiB
TypeScript
255 lines
9.9 KiB
TypeScript
'use client';
|
|
|
|
import { FormikContextType } from 'formik';
|
|
|
|
import Card from '@/components/Card';
|
|
import SelectInput, {
|
|
OptionType,
|
|
useSelect,
|
|
} from '@/components/input/SelectInput';
|
|
import NumberInput from '@/components/input/NumberInput';
|
|
import TextInput from '@/components/input/TextInput';
|
|
|
|
import { ExpenseRealizationFormValues } from '@/components/pages/expense/form/ExpenseRealizationForm.schema';
|
|
import { cn } from '@/lib/helper';
|
|
import { NonstockApi } from '@/services/api/master-data';
|
|
import { Nonstock } from '@/types/api/master-data/nonstock';
|
|
|
|
interface ExpenseRealizationKandangDetailExpenseProps {
|
|
type?: 'add' | 'edit' | 'detail';
|
|
formik: FormikContextType<ExpenseRealizationFormValues>;
|
|
supplierId?: number;
|
|
location?: {
|
|
value: number;
|
|
label: string;
|
|
};
|
|
className?: {
|
|
wrapper?: string;
|
|
};
|
|
}
|
|
|
|
const ExpenseRealizationKandangDetailExpense: React.FC<
|
|
ExpenseRealizationKandangDetailExpenseProps
|
|
> = ({ formik, supplierId, location, className }) => {
|
|
const {
|
|
setInputValue: setNonstockInputValue,
|
|
options: nonstockOptions,
|
|
isLoadingOptions: isLoadingNonstockOptions,
|
|
} = useSelect<Nonstock>(
|
|
NonstockApi.basePath,
|
|
'id',
|
|
'name',
|
|
'search',
|
|
supplierId ? { supplier_id: String(supplierId) } : undefined
|
|
);
|
|
|
|
const nonstockChangeHandler = (
|
|
kandangExpenseIdx: number,
|
|
costItemIdx: number,
|
|
val: OptionType | OptionType[] | null
|
|
) => {
|
|
formik.setFieldTouched(
|
|
`realizations[${kandangExpenseIdx}].cost_items[${costItemIdx}].nonstock`,
|
|
true
|
|
);
|
|
formik.setFieldValue(
|
|
`realizations[${kandangExpenseIdx}].cost_items[${costItemIdx}].nonstock`,
|
|
val
|
|
);
|
|
};
|
|
|
|
const isExpenseRepeaterInputError = (
|
|
column: 'nonstock' | 'quantity' | 'price' | 'notes',
|
|
kandangExpenseIdx: number,
|
|
expenseIdx: number
|
|
) => {
|
|
return (
|
|
formik.touched.realizations?.[kandangExpenseIdx]?.cost_items?.[
|
|
expenseIdx
|
|
]?.[column] &&
|
|
Boolean(
|
|
formik.errors.realizations?.[kandangExpenseIdx] instanceof Object &&
|
|
formik.errors.realizations?.[kandangExpenseIdx].cost_items?.[
|
|
expenseIdx
|
|
] instanceof Object &&
|
|
formik.errors.realizations?.[kandangExpenseIdx].cost_items?.[
|
|
expenseIdx
|
|
]?.[column]
|
|
)
|
|
);
|
|
};
|
|
|
|
return (
|
|
<Card
|
|
className={{
|
|
wrapper: cn('w-full', className?.wrapper),
|
|
body: 'p-4 shadow',
|
|
}}
|
|
>
|
|
<div className='mb-4 text-center'>
|
|
<h4 className='font-bold text-xl'>
|
|
Rincian Realisasi Biaya Operasional
|
|
</h4>
|
|
</div>
|
|
|
|
<div className='w-full flex flex-col gap-6'>
|
|
{!formik.values.supplier?.value && (
|
|
<div>
|
|
<p className='text-sm text-gray-400 text-center'>
|
|
Pilih supplier terlebih dahulu!
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{formik.values.realizations.length === 0 &&
|
|
formik.values.supplier?.value && (
|
|
<div>
|
|
<p className='text-sm text-gray-400 text-center'>
|
|
Belum ada item biaya. Silakan pilih lokasi terlebih dahulu.
|
|
</p>
|
|
</div>
|
|
)}
|
|
|
|
{formik.values.realizations.length > 0 &&
|
|
formik.values.supplier?.value &&
|
|
formik.values.realizations.map(
|
|
(kandangExpense, kandangExpenseIdx) => {
|
|
const kandangName = kandangExpense.kandang_id
|
|
? formik.values.kandangs?.find(
|
|
(kandang) => kandang.id === kandangExpense.kandang_id
|
|
)
|
|
: null;
|
|
|
|
return (
|
|
(kandangName?.name || !kandangExpense.kandang_id) && (
|
|
<div
|
|
key={`kandangExpense-${kandangExpenseIdx}`}
|
|
className='w-full flex flex-col gap-4'
|
|
>
|
|
<div>
|
|
<h5 className='mb-2 text-lg font-bold text-center'>
|
|
{kandangName?.name
|
|
? `Biaya ${kandangName.name}`
|
|
: location?.label
|
|
? `Biaya ${location.label}`
|
|
: 'Biaya Umum'}
|
|
</h5>
|
|
|
|
<div className='overflow-x-auto'>
|
|
<table className='table'>
|
|
<thead>
|
|
<tr>
|
|
<th>Nonstock</th>
|
|
<th>Total Kuantitas</th>
|
|
<th>Harga Satuan</th>
|
|
<th>Catatan</th>
|
|
</tr>
|
|
</thead>
|
|
|
|
<tbody>
|
|
{kandangExpense.cost_items.map(
|
|
(expenseItem, expenseIdx) => (
|
|
<tr key={`expense-${expenseIdx}`}>
|
|
<td className='p-2'>
|
|
<SelectInput
|
|
placeholder='Pilih Nonstock'
|
|
value={expenseItem.nonstock}
|
|
onChange={(val) => {
|
|
nonstockChangeHandler(
|
|
kandangExpenseIdx,
|
|
expenseIdx,
|
|
val
|
|
);
|
|
}}
|
|
options={nonstockOptions}
|
|
isLoading={isLoadingNonstockOptions}
|
|
onInputChange={setNonstockInputValue}
|
|
className={{ wrapper: 'min-w-48' }}
|
|
isDisabled
|
|
/>
|
|
</td>
|
|
|
|
<td className='p-2'>
|
|
<NumberInput
|
|
required
|
|
name={`realizations[${kandangExpenseIdx}].cost_items[${expenseIdx}].quantity`}
|
|
placeholder='Masukkan Total Kuantitas'
|
|
value={
|
|
formik.values.realizations[
|
|
kandangExpenseIdx
|
|
].cost_items[expenseIdx].quantity ?? ''
|
|
}
|
|
onChange={formik.handleChange}
|
|
onBlur={formik.handleBlur}
|
|
isError={isExpenseRepeaterInputError(
|
|
'quantity',
|
|
kandangExpenseIdx,
|
|
expenseIdx
|
|
)}
|
|
className={{ wrapper: 'min-w-24' }}
|
|
/>
|
|
</td>
|
|
|
|
<td className='p-2'>
|
|
<NumberInput
|
|
name={`realizations[${kandangExpenseIdx}].cost_items[${expenseIdx}].price`}
|
|
placeholder='Masukkan Harga Satuan'
|
|
value={
|
|
formik.values.realizations[
|
|
kandangExpenseIdx
|
|
].cost_items[expenseIdx].price ?? ''
|
|
}
|
|
onChange={formik.handleChange}
|
|
onBlur={formik.handleBlur}
|
|
isError={isExpenseRepeaterInputError(
|
|
'price',
|
|
kandangExpenseIdx,
|
|
expenseIdx
|
|
)}
|
|
inputPrefix={
|
|
<span className='text-gray-600 font-medium'>
|
|
Rp
|
|
</span>
|
|
}
|
|
className={{ wrapper: 'min-w-24' }}
|
|
/>
|
|
</td>
|
|
|
|
<td className='p-2'>
|
|
<TextInput
|
|
name={`realizations[${kandangExpenseIdx}].cost_items[${expenseIdx}].notes`}
|
|
placeholder='Tuliskan catatan'
|
|
value={
|
|
formik.values.realizations[
|
|
kandangExpenseIdx
|
|
].cost_items[expenseIdx].notes ?? ''
|
|
}
|
|
onChange={formik.handleChange}
|
|
onBlur={formik.handleBlur}
|
|
isError={isExpenseRepeaterInputError(
|
|
'notes',
|
|
kandangExpenseIdx,
|
|
expenseIdx
|
|
)}
|
|
className={{ wrapper: 'min-w-24' }}
|
|
/>
|
|
</td>
|
|
</tr>
|
|
)
|
|
)}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
);
|
|
}
|
|
)}
|
|
</div>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export default ExpenseRealizationKandangDetailExpense;
|