First attempt on campaign editing. Misses attachments. Untested.

This commit is contained in:
Tomas Bures 2018-07-31 10:04:28 +05:30
parent ee786bc8ad
commit 0e0fb944e3
26 changed files with 1244 additions and 233 deletions

View file

@ -17,19 +17,20 @@ import {
} from "../lib/mosaico";
import {getTemplateTypes as getMosaicoTemplateTypes} from './mosaico/helpers';
import {getTrustedUrl, getSandboxUrl} from "../lib/urls";
import {getSandboxUrl} from "../lib/urls";
import mailtrainConfig from 'mailtrainConfig';
export function getTemplateTypes(t) {
export function getTemplateTypes(t, prefix = '') {
// The prefix is used to to enable use within other forms (i.e. campaign form)
const templateTypes = {};
function initFieldsIfMissing(mutState, templateType) {
const initVals = templateTypes[templateType].initData();
for (const key in initVals) {
if (!mutState.hasIn([key])) {
mutState.setIn([key, 'value'], initVals[key]);
if (!mutState.hasIn([prefix + key])) {
mutState.setIn([prefix + key, 'value'], initVals[key]);
}
}
}
@ -55,43 +56,43 @@ export function getTemplateTypes(t) {
templateTypes.mosaico = {
typeName: t('Mosaico'),
getTypeForm: (owner, isEdit) =>
<TableSelect id="mosaicoTemplate" label={t('Mosaico template')} withHeader dropdown dataUrl='rest/mosaico-templates-table' columns={mosaicoTemplatesColumns} selectionLabelIndex={1} disabled={isEdit} />,
<TableSelect id={prefix + 'mosaicoTemplate'} label={t('Mosaico template')} withHeader dropdown dataUrl='rest/mosaico-templates-table' columns={mosaicoTemplatesColumns} selectionLabelIndex={1} disabled={isEdit} />,
getHTMLEditor: owner =>
<AlignedRow label={t('Template content (HTML)')}>
<MosaicoEditor
ref={node => owner.editorNode = node}
entity={owner.props.entity}
initialModel={owner.getFormValue('mosaicoData').model}
initialMetadata={owner.getFormValue('mosaicoData').metadata}
templatePath={getSandboxUrl(`mosaico/templates/${owner.getFormValue('mosaicoTemplate')}/index.html`)}
initialModel={owner.getFormValue(prefix + 'mosaicoData').model}
initialMetadata={owner.getFormValue(prefix + 'mosaicoData').metadata}
templatePath={getSandboxUrl(`mosaico/templates/${owner.getFormValue(prefix + 'mosaicoTemplate')}/index.html`)}
entityTypeId={ResourceType.TEMPLATE}
title={t('Mosaico Template Designer')}
onFullscreenAsync={::owner.setElementInFullscreen}/>
</AlignedRow>,
exportHTMLEditorData: async owner => {
const {html, metadata, model} = await owner.editorNode.exportState();
owner.updateFormValue('html', html);
owner.updateFormValue('mosaicoData', {
owner.updateFormValue(prefix + 'html', html);
owner.updateFormValue(prefix + 'mosaicoData', {
metadata,
model
});
},
initData: () => ({
mosaicoTemplate: '',
mosaicoData: {}
[prefix + 'mosaicoTemplate']: '',
[prefix + 'mosaicoData']: {}
}),
afterLoad: data => {
data.mosaicoTemplate = data.data.mosaicoTemplate;
data.mosaicoData = {
metadata: data.data.metadata,
model: data.data.model
data[prefix + 'mosaicoTemplate'] = data[prefix + 'data'].mosaicoTemplate;
data[prefix + 'mosaicoData'] = {
metadata: data[prefix + 'data'].metadata,
model: data[prefix + 'data'].model
};
},
beforeSave: data => {
data.data = {
mosaicoTemplate: data.mosaicoTemplate,
metadata: data.mosaicoData.metadata,
model: data.mosaicoData.model
data[prefix + 'data'] = {
mosaicoTemplate: data[prefix + 'mosaicoTemplate'],
metadata: data[prefix + 'mosaicoData'].metadata,
model: data[prefix + 'mosaicoData'].model
};
clearBeforeSave(data);
},
@ -99,11 +100,11 @@ export function getTemplateTypes(t) {
initFieldsIfMissing(mutState, 'mosaico');
},
validate: state => {
const mosaicoTemplate = state.getIn(['mosaicoTemplate', 'value']);
const mosaicoTemplate = state.getIn([prefix + 'mosaicoTemplate', 'value']);
if (!mosaicoTemplate) {
state.setIn(['mosaicoTemplate', 'error'], t('Mosaico template must be selected'));
state.setIn([prefix + 'mosaicoTemplate', 'error'], t('Mosaico template must be selected'));
} else {
state.setIn(['mosaicoTemplate', 'error'], null);
state.setIn([prefix + 'mosaicoTemplate', 'error'], null);
}
}
};
@ -113,23 +114,23 @@ export function getTemplateTypes(t) {
templateTypes.mosaicoWithFsTemplate = {
typeName: t('Mosaico with predefined templates'),
getTypeForm: (owner, isEdit) =>
<Dropdown id="mosaicoFsTemplate" label={t('Mosaico Template')} options={mosaicoFsTemplatesOptions}/>,
<Dropdown id={prefix + 'mosaicoFsTemplate'} label={t('Mosaico Template')} options={mosaicoFsTemplatesOptions}/>,
getHTMLEditor: owner =>
<AlignedRow label={t('Template content (HTML)')}>
<MosaicoEditor
ref={node => owner.editorNode = node}
entity={owner.props.entity}
initialModel={owner.getFormValue('mosaicoData').model}
initialMetadata={owner.getFormValue('mosaicoData').metadata}
templatePath={getSandboxUrl(`public/mosaico/templates/${owner.getFormValue('mosaicoFsTemplate')}/index.html`)}
initialModel={owner.getFormValue(prefix + 'mosaicoData').model}
initialMetadata={owner.getFormValue(prefix + 'mosaicoData').metadata}
templatePath={getSandboxUrl(`public/mosaico/templates/${owner.getFormValue(prefix + 'mosaicoFsTemplate')}/index.html`)}
entityTypeId={ResourceType.TEMPLATE}
title={t('Mosaico Template Designer')}
onFullscreenAsync={::owner.setElementInFullscreen}/>
</AlignedRow>,
exportHTMLEditorData: async owner => {
const {html, metadata, model} = await owner.editorNode.exportState();
owner.updateFormValue('html', html);
owner.updateFormValue('mosaicoData', {
owner.updateFormValue(prefix + 'html', html);
owner.updateFormValue(prefix + 'mosaicoData', {
metadata,
model
});
@ -139,17 +140,17 @@ export function getTemplateTypes(t) {
mosaicoData: {}
}),
afterLoad: data => {
data.mosaicoFsTemplate = data.data.mosaicoFsTemplate;
data.mosaicoData = {
metadata: data.data.metadata,
model: data.data.model
data['mosaicoFsTemplate'] = data[prefix + 'data'].mosaicoFsTemplate;
data[prefix + 'mosaicoData'] = {
metadata: data[prefix + 'data'].metadata,
model: data[prefix + 'data'].model
};
},
beforeSave: data => {
data.data = {
mosaicoFsTemplate: data.mosaicoFsTemplate,
metadata: data.mosaicoData.metadata,
model: data.mosaicoData.model
data[prefix + 'data'] = {
mosaicoFsTemplate: data[prefix + 'mosaicoFsTemplate'],
metadata: data[prefix + 'mosaicoData'].metadata,
model: data[prefix + 'mosaicoData'].model
};
clearBeforeSave(data);
},
@ -176,7 +177,7 @@ export function getTemplateTypes(t) {
templateTypes.ckeditor = {
typeName: t('CKEditor'),
getTypeForm: (owner, isEdit) => null,
getHTMLEditor: owner => <CKEditor id="html" height="600px" label={t('Template content (HTML)')}/>,
getHTMLEditor: owner => <CKEditor id={prefix + 'html'} height="600px" label={t('Template content (HTML)')}/>,
exportHTMLEditorData: async owner => {},
initData: () => ({}),
afterLoad: data => {},
@ -190,7 +191,7 @@ export function getTemplateTypes(t) {
templateTypes.codeeditor = {
typeName: t('Code Editor'),
getTypeForm: (owner, isEdit) => null,
getHTMLEditor: owner => <ACEEditor id="html" height="600px" mode="html" label={t('Template content (HTML)')}/>,
getHTMLEditor: owner => <ACEEditor id={prefix + 'html'} height="600px" mode="html" label={t('Template content (HTML)')}/>,
exportHTMLEditorData: async owner => {},
initData: () => ({}),
afterLoad: data => {},
@ -215,4 +216,101 @@ export function getTemplateTypes(t) {
};
return templateTypes;
}
}
export function getEditForm(owner, typeKey, prefix = '') {
const t = owner.props.t;
return <div>
<AlignedRow>
<Button className="btn-default" onClickAsync={::owner.toggleMergeTagReference} label={t('Merge tag reference')}/>
{owner.state.showMergeTagReference &&
<div style={{marginTop: '15px'}}>
<Trans><p>Merge tags are tags that are replaced before sending out the message. The format of the merge tag is the following: <code>[TAG_NAME]</code> or <code>[TAG_NAME/fallback]</code> where <code>fallback</code> is an optional text value used when <code>TAG_NAME</code> is empty.</p></Trans>
<Trans><p>You can use any of the standard merge tags below. In addition to that every custom field has its own merge tag. Check the fields of the list you are going to send to.</p></Trans>
<table className="table table-bordered table-condensed table-striped">
<thead>
<tr>
<th>
<Trans>Merge tag</Trans>
</th>
<th>
<Trans>Description</Trans>
</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
[LINK_UNSUBSCRIBE]
</th>
<td>
<Trans>URL that points to the unsubscribe page</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LINK_PREFERENCES]
</th>
<td>
<Trans>URL that points to the preferences page of the subscriber</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LINK_BROWSER]
</th>
<td>
<Trans>URL to preview the message in a browser</Trans>
</td>
</tr>
<tr>
<th scope="row">
[EMAIL]
</th>
<td>
<Trans>Email address</Trans>
</td>
</tr>
<tr>
<th scope="row">
[SUBSCRIPTION_ID]
</th>
<td>
<Trans>Unique ID that identifies the recipient</Trans>
</td>
</tr>
<tr>
<th scope="row">
[LIST_ID]
</th>
<td>
<Trans>Unique ID that identifies the list used for this campaign</Trans>
</td>
</tr>
<tr>
<th scope="row">
[CAMPAIGN_ID]
</th>
<td>
<Trans>Unique ID that identifies current campaign</Trans>
</td>
</tr>
</tbody>
</table>
</div>}
</AlignedRow>
{owner.templateTypes[typeKey].getHTMLEditor(owner)}
<ACEEditor id={prefix + 'text'} height="400px" mode="text" label={t('Template content (plain text)')} help={<Trans>To extract the text from HTML click <ActionLink onClickAsync={::owner.extractPlainText}>here</ActionLink>. Please note that your existing plaintext in the field above will be overwritten. This feature uses the <a href="http://premailer.dialect.ca/api">Premailer API</a>, a third party service. Their Terms of Service and Privacy Policy apply.</Trans>}/>
</div>;
}
export function getTypeForm(owner, typeKey, isEdit) {
return <div>
{owner.templateTypes[typeKey].getTypeForm(this, isEdit)}
</div>;
}