mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-114,136): update RecordingForm validation and input handling for feed and vaccination data
This commit is contained in:
@@ -49,20 +49,19 @@ export const RecordingFormSchema = Yup.object({
|
||||
.of(
|
||||
Yup.object({
|
||||
feed_id: Yup.string().required('Nama pakan wajib diisi!'),
|
||||
feed_qty: Yup.number()
|
||||
.required('Qty pakan wajib diisi!')
|
||||
.min(1, 'Qty minimal 1!')
|
||||
.typeError('Qty pakan wajib diisi!'),
|
||||
feed_qty: Yup.mixed<number | ''>().notRequired(),
|
||||
feed_stock: Yup.number()
|
||||
.required('Stock pakan wajib diisi!')
|
||||
.min(1, 'Stock minimal 1!')
|
||||
.typeError('Stock pakan wajib diisi!')
|
||||
.required('Jumlah pakan yang digunakan wajib diisi!')
|
||||
.min(1, 'Jumlah pakan minimal 1 kg!')
|
||||
.typeError('Jumlah pakan yang digunakan harus berupa angka!')
|
||||
.test(
|
||||
'is-not-exceed-qty',
|
||||
'Feed stock tidak boleh melebihi feed qty yang tersedia!',
|
||||
'Jumlah pakan yang digunakan tidak boleh melebihi stok tersedia!',
|
||||
function (value) {
|
||||
const { feed_qty } = this.parent;
|
||||
return value === undefined || value <= feed_qty;
|
||||
if (value === undefined) return true;
|
||||
if (feed_qty === undefined || feed_qty === '' || typeof feed_qty !== 'number') return true;
|
||||
return value <= feed_qty;
|
||||
}
|
||||
),
|
||||
})
|
||||
@@ -74,13 +73,16 @@ export const RecordingFormSchema = Yup.object({
|
||||
Yup.object({
|
||||
chicken_weight: Yup.number()
|
||||
.required('Berat ayam wajib diisi!')
|
||||
.min(1, 'Berat minimal 1!'),
|
||||
.min(1, 'Berat ayam minimal 1 gram!')
|
||||
.typeError('Berat ayam harus berupa angka!'),
|
||||
chicken_count: Yup.number()
|
||||
.required('Jumlah ayam wajib diisi!')
|
||||
.min(1, 'Jumlah minimal 1!'),
|
||||
.min(1, 'Jumlah ayam minimal 1 ekor!')
|
||||
.typeError('Jumlah ayam harus berupa angka!'),
|
||||
average_chicken_weight: Yup.number()
|
||||
.required('Rata-rata berat ayam wajib diisi!')
|
||||
.min(1, 'Rata-rata minimal 1!'),
|
||||
.min(1, 'Rata-rata berat ayam minimal 1 gram!')
|
||||
.typeError('Rata-rata berat ayam harus berupa angka!'),
|
||||
})
|
||||
)
|
||||
.min(1, 'Minimal harus ada 1 data bobot badan!')
|
||||
@@ -89,20 +91,19 @@ export const RecordingFormSchema = Yup.object({
|
||||
.of(
|
||||
Yup.object({
|
||||
vaccine_id: Yup.string().required('Nama vaksin wajib diisi!'),
|
||||
total_stock: Yup.number()
|
||||
.required('Total stock wajib diisi!')
|
||||
.min(1, 'Total stock minimal 1!')
|
||||
.typeError('Total stock wajib diisi!'),
|
||||
total_stock: Yup.mixed<number | ''>().notRequired(),
|
||||
used_stock: Yup.number()
|
||||
.required('Jumlah stock wajib diisi!')
|
||||
.min(1, 'Jumlah stock minimal 1!')
|
||||
.typeError('Jumlah stock wajib diisi!')
|
||||
.required('Jumlah vaksin yang digunakan wajib diisi!')
|
||||
.min(1, 'Jumlah vaksin minimal 1!')
|
||||
.typeError('Jumlah vaksin yang digunakan harus berupa angka!')
|
||||
.test(
|
||||
'is-not-exceed-total',
|
||||
'Used stock tidak boleh melebihi total stock yang tersedia!',
|
||||
'Jumlah vaksin yang digunakan tidak boleh melebihi stok tersedia!',
|
||||
function (value) {
|
||||
const { total_stock } = this.parent;
|
||||
return value === undefined || value <= total_stock;
|
||||
if (value === undefined) return true;
|
||||
if (total_stock === undefined || total_stock === '' || typeof total_stock !== 'number') return true;
|
||||
return value <= total_stock;
|
||||
}
|
||||
),
|
||||
})
|
||||
@@ -119,8 +120,9 @@ export const RecordingFormSchema = Yup.object({
|
||||
)
|
||||
.required('Kondisi wajib diisi!'),
|
||||
count: Yup.number()
|
||||
.required('Jumlah wajib diisi!')
|
||||
.min(1, 'Jumlah minimal 1!'),
|
||||
.required('Jumlah mortalitas wajib diisi!')
|
||||
.min(1, 'Jumlah mortalitas minimal 1 ekor!')
|
||||
.typeError('Jumlah mortalitas harus berupa angka!'),
|
||||
})
|
||||
)
|
||||
.min(1, 'Minimal harus ada 1 data mortalitas!')
|
||||
@@ -167,7 +169,7 @@ export const getRecordingFormInitialValues = (
|
||||
: [
|
||||
{
|
||||
feed_id: '',
|
||||
feed_qty: 0,
|
||||
feed_qty: '',
|
||||
feed_stock: 0,
|
||||
},
|
||||
],
|
||||
@@ -187,7 +189,7 @@ export const getRecordingFormInitialValues = (
|
||||
: [
|
||||
{
|
||||
vaccine_id: '',
|
||||
total_stock: 0,
|
||||
total_stock: '',
|
||||
used_stock: 0,
|
||||
},
|
||||
],
|
||||
|
||||
@@ -74,7 +74,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
: '',
|
||||
feed_data: (values.feed_data ?? []).map((p) => ({
|
||||
feed_id: p.feed_id,
|
||||
feed_qty: p.feed_qty,
|
||||
feed_qty: typeof p.feed_qty === 'number' ? p.feed_qty : 0,
|
||||
feed_stock: p.feed_stock,
|
||||
})),
|
||||
body_weight: (values.body_weight ?? []).map((b) => ({
|
||||
@@ -84,7 +84,7 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
})),
|
||||
vaccination: (values.vaccination ?? []).map((v) => ({
|
||||
vaccine_id: v.vaccine_id,
|
||||
total_stock: v.total_stock,
|
||||
total_stock: typeof v.total_stock === 'number' ? v.total_stock : 0,
|
||||
used_stock: v.used_stock,
|
||||
})),
|
||||
mortality: (values.mortality ?? []).map((m) => ({
|
||||
@@ -132,8 +132,9 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
|
||||
// Create stock mapping for pakan (Feed)
|
||||
const pakanStockMap = useMemo(() => {
|
||||
if (!isResponseSuccess(pakanProducts)) return new Map<number, number>();
|
||||
const map = new Map<number, number>();
|
||||
if (!isResponseSuccess(pakanProducts))
|
||||
return new Map<number, number | ''>();
|
||||
const map = new Map<number, number | ''>();
|
||||
pakanProducts.data.forEach((product) => {
|
||||
map.set(product.id, product.quantity);
|
||||
});
|
||||
@@ -155,8 +156,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
|
||||
// Create stock mapping for OVK (Vaccination)
|
||||
const ovkStockMap = useMemo(() => {
|
||||
if (!isResponseSuccess(ovkProducts)) return new Map<number, number>();
|
||||
const map = new Map<number, number>();
|
||||
if (!isResponseSuccess(ovkProducts)) return new Map<number, number | ''>();
|
||||
const map = new Map<number, number | ''>();
|
||||
ovkProducts.data.forEach((product) => {
|
||||
map.set(product.id, product.quantity);
|
||||
});
|
||||
@@ -256,8 +257,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
...(formik.values.feed_data || []),
|
||||
{
|
||||
feed: null,
|
||||
feed_id: 0,
|
||||
feed_qty: 0,
|
||||
feed_id: '',
|
||||
feed_qty: '',
|
||||
feed_stock: 0,
|
||||
},
|
||||
];
|
||||
@@ -311,8 +312,8 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
...(formik.values.vaccination || []),
|
||||
{
|
||||
vaccine: null,
|
||||
vaccine_id: 0,
|
||||
total_stock: 0,
|
||||
vaccine_id: '',
|
||||
total_stock: '',
|
||||
used_stock: 0,
|
||||
},
|
||||
];
|
||||
@@ -532,10 +533,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
onChange={(val) => {
|
||||
const productWarehouseId =
|
||||
(val as OptionType)?.value ?? 0;
|
||||
const stock =
|
||||
pakanStockMap.get(
|
||||
const stock = productWarehouseId
|
||||
? (pakanStockMap.get(
|
||||
productWarehouseId as number
|
||||
) ?? 0;
|
||||
) ?? '')
|
||||
: '';
|
||||
|
||||
formik.setFieldValue(
|
||||
`feed_data.${idx}.feed`,
|
||||
@@ -543,12 +545,17 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`feed_data.${idx}.feed_id`,
|
||||
productWarehouseId
|
||||
productWarehouseId || ''
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`feed_data.${idx}.feed_qty`,
|
||||
stock
|
||||
);
|
||||
// Reset feed_stock when changing feed
|
||||
formik.setFieldValue(
|
||||
`feed_data.${idx}.feed_stock`,
|
||||
0
|
||||
);
|
||||
}}
|
||||
options={pakanOptions}
|
||||
isLoading={false}
|
||||
@@ -569,21 +576,18 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
</td>
|
||||
<td>
|
||||
<TextInput
|
||||
required
|
||||
type='number'
|
||||
type='text'
|
||||
name={`feed_data.${idx}.feed_qty`}
|
||||
value={feed.feed_qty}
|
||||
value={
|
||||
feed.feed_qty === '' ||
|
||||
feed.feed_qty === undefined
|
||||
? ''
|
||||
: String(feed.feed_qty)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
isError={
|
||||
isRepeaterInputError('feed_data', 'feed_qty', idx)
|
||||
.isError
|
||||
}
|
||||
errorMessage={
|
||||
isRepeaterInputError('feed_data', 'feed_qty', idx)
|
||||
.errorMessage
|
||||
}
|
||||
readOnly={true}
|
||||
placeholder='Pilih pakan terlebih dahulu'
|
||||
className={{
|
||||
wrapper: 'w-full min-w-24',
|
||||
}}
|
||||
@@ -946,9 +950,11 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
onChange={(val) => {
|
||||
const productWarehouseId =
|
||||
(val as OptionType)?.value ?? 0;
|
||||
const stock =
|
||||
ovkStockMap.get(productWarehouseId as number) ??
|
||||
0;
|
||||
const stock = productWarehouseId
|
||||
? (ovkStockMap.get(
|
||||
productWarehouseId as number
|
||||
) ?? '')
|
||||
: '';
|
||||
|
||||
formik.setFieldValue(
|
||||
`vaccination.${idx}.vaccine`,
|
||||
@@ -956,12 +962,17 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`vaccination.${idx}.vaccine_id`,
|
||||
productWarehouseId
|
||||
productWarehouseId || ''
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`vaccination.${idx}.total_stock`,
|
||||
stock
|
||||
);
|
||||
// Reset used_stock when changing vaccine
|
||||
formik.setFieldValue(
|
||||
`vaccination.${idx}.used_stock`,
|
||||
0
|
||||
);
|
||||
}}
|
||||
options={ovkOptions}
|
||||
isLoading={false}
|
||||
@@ -988,27 +999,18 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
</td>
|
||||
<td>
|
||||
<TextInput
|
||||
required
|
||||
type='number'
|
||||
type='text'
|
||||
name={`vaccination.${idx}.total_stock`}
|
||||
value={vaccine.total_stock}
|
||||
value={
|
||||
vaccine.total_stock === '' ||
|
||||
vaccine.total_stock === undefined
|
||||
? ''
|
||||
: String(vaccine.total_stock)
|
||||
}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
isError={
|
||||
isRepeaterInputError(
|
||||
'vaccination',
|
||||
'total_stock',
|
||||
idx
|
||||
).isError
|
||||
}
|
||||
errorMessage={
|
||||
isRepeaterInputError(
|
||||
'vaccination',
|
||||
'total_stock',
|
||||
idx
|
||||
).errorMessage
|
||||
}
|
||||
readOnly={true}
|
||||
placeholder='Pilih vaksin terlebih dahulu'
|
||||
className={{
|
||||
wrapper: 'w-full min-w-24',
|
||||
}}
|
||||
@@ -1189,13 +1191,15 @@ const RecordingForm = ({ type = 'add', initialValues }: RecordingFormProps) => {
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<TextInput
|
||||
<NumberInput
|
||||
required
|
||||
type='number'
|
||||
name={`mortality.${idx}.count`}
|
||||
value={mortality.count}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
maskType='number'
|
||||
decimals={0}
|
||||
min={0}
|
||||
isError={
|
||||
isRepeaterInputError('mortality', 'count', idx)
|
||||
.isError
|
||||
|
||||
Reference in New Issue
Block a user