Merge pull request #1234 from mailpoet/tempales-categories

Add template categorization [MAILPOET-1159]
This commit is contained in:
Tautvidas Sipavičius
2018-01-30 16:20:01 +02:00
committed by GitHub
39 changed files with 1288 additions and 122 deletions

View File

@@ -12,7 +12,7 @@ define([
// Does not hold newsletter content nor newsletter styles, those are
// handled by other components.
Module.NewsletterModel = SuperModel.extend({
whitelisted: ['id', 'subject', 'preheader'],
whitelisted: ['id', 'subject', 'preheader', 'type'],
initialize: function () { // eslint-disable-line func-names
this.on('change', function () { // eslint-disable-line func-names
App.getChannel().trigger('autoSave');

View File

@@ -98,7 +98,11 @@ define([
promise.then(function (thumbnail) {
var data = _.extend(options || {}, {
thumbnail: thumbnail.toDataURL('image/jpeg'),
body: JSON.stringify(App.getBody())
body: JSON.stringify(App.getBody()),
categories: JSON.stringify([
'saved',
App.getNewsletter().get('type')
])
});
return MailPoet.Ajax.post({
@@ -124,7 +128,8 @@ define([
).then(function (thumbnail) {
var data = _.extend(options || {}, {
thumbnail: thumbnail.toDataURL('image/jpeg'),
body: App.getBody()
body: App.getBody(),
categories: JSON.stringify([App.getNewsletter().get('type')])
});
var blob = new Blob(
[JSON.stringify(data)],

View File

@@ -11,6 +11,7 @@ define(
'newsletters/breadcrumb.jsx',
'help-tooltip.jsx',
'jquery',
'html2canvas',
],
(
React,
@@ -23,7 +24,8 @@ define(
WelcomeNewsletterFields,
Breadcrumb,
HelpTooltip,
jQuery
jQuery,
html2canvas
) => {
const NewsletterSend = React.createClass({
contextTypes: {
@@ -88,12 +90,38 @@ define(
});
});
},
saveTemplate: function (response, done) {
const iframe = document.createElement('iframe');
iframe.src = response.meta.preview_url;
iframe.onload = () => {
html2canvas(iframe.contentDocument.documentElement).then((thumbnail) => {
document.body.removeChild(iframe);
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'newsletterTemplates',
action: 'save',
data: {
newsletter_id: response.data.id,
name: response.data.subject,
description: response.data.preheader,
thumbnail: thumbnail.toDataURL('image/jpeg'),
body: JSON.stringify(response.data.body),
categories: '["recent"]',
},
}).then(done).fail(this.showError);
});
};
// just to hide the iframe
iframe.className ='mailpoet_template_iframe';
document.body.appendChild(iframe);
},
handleSend: function (e) {
e.preventDefault();
if (!this.isValid()) {
jQuery('#mailpoet_newsletter').parsley().validate();
} else {
MailPoet.Modal.loading(true);
this.saveNewsletter(e).done(() => {
this.setState({ loading: true });
}).done((response) => {
@@ -109,29 +137,37 @@ define(
status: 'active',
},
}).done((response2) => {
// redirect to listing based on newsletter type
this.context.router.push(`/${this.state.item.type || ''}`);
const opts = this.state.item.options;
// display success message depending on newsletter type
if (response2.data.type === 'welcome') {
MailPoet.Notice.success(
MailPoet.I18n.t('welcomeEmailActivated')
);
MailPoet.trackEvent('Emails > Welcome email activated', {
'MailPoet Free version': window.mailpoet_version,
'List type': opts.event,
Delay: `${opts.afterTimeNumber} ${opts.afterTimeType}`,
});
} else if (response2.data.type === 'notification') {
MailPoet.Notice.success(
MailPoet.I18n.t('postNotificationActivated')
);
MailPoet.trackEvent('Emails > Post notifications activated', {
'MailPoet Free version': window.mailpoet_version,
Frequency: opts.intervalType,
});
}
}).fail(this.showError);
// save template in recently sent category
this.saveTemplate(response, () => {
// redirect to listing based on newsletter type
this.context.router.push(`/${this.state.item.type || ''}`);
const opts = this.state.item.options;
// display success message depending on newsletter type
if (response2.data.type === 'welcome') {
MailPoet.Notice.success(
MailPoet.I18n.t('welcomeEmailActivated')
);
MailPoet.trackEvent('Emails > Welcome email activated', {
'MailPoet Free version': window.mailpoet_version,
'List type': opts.event,
Delay: `${opts.afterTimeNumber} ${opts.afterTimeType}`,
});
} else if (response2.data.type === 'notification') {
MailPoet.Notice.success(
MailPoet.I18n.t('postNotificationActivated')
);
MailPoet.trackEvent('Emails > Post notifications activated', {
'MailPoet Free version': window.mailpoet_version,
Frequency: opts.intervalType,
});
}
MailPoet.Modal.loading(false);
});
}).fail((err) => {
this.showError(err);
this.setState({ loading: false });
MailPoet.Modal.loading(false);
});
default:
return MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
@@ -141,32 +177,42 @@ define(
newsletter_id: this.props.params.id,
},
}).done((response2) => {
// redirect to listing based on newsletter type
this.context.router.push(`/${this.state.item.type || ''}`);
// save template in recently sent category
this.saveTemplate(response, () => {
// redirect to listing based on newsletter type
this.context.router.push(`/${this.state.item.type || ''}`);
if (response2.data.status === 'scheduled') {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterHasBeenScheduled')
);
MailPoet.trackEvent('Emails > Newsletter sent', {
scheduled: true,
'MailPoet Free version': window.mailpoet_version,
});
} else {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterBeingSent')
);
MailPoet.trackEvent('Emails > Newsletter sent', {
scheduled: false,
'MailPoet Free version': window.mailpoet_version,
});
}
}).fail(this.showError);
if (response2.data.status === 'scheduled') {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterHasBeenScheduled')
);
MailPoet.trackEvent('Emails > Newsletter sent', {
scheduled: true,
'MailPoet Free version': window.mailpoet_version,
});
} else {
MailPoet.Notice.success(
MailPoet.I18n.t('newsletterBeingSent')
);
MailPoet.trackEvent('Emails > Newsletter sent', {
scheduled: false,
'MailPoet Free version': window.mailpoet_version,
});
}
MailPoet.Modal.loading(false);
});
})
.fail((err) => {
this.showError(err);
this.setState({ loading: false });
MailPoet.Modal.loading(false);
});
}
})
.fail(this.showError)
.always(() => {
.fail((err) => {
this.showError(err);
this.setState({ loading: false });
MailPoet.Modal.loading(false);
});
}
return false;

View File

@@ -15,6 +15,9 @@ const ImportTemplate = React.createClass({
template.body = JSON.stringify(template.body);
}
if (undefined === template.categories) {
template.categories = '["saved"]';
}
MailPoet.Modal.loading(true);
MailPoet.Ajax.post({
@@ -81,11 +84,52 @@ const ImportTemplate = React.createClass({
},
});
const templatesCategories = [
{
name: 'standard',
label: MailPoet.I18n.t('tabStandardTitle'),
},
{
name: 'welcome',
label: MailPoet.I18n.t('tabWelcomeTitle'),
},
{
name: 'notification',
label: MailPoet.I18n.t('tabNotificationTitle'),
},
{
name: 'sample',
label: MailPoet.I18n.t('sample'),
},
{
name: 'blank',
label: MailPoet.I18n.t('blank'),
},
{
name: 'recent',
label: MailPoet.I18n.t('recentlySent'),
},
{
name: 'saved',
label: MailPoet.I18n.t('savedTemplates'),
},
];
const CategoryTab = ({ name, label, selected, select }) => (
<li><a
href="javascript:"
className={selected === name ? 'current' : ''}
onClick={() => select(name)}
> {label}
</a></li>
);
const NewsletterTemplates = React.createClass({
getInitialState: function () {
return {
loading: false,
templates: [],
templates: {},
selectedCategory: '',
};
},
componentDidMount: function () {
@@ -100,8 +144,6 @@ const NewsletterTemplates = React.createClass({
api_version: window.mailpoet_api_version,
endpoint: 'newsletterTemplates',
action: 'getAll',
}).always(() => {
MailPoet.Modal.loading(false);
}).done((response) => {
if (this.isMounted()) {
if (response.data.length === 0) {
@@ -111,15 +153,53 @@ const NewsletterTemplates = React.createClass({
MailPoet.I18n.t('mailpoetGuideTemplateTitle'),
description:
MailPoet.I18n.t('mailpoetGuideTemplateDescription'),
categories: '["welcome", "notification", "standard"]',
readonly: '1',
},
];
}
this.setState({
templates: response.data,
loading: false,
});
let templates = templatesCategories.reduce((result, { name }) => {
const obj = result;
obj[name] = [];
return obj;
}, {});
templates = response.data.reduce((result, item) => {
JSON.parse(item.categories).forEach((category) => {
result[category].push(item);
});
return result;
}, templates);
this.selectInitialCategory(templates);
}
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
response.errors.map(error => error.message),
{ scroll: true }
);
}
MailPoet.Modal.loading(false);
});
},
selectInitialCategory: function (templates) {
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'get',
data: {
id: this.props.params.id,
},
}).always(() => {
MailPoet.Modal.loading(false);
}).done((response) => {
this.setState({
templates: templates,
selectedCategory: response.data.type,
loading: false,
});
}).fail((response) => {
if (response.errors.length > 0) {
MailPoet.Notice.error(
@@ -206,7 +286,9 @@ const NewsletterTemplates = React.createClass({
this.getTemplates();
},
render: function () {
const templates = this.state.templates.map((template, index) => {
let templates = this.state.templates[this.state.selectedCategory] || [];
templates = templates.map((template, index) => {
const deleteLink = (
<div className="mailpoet_delete">
<a
@@ -261,6 +343,10 @@ const NewsletterTemplates = React.createClass({
);
});
if (templates.length === 0) {
templates = <p>{MailPoet.I18n.t('noTemplates')}</p>;
}
const boxClasses = classNames(
'mailpoet_boxes',
'clearfix',
@@ -273,6 +359,19 @@ const NewsletterTemplates = React.createClass({
<Breadcrumb step="template" />
<div className="wp-filter hide-if-no-js">
<ul className="filter-links">
{templatesCategories.map(({ name, label }) => (
<CategoryTab
key={name}
name={name}
label={label}
selected={this.state.selectedCategory}
select={category => this.setState({ selectedCategory: category })} />
))}
</ul>
</div>
<ul className={boxClasses}>
{ templates }
</ul>