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