form to edit email templates

This commit is contained in:
cyril lopez 2018-01-19 13:34:55 +01:00
parent f6497639e7
commit 11c5905d25
9 changed files with 165 additions and 92 deletions

View File

@ -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',

View File

@ -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,

View File

@ -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) {

View File

@ -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';

View File

@ -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,
);

View File

@ -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;
}

View File

@ -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"
}

View File

@ -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: ''
}

View File

@ -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