refactor(FE): Tighten product form validation and layout

This commit is contained in:
rstubryan
2026-01-07 14:21:37 +07:00
parent 8b7ed9e46b
commit d049f6c34f
2 changed files with 195 additions and 179 deletions
@@ -29,36 +29,38 @@ export const ProductFormSchema: Yup.ObjectSchema<ProductFormSchemaType> =
sku: Yup.string().required('SKU wajib diisi!'),
uom: Yup.object({
value: Yup.number().min(1).required(),
value: Yup.number().min(1, 'Satuan wajib dipilih!').required(),
label: Yup.string().required(),
})
.nullable()
.required('Satuan wajib diisi!'),
uom_id: Yup.number()
.min(1, 'Satuan wajib dipilih!')
.required('Satuan wajib diisi!')
.typeError('Satuan wajib diisi!'),
product_category: Yup.object({
value: Yup.number().min(1).required(),
value: Yup.number().min(1, 'Kategori produk wajib dipilih!').required(),
label: Yup.string().required(),
})
.nullable()
.required('Kategori produk wajib diisi!'),
product_category_id: Yup.number()
.min(1, 'Kategori produk wajib dipilih!')
.required('Kategori produk wajib diisi!')
.typeError('Kategori produk wajib diisi!'),
product_price: Yup.number()
.required('Harga produk wajib diisi!')
.typeError('Harga produk wajib diisi!')
.min(0, 'Harga produk tidak boleh kurang dari 0!'),
.min(1, 'Harga produk tidak boleh kurang dari 1!'),
selling_price: Yup.number()
.required('Harga jual wajib diisi!')
.typeError('Harga jual wajib diisi!')
.min(0, 'Harga jual tidak boleh kurang dari 0!'),
.min(1, 'Harga jual tidak boleh kurang dari 1!'),
tax: Yup.number()
.required('Pajak wajib diisi!')
@@ -69,7 +71,7 @@ export const ProductFormSchema: Yup.ObjectSchema<ProductFormSchemaType> =
expiry_period: Yup.number()
.required('Periode kadaluarsa wajib diisi!')
.typeError('Periode kadaluarsa wajib diisi!')
.min(0, 'Periode kadaluarsa tidak boleh kurang dari 0!'),
.min(1, 'Periode kadaluarsa tidak boleh kurang dari 1 hari!'),
supplier_ids: Yup.array()
.of(Yup.number().required().typeError('Supplier tidak valid!'))
@@ -234,7 +234,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
<span>{productFormErrorMessage}</span>
</div>
)}
<div className='flex flex-col gap-4'>
<div className='grid grid-cols-1 gap-4'>
<TextInput
required
label='Nama'
@@ -247,6 +247,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
errorMessage={formik.errors.name}
readOnly={type === 'detail'}
/>
<div className='grid grid-cols-2 gap-4'>
<TextInput
required
label='Merek'
@@ -271,6 +272,8 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
errorMessage={formik.errors.sku}
readOnly={type === 'detail'}
/>
</div>
<div className='grid grid-cols-2 gap-4'>
<SelectInput
required
label='Satuan'
@@ -280,7 +283,10 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
options={uomOptions}
onInputChange={setUomSelectInputValue}
isLoading={isLoadingUoms}
isError={formik.touched.uom_id && Boolean(formik.errors.uom_id)}
isError={
(formik.touched.uom || formik.touched.uom_id) &&
Boolean(formik.errors.uom_id)
}
errorMessage={formik.errors.uom_id as string}
isDisabled={type === 'detail'}
isClearable
@@ -295,13 +301,16 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
onInputChange={setCategorySelectInputValue}
isLoading={isLoadingCategories}
isError={
formik.touched.product_category_id &&
(formik.touched.product_category ||
formik.touched.product_category_id) &&
Boolean(formik.errors.product_category_id)
}
errorMessage={formik.errors.product_category_id as string}
isDisabled={type === 'detail'}
isClearable
/>
</div>
<div className='grid grid-cols-2 gap-4'>
<NumberInput
required
label='Harga Produk'
@@ -342,6 +351,8 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
errorMessage={formik.errors.selling_price as string}
readOnly={type === 'detail'}
/>
</div>
<div className='grid grid-cols-2 gap-4'>
<NumberInput
required
label='Pajak (%)'
@@ -379,6 +390,8 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
errorMessage={formik.errors.expiry_period as string}
readOnly={type === 'detail'}
/>
</div>
<div className='grid grid-cols-2 gap-4'>
<SelectInput
required
label='Supplier'
@@ -421,6 +434,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
isClearable
/>
</div>
</div>
<div className='flex flex-row justify-between gap-2 flex-wrap'>
{type !== 'add' && (
<div className='flex flex-row justify-start gap-2'>