Basic support for Mosaico templates.
TODO: - Allow choosing a mosaico template in a mosaico-based template - Integrate the custom mosaico templates with templates (endpoint for retrieving a mosaico template, replacement of URL_BASE and PLACEHOLDER tags - Implement support for MJML-based Mosaico templates - Implement support for MJML-based templates - Implement support for GrapeJS-based templates
This commit is contained in:
parent
7b5642e911
commit
6706d93bc1
21 changed files with 2192 additions and 26 deletions
192
client/src/templates/mosaico/CUD.js
Normal file
192
client/src/templates/mosaico/CUD.js
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
'use strict';
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { translate, Trans } from 'react-i18next';
|
||||
import {requiresAuthenticatedUser, withPageHelpers, Title, NavButton} from '../../lib/page'
|
||||
import { withForm, Form, FormSendMethod, InputField, TextArea, Dropdown, ButtonRow, Button } from '../../lib/form';
|
||||
import { withErrorHandling, withAsyncErrorHandler } from '../../lib/error-handling';
|
||||
import { validateNamespace, NamespaceSelect } from '../../lib/namespace';
|
||||
import {DeleteModalDialog} from "../../lib/modals";
|
||||
|
||||
import { versafix } from "../../../../shared/mosaico-templates";
|
||||
import { getTemplateTypes } from "./helpers";
|
||||
|
||||
@translate()
|
||||
@withForm
|
||||
@withPageHelpers
|
||||
@withErrorHandling
|
||||
@requiresAuthenticatedUser
|
||||
export default class CUD extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.templateTypes = getTemplateTypes(props.t);
|
||||
|
||||
this.state = {};
|
||||
|
||||
this.initForm();
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
action: PropTypes.string.isRequired,
|
||||
wizard: PropTypes.string,
|
||||
entity: PropTypes.object
|
||||
}
|
||||
|
||||
@withAsyncErrorHandler
|
||||
async loadFormValues() {
|
||||
await this.getFormValuesFromURL(`/rest/mosaico-templates/${this.props.entity.id}`, data => {
|
||||
this.templateTypes[data.type].afterLoad(data);
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.entity) {
|
||||
this.getFormValuesFromEntity(this.props.entity, data => {
|
||||
this.templateTypes[data.type].afterLoad(data);
|
||||
});
|
||||
|
||||
} else {
|
||||
const wizard = this.props.wizard;
|
||||
|
||||
if (wizard === 'versafix') {
|
||||
this.populateFormValues({
|
||||
name: '',
|
||||
description: '',
|
||||
namespace: mailtrainConfig.user.namespace,
|
||||
type: 'html',
|
||||
html: versafix
|
||||
});
|
||||
|
||||
} else {
|
||||
this.populateFormValues({
|
||||
name: '',
|
||||
description: '',
|
||||
namespace: mailtrainConfig.user.namespace,
|
||||
type: 'html',
|
||||
html: ''
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localValidateFormValues(state) {
|
||||
const t = this.props.t;
|
||||
|
||||
if (!state.getIn(['name', 'value'])) {
|
||||
state.setIn(['name', 'error'], t('Name must not be empty'));
|
||||
} else {
|
||||
state.setIn(['name', 'error'], null);
|
||||
}
|
||||
|
||||
if (!state.getIn(['type', 'value'])) {
|
||||
state.setIn(['type', 'error'], t('Type must be selected'));
|
||||
} else {
|
||||
state.setIn(['type', 'error'], null);
|
||||
}
|
||||
|
||||
validateNamespace(t, state);
|
||||
}
|
||||
|
||||
async submitAndStay() {
|
||||
await this.formHandleChangedError(async () => await this.doSubmit(true));
|
||||
}
|
||||
|
||||
async submitAndLeave() {
|
||||
await this.formHandleChangedError(async () => await this.doSubmit(false));
|
||||
}
|
||||
|
||||
async doSubmit(stay) {
|
||||
const t = this.props.t;
|
||||
|
||||
let sendMethod, url;
|
||||
if (this.props.entity) {
|
||||
sendMethod = FormSendMethod.PUT;
|
||||
url = `/rest/mosaico-templates/${this.props.entity.id}`
|
||||
} else {
|
||||
sendMethod = FormSendMethod.POST;
|
||||
url = '/rest/mosaico-templates'
|
||||
}
|
||||
|
||||
this.disableForm();
|
||||
this.setFormStatusMessage('info', t('Saving ...'));
|
||||
|
||||
const submitSuccessful = await this.validateAndSendFormValuesToURL(sendMethod, url, data => {
|
||||
this.templateTypes[data.type].beforeSave(data);
|
||||
});
|
||||
|
||||
if (submitSuccessful) {
|
||||
if (stay) {
|
||||
await this.loadFormValues();
|
||||
this.enableForm();
|
||||
this.setFormStatusMessage('success', t('Mosaico template saved'));
|
||||
} else {
|
||||
this.navigateToWithFlashMessage('/templates/mosaico', 'success', t('Mosaico template saved'));
|
||||
}
|
||||
} else {
|
||||
this.enableForm();
|
||||
this.setFormStatusMessage('warning', t('There are errors in the form. Please fix them and submit again.'));
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const t = this.props.t;
|
||||
const isEdit = !!this.props.entity;
|
||||
const canDelete = isEdit && this.props.entity.permissions.includes('delete');
|
||||
|
||||
const typeKey = this.getFormValue('type');
|
||||
let form = null;
|
||||
if (typeKey) {
|
||||
form = this.templateTypes[typeKey].getForm(this);
|
||||
}
|
||||
|
||||
const typeOptions = [];
|
||||
for (const type of ['html', 'mjml']) {
|
||||
typeOptions.push({
|
||||
key: type,
|
||||
label: this.templateTypes.typeName
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{canDelete &&
|
||||
<DeleteModalDialog
|
||||
stateOwner={this}
|
||||
visible={this.props.action === 'delete'}
|
||||
deleteUrl={`/rest/templates/mosaico/${this.props.entity.id}`}
|
||||
cudUrl={`/templates/mosaico/${this.props.entity.id}/edit`}
|
||||
listUrl="/templates/mosaico"
|
||||
deletingMsg={t('Deleting mosaico template ...')}
|
||||
deletedMsg={t('Mosaico template deleted')}/>
|
||||
}
|
||||
|
||||
<Title>{isEdit ? t('Edit Mosaico Template') : t('Create Mosaico Template')}</Title>
|
||||
|
||||
<Form stateOwner={this} onSubmitAsync={::this.submitAndLeave}>
|
||||
<InputField id="name" label={t('Name')}/>
|
||||
<TextArea id="description" label={t('Description')} help={t('HTML is allowed')}/>
|
||||
<Dropdown id="type" label={t('Type')} options={typeOptions}/>
|
||||
<NamespaceSelect/>
|
||||
|
||||
{form}
|
||||
|
||||
{isEdit ?
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('Save and Stay')} onClickAsync={::this.submitAndStay}/>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('Save and Leave')}/>
|
||||
{canDelete &&
|
||||
<NavButton className="btn-danger" icon="remove" label={t('Delete')} linkTo={`/templates/mosaico/${this.props.entity.id}/delete`}/>
|
||||
}
|
||||
</ButtonRow>
|
||||
:
|
||||
<ButtonRow>
|
||||
<Button type="submit" className="btn-primary" icon="ok" label={t('Save')}/>
|
||||
</ButtonRow>
|
||||
}
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue