mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
handle Errors message api
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
export const ERROR = {
|
||||||
|
// Sales Estimates
|
||||||
|
ESTIMATE_NUMBER_IS_NOT_UNQIUE: 'ESTIMATE.NUMBER.IS.NOT.UNQIUE',
|
||||||
|
|
||||||
|
// Sales Invoices
|
||||||
|
SALE_INVOICE_NUMBER_IS_EXISTS: 'SALE.INVOICE.NUMBER.IS.EXISTS',
|
||||||
|
SALE_INVOICE_NO_NOT_UNIQUE: 'SALE_INVOICE_NO_NOT_UNIQUE',
|
||||||
|
|
||||||
|
// Sales Receipts
|
||||||
|
SALE_RECEIPT_NUMBER_NOT_UNIQUE: 'SALE_RECEIPT_NUMBER_NOT_UNIQUE',
|
||||||
|
|
||||||
|
// Bills
|
||||||
|
BILL_NUMBER_EXISTS: 'BILL.NUMBER.EXISTS',
|
||||||
|
};
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ import withBillDetail from './withBillDetail';
|
|||||||
|
|
||||||
import { AppToaster } from 'components';
|
import { AppToaster } from 'components';
|
||||||
import useMedia from 'hooks/useMedia';
|
import useMedia from 'hooks/useMedia';
|
||||||
|
import { ERROR } from 'common/errors';
|
||||||
import { compose, repeatValue } from 'utils';
|
import { compose, repeatValue } from 'utils';
|
||||||
|
|
||||||
const MIN_LINES_NUMBER = 5;
|
const MIN_LINES_NUMBER = 5;
|
||||||
@@ -137,7 +137,6 @@ function BillForm({
|
|||||||
[],
|
[],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const defaultInitialValues = useMemo(
|
const defaultInitialValues = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
vendor_id: '',
|
vendor_id: '',
|
||||||
@@ -192,6 +191,16 @@ function BillForm({
|
|||||||
: [];
|
: [];
|
||||||
}, [bill]);
|
}, [bill]);
|
||||||
|
|
||||||
|
const handleErrors = (errors, { setErrors }) => {
|
||||||
|
if (errors.some((e) => e.type === ERROR.BILL_NUMBER_EXISTS)) {
|
||||||
|
setErrors({
|
||||||
|
bill_number: formatMessage({
|
||||||
|
id: 'bill_number_exists',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
// enableReinitialize: true,
|
// enableReinitialize: true,
|
||||||
validationSchema,
|
validationSchema,
|
||||||
@@ -222,7 +231,8 @@ function BillForm({
|
|||||||
saveBillSubmit({ action: 'update', ...payload });
|
saveBillSubmit({ action: 'update', ...payload });
|
||||||
resetForm();
|
resetForm();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((errors) => {
|
||||||
|
handleErrors(errors, { setErrors });
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -240,6 +250,7 @@ function BillForm({
|
|||||||
resetForm();
|
resetForm();
|
||||||
})
|
})
|
||||||
.catch((errors) => {
|
.catch((errors) => {
|
||||||
|
handleErrors(errors, { setErrors });
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import withSettings from 'containers/Settings/withSettings';
|
|||||||
import { AppToaster, Row, Col } from 'components';
|
import { AppToaster, Row, Col } from 'components';
|
||||||
import Dragzone from 'components/Dragzone';
|
import Dragzone from 'components/Dragzone';
|
||||||
import useMedia from 'hooks/useMedia';
|
import useMedia from 'hooks/useMedia';
|
||||||
|
import { ERROR } from 'common/errors';
|
||||||
|
|
||||||
import { compose, repeatValue } from 'utils';
|
import { compose, repeatValue } from 'utils';
|
||||||
|
|
||||||
@@ -204,6 +205,16 @@ const EstimateForm = ({
|
|||||||
: [];
|
: [];
|
||||||
}, [estimate]);
|
}, [estimate]);
|
||||||
|
|
||||||
|
const handleErrors = (errors, { setErrors }) => {
|
||||||
|
if (errors.some((e) => e.type === ERROR.ESTIMATE_NUMBER_IS_NOT_UNQIUE)) {
|
||||||
|
setErrors({
|
||||||
|
estimate_number: formatMessage({
|
||||||
|
id: 'estimate_number_is_not_unqiue',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
validationSchema,
|
validationSchema,
|
||||||
initialValues: {
|
initialValues: {
|
||||||
@@ -220,20 +231,25 @@ const EstimateForm = ({
|
|||||||
const requestForm = { ...form };
|
const requestForm = { ...form };
|
||||||
|
|
||||||
if (estimate && estimate.id) {
|
if (estimate && estimate.id) {
|
||||||
requestEditEstimate(estimate.id, requestForm).then((response) => {
|
requestEditEstimate(estimate.id, requestForm)
|
||||||
AppToaster.show({
|
.then((response) => {
|
||||||
message: formatMessage(
|
AppToaster.show({
|
||||||
{
|
message: formatMessage(
|
||||||
id: 'the_estimate_has_been_successfully_edited',
|
{
|
||||||
},
|
id: 'the_estimate_has_been_successfully_edited',
|
||||||
{ number: values.estimate_number },
|
},
|
||||||
),
|
{ number: values.estimate_number },
|
||||||
intent: Intent.SUCCESS,
|
),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
setSubmitting(false);
|
||||||
|
saveEstimateSubmit({ action: 'update', ...payload });
|
||||||
|
resetForm();
|
||||||
|
})
|
||||||
|
.catch((errors) => {
|
||||||
|
handleErrors(errors, { setErrors });
|
||||||
|
setSubmitting(false);
|
||||||
});
|
});
|
||||||
setSubmitting(false);
|
|
||||||
saveEstimateSubmit({ action: 'update', ...payload });
|
|
||||||
resetForm();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
requestSubmitEstimate(requestForm)
|
requestSubmitEstimate(requestForm)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@@ -249,6 +265,7 @@ const EstimateForm = ({
|
|||||||
saveEstimateSubmit({ action: 'new', ...payload });
|
saveEstimateSubmit({ action: 'new', ...payload });
|
||||||
})
|
})
|
||||||
.catch((errors) => {
|
.catch((errors) => {
|
||||||
|
handleErrors(errors, { setErrors });
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -302,10 +319,7 @@ const EstimateForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classNames(
|
<div className={classNames(CLASSES.PAGE_FORM, CLASSES.PAGE_FORM_ESTIMATE)}>
|
||||||
CLASSES.PAGE_FORM,
|
|
||||||
CLASSES.PAGE_FORM_ESTIMATE,
|
|
||||||
)}>
|
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={formik.handleSubmit}>
|
||||||
<EstimateFormHeader formik={formik} />
|
<EstimateFormHeader formik={formik} />
|
||||||
<EntriesItemsTable
|
<EntriesItemsTable
|
||||||
@@ -366,7 +380,7 @@ export default compose(
|
|||||||
withDashboardActions,
|
withDashboardActions,
|
||||||
withMediaActions,
|
withMediaActions,
|
||||||
withSettings(({ estimatesSettings }) => ({
|
withSettings(({ estimatesSettings }) => ({
|
||||||
estimateNextNumber: estimatesSettings?.next_number,
|
estimateNextNumber: estimatesSettings?.nextNumber,
|
||||||
estimateNumberPrefix: estimatesSettings?.number_prefix,
|
estimateNumberPrefix: estimatesSettings?.numberPrefix,
|
||||||
})),
|
})),
|
||||||
)(EstimateForm);
|
)(EstimateForm);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import withSettings from 'containers/Settings/withSettings';
|
|||||||
import { AppToaster, Col, Row } from 'components';
|
import { AppToaster, Col, Row } from 'components';
|
||||||
import Dragzone from 'components/Dragzone';
|
import Dragzone from 'components/Dragzone';
|
||||||
import useMedia from 'hooks/useMedia';
|
import useMedia from 'hooks/useMedia';
|
||||||
|
import { ERROR } from 'common/errors';
|
||||||
|
|
||||||
import { compose, repeatValue } from 'utils';
|
import { compose, repeatValue } from 'utils';
|
||||||
|
|
||||||
@@ -206,6 +207,16 @@ function InvoiceForm({
|
|||||||
: [];
|
: [];
|
||||||
}, [invoice]);
|
}, [invoice]);
|
||||||
|
|
||||||
|
const handleErrors = (errors, { setErrors }) => {
|
||||||
|
if (errors.some((e) => e.type === ERROR.SALE_INVOICE_NUMBER_IS_EXISTS)) {
|
||||||
|
setErrors({
|
||||||
|
invoice_no: formatMessage({
|
||||||
|
id: 'sale_invoice_number_is_exists',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
validationSchema,
|
validationSchema,
|
||||||
initialValues: {
|
initialValues: {
|
||||||
@@ -239,7 +250,8 @@ function InvoiceForm({
|
|||||||
saveInvokeSubmit({ action: 'update', ...payload });
|
saveInvokeSubmit({ action: 'update', ...payload });
|
||||||
resetForm();
|
resetForm();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((errors) => {
|
||||||
|
handleErrors(errors, { setErrors });
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -257,12 +269,12 @@ function InvoiceForm({
|
|||||||
resetForm();
|
resetForm();
|
||||||
})
|
})
|
||||||
.catch((errors) => {
|
.catch((errors) => {
|
||||||
|
handleErrors(errors, { setErrors });
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
formik.setFieldValue('invoice_no', invoiceNumber);
|
formik.setFieldValue('invoice_no', invoiceNumber);
|
||||||
}, [invoiceNumber]);
|
}, [invoiceNumber]);
|
||||||
@@ -373,7 +385,7 @@ export default compose(
|
|||||||
withInvoiceDetail(),
|
withInvoiceDetail(),
|
||||||
|
|
||||||
withSettings(({ invoiceSettings }) => ({
|
withSettings(({ invoiceSettings }) => ({
|
||||||
invoiceNextNumber: invoiceSettings?.next_number,
|
invoiceNextNumber: invoiceSettings?.nextNumber,
|
||||||
invoiceNumberPrefix: invoiceSettings?.number_prefix,
|
invoiceNumberPrefix: invoiceSettings?.numberPrefix,
|
||||||
})),
|
})),
|
||||||
)(InvoiceForm);
|
)(InvoiceForm);
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ function InvoiceFormHeader({
|
|||||||
className={classNames(
|
className={classNames(
|
||||||
'form-group--select-list',
|
'form-group--select-list',
|
||||||
'form-group--invoice-date',
|
'form-group--invoice-date',
|
||||||
CLASSES.FILL
|
CLASSES.FILL,
|
||||||
)}
|
)}
|
||||||
intent={
|
intent={
|
||||||
errors.invoice_date && touched.invoice_date && Intent.DANGER
|
errors.invoice_date && touched.invoice_date && Intent.DANGER
|
||||||
@@ -149,7 +149,7 @@ function InvoiceFormHeader({
|
|||||||
className={classNames(
|
className={classNames(
|
||||||
'form-group--select-list',
|
'form-group--select-list',
|
||||||
'form-group--due-date',
|
'form-group--due-date',
|
||||||
CLASSES.FILL
|
CLASSES.FILL,
|
||||||
)}
|
)}
|
||||||
intent={errors.due_date && touched.due_date && Intent.DANGER}
|
intent={errors.due_date && touched.due_date && Intent.DANGER}
|
||||||
helperText={
|
helperText={
|
||||||
@@ -175,23 +175,23 @@ function InvoiceFormHeader({
|
|||||||
helperText={
|
helperText={
|
||||||
<ErrorMessage name="invoice_no" {...{ errors, touched }} />
|
<ErrorMessage name="invoice_no" {...{ errors, touched }} />
|
||||||
}
|
}
|
||||||
rightElement={
|
|
||||||
<InputPrependButton
|
|
||||||
buttonProps={{
|
|
||||||
onClick: handleInvoiceNumberChange,
|
|
||||||
icon: <Icon icon={'settings-18'} />,
|
|
||||||
}}
|
|
||||||
tooltip={true}
|
|
||||||
tooltipProps={{
|
|
||||||
content: 'Setting your auto-generated invoice number',
|
|
||||||
position: Position.BOTTOM_LEFT,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<InputGroup
|
<InputGroup
|
||||||
intent={errors.invoice_no && touched.invoice_no && Intent.DANGER}
|
intent={errors.invoice_no && touched.invoice_no && Intent.DANGER}
|
||||||
minimal={true}
|
minimal={true}
|
||||||
|
rightElement={
|
||||||
|
<InputPrependButton
|
||||||
|
buttonProps={{
|
||||||
|
onClick: handleInvoiceNumberChange,
|
||||||
|
icon: <Icon icon={'settings-18'} />,
|
||||||
|
}}
|
||||||
|
tooltip={true}
|
||||||
|
tooltipProps={{
|
||||||
|
content: 'Setting your auto-generated invoice number',
|
||||||
|
position: Position.BOTTOM_LEFT,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
{...getFieldProps('invoice_no')}
|
{...getFieldProps('invoice_no')}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|||||||
@@ -8,13 +8,22 @@ import DashboardInsider from 'components/Dashboard/DashboardInsider';
|
|||||||
import withCustomersActions from 'containers/Customers/withCustomersActions';
|
import withCustomersActions from 'containers/Customers/withCustomersActions';
|
||||||
import withItemsActions from 'containers/Items/withItemsActions';
|
import withItemsActions from 'containers/Items/withItemsActions';
|
||||||
import withInvoiceActions from './withInvoiceActions';
|
import withInvoiceActions from './withInvoiceActions';
|
||||||
|
import withSettingsActions from 'containers/Settings/withSettingsActions';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
function Invoices({
|
function Invoices({
|
||||||
|
// #withCustomersActions
|
||||||
requestFetchCustomers,
|
requestFetchCustomers,
|
||||||
|
|
||||||
|
// #withItemsActions
|
||||||
requestFetchItems,
|
requestFetchItems,
|
||||||
|
|
||||||
|
// #withInvoiceActions
|
||||||
requsetFetchInvoice,
|
requsetFetchInvoice,
|
||||||
|
|
||||||
|
// #withSettingsActions
|
||||||
|
requestFetchOptions,
|
||||||
}) {
|
}) {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@@ -25,6 +34,8 @@ function Invoices({
|
|||||||
{ enabled: !!id },
|
{ enabled: !!id },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fetchSettings = useQuery(['settings'], () => requestFetchOptions({}));
|
||||||
|
|
||||||
// Handle fetch Items data table or list
|
// Handle fetch Items data table or list
|
||||||
const fetchItems = useQuery('items-table', () => requestFetchItems({}));
|
const fetchItems = useQuery('items-table', () => requestFetchItems({}));
|
||||||
|
|
||||||
@@ -65,4 +76,5 @@ export default compose(
|
|||||||
withInvoiceActions,
|
withInvoiceActions,
|
||||||
withCustomersActions,
|
withCustomersActions,
|
||||||
withItemsActions,
|
withItemsActions,
|
||||||
|
withSettingsActions,
|
||||||
)(Invoices);
|
)(Invoices);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import { pick } from 'lodash';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
|
import { ERROR } from 'common/errors';
|
||||||
import ReceiptFromHeader from './ReceiptFormHeader';
|
import ReceiptFromHeader from './ReceiptFormHeader';
|
||||||
import EntriesItemsTable from 'containers/Sales/Estimate/EntriesItemsTable';
|
import EntriesItemsTable from 'containers/Sales/Estimate/EntriesItemsTable';
|
||||||
import ReceiptReceiveFloatingActions from './ReceiptReceiveFloatingActions';
|
import ReceiptReceiveFloatingActions from './ReceiptReceiveFloatingActions';
|
||||||
@@ -108,7 +108,6 @@ function ReceiptForm({
|
|||||||
.min(1)
|
.min(1)
|
||||||
.max(1024)
|
.max(1024)
|
||||||
.label(formatMessage({ id: 'receipt_message_' })),
|
.label(formatMessage({ id: 'receipt_message_' })),
|
||||||
send_to_email: Yup.string().email().nullable(),
|
|
||||||
statement: Yup.string()
|
statement: Yup.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(1)
|
.min(1)
|
||||||
@@ -159,7 +158,6 @@ function ReceiptForm({
|
|||||||
deposit_account_id: '',
|
deposit_account_id: '',
|
||||||
receipt_number: receiptNumber,
|
receipt_number: receiptNumber,
|
||||||
receipt_date: moment(new Date()).format('YYYY-MM-DD'),
|
receipt_date: moment(new Date()).format('YYYY-MM-DD'),
|
||||||
send_to_email: '',
|
|
||||||
reference_no: '',
|
reference_no: '',
|
||||||
receipt_message: '',
|
receipt_message: '',
|
||||||
statement: '',
|
statement: '',
|
||||||
@@ -208,6 +206,15 @@ function ReceiptForm({
|
|||||||
: [];
|
: [];
|
||||||
}, [receipt]);
|
}, [receipt]);
|
||||||
|
|
||||||
|
const handleErrors = (errors, { setErrors }) => {
|
||||||
|
if (errors.some((e) => e.type === ERROR.SALE_RECEIPT_NUMBER_NOT_UNIQUE)) {
|
||||||
|
setErrors({
|
||||||
|
receipt_number: formatMessage({
|
||||||
|
id: 'sale_receipt_number_not_unique',
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
validationSchema,
|
validationSchema,
|
||||||
initialValues: {
|
initialValues: {
|
||||||
@@ -225,20 +232,25 @@ function ReceiptForm({
|
|||||||
const requestForm = { ...form };
|
const requestForm = { ...form };
|
||||||
|
|
||||||
if (receipt && receipt.id) {
|
if (receipt && receipt.id) {
|
||||||
requestEditReceipt(receipt.id, requestForm).then(() => {
|
requestEditReceipt(receipt.id, requestForm)
|
||||||
AppToaster.show({
|
.then(() => {
|
||||||
message: formatMessage(
|
AppToaster.show({
|
||||||
{
|
message: formatMessage(
|
||||||
id: 'the_receipt_has_been_successfully_edited',
|
{
|
||||||
},
|
id: 'the_receipt_has_been_successfully_edited',
|
||||||
{ number: values.receipt_number },
|
},
|
||||||
),
|
{ number: values.receipt_number },
|
||||||
intent: Intent.SUCCESS,
|
),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
setSubmitting(false);
|
||||||
|
saveInvokeSubmit({ action: 'update', ...payload });
|
||||||
|
resetForm();
|
||||||
|
})
|
||||||
|
.catch((errors) => {
|
||||||
|
handleErrors(errors, { setErrors });
|
||||||
|
setSubmitting(false);
|
||||||
});
|
});
|
||||||
setSubmitting(false);
|
|
||||||
saveInvokeSubmit({ action: 'update', ...payload });
|
|
||||||
resetForm();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
requestSubmitReceipt(requestForm)
|
requestSubmitReceipt(requestForm)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
@@ -256,6 +268,7 @@ function ReceiptForm({
|
|||||||
resetForm();
|
resetForm();
|
||||||
})
|
})
|
||||||
.catch((errors) => {
|
.catch((errors) => {
|
||||||
|
handleErrors(errors, { setErrors });
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -783,4 +783,9 @@ export default {
|
|||||||
receipt_number_settings: 'Receipt Number Settings',
|
receipt_number_settings: 'Receipt Number Settings',
|
||||||
invoice_number_settings: 'Invoice Number Settings',
|
invoice_number_settings: 'Invoice Number Settings',
|
||||||
receipt_number: 'Receipt Number',
|
receipt_number: 'Receipt Number',
|
||||||
|
estimate_number_is_not_unqiue: 'Estimate number is not unqiue',
|
||||||
|
invoice_number_is_not_unqiue: 'Invoice number is not unqiue',
|
||||||
|
sale_receipt_number_not_unique: 'Receipt number is not unique',
|
||||||
|
sale_invoice_number_is_exists: 'Sale invoice number is exists',
|
||||||
|
bill_number_exists:'Bill number exists'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ export default class SalesReceiptsController extends BaseController{
|
|||||||
check('customer_id').exists().isNumeric().toInt(),
|
check('customer_id').exists().isNumeric().toInt(),
|
||||||
check('deposit_account_id').exists().isNumeric().toInt(),
|
check('deposit_account_id').exists().isNumeric().toInt(),
|
||||||
check('receipt_date').exists().isISO8601(),
|
check('receipt_date').exists().isISO8601(),
|
||||||
check('send_to_email').optional().isEmail(),
|
|
||||||
check('receipt_number').optional().trim().escape(),
|
check('receipt_number').optional().trim().escape(),
|
||||||
check('reference_no').optional().trim().escape(),
|
check('reference_no').optional().trim().escape(),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user