mirror of
https://github.com/strapi/strapi.git
synced 2025-10-13 17:15:33 +00:00
form to edit email templates
This commit is contained in:
parent
f6497639e7
commit
11c5905d25
@ -141,7 +141,7 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
|
||||
}
|
||||
case 'providers':
|
||||
case 'email-templates':
|
||||
return router.push(`${router.location.pathname}#edit::${this.props.settingType}::${this.props.item.id}`);
|
||||
return this.context.setDataToEdit(this.props.item.name);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
@ -168,6 +168,10 @@ class ListRow extends React.Component { // eslint-disable-line react/prefer-stat
|
||||
}
|
||||
}
|
||||
|
||||
ListRow.contextTypes = {
|
||||
setDataToEdit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
ListRow.defaultProps = {
|
||||
item: {
|
||||
name: 'Owner',
|
||||
|
@ -8,16 +8,16 @@ import React from 'react';
|
||||
import { Button, Modal, ModalHeader, ModalBody, ModalFooter } from 'reactstrap';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { get } from 'lodash';
|
||||
import { router } from 'app';
|
||||
import { get, isObject, includes, map, take, takeRight } from 'lodash';
|
||||
|
||||
// Translations
|
||||
import en from 'translations/en.json';
|
||||
|
||||
import Input from 'components/Input';
|
||||
|
||||
import styles from './styles.scss';
|
||||
|
||||
class PopUpForm extends React.Component { // eslint-disable-line react/prefer-stateless-function
|
||||
toggleModal = () => router.push(router.location.pathname);
|
||||
|
||||
renderButton = () => {
|
||||
if (this.props.showLoader) {
|
||||
return (
|
||||
@ -37,6 +37,8 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
|
||||
}
|
||||
|
||||
renderForm = () => {
|
||||
const { dataToEdit, values } = this.props;
|
||||
|
||||
if (this.props.settingType === 'providers') {
|
||||
return (
|
||||
<div className="row">
|
||||
@ -64,71 +66,74 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
|
||||
);
|
||||
}
|
||||
|
||||
const form = Object.keys(values.options || {}).reduce((acc, current) => {
|
||||
if (isObject(get(values, ['options', current]))) {
|
||||
return Object.keys(get(values, ['options', current], {}))
|
||||
.reduce((acc, curr) => {
|
||||
acc.push(`options.${current}.${curr}`);
|
||||
|
||||
return acc;
|
||||
}, []).concat(acc);
|
||||
} else {
|
||||
acc.push(`options.${current}`);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="row">
|
||||
<Input
|
||||
autoFocus
|
||||
label="users-permissions.PopUpForm.inputText.shipperName.label"
|
||||
name="shipperName"
|
||||
onChange={this.props.onChange}
|
||||
value={get(this.props.values, 'shipperName')}
|
||||
placeholder="users-permissions.PopUpForm.inputText.shipperName.placeholder"
|
||||
type="text"
|
||||
validations={{}}
|
||||
/>
|
||||
<Input
|
||||
label="users-permissions.PopUpForm.inputEmail.shipperEmail.label"
|
||||
name="shipperEmail"
|
||||
onChange={this.props.onChange}
|
||||
placeholder="users-permissions.PopUpForm.inputEmail.placeholder"
|
||||
type="email"
|
||||
validations={{ required: true }}
|
||||
value={get(this.props.values, 'shipperEmail')}
|
||||
/>
|
||||
<Input
|
||||
label="users-permissions.PopUpForm.inputEmail.responseEmail.label"
|
||||
name="responseEmail"
|
||||
onChange={this.props.onChange}
|
||||
placeholder="users-permissions.PopUpForm.inputEmail.placeholder"
|
||||
type="email"
|
||||
validations={{}}
|
||||
value={get(this.props.values, 'responseEmail')}
|
||||
/>
|
||||
{map(take(form, 3), (value, key) => (
|
||||
<Input
|
||||
autoFocus={key === 0}
|
||||
key={value}
|
||||
label={`users-permissions.PopUpForm.Email.${value}.label`}
|
||||
name={`${dataToEdit}.${value}`}
|
||||
onChange={this.props.onChange}
|
||||
placeholder={`users-permissions.PopUpForm.Email.${value}.placeholder`}
|
||||
type={includes(value, 'email') ? 'email' : 'text'}
|
||||
value={get(values, value)}
|
||||
validations={{}}
|
||||
/>
|
||||
))}
|
||||
<div className="col-md-6" />
|
||||
<Input
|
||||
customBootstrapClass="col-md-12"
|
||||
label="users-permissions.PopUpForm.inputText.emailObject.label"
|
||||
name="emailObject"
|
||||
onChange={this.props.onChange}
|
||||
placeholder="users-permissions.PopUpForm.inputText.emailObject.placeholder"
|
||||
type="text"
|
||||
validations={{}}
|
||||
value={get(this.props.values, 'emailObject')}
|
||||
/>
|
||||
<Input
|
||||
customBootstrapClass="col-md-12"
|
||||
label="users-permissions.PopUpForm.inputTextArea.message.label"
|
||||
name="message"
|
||||
onChange={this.props.onChange}
|
||||
placeholder="users-permissions.PopUpForm.inputTextArea.message.placeholder"
|
||||
type="textarea"
|
||||
validations={{}}
|
||||
value={get(this.props.values, 'message')}
|
||||
/>
|
||||
{map(takeRight(form, 2), (value) => (
|
||||
<Input
|
||||
key={value}
|
||||
customBootstrapClass="col-md-12"
|
||||
label={`users-permissions.PopUpForm.Email.${value}.label`}
|
||||
name={`${dataToEdit}.${value}`}
|
||||
onChange={this.props.onChange}
|
||||
placeholder={`users-permissions.PopUpForm.Email.${this.props.dataToEdit}.${value}.placeholder`}
|
||||
type={includes(value, 'object') ? 'text' : 'textarea'}
|
||||
validations={{}}
|
||||
value={get(values, value)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { actionType, dataToEdit, display, settingType } = this.props.values;
|
||||
|
||||
let header = <span>{dataToEdit}</span>;
|
||||
|
||||
if (actionType) {
|
||||
header = <FormattedMessage id={`users-permissions.PopUpForm.header.${actionType}.${settingType}`} />;
|
||||
}
|
||||
|
||||
if (display && en[display]) {
|
||||
header = <FormattedMessage id={`users-permissions.${display}`} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.popUpForm}>
|
||||
<Modal isOpen={this.props.isOpen} toggle={this.toggleModal} className={`${styles.modalPosition}`}>
|
||||
<ModalHeader toggle={this.toggleModal} className={styles.modalHeader} />
|
||||
<Modal isOpen={this.props.isOpen} toggle={this.context.unsetDataToEdit} className={`${styles.modalPosition}`}>
|
||||
<ModalHeader toggle={this.context.unsetDataToEdit} className={styles.modalHeader} />
|
||||
<div className={styles.headerContainer}>
|
||||
<div>
|
||||
{this.props.actionType ? (
|
||||
<FormattedMessage id={`users-permissions.PopUpForm.header.${this.props.actionType}.${this.props.settingType}`} />
|
||||
) : <div />}
|
||||
{header}
|
||||
</div>
|
||||
</div>
|
||||
<form onSubmit={this.props.onSubmit}>
|
||||
@ -138,7 +143,7 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
|
||||
</div>
|
||||
</ModalBody>
|
||||
<ModalFooter className={styles.modalFooter}>
|
||||
<Button onClick={() => router.push(router.location.pathname)} className={styles.secondary}>
|
||||
<Button onClick={() => this.context.unsetDataToEdit()} className={styles.secondary}>
|
||||
<FormattedMessage id="users-permissions.PopUpForm.button.cancel" />
|
||||
</Button>
|
||||
{this.renderButton()}
|
||||
@ -150,6 +155,10 @@ class PopUpForm extends React.Component { // eslint-disable-line react/prefer-st
|
||||
}
|
||||
}
|
||||
|
||||
PopUpForm.contextTypes = {
|
||||
unsetDataToEdit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
PopUpForm.defaultProps = {
|
||||
settingType: 'providers',
|
||||
showLoader: false,
|
||||
@ -157,6 +166,7 @@ PopUpForm.defaultProps = {
|
||||
|
||||
PopUpForm.propTypes = {
|
||||
actionType: PropTypes.string.isRequired,
|
||||
dataToEdit: PropTypes.string.isRequired,
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
onSubmit: PropTypes.func.isRequired,
|
||||
|
@ -3,7 +3,7 @@
|
||||
* HomePage actions
|
||||
*
|
||||
*/
|
||||
import { Map } from 'immutable';
|
||||
import { fromJS } from 'immutable';
|
||||
import { isArray } from 'lodash';
|
||||
import {
|
||||
CANCEL_CHANGES,
|
||||
@ -12,9 +12,11 @@ import {
|
||||
FETCH_DATA,
|
||||
FETCH_DATA_SUCCEEDED,
|
||||
ON_CHANGE,
|
||||
SET_DATA_TO_EDIT,
|
||||
SET_FORM,
|
||||
SUBMIT,
|
||||
SUBMIT_SUCCEEDED,
|
||||
UNSET_DATA_TO_EDIT,
|
||||
} from './constants';
|
||||
|
||||
export function cancelChanges() {
|
||||
@ -57,12 +59,14 @@ export function fetchDataSucceeded(data) {
|
||||
return {
|
||||
type: FETCH_DATA_SUCCEEDED,
|
||||
data: list,
|
||||
modifiedData: fromJS(data),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
type: FETCH_DATA_SUCCEEDED,
|
||||
data,
|
||||
modifiedData: Map({}),
|
||||
};
|
||||
}
|
||||
|
||||
@ -74,6 +78,13 @@ export function onChange({ target }) {
|
||||
};
|
||||
}
|
||||
|
||||
export function setDataToEdit(dataToEdit) {
|
||||
return {
|
||||
type: SET_DATA_TO_EDIT,
|
||||
dataToEdit,
|
||||
};
|
||||
}
|
||||
|
||||
export function setForm(data) {
|
||||
// const form = generateForm(formType);
|
||||
return {
|
||||
@ -95,6 +106,12 @@ export function submitSucceeded() {
|
||||
};
|
||||
}
|
||||
|
||||
export function unsetDataToEdit() {
|
||||
return {
|
||||
type: UNSET_DATA_TO_EDIT,
|
||||
};
|
||||
}
|
||||
|
||||
// Utils
|
||||
|
||||
// function generateForm(formType) {
|
||||
|
@ -10,6 +10,8 @@ export const DELETE_DATA_SUCCEEDED = 'UsersPermissions/HomePage/DELETE_DATA_SUCC
|
||||
export const FETCH_DATA = 'UsersPermissions/HomePage/FETCH_DATA';
|
||||
export const FETCH_DATA_SUCCEEDED = 'UsersPermissions/HomePage/FETCH_DATA_SUCCEEDED';
|
||||
export const ON_CHANGE = 'UsersPermissions/HomePage/ON_CHANGE';
|
||||
export const SET_DATA_TO_EDIT = 'UsersPermissions/HomePage/SET_DATA_TO_EDIT';
|
||||
export const SET_FORM = 'UsersPermissions/HomePage/SET_FORM';
|
||||
export const SUBMIT = 'UsersPermissions/HomePage/SUBMIT';
|
||||
export const SUBMIT_SUCCEEDED = 'UsersPermissions/HomePage/SUBMIT_SUCCEEDED';
|
||||
export const UNSET_DATA_TO_EDIT = 'UsersPermissions/HomePage/UNSET_DATA_TO_EDIT';
|
||||
|
@ -10,7 +10,7 @@ import { connect } from 'react-redux';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import { bindActionCreators, compose } from 'redux';
|
||||
import cn from 'classnames';
|
||||
import { clone, includes, isEqual, isEmpty, replace } from 'lodash';
|
||||
import { clone, includes, isEqual, isEmpty } from 'lodash';
|
||||
|
||||
// Design
|
||||
import EditForm from 'components/EditForm';
|
||||
@ -35,7 +35,9 @@ import {
|
||||
deleteData,
|
||||
fetchData,
|
||||
onChange,
|
||||
setDataToEdit,
|
||||
submit,
|
||||
unsetDataToEdit,
|
||||
} from './actions';
|
||||
|
||||
import reducer from './reducer';
|
||||
@ -44,7 +46,14 @@ import saga from './saga';
|
||||
const keyBoardShortCuts = [18, 78];
|
||||
|
||||
export class HomePage extends React.Component {
|
||||
state = { mapKey: {} };
|
||||
state = { mapKey: {}, showModalEdit: false };
|
||||
|
||||
getChildContext = () => (
|
||||
{
|
||||
setDataToEdit: this.props.setDataToEdit,
|
||||
unsetDataToEdit: this.props.unsetDataToEdit,
|
||||
}
|
||||
);
|
||||
|
||||
componentDidMount() {
|
||||
this.props.fetchData(this.props.match.params.settingType);
|
||||
@ -52,6 +61,12 @@ export class HomePage extends React.Component {
|
||||
document.addEventListener('keyup', this.handleKeyBoardShortCut);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
if (nextProps.dataToEdit !== this.props.dataToEdit) {
|
||||
this.setState({ showModalEdit: !isEmpty(nextProps.dataToEdit) });
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUpdate(nextProps) {
|
||||
const allowedPaths = ['roles', 'providers', 'email-templates', 'advanced'];
|
||||
const shouldRedirect = allowedPaths.filter(el => el === nextProps.match.params.settingType).length === 0;
|
||||
@ -111,7 +126,7 @@ export class HomePage extends React.Component {
|
||||
];
|
||||
|
||||
render() {
|
||||
const { modifiedData, initialData, match } = this.props;
|
||||
const { modifiedData, initialData, match, dataToEdit } = this.props;
|
||||
const headerActions = match.params.settingType === 'advanced' && !isEqual(modifiedData, initialData) ?
|
||||
this.pluginHeaderActions : [];
|
||||
const noButtonList = match.params.settingType === 'email-templates' || match.params.settingType === 'providers';
|
||||
@ -122,10 +137,9 @@ export class HomePage extends React.Component {
|
||||
deleteData={this.props.deleteData}
|
||||
noButton={noButtonList}
|
||||
onButtonClick={this.handleButtonClick}
|
||||
settingType={this.props.match.params.settingType}
|
||||
settingType={match.params.settingType}
|
||||
/>
|
||||
);
|
||||
const hashArray = replace(this.props.location.hash, '#', '').split('::');
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -140,14 +154,15 @@ export class HomePage extends React.Component {
|
||||
{component}
|
||||
</div>
|
||||
<PopUpForm
|
||||
actionType={hashArray[0]}
|
||||
isOpen={!isEmpty(this.props.location.hash)}
|
||||
actionType={'edit'}
|
||||
isOpen={this.state.showModalEdit}
|
||||
dataToEdit={dataToEdit}
|
||||
onChange={this.props.onChange}
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
}}
|
||||
settingType={hashArray[1]}
|
||||
values={modifiedData}
|
||||
settingType={match.params.settingType}
|
||||
values={modifiedData[dataToEdit] || {}}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
@ -155,11 +170,17 @@ export class HomePage extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
HomePage.childContextTypes = {
|
||||
setDataToEdit: PropTypes.func,
|
||||
unsetDataToEdit: PropTypes.func,
|
||||
};
|
||||
|
||||
HomePage.defaultProps = {};
|
||||
|
||||
HomePage.propTypes = {
|
||||
cancelChanges: PropTypes.func.isRequired,
|
||||
data: PropTypes.array.isRequired,
|
||||
dataToEdit: PropTypes.string.isRequired,
|
||||
deleteData: PropTypes.func.isRequired,
|
||||
fetchData: PropTypes.func.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
@ -168,7 +189,9 @@ HomePage.propTypes = {
|
||||
match: PropTypes.object.isRequired,
|
||||
modifiedData: PropTypes.object.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
setDataToEdit: PropTypes.func.isRequired,
|
||||
submit: PropTypes.func.isRequired,
|
||||
unsetDataToEdit: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
|
||||
@ -179,7 +202,9 @@ function mapDispatchToProps(dispatch) {
|
||||
deleteData,
|
||||
fetchData,
|
||||
onChange,
|
||||
setDataToEdit,
|
||||
submit,
|
||||
unsetDataToEdit,
|
||||
},
|
||||
dispatch,
|
||||
);
|
||||
|
@ -12,13 +12,16 @@ import {
|
||||
DELETE_DATA_SUCCEEDED,
|
||||
FETCH_DATA_SUCCEEDED,
|
||||
ON_CHANGE,
|
||||
SET_DATA_TO_EDIT,
|
||||
SET_FORM,
|
||||
SUBMIT_SUCCEEDED,
|
||||
UNSET_DATA_TO_EDIT,
|
||||
} from './constants';
|
||||
|
||||
const initialState = fromJS({
|
||||
data: List([]),
|
||||
dataToDelete: Map({}),
|
||||
dataToEdit: '',
|
||||
deleteEndPoint: '',
|
||||
initialData: Map({}),
|
||||
modifiedData: Map({}),
|
||||
@ -27,8 +30,7 @@ const initialState = fromJS({
|
||||
function homePageReducer(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case CANCEL_CHANGES:
|
||||
return state
|
||||
.update('modifiedData', () => state.get('initialData'));
|
||||
return state.update('modifiedData', () => state.get('initialData'));
|
||||
case DELETE_DATA:
|
||||
return state
|
||||
.set('dataToDelete', Map(action.dataToDelete))
|
||||
@ -39,17 +41,25 @@ function homePageReducer(state = initialState, action) {
|
||||
.set('deleteEndPoint', '')
|
||||
.set('dataToDelete', Map({}));
|
||||
case FETCH_DATA_SUCCEEDED:
|
||||
return state.set('data', List(action.data));
|
||||
return state
|
||||
.set('data', List(action.data))
|
||||
.set('initialData', action.modifiedData)
|
||||
.set('modifiedData', action.modifiedData);
|
||||
case ON_CHANGE:
|
||||
return state
|
||||
.updateIn(action.keys, () => action.value);
|
||||
case SET_DATA_TO_EDIT:
|
||||
return state.update('dataToEdit', () => action.dataToEdit);
|
||||
case SET_FORM:
|
||||
return state
|
||||
.set('initialData', action.form)
|
||||
.set('modifiedData', action.form);
|
||||
case SUBMIT_SUCCEEDED:
|
||||
return state.update('initialData', () => state.get('modifiedData'));
|
||||
case UNSET_DATA_TO_EDIT:
|
||||
return state
|
||||
.update('initialData', () => state.get('modifiedData'));
|
||||
.update('dataToEdit', () => '')
|
||||
.update('modifiedData', () => state.get('initialData'));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -138,13 +138,18 @@
|
||||
"PopUpForm.inputSelect.providers.label": "Choose the provider",
|
||||
"PopUpForm.inputToggle.providers.label": "Enable",
|
||||
"PopUpForm.inputToggle.providers.description": "If disabled, the users won't be able to use this provider.",
|
||||
"PopUpForm.inputText.shipperName.label": "Shipper name",
|
||||
"PopUpForm.inputEmail.shipperEmail.label": "Shipper email",
|
||||
"PopUpForm.inputEmail.responseEmail.label": "Response email",
|
||||
"PopUpForm.inputText.emailObject.label": "Object",
|
||||
"PopUpForm.inputText.emailObject.placeholder": "Please confirm your email address for %APP_NAME%",
|
||||
"PopUpForm.inputTextArea.message.label": "Message",
|
||||
"PopUpForm.inputTextArea.message.placeholder": "<p>Please click on this link to validate your account</p>",
|
||||
"PopUpForm.inputEmail.placeholder": "johndoe@gmail.com",
|
||||
"PopUpForm.inputText.shipperName.placeholder": "John Doe"
|
||||
"PopUpForm.Email.options.from.name.label": "Shipper name",
|
||||
"PopUpForm.Email.options.from.email.label": "Shipper email",
|
||||
"PopUpForm.Email.options.response_email.label": "Response email",
|
||||
"PopUpForm.Email.options.object.label": "Object",
|
||||
"PopUpForm.Email.options.message.label": "Message",
|
||||
"PopUpForm.Email.validation_email.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
|
||||
"PopUpForm.Email.reset_password.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
|
||||
"PopUpForm.Email.success_register.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
|
||||
"PopUpForm.Email.validation_email.options.message.placeholder": "<p>Please click on this link to validate your account</p>",
|
||||
"PopUpForm.Email.reset_password.options.message.placeholder": "<p>Please click on this link to validate your account</p>",
|
||||
"PopUpForm.Email.success_register.options.message.placeholder": "<p>Please click on this link to validate your account</p>",
|
||||
"PopUpForm.Email.options.from.email.placeholder": "johndoe@gmail.com",
|
||||
"PopUpForm.Email.options.response_email.placeholder": "johndoe@gmail.com",
|
||||
"PopUpForm.Email.options.from.name.placeholder": "John Doe"
|
||||
}
|
||||
|
@ -82,10 +82,10 @@ module.exports = cb => {
|
||||
icon: 'envelope',
|
||||
options: {
|
||||
from: {
|
||||
email: '',
|
||||
name: ''
|
||||
name: 'Administration Panel',
|
||||
email: 'no-reply@strapi.io'
|
||||
},
|
||||
respond: '',
|
||||
response_email: '',
|
||||
object: '',
|
||||
message: ''
|
||||
}
|
||||
@ -95,10 +95,10 @@ module.exports = cb => {
|
||||
icon: 'refresh',
|
||||
options: {
|
||||
from: {
|
||||
email: '',
|
||||
name: ''
|
||||
name: 'Administration Panel',
|
||||
email: 'no-reply@strapi.io'
|
||||
},
|
||||
respond: '',
|
||||
response_email: '',
|
||||
object: 'Reset password 🔑 ',
|
||||
message: `<p>We heard that you lost your password. Sorry about that!</p>
|
||||
|
||||
@ -114,10 +114,10 @@ module.exports = cb => {
|
||||
icon: 'check',
|
||||
options: {
|
||||
from: {
|
||||
email: '',
|
||||
name: ''
|
||||
name: 'Administration Panel',
|
||||
email: 'no-reply@strapi.io'
|
||||
},
|
||||
respond: '',
|
||||
response_email: '',
|
||||
object: '',
|
||||
message: ''
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ module.exports = {
|
||||
await strapi.plugins['email'].services.email.send({
|
||||
to: user.email,
|
||||
from: (settings.from.email || settings.from.email) ? `"${settings.from.name}" <${settings.from.email}>` : undefined,
|
||||
replyTo: settings.respond,
|
||||
replyTo: settings.response_email,
|
||||
subject: object,
|
||||
text: message,
|
||||
html: message
|
||||
|
Loading…
x
Reference in New Issue
Block a user