mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE): Refactor formik field methods to use destructured helpers
This commit is contained in:
@@ -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') {
|
||||
|
||||
Reference in New Issue
Block a user