Add a green box in stats for recently sent newsletters, add help KB link [MAILPOET-877]

This commit is contained in:
Alexey Stoletniy
2017-04-18 15:30:55 +03:00
parent e9070de9c4
commit 95ff83557f
7 changed files with 83 additions and 22 deletions

View File

@ -1,6 +1,7 @@
$excellent-badge-color = #2993ab $excellent-badge-color = #2993ab
$good-badge-color = #f0b849 $good-badge-color = #f0b849
$bad-badge-color = #d54e21 $bad-badge-color = #d54e21
$green-badge-color = #55bd56
$grey-stat-color = #707070 $grey-stat-color = #707070
#newsletters_container #newsletters_container
@ -39,6 +40,10 @@ $grey-stat-color = #707070
&_hidden &_hidden
display: none display: none
&_link_small
text-decoration: underline !important
font-size: 0.75rem
.mailpoet_badge .mailpoet_badge
padding: 4px 6px 3px 6px padding: 4px 6px 3px 6px
color: #FFFFFF color: #FFFFFF
@ -57,3 +62,6 @@ $grey-stat-color = #707070
&_bad &_bad
background: $bad-badge-color background: $bad-badge-color
&_green
background: $green-badge-color

View File

@ -10,7 +10,7 @@ class Badge extends React.Component {
this.props.size ? `mailpoet_badge_size_${this.props.size}` : '' this.props.size ? `mailpoet_badge_size_${this.props.size}` : ''
); );
const tooltip = this.props.tooltip.replace(/\n/g, '<br />') || false; const tooltip = this.props.tooltip ? this.props.tooltip.replace(/\n/g, '<br />') : false;
// tooltip ID must be unique, defaults to tooltip text // tooltip ID must be unique, defaults to tooltip text
const tooltipId = this.props.tooltipId || tooltip; const tooltipId = this.props.tooltipId || tooltip;

View File

@ -4,6 +4,7 @@ import ReactStringReplace from 'react-string-replace'
import { Link } from 'react-router' import { Link } from 'react-router'
import MailPoet from 'mailpoet' import MailPoet from 'mailpoet'
import classNames from 'classnames' import classNames from 'classnames'
import moment from 'moment'
import jQuery from 'jquery' import jQuery from 'jquery'
import Hooks from 'wp-js-hooks' import Hooks from 'wp-js-hooks'
import StatsBadge from 'newsletters/badges/stats.jsx' import StatsBadge from 'newsletters/badges/stats.jsx'
@ -143,14 +144,14 @@ const _QueueMixin = {
}; };
const _StatisticsMixin = { const _StatisticsMixin = {
renderStatistics: function(newsletter, sentCondition) { renderStatistics: function(newsletter, sent_condition, current_time) {
if (sentCondition === undefined) { if (sent_condition === undefined) {
// condition for standard and post notification listings // condition for standard and post notification listings
sentCondition = newsletter.statistics sent_condition = newsletter.statistics
&& newsletter.queue && newsletter.queue
&& newsletter.queue.status !== 'scheduled' && newsletter.queue.status !== 'scheduled'
} }
if (!sentCondition) { if (!sent_condition) {
return ( return (
<span>{MailPoet.I18n.t('notSentYet')}</span> <span>{MailPoet.I18n.t('notSentYet')}</span>
); );
@ -177,8 +178,19 @@ const _StatisticsMixin = {
const percentage_opened_display = MailPoet.Num.toLocaleFixed(percentage_opened, 1); const percentage_opened_display = MailPoet.Num.toLocaleFixed(percentage_opened, 1);
const percentage_unsubscribed_display = MailPoet.Num.toLocaleFixed(percentage_unsubscribed, 1); const percentage_unsubscribed_display = MailPoet.Num.toLocaleFixed(percentage_unsubscribed, 1);
// green box for newsletters that were just sent
const show_stats_timeout = 6; // in hours
const newsletter_date = newsletter.queue.scheduled_at || newsletter.queue.created_at;
const sent_hours_ago = moment(current_time).diff(moment(newsletter_date), 'hours');
const too_early_for_stats = sent_hours_ago < show_stats_timeout;
const improveStatsKBLink = 'http://beta.docs.mailpoet.com/article/190-whats-a-good-email-open-rate';
let content; let content;
if (total_sent >= 20 && newsletter.statistics.opened >= 5) { if (total_sent >= 20
&& newsletter.statistics.opened >= 5
&& !too_early_for_stats
) {
// display stats with badges // display stats with badges
content = ( content = (
<div className="mailpoet_stats_text"> <div className="mailpoet_stats_text">
@ -206,27 +218,65 @@ const _StatisticsMixin = {
} else { } else {
// display simple stats // display simple stats
content = ( content = (
<span className="mailpoet_stats_text"> <div>
{ percentage_opened_display }%, <span className="mailpoet_stats_text">
{ " " } { percentage_opened_display }%,
{ percentage_clicked_display }% { " " }
<span className="mailpoet_stat_hidden"> { percentage_clicked_display }%
, { percentage_unsubscribed_display }% <span className="mailpoet_stat_hidden">
, { percentage_unsubscribed_display }%
</span>
</span> </span>
</span> { too_early_for_stats && (
<div className="mailpoet_badge mailpoet_badge_green">
{MailPoet.I18n.t('checkBackInHours')
.replace('%$1d', show_stats_timeout - sent_hours_ago)}
</div>
) }
</div>
); );
} }
if (total_sent > 0 && params.link) { let after_content;
if (percentage_opened < 5
&& sent_hours_ago >= 24
&& total_sent >= 10
) {
// help link for bad open rate
after_content = (
<div>
<a
href={improveStatsKBLink}
target="_blank"
className="mailpoet_stat_link_small"
>
{MailPoet.I18n.t('improveThisLinkText')}
</a>
</div>
)
}
if (total_sent > 0 && !too_early_for_stats && params.link) {
// wrap content in a link
return ( return (
<Link <div>
key={ `stats-${newsletter.id}` } <Link
to={ params.link } key={ `stats-${newsletter.id}` }
>{ content }</Link> to={ params.link }
>
{content}
</Link>
{after_content}
</div>
); );
} }
return content; return (
<div>
{content}
{after_content}
</div>
);
} }
} }

View File

@ -87,7 +87,7 @@ const NewsletterListNotificationHistory = React.createClass({
</td> </td>
{ (mailpoet_tracking_enabled === true) ? ( { (mailpoet_tracking_enabled === true) ? (
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }> <td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
{ this.renderStatistics(newsletter) } { this.renderStatistics(newsletter, undefined, meta.current_time) }
</td> </td>
) : null } ) : null }
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }> <td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>

View File

@ -184,7 +184,7 @@ const NewsletterListStandard = React.createClass({
</td> </td>
{ (mailpoet_tracking_enabled === true) ? ( { (mailpoet_tracking_enabled === true) ? (
<td className="column" data-colname={ MailPoet.I18n.t('statistics') }> <td className="column" data-colname={ MailPoet.I18n.t('statistics') }>
{ this.renderStatistics(newsletter) } { this.renderStatistics(newsletter, undefined, meta.current_time) }
</td> </td>
) : null } ) : null }
<td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }> <td className="column-date" data-colname={ MailPoet.I18n.t('lastModifiedOn') }>

View File

@ -372,7 +372,8 @@ class Newsletters extends APIEndpoint {
'filters' => $listing_data['filters'], 'filters' => $listing_data['filters'],
'groups' => $listing_data['groups'], 'groups' => $listing_data['groups'],
'mta_log' => Setting::getValue('mta_log'), 'mta_log' => Setting::getValue('mta_log'),
'mta_method' => Setting::getValue('mta.method') 'mta_method' => Setting::getValue('mta.method'),
'current_time' => current_time('mysql')
)); ));
} }

View File

@ -99,6 +99,8 @@
'openedStatTooltip': __('Above 30% is excellent.\\nBetween 15 and 30% is good.\\nUnder 15% is bad.'), 'openedStatTooltip': __('Above 30% is excellent.\\nBetween 15 and 30% is good.\\nUnder 15% is bad.'),
'clickedStatTooltip': __('Above 3% is excellent.\\nBetween 1 and 3% is good.\\nUnder 1% is bad.'), 'clickedStatTooltip': __('Above 3% is excellent.\\nBetween 1 and 3% is good.\\nUnder 1% is bad.'),
'unsubscribedStatTooltip': __('Under 1% is excellent.\\nBetween 1 and 3% is good.\\nOver 3% is bad.'), 'unsubscribedStatTooltip': __('Under 1% is excellent.\\nBetween 1 and 3% is good.\\nOver 3% is bad.'),
'checkBackInHours': __('Nice job! Check back in %$1d hour(s) for more stats.'),
'improveThisLinkText': __('What can I do to improve this?'),
'templateFileMalformedError': __('This template file appears to be damaged. Please try another one.'), 'templateFileMalformedError': __('This template file appears to be damaged. Please try another one.'),
'importTemplateTitle': __('Import a template'), 'importTemplateTitle': __('Import a template'),