mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-208,212): refine PurchaseRequestForm validation and state management
This commit is contained in:
@@ -21,7 +21,7 @@ type PurchaseRequestFormSchemaType = {
|
||||
warehouse?: {
|
||||
value: number;
|
||||
label: string;
|
||||
};
|
||||
} | null;
|
||||
warehouse_id: number;
|
||||
notes: string | null;
|
||||
items: {
|
||||
|
||||
@@ -74,35 +74,26 @@ const PurchaseRequestForm = ({
|
||||
// ===== UTILITY FUNCTIONS =====
|
||||
const getPurchaseItemError = (
|
||||
idx: number,
|
||||
field: 'warehouse_id' | 'product_warehouse_id' | 'product_id' | 'qty'
|
||||
field: 'product_warehouse_id' | 'product_id' | 'qty'
|
||||
): { isError: boolean; errorMessage: string } => {
|
||||
const touchedItem = formik.touched.items?.[idx];
|
||||
if (!formik.touched.items || !Array.isArray(formik.touched.items)) {
|
||||
return {
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
};
|
||||
}
|
||||
|
||||
const touchedField = formik.touched.items[idx]?.[field];
|
||||
const errorItem = formik.errors.items?.[idx] as
|
||||
| Record<string, string>
|
||||
| undefined;
|
||||
|
||||
if (!touchedItem) {
|
||||
return { isError: false, errorMessage: '' };
|
||||
}
|
||||
|
||||
const isTouched = (touchedItem as Record<string, boolean>)?.[field];
|
||||
const errorMessage = errorItem?.[field] || '';
|
||||
|
||||
return {
|
||||
isError: Boolean(isTouched && errorMessage),
|
||||
errorMessage: isTouched && errorMessage ? errorMessage : '',
|
||||
isError: Boolean(touchedField && Boolean(errorItem?.[field])),
|
||||
errorMessage: touchedField && errorItem?.[field] ? errorItem[field] : '',
|
||||
};
|
||||
};
|
||||
|
||||
const getSupplierById = (supplierId: number): Supplier | null => {
|
||||
if (!isResponseSuccess(supplierRawData)) return null;
|
||||
return (
|
||||
supplierRawData?.data.find(
|
||||
(supplier: Supplier) => supplier.id === supplierId
|
||||
) || null
|
||||
);
|
||||
};
|
||||
|
||||
// ===== SUBMISSION HANDLERS =====
|
||||
const createPurchaseRequestHandler = useCallback(
|
||||
async (payload: CreatePurchaseRequestPayload) => {
|
||||
@@ -349,74 +340,6 @@ const PurchaseRequestForm = ({
|
||||
);
|
||||
}, [warehouses]);
|
||||
|
||||
// ===== FIELD CHANGE HANDLERS =====
|
||||
const supplierChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
const supplier = val as OptionType | null;
|
||||
formik.setFieldTouched('supplier', true);
|
||||
formik.setFieldValue('supplier', supplier);
|
||||
formik.setFieldTouched('supplier_id', true);
|
||||
formik.setFieldValue('supplier_id', (supplier as OptionType)?.value || 0);
|
||||
|
||||
if (supplier?.value) {
|
||||
const supplierId =
|
||||
typeof supplier.value === 'string'
|
||||
? parseInt(supplier.value)
|
||||
: supplier.value;
|
||||
const supplierData = getSupplierById(supplierId);
|
||||
if (supplierData?.due_date) {
|
||||
formik.setFieldTouched('credit_term', true);
|
||||
formik.setFieldValue('credit_term', supplierData.due_date.toString());
|
||||
}
|
||||
} else {
|
||||
// Reset credit_term field and its touched state when supplier is cleared
|
||||
formik.setFieldTouched('credit_term', false);
|
||||
formik.setFieldValue('credit_term', '');
|
||||
}
|
||||
};
|
||||
|
||||
const areaChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
const area = val as OptionType | null;
|
||||
formik.setFieldTouched('area', true);
|
||||
formik.setFieldValue('area', area);
|
||||
formik.setFieldTouched('area_id', true);
|
||||
formik.setFieldValue('area_id', (area as OptionType)?.value || 0);
|
||||
|
||||
// Reset area dependent fields
|
||||
formik.setFieldTouched('location', false);
|
||||
formik.setFieldValue('location', undefined);
|
||||
formik.setFieldTouched('location_id', false);
|
||||
formik.setFieldValue('location_id', 0);
|
||||
setLocationSelectInputValue('');
|
||||
|
||||
// Reset area dependent fields in all purchase items
|
||||
if (formik.values.items) {
|
||||
formik.values.items.forEach((_, idx) => {
|
||||
formik.setFieldValue(`items.${idx}.product_warehouse`, null);
|
||||
formik.setFieldValue(`items.${idx}.product_warehouse_id`, null);
|
||||
formik.setFieldValue(`items.${idx}.product`, null);
|
||||
formik.setFieldValue(`items.${idx}.product_id`, '');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const locationChangeHandler = (val: OptionType | OptionType[] | null) => {
|
||||
const location = val as OptionType | null;
|
||||
formik.setFieldTouched('location', true);
|
||||
formik.setFieldValue('location', location);
|
||||
formik.setFieldTouched('location_id', true);
|
||||
formik.setFieldValue('location_id', (location as OptionType)?.value || 0);
|
||||
|
||||
// Reset location dependent fields in all purchase items
|
||||
if (formik.values.items) {
|
||||
formik.values.items.forEach((_, idx) => {
|
||||
formik.setFieldValue(`items.${idx}.product_warehouse`, null);
|
||||
formik.setFieldValue(`items.${idx}.product_warehouse_id`, null);
|
||||
formik.setFieldValue(`items.${idx}.product`, null);
|
||||
formik.setFieldValue(`items.${idx}.product_id`, '');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Purchase Items Handlers
|
||||
const addPurchaseItem = () => {
|
||||
const newPurchaseItems = [
|
||||
@@ -456,6 +379,7 @@ const PurchaseRequestForm = ({
|
||||
if (field === 'qty') {
|
||||
const numValue =
|
||||
typeof value === 'string' ? parseFloat(value) || 0 : value;
|
||||
formik.setFieldTouched(`items.${idx}.qty`, true);
|
||||
formik.setFieldValue(`items.${idx}.qty`, numValue);
|
||||
}
|
||||
};
|
||||
@@ -497,12 +421,41 @@ const PurchaseRequestForm = ({
|
||||
label='Vendor'
|
||||
placeholder='Pilih Vendor...'
|
||||
value={formik.values.supplier}
|
||||
onChange={supplierChangeHandler}
|
||||
onChange={(val) => {
|
||||
const supplier = val as OptionType | null;
|
||||
const supplierId = supplier?.value
|
||||
? typeof supplier.value === 'string'
|
||||
? parseInt(supplier.value)
|
||||
: supplier.value
|
||||
: 0;
|
||||
|
||||
formik.setFieldTouched('supplier_id', true);
|
||||
formik.setFieldValue('supplier_id', supplierId);
|
||||
formik.setFieldTouched('supplier', true);
|
||||
formik.setFieldValue('supplier', supplier);
|
||||
|
||||
if (supplierId > 0 && isResponseSuccess(supplierRawData)) {
|
||||
const supplierData = supplierRawData.data.find(
|
||||
(s: Supplier) => s.id === supplierId
|
||||
);
|
||||
if (supplierData?.due_date) {
|
||||
formik.setFieldTouched('credit_term', true);
|
||||
formik.setFieldValue(
|
||||
'credit_term',
|
||||
supplierData.due_date.toString()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
formik.setFieldTouched('credit_term', false);
|
||||
formik.setFieldValue('credit_term', '');
|
||||
}
|
||||
}}
|
||||
options={supplierOptions}
|
||||
onInputChange={setSupplierSelectInputValue}
|
||||
isLoading={isLoadingSuppliers}
|
||||
isError={
|
||||
formik.touched.supplier && Boolean(formik.errors.supplier_id)
|
||||
formik.touched.supplier_id &&
|
||||
Boolean(formik.errors.supplier_id)
|
||||
}
|
||||
errorMessage={formik.errors.supplier_id as string}
|
||||
isDisabled={type === 'detail'}
|
||||
@@ -537,11 +490,43 @@ const PurchaseRequestForm = ({
|
||||
label='Area'
|
||||
placeholder='Pilih Area...'
|
||||
value={formik.values.area}
|
||||
onChange={areaChangeHandler}
|
||||
onChange={(val) => {
|
||||
const area = val as OptionType | null;
|
||||
formik.setFieldTouched('area_id', true);
|
||||
formik.setFieldValue(
|
||||
'area_id',
|
||||
(area as OptionType)?.value || 0
|
||||
);
|
||||
formik.setFieldTouched('area', true);
|
||||
formik.setFieldValue('area', area);
|
||||
|
||||
formik.setFieldTouched('location', false);
|
||||
formik.setFieldValue('location', undefined);
|
||||
formik.setFieldTouched('location_id', false);
|
||||
formik.setFieldValue('location_id', 0);
|
||||
setLocationSelectInputValue('');
|
||||
|
||||
if (formik.values.items) {
|
||||
formik.values.items.forEach((_, idx) => {
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse_id`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(`items.${idx}.product`, null);
|
||||
formik.setFieldValue(`items.${idx}.product_id`, '');
|
||||
});
|
||||
}
|
||||
}}
|
||||
options={areaOptions}
|
||||
onInputChange={setAreaSelectInputValue}
|
||||
isLoading={isLoadingAreas}
|
||||
isError={formik.touched.area && Boolean(formik.errors.area_id)}
|
||||
isError={
|
||||
formik.touched.area_id && Boolean(formik.errors.area_id)
|
||||
}
|
||||
errorMessage={formik.errors.area_id as string}
|
||||
isDisabled={type === 'detail'}
|
||||
isClearable
|
||||
@@ -556,12 +541,37 @@ const PurchaseRequestForm = ({
|
||||
: 'Pilih Lokasi...'
|
||||
}
|
||||
value={formik.values.area_id ? formik.values.location : null}
|
||||
onChange={locationChangeHandler}
|
||||
onChange={(val) => {
|
||||
const location = val as OptionType | null;
|
||||
formik.setFieldTouched('location_id', true);
|
||||
formik.setFieldValue(
|
||||
'location_id',
|
||||
(location as OptionType)?.value || 0
|
||||
);
|
||||
formik.setFieldTouched('location', true);
|
||||
formik.setFieldValue('location', location);
|
||||
|
||||
if (formik.values.items) {
|
||||
formik.values.items.forEach((_, idx) => {
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse_id`,
|
||||
null
|
||||
);
|
||||
formik.setFieldValue(`items.${idx}.product`, null);
|
||||
formik.setFieldValue(`items.${idx}.product_id`, '');
|
||||
});
|
||||
}
|
||||
}}
|
||||
options={locationOptions}
|
||||
onInputChange={setLocationSelectInputValue}
|
||||
isLoading={isLoadingLocations}
|
||||
isError={
|
||||
formik.touched.location && Boolean(formik.errors.location_id)
|
||||
formik.touched.location_id &&
|
||||
Boolean(formik.errors.location_id)
|
||||
}
|
||||
errorMessage={formik.errors.location_id as string}
|
||||
isDisabled={type === 'detail' || !formik.values.area_id}
|
||||
@@ -684,13 +694,13 @@ const PurchaseRequestForm = ({
|
||||
value={formik.values.warehouse}
|
||||
onChange={(val) => {
|
||||
const warehouse = val as OptionType | null;
|
||||
formik.setFieldTouched('warehouse', true);
|
||||
formik.setFieldValue('warehouse', warehouse);
|
||||
formik.setFieldTouched('warehouse_id', true);
|
||||
formik.setFieldValue(
|
||||
'warehouse_id',
|
||||
(warehouse as OptionType)?.value || 0
|
||||
);
|
||||
formik.setFieldTouched('warehouse', true);
|
||||
formik.setFieldValue('warehouse', warehouse);
|
||||
if (formik.values.items) {
|
||||
formik.values.items.forEach((_, idx) => {
|
||||
formik.setFieldValue(
|
||||
@@ -716,7 +726,7 @@ const PurchaseRequestForm = ({
|
||||
onInputChange={setWarehouseSelectInputValue}
|
||||
isLoading={isLoadingWarehouses}
|
||||
isError={
|
||||
formik.touched.warehouse &&
|
||||
formik.touched.warehouse_id &&
|
||||
Boolean(formik.errors.warehouse_id)
|
||||
}
|
||||
errorMessage={formik.errors.warehouse_id as string}
|
||||
@@ -741,10 +751,18 @@ const PurchaseRequestForm = ({
|
||||
onChange={(val) => {
|
||||
const productWarehouse =
|
||||
val as ProductWarehouseOptionType | null;
|
||||
formik.setFieldTouched(
|
||||
`items.${idx}.product_warehouse`,
|
||||
true
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse`,
|
||||
productWarehouse
|
||||
);
|
||||
formik.setFieldTouched(
|
||||
`items.${idx}.product_warehouse_id`,
|
||||
true
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_warehouse_id`,
|
||||
(productWarehouse as ProductWarehouseOptionType)
|
||||
@@ -754,6 +772,10 @@ const PurchaseRequestForm = ({
|
||||
const productId =
|
||||
(productWarehouse as ProductWarehouseOptionType)
|
||||
?.product_id || 0;
|
||||
formik.setFieldTouched(
|
||||
`items.${idx}.product_id`,
|
||||
true
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`items.${idx}.product_id`,
|
||||
productId
|
||||
|
||||
Reference in New Issue
Block a user