refactor(FE): Refactor formik field methods to use destructured helpers

This commit is contained in:
rstubryan
2026-03-06 13:53:15 +07:00
parent c2653e5068
commit 46483af4c2
@@ -323,6 +323,8 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
},
});
const { setFieldValue, setFieldTouched, setFieldError } = formik;
const prevSourceWarehouseIdRef = useRef<number | null>(
formik.values.source_warehouse_id
);
@@ -336,14 +338,14 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
prevSourceWarehouseId !== currentSourceWarehouseId &&
prevSourceWarehouseId !== null
) {
formik.setFieldValue('products', [
setFieldValue('products', [
{
product: null,
product_id: 0,
product_qty: '',
},
]);
formik.setFieldTouched('products', false);
setFieldTouched('products', false);
const updatedDeliveries = formik.values.deliveries.map(
(delivery: DeliverySchema) => ({
@@ -357,12 +359,17 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
],
})
);
formik.setFieldValue('deliveries', updatedDeliveries);
formik.setFieldTouched('deliveries', false);
setFieldValue('deliveries', updatedDeliveries);
setFieldTouched('deliveries', false);
}
prevSourceWarehouseIdRef.current = currentSourceWarehouseId;
}, [formik.values.source_warehouse_id, formik.values.deliveries]);
}, [
formik.values.source_warehouse_id,
formik.values.deliveries,
setFieldValue,
setFieldTouched,
]);
// ===== PRODUCT WAREHOUSE FETCHING (after form initialization) =====
const {
@@ -455,9 +462,9 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
// ===== EVENT HANDLERS =====
const handleTransferDateChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
formik.setFieldValue('transfer_date', e.target.value);
setFieldValue('transfer_date', e.target.value);
},
[]
[setFieldValue]
);
const handleSourceWarehouseChange = useCallback(
@@ -477,14 +484,16 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
return;
}
formik.setFieldTouched('source_warehouse', true);
formik.setFieldValue('source_warehouse', val);
formik.setFieldTouched('source_warehouse_id', true);
formik.setFieldValue('source_warehouse_id', newSourceWarehouseId);
setFieldTouched('source_warehouse', true);
setFieldValue('source_warehouse', val);
setFieldTouched('source_warehouse_id', true);
setFieldValue('source_warehouse_id', newSourceWarehouseId);
},
[
formik.values.destination_warehouse_id,
formik.values.destination_warehouse,
setFieldTouched,
setFieldValue,
]
);
@@ -505,15 +514,17 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
return;
}
formik.setFieldTouched('destination_warehouse', true);
formik.setFieldValue('destination_warehouse', val);
formik.setFieldTouched('destination_warehouse_id', true);
formik.setFieldValue(
'destination_warehouse_id',
newDestinationWarehouseId
);
setFieldTouched('destination_warehouse', true);
setFieldValue('destination_warehouse', val);
setFieldTouched('destination_warehouse_id', true);
setFieldValue('destination_warehouse_id', newDestinationWarehouseId);
},
[formik.values.source_warehouse_id, formik.values.source_warehouse]
[
formik.values.source_warehouse_id,
formik.values.source_warehouse,
setFieldTouched,
setFieldValue,
]
);
const addProduct = useCallback(() => {
@@ -525,15 +536,15 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
product_qty: '',
},
];
formik.setFieldValue('products', newProducts);
}, [formik.values.products]);
setFieldValue('products', newProducts);
}, [formik.values.products, setFieldValue]);
const removeProduct = useCallback(
(i: number) => {
const updatedProducts = formik.values.products?.filter(
(_, idx) => idx !== i
);
formik.setFieldValue('products', updatedProducts);
setFieldValue('products', updatedProducts);
setSelectedProducts([]);
@@ -542,7 +553,12 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
setProductQtyErrorShown(false);
}
},
[formik.values.products, productQtyErrorShown, setSelectedProducts]
[
formik.values.products,
productQtyErrorShown,
setSelectedProducts,
setFieldValue,
]
);
const bulkRemoveProduct = useCallback(() => {
@@ -550,26 +566,32 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
formik.values.products?.filter(
(_, idx) => !selectedProducts.includes(idx)
) ?? [];
formik.setFieldValue('products', updatedProducts);
setFieldValue('products', updatedProducts);
setSelectedProducts([]);
if (productQtyErrorShown) {
toast.dismiss();
setProductQtyErrorShown(false);
}
}, [formik, selectedProducts, setSelectedProducts, productQtyErrorShown]);
}, [
selectedProducts,
setSelectedProducts,
productQtyErrorShown,
setFieldValue,
formik.values.products,
]);
const handleProductChange = useCallback(
(idx: number, val: OptionType | OptionType[] | null) => {
formik.setFieldTouched(`products.${idx}.product`, true);
formik.setFieldValue(`products.${idx}.product`, val);
formik.setFieldTouched(`products.${idx}.product_id`, true);
formik.setFieldValue(
setFieldTouched(`products.${idx}.product`, true);
setFieldValue(`products.${idx}.product`, val);
setFieldTouched(`products.${idx}.product_id`, true);
setFieldValue(
`products.${idx}.product_id`,
(val as ProductWarehouseOptionType)?.value
);
},
[]
[setFieldTouched, setFieldValue]
);
const handleProductSelectAllChange = useCallback(
@@ -596,7 +618,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
);
const addDelivery = useCallback(() => {
formik.setFieldValue('deliveries', [
setFieldValue('deliveries', [
...(formik.values.deliveries || []),
{
delivery_cost: '',
@@ -615,14 +637,14 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
],
},
]);
}, [formik.values.deliveries]);
}, [formik.values.deliveries, setFieldValue]);
const removeDelivery = useCallback(
(i: number) => {
const updatedDeliveries = formik.values.deliveries?.filter(
(_, idx) => idx !== i
);
formik.setFieldValue('deliveries', updatedDeliveries);
setFieldValue('deliveries', updatedDeliveries);
setSelectedDeliveries([]);
@@ -631,7 +653,12 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
setDeliveryQtyErrorShown(false);
}
},
[formik.values.deliveries, deliveryQtyErrorShown, setSelectedDeliveries]
[
formik.values.deliveries,
deliveryQtyErrorShown,
setSelectedDeliveries,
setFieldValue,
]
);
const bulkRemoveDelivery = useCallback(() => {
@@ -639,7 +666,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
formik.values.deliveries?.filter(
(_, idx) => !selectedDeliveries.includes(idx)
) ?? [];
formik.setFieldValue('deliveries', updatedDeliveries);
setFieldValue('deliveries', updatedDeliveries);
setSelectedDeliveries([]);
if (deliveryQtyErrorShown) {
@@ -647,10 +674,11 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
setDeliveryQtyErrorShown(false);
}
}, [
formik,
selectedDeliveries,
setSelectedDeliveries,
deliveryQtyErrorShown,
setFieldValue,
formik.values.deliveries,
]);
const handleDeliverySelectAllChange = useCallback(
@@ -680,34 +708,28 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
const handleDeliveryProductChange = useCallback(
(deliveryIdx: number, val: OptionType | OptionType[] | null) => {
formik.setFieldTouched(
`deliveries.${deliveryIdx}.products.0.product`,
true
);
formik.setFieldValue(`deliveries.${deliveryIdx}.products.0.product`, val);
formik.setFieldTouched(
`deliveries.${deliveryIdx}.products.0.product_id`,
true
);
formik.setFieldValue(
setFieldTouched(`deliveries.${deliveryIdx}.products.0.product`, true);
setFieldValue(`deliveries.${deliveryIdx}.products.0.product`, val);
setFieldTouched(`deliveries.${deliveryIdx}.products.0.product_id`, true);
setFieldValue(
`deliveries.${deliveryIdx}.products.0.product_id`,
(val as OptionType)?.value
);
},
[]
[setFieldTouched, setFieldValue]
);
const handleDeliverySupplierChange = useCallback(
(deliveryIdx: number, val: OptionType | OptionType[] | null) => {
formik.setFieldTouched(`deliveries.${deliveryIdx}.supplier`, true);
formik.setFieldValue(`deliveries.${deliveryIdx}.supplier`, val);
formik.setFieldTouched(`deliveries.${deliveryIdx}.supplier_id`, true);
formik.setFieldValue(
setFieldTouched(`deliveries.${deliveryIdx}.supplier`, true);
setFieldValue(`deliveries.${deliveryIdx}.supplier`, val);
setFieldTouched(`deliveries.${deliveryIdx}.supplier_id`, true);
setFieldValue(
`deliveries.${deliveryIdx}.supplier_id`,
(val as OptionType)?.value
);
},
[]
[setFieldTouched, setFieldValue]
);
const handleDeliveryDocumentChange = useCallback(
@@ -719,15 +741,15 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
e.target.value = '';
return;
}
formik.setFieldValue(`deliveries.${deliveryIdx}.document`, file);
setFieldValue(`deliveries.${deliveryIdx}.document`, file);
}
},
[]
[setFieldValue]
);
const handleDeliveryCostChange = useCallback(
(idx: number, value: number) => {
formik.setFieldValue(`deliveries.${idx}.delivery_cost`, value);
setFieldValue(`deliveries.${idx}.delivery_cost`, value);
const delivery = formik.values.deliveries?.[idx];
if (delivery) {
@@ -737,21 +759,18 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
);
if (productQty > 0 && value > 0) {
const perItem = value / productQty;
formik.setFieldValue(
`deliveries.${idx}.delivery_cost_per_item`,
perItem
);
setFieldValue(`deliveries.${idx}.delivery_cost_per_item`, perItem);
} else if (value === 0) {
formik.setFieldValue(`deliveries.${idx}.delivery_cost_per_item`, 0);
setFieldValue(`deliveries.${idx}.delivery_cost_per_item`, 0);
}
}
},
[formik.values.deliveries]
[formik.values.deliveries, setFieldValue]
);
const handleDeliveryCostPerItemChange = useCallback(
(idx: number, value: number) => {
formik.setFieldValue(`deliveries.${idx}.delivery_cost_per_item`, value);
setFieldValue(`deliveries.${idx}.delivery_cost_per_item`, value);
const delivery = formik.values.deliveries?.[idx];
if (delivery) {
@@ -761,13 +780,13 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
);
if (productQty > 0 && value > 0) {
const totalCost = value * productQty;
formik.setFieldValue(`deliveries.${idx}.delivery_cost`, totalCost);
setFieldValue(`deliveries.${idx}.delivery_cost`, totalCost);
} else if (value === 0) {
formik.setFieldValue(`deliveries.${idx}.delivery_cost`, 0);
setFieldValue(`deliveries.${idx}.delivery_cost`, 0);
}
}
},
[formik.values.deliveries]
[formik.values.deliveries, setFieldValue]
);
const handleDeliveryCostChangeWrapper = useCallback(
@@ -1044,12 +1063,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
return !validateDeliveryQty(deliveryIdx, productIdx, qty);
})
) ?? []),
[
formik.values.deliveries,
formik.values.products,
validateDeliveryQty,
type,
]
[formik.values.deliveries, validateDeliveryQty, type]
);
const hasInvalidQty = useMemo(
@@ -1066,6 +1080,27 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
);
}, [formik.values.products, getProductQtyError, type]);
const deliveryCostDepString = useMemo(
() =>
formik.values.deliveries
?.map((d, idx) => ({
idx,
productQty: d.products.reduce(
(sum, p) => sum + (parseInt(p.product_qty.toString()) || 0),
0
),
deliveryCost: parseInt((d.delivery_cost || '').toString()) || 0,
deliveryCostPerItem:
parseInt((d.delivery_cost_per_item || '').toString()) || 0,
}))
.map(
(item) =>
`${item.idx}:${item.productQty}:${item.deliveryCost}:${item.deliveryCostPerItem}`
)
.join('|'),
[formik.values.deliveries]
);
// ===== EFFECTS =====
useEffect(() => {
formik.values.deliveries?.forEach((delivery, idx) => {
@@ -1082,36 +1117,16 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
if (deliveryCost > 0 && productQty > 0) {
const perItem = deliveryCost / productQty;
if (Math.abs(deliveryCostPerItem - perItem) > 0.01) {
formik.setFieldValue(
`deliveries.${idx}.delivery_cost_per_item`,
perItem
);
setFieldValue(`deliveries.${idx}.delivery_cost_per_item`, perItem);
}
} else if (deliveryCostPerItem > 0 && productQty > 0) {
const totalCost = deliveryCostPerItem * productQty;
if (Math.abs(deliveryCost - totalCost) > 0.01) {
formik.setFieldValue(`deliveries.${idx}.delivery_cost`, totalCost);
setFieldValue(`deliveries.${idx}.delivery_cost`, totalCost);
}
}
});
}, [
formik.values.deliveries
?.map((d, idx) => ({
idx,
productQty: d.products.reduce(
(sum, p) => sum + (parseInt(p.product_qty.toString()) || 0),
0
),
deliveryCost: parseInt((d.delivery_cost || '').toString()) || 0,
deliveryCostPerItem:
parseInt((d.delivery_cost_per_item || '').toString()) || 0,
}))
.map(
(item) =>
`${item.idx}:${item.productQty}:${item.deliveryCost}:${item.deliveryCostPerItem}`
)
.join('|'),
]);
}, [deliveryCostDepString, setFieldValue, formik.values.deliveries]);
useEffect(() => {
if (
@@ -1121,7 +1136,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
!isInitialized
) {
if (formik.values.products.length === 0) {
formik.setFieldValue('products', [
setFieldValue('products', [
{
product: null,
product_id: 0,
@@ -1130,7 +1145,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
]);
}
if (formik.values.deliveries.length === 0) {
formik.setFieldValue('deliveries', [
setFieldValue('deliveries', [
{
delivery_cost: undefined,
delivery_cost_per_item: undefined,
@@ -1152,7 +1167,14 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
}
setIsInitialized(true);
}
}, [formik.values.source_warehouse_id, isInitialized, type]);
}, [
formik.values.source_warehouse_id,
isInitialized,
type,
setFieldValue,
formik.values.products.length,
formik.values.deliveries.length,
]);
useEffect(() => {
if (
@@ -1161,7 +1183,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
formik.values.source_warehouse_id ===
formik.values.destination_warehouse_id
) {
formik.setFieldError(
setFieldError(
'destination_warehouse_id',
'Gudang tujuan tidak boleh sama dengan gudang asal!'
);
@@ -1170,13 +1192,14 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
formik.errors.destination_warehouse_id ===
'Gudang tujuan tidak boleh sama dengan gudang asal!'
) {
formik.setFieldError('destination_warehouse_id', undefined);
setFieldError('destination_warehouse_id', undefined);
}
}
}, [
formik.values.source_warehouse_id,
formik.values.destination_warehouse_id,
formik.errors.destination_warehouse_id,
setFieldError,
]);
useEffect(() => {
@@ -1212,29 +1235,37 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
);
if (hasChanges) {
formik.setFieldValue('deliveries', updatedDeliveries);
setFieldValue('deliveries', updatedDeliveries);
}
}
}, [formik.values.products]);
}, [formik.values.products, formik.values.deliveries, setFieldValue]);
const productQtyDepString = useMemo(
() => formik.values.products?.map((p) => p.product_qty).join(','),
[formik.values.products]
);
useEffect(() => {
if (productQtyErrorShown) {
toast.dismiss();
setProductQtyErrorShown(false);
}
}, [formik.values.products?.map((p) => p.product_qty).join(',')]);
}, [productQtyErrorShown]);
const deliveryProductQtyDepString = useMemo(
() =>
formik.values.deliveries
?.map((d) => d.products.map((p) => p.product_qty).join(','))
.join('|'),
[formik.values.deliveries]
);
useEffect(() => {
if (deliveryQtyErrorShown) {
toast.dismiss();
setDeliveryQtyErrorShown(false);
}
}, [
formik.values.deliveries
?.map((d) => d.products.map((p) => p.product_qty).join(','))
.join('|'),
formik.values.products?.map((p) => p.product_qty).join(','),
]);
}, [deliveryProductQtyDepString, productQtyDepString, deliveryQtyErrorShown]);
useEffect(() => {
if (hasExceededStock && !productQtyErrorShown && type !== 'detail') {