Merge pull request #1234 from mailpoet/tempales-categories
Add template categorization [MAILPOET-1159]
This commit is contained in:
@@ -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');
|
||||
|
@@ -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)],
|
||||
|
@@ -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;
|
||||
|
@@ -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>
|
||||
|
Reference in New Issue
Block a user