Added parent_id to Newsletters table

- added NOTIFICATION_HISTORY Newsletter's type
- implement basic UI for notification_history
- TODO: implement passing extra parameters in order to handle the :id part
This commit is contained in:
Jonathan Labreuille
2016-07-12 16:37:15 +02:00
parent 101ef0cff4
commit f5552847a3
10 changed files with 301 additions and 8 deletions

View File

@@ -379,8 +379,16 @@ const Listing = React.createClass({
.join('/');
// prepend url with "tab" if specified
if (this.props.tab !== undefined) {
params = `/${ this.props.tab }/${ params }`;
if (this.props.tab !== undefined || this.props.base_path !== undefined) {
let base_path = (this.props.base_path !== undefined)
? this.props.base_path
: this.props.tab;
// TODO: add method to replace dynamic path elements
base_path = base_path.replace(':id', this.props.params.id);
// /-TODO--
params = `/${ base_path }/${ params }`;
} else {
params = `/${ params }`;
}

View File

@@ -277,7 +277,9 @@ const NewsletterListNotification = React.createClass({
{ this.renderSettings(newsletter) }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('history') }>
<a href="#TODO">{ MailPoet.I18n.t('viewHistory') }</a>
<Link
to={ `/notification/history/${ newsletter.id }` }
>{ MailPoet.I18n.t('viewHistory') }</Link>
</td>
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>

View File

@@ -0,0 +1,251 @@
import React from 'react'
import { Router, Link } from 'react-router'
import classNames from 'classnames'
import jQuery from 'jquery'
import MailPoet from 'mailpoet'
import Listing from 'listing/listing.jsx'
import ListingTabs from 'newsletters/listings/tabs.jsx'
const mailpoet_tracking_enabled = (!!(window['mailpoet_tracking_enabled']));
const columns = [
{
name: 'subject',
label: MailPoet.I18n.t('subject'),
},
{
name: 'status',
label: MailPoet.I18n.t('status')
},
{
name: 'segments',
label: MailPoet.I18n.t('lists')
},
{
name: 'statistics',
label: MailPoet.I18n.t('statistics'),
display: mailpoet_tracking_enabled
},
{
name: 'processed_at',
label: MailPoet.I18n.t('sentOn'),
}
];
const newsletter_actions = [
{
name: 'view',
link: function(newsletter) {
return (
<a href={ newsletter.preview_url } target="_blank">
{MailPoet.I18n.t('preview')}
</a>
);
}
}
];
const NewsletterListNotificationHistory = React.createClass({
pauseSending: function(newsletter) {
MailPoet.Ajax.post({
endpoint: 'sendingQueue',
action: 'pause',
data: newsletter.id
}).done(function() {
jQuery('#resume_'+newsletter.id).show();
jQuery('#pause_'+newsletter.id).hide();
});
},
resumeSending: function(newsletter) {
MailPoet.Ajax.post({
endpoint: 'sendingQueue',
action: 'resume',
data: newsletter.id
}).done(function() {
jQuery('#pause_'+newsletter.id).show();
jQuery('#resume_'+newsletter.id).hide();
});
},
renderStatus: function(newsletter) {
if (!newsletter.queue) {
return (
<span>{MailPoet.I18n.t('notSentYet')}</span>
);
} else {
if (newsletter.queue.status === 'scheduled') {
return (
<span>{MailPoet.I18n.t('scheduledFor')} { MailPoet.Date.format(newsletter.queue.scheduled_at) } </span>
)
}
const progressClasses = classNames(
'mailpoet_progress',
{ 'mailpoet_progress_complete': newsletter.queue.status === 'completed'}
);
// calculate percentage done
const percentage = Math.round(
(newsletter.queue.count_processed * 100) / (newsletter.queue.count_total)
);
let label;
if (newsletter.queue.status === 'completed') {
label = (
<span>
{
MailPoet.I18n.t('newsletterQueueCompleted')
.replace("%$1d", newsletter.queue.count_processed - newsletter.queue.count_failed)
.replace("%$2d", newsletter.queue.count_total)
}
</span>
);
} else {
label = (
<span>
{ newsletter.queue.count_processed } / { newsletter.queue.count_total }
&nbsp;&nbsp;
<a
id={ 'resume_'+newsletter.id }
className="button"
style={{ display: (newsletter.queue.status === 'paused') ? 'inline-block': 'none' }}
href="javascript:;"
onClick={ this.resumeSending.bind(null, newsletter) }
>{MailPoet.I18n.t('resume')}</a>
<a
id={ 'pause_'+newsletter.id }
className="button mailpoet_pause"
style={{ display: (newsletter.queue.status === null) ? 'inline-block': 'none' }}
href="javascript:;"
onClick={ this.pauseSending.bind(null, newsletter) }
>{MailPoet.I18n.t('pause')}</a>
</span>
);
}
return (
<div>
<div className={ progressClasses }>
<span
className="mailpoet_progress_bar"
style={ { width: percentage + "%"} }
></span>
<span className="mailpoet_progress_label">
{ percentage + "%" }
</span>
</div>
<p style={{ textAlign:'center' }}>
{ label }
</p>
</div>
);
}
},
renderStatistics: function(newsletter) {
if (mailpoet_tracking_enabled === false) {
return;
}
if (newsletter.statistics && newsletter.queue && newsletter.queue.status !== 'scheduled') {
const total_sent = ~~(newsletter.queue.count_processed);
let percentage_clicked = 0;
let percentage_opened = 0;
let percentage_unsubscribed = 0;
if (total_sent > 0) {
percentage_clicked = Math.round(
(~~(newsletter.statistics.clicked) * 100) / total_sent
);
percentage_opened = Math.round(
(~~(newsletter.statistics.opened) * 100) / total_sent
);
percentage_unsubscribed = Math.round(
(~~(newsletter.statistics.unsubscribed) * 100) / total_sent
);
}
return (
<span>
{ percentage_opened }%, { percentage_clicked }%, { percentage_unsubscribed }%
</span>
);
} else {
return (
<span>{MailPoet.I18n.t('notSentYet')}</span>
);
}
},
renderItem: function(newsletter, actions) {
const rowClasses = classNames(
'manage-column',
'column-primary',
'has-row-actions'
);
const segments = newsletter.segments.map(function(segment) {
return segment.name
}).join(', ');
return (
<div>
<td className={ rowClasses }>
<strong>
<a
className="row-title"
href={ `?page=mailpoet-newsletter-editor&id=${ newsletter.id }` }
>{ newsletter.subject }</a>
</strong>
{ actions }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('status') }>
{ this.renderStatus(newsletter) }
</td>
<td className="column" data-colname={ MailPoet.I18n.t('lists') }>
{ segments }
</td>
{ (mailpoet_tracking_enabled === true) ? (
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
{ this.renderStatistics(newsletter) }
</td>
) : null }
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>
<abbr>{ MailPoet.Date.format(newsletter.updated_at) }</abbr>
</td>
</div>
);
},
render: function() {
return (
<div>
<h1 className="title">
{MailPoet.I18n.t('pageTitle')} <Link className="page-title-action" to="/new">{MailPoet.I18n.t('new')}</Link>
</h1>
<ListingTabs tab="notification" />
<Link
className="page-title-action"
to="/notification"
>{MailPoet.I18n.t('backToPostNotifications')}</Link>
<Listing
limit={ mailpoet_listing_per_page }
location={ this.props.location }
params={ this.props.params }
endpoint="newsletters"
tab="notification_history"
base_path="notification/history/:id"
onRenderItem={ this.renderItem }
columns={columns}
item_actions={ newsletter_actions }
auto_refresh={ true }
sort_by="updated_at"
sort_order="desc"
/>
</div>
);
}
});
module.exports = NewsletterListNotificationHistory;

View File

@@ -14,6 +14,7 @@ import NewsletterTypeNotification from 'newsletters/types/notification/notificat
import NewsletterListStandard from 'newsletters/listings/standard.jsx'
import NewsletterListWelcome from 'newsletters/listings/welcome.jsx'
import NewsletterListNotification from 'newsletters/listings/notification.jsx'
import NewsletterListNotificationHistory from 'newsletters/listings/notification_history.jsx'
const history = useRouterHistory(createHashHistory)({ queryKey: false });
@@ -34,8 +35,11 @@ if(container) {
<Route name="listing/standard" path="standard" component={ NewsletterListStandard } />
<Route name="listing/welcome" path="welcome" component={ NewsletterListWelcome } />
<Route name="listing/notification" path="notification" component={ NewsletterListNotification } />
<Route name="listing/notification/history" path="notification/history/:id" component={ NewsletterListNotificationHistory } />
<Route path="standard/*" component={ NewsletterListStandard } />
<Route path="welcome/*" component={ NewsletterListWelcome } />
<Route path="notification/history/:id/*" component={ NewsletterListNotificationHistory } />
<Route path="notification/*" component={ NewsletterListNotification } />
{/* Newsletter: type selection */}
<Route path="new" component={ NewsletterTypes } />