refactor(FE-Storyless): enhance ProductForm schema and handling, add required fields and improve validation

This commit is contained in:
rstubryan
2025-11-02 21:15:41 +07:00
parent fc3b090da5
commit 39dd583e77
2 changed files with 79 additions and 46 deletions
@@ -1,53 +1,83 @@
import * as Yup from 'yup';
export const ProductFormSchema = Yup.object({
name: Yup.string().required('Nama wajib diisi!'),
brand: Yup.string().required('Merek wajib diisi!'),
sku: Yup.string().required('SKU wajib diisi!'),
uom: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
uom_id: Yup.number().required('Satuan wajib diisi!').typeError('Satuan wajib diisi!'),
product_category: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
product_category_id: Yup.number()
type ProductFormSchemaType = {
name: string;
brand: string;
sku: string;
uom?: {
value: number;
label: string;
} | null;
uom_id: number;
product_category?: {
value: number;
label: string;
} | null;
product_category_id: number;
product_price: number | string;
selling_price: number | string;
tax: number | string;
expiry_period: number | string;
supplier_ids: number[];
flags: string[];
};
export const ProductFormSchema: Yup.ObjectSchema<ProductFormSchemaType> =
Yup.object({
name: Yup.string().required('Nama wajib diisi!'),
brand: Yup.string().required('Merek wajib diisi!'),
sku: Yup.string().required('SKU wajib diisi!'),
uom: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable().required('Satuan wajib diisi!'),
uom_id: Yup.number()
.required('Satuan wajib diisi!')
.typeError('Satuan wajib diisi!'),
product_category: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable().required('Kategori produk wajib diisi!'),
product_category_id: Yup.number()
.required('Kategori produk wajib diisi!')
.typeError('Kategori produk wajib diisi!'),
product_price: Yup.number()
product_price: Yup.number()
.required('Harga produk wajib diisi!')
.typeError('Harga produk wajib diisi!')
.min(0, 'Harga produk tidak boleh kurang dari 0!'),
selling_price: Yup.number()
selling_price: Yup.number()
.required('Harga jual wajib diisi!')
.typeError('Harga jual wajib diisi!')
.min(0, 'Harga jual tidak boleh kurang dari 0!'),
tax: Yup.number()
tax: Yup.number()
.required('Pajak wajib diisi!')
.typeError('Pajak wajib diisi!')
.min(0, 'Pajak tidak boleh kurang dari 0!')
.max(100, 'Pajak tidak boleh lebih dari 100%!'),
expiry_period: Yup.number()
expiry_period: Yup.number()
.required('Periode kadaluarsa wajib diisi!')
.typeError('Periode kadaluarsa wajib diisi!')
.min(0, 'Periode kadaluarsa tidak boleh kurang dari 0!'),
supplier: Yup.object({
value: Yup.number().min(1).required(),
label: Yup.string().required(),
}).nullable(),
supplier_ids: Yup.array()
.of(Yup.number().typeError('Supplier tidak valid!'))
supplier_ids: Yup.array()
.of(Yup.number().required().typeError('Supplier tidak valid!'))
.min(1, 'Minimal harus ada 1 supplier!')
.required('Supplier wajib diisi!'),
flags: Yup.array()
.of(Yup.string())
flags: Yup.array()
.of(Yup.string().required())
.min(1, 'Minimal harus ada 1 flag!')
.required('Flag wajib diisi!'),
});
});
export const UpdateProductFormSchema = ProductFormSchema;
export type ProductFormValues = Yup.InferType<typeof ProductFormSchema>;
@@ -83,20 +83,19 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
sku: initialValues?.sku ?? '',
uom: initialValues?.uom
? { value: initialValues.uom.id, label: initialValues.uom.name }
: null,
: undefined,
uom_id: initialValues?.uom?.id ?? 0,
product_category: initialValues?.product_category
? {
value: initialValues.product_category.id,
label: initialValues.product_category.name,
}
: null,
: undefined,
product_category_id: initialValues?.product_category?.id ?? 0,
product_price: initialValues?.product_price ?? 0,
selling_price: initialValues?.selling_price ?? 0,
tax: initialValues?.tax ?? 0,
expiry_period: initialValues?.expiry_period ?? 0,
supplier: null, // not used for payload, just for UI
product_price: initialValues?.product_price ?? '',
selling_price: initialValues?.selling_price ?? '',
tax: initialValues?.tax ?? '',
expiry_period: initialValues?.expiry_period ?? '',
supplier_ids: initialValues?.suppliers?.map((s) => s.id) ?? [],
flags: initialValues?.flags ?? [],
}),
@@ -119,10 +118,10 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
selling_price: parseInt(values.selling_price.toString()) || 0,
tax: parseInt(values.tax.toString()) || 0,
expiry_period: parseInt(values.expiry_period.toString()) || 0,
supplier_ids: (values.supplier_ids ?? []).filter(
supplier_ids: values.supplier_ids.filter(
(id): id is number => typeof id === 'number'
),
flags: (values.flags ?? []).filter(
flags: values.flags.filter(
(f): f is string => typeof f === 'string'
),
};
@@ -231,7 +230,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
required
label='Nama'
name='name'
placeholder='Masukkan nama produk'
placeholder='Masukkan nama...'
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
@@ -243,7 +242,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
required
label='Merek'
name='brand'
placeholder='Masukkan merek produk'
placeholder='Masukkan merek...'
value={formik.values.brand}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
@@ -255,7 +254,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
required
label='SKU'
name='sku'
placeholder='Masukkan SKU produk'
placeholder='Masukkan SKU...'
value={formik.values.sku}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
@@ -266,6 +265,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
<SelectInput
required
label='Satuan'
placeholder='Pilih satuan...'
value={formik.values.uom ?? undefined}
onChange={uomChangeHandler}
options={uomOptions}
@@ -279,6 +279,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
<SelectInput
required
label='Kategori Produk'
placeholder='Pilih kategori produk...'
value={formik.values.product_category ?? undefined}
onChange={categoryChangeHandler}
options={categoryOptions}
@@ -296,7 +297,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
required
label='Harga Produk'
name='product_price'
placeholder='Masukkan harga produk'
placeholder='Masukkan harga produk...'
value={formik.values.product_price}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
@@ -316,7 +317,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
required
label='Harga Jual'
name='selling_price'
placeholder='Masukkan harga jual'
placeholder='Masukkan harga jual...'
value={formik.values.selling_price}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
@@ -336,7 +337,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
required
label='Pajak (%)'
name='tax'
placeholder='Masukkan pajak'
placeholder='Masukkan pajak...'
value={formik.values.tax}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
@@ -353,7 +354,7 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
required
label='Periode Kadaluarsa (hari)'
name='expiry_period'
placeholder='Masukkan periode kadaluarsa'
placeholder='Masukkan periode kadaluarsa...'
value={formik.values.expiry_period}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
@@ -372,9 +373,10 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
<SelectInput
required
label='Supplier'
placeholder='Pilih supplier...'
isMulti
value={supplierOptions.filter((opt) =>
formik.values.supplier_ids.includes(opt.value)
(formik.values.supplier_ids || []).includes(opt.value)
)}
onChange={supplierChangeHandler}
options={supplierOptions}
@@ -391,9 +393,10 @@ const ProductForm = ({ type = 'add', initialValues }: ProductFormProps) => {
<SelectInput
required
label='Flags'
placeholder='Pilih flags...'
isMulti
value={PRODUCT_FLAG_OPTIONS.filter((opt) =>
formik.values.flags.includes(opt.value)
(formik.values.flags || []).includes(opt.value)
)}
onChange={(val) => {
const arr = Array.isArray(val) ? val : val ? [val] : [];