Add a component for stats
[MAILPOET-2791]
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import React from 'react';
|
||||
import MailPoet from 'mailpoet';
|
||||
import Hooks from 'wp-js-hooks';
|
||||
import Grid from 'common/grid';
|
||||
import StatsBadge from 'common/listings/newsletter_stats/stats';
|
||||
|
||||
import { NewsletterType } from './newsletter_type';
|
||||
|
||||
type Props = {
|
||||
newsletter: NewsletterType
|
||||
}
|
||||
|
||||
const minNewslettersSent = 20;
|
||||
const minNewslettersOpened = 5;
|
||||
|
||||
export const NewsletterGeneralStats = ({
|
||||
newsletter,
|
||||
}: Props) => {
|
||||
const totalSent = newsletter.total_sent || 0;
|
||||
|
||||
let percentageClicked = 0;
|
||||
let percentageOpened = 0;
|
||||
let percentageUnsubscribed = 0;
|
||||
if (totalSent > 0) {
|
||||
percentageClicked = (newsletter.statistics.clicked * 100) / totalSent;
|
||||
percentageOpened = (newsletter.statistics.opened * 100) / totalSent;
|
||||
percentageUnsubscribed = (newsletter.statistics.unsubscribed * 100) / totalSent;
|
||||
}
|
||||
// format to 1 decimal place
|
||||
const percentageClickedDisplay = MailPoet.Num.toLocaleFixed(percentageClicked, 1);
|
||||
const percentageOpenedDisplay = MailPoet.Num.toLocaleFixed(percentageOpened, 1);
|
||||
const percentageUnsubscribedDisplay = MailPoet.Num.toLocaleFixed(percentageUnsubscribed, 1);
|
||||
|
||||
const headlineClicked = `${percentageClickedDisplay}% ${MailPoet.I18n.t('percentageClicked')}`;
|
||||
|
||||
const displayBadges = ((totalSent >= minNewslettersSent)
|
||||
&& (newsletter.statistics.opened >= minNewslettersOpened)
|
||||
);
|
||||
|
||||
const opened = (
|
||||
<>
|
||||
<div>{`${percentageOpenedDisplay}% ${MailPoet.I18n.t('percentageOpened')}`}</div>
|
||||
{displayBadges && (
|
||||
<StatsBadge
|
||||
stat="opened"
|
||||
rate={percentageOpened}
|
||||
tooltipId={`opened-${newsletter.id || '0'}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
const unsubscribed = (
|
||||
<>
|
||||
<div>{`${percentageUnsubscribedDisplay}% ${MailPoet.I18n.t('percentageUnsubscribed')}`}</div>
|
||||
{displayBadges && (
|
||||
<StatsBadge
|
||||
stat="unsubscribed"
|
||||
rate={percentageUnsubscribed}
|
||||
tooltipId={`unsubscribed-${newsletter.id || '0'}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
const clicked = (
|
||||
<>
|
||||
<div>{`${percentageClickedDisplay}% ${MailPoet.I18n.t('percentageClicked')}`}</div>
|
||||
{displayBadges && (
|
||||
<StatsBadge
|
||||
stat="clicked"
|
||||
rate={percentageClicked}
|
||||
tooltipId={`clicked-${newsletter.id || '0'}`}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid.ThreeColumns>
|
||||
<div>
|
||||
{MailPoet.I18n.t('statsTotalSent')}
|
||||
{': '}
|
||||
{totalSent.toLocaleString()}
|
||||
{opened}
|
||||
</div>
|
||||
<div>
|
||||
{unsubscribed}
|
||||
|
||||
{clicked}
|
||||
</div>
|
||||
<div>
|
||||
{Hooks.applyFilters('mailpoet_newsletters_revenues_stats', null, newsletter.statistics.revenue)}
|
||||
</div>
|
||||
</Grid.ThreeColumns>
|
||||
<p>
|
||||
<a
|
||||
href="https://kb.mailpoet.com/article/190-whats-a-good-email-open-rate"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
data-beacon-article="58f671152c7d3a057f8858e8"
|
||||
>
|
||||
{MailPoet.I18n.t('readMoreOnStats')}
|
||||
</a>
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
};
|
17
assets/js/src/newsletters/campaign_stats/newsletter_type.ts
Normal file
17
assets/js/src/newsletters/campaign_stats/newsletter_type.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
export type NewsletterType = {
|
||||
id: string
|
||||
total_sent: number
|
||||
subject: string
|
||||
queue: object
|
||||
clicked_links: {cnt: string, url: string}[]
|
||||
statistics: {
|
||||
clicked: number
|
||||
opened: number
|
||||
unsubscribed: number
|
||||
revenue: {
|
||||
value: number
|
||||
formatted: string
|
||||
count: number
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,11 +1,12 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import Hooks from 'wp-js-hooks';
|
||||
import MailPoet from 'mailpoet';
|
||||
import { Link, withRouter } from 'react-router-dom';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
import InvalidMssKeyNotice from 'notices/invalid_mss_key_notice';
|
||||
import { TopBarWithBeamer } from 'common/top_bar/top_bar';
|
||||
|
||||
import NewsletterGeneralStats from './newsletter_stats.jsx';
|
||||
import { NewsletterGeneralStats } from './newsletter_general_stats';
|
||||
import { NewsletterType } from './newsletter_type';
|
||||
import NewsletterStatsInfo from './newsletter_info.jsx';
|
||||
import PremiumBanner from './premium_banner.jsx';
|
||||
import Heading from '../../common/typography/heading/heading';
|
||||
@@ -37,12 +38,7 @@ type Props = {
|
||||
};
|
||||
|
||||
type State = {
|
||||
item?: {
|
||||
id: string,
|
||||
queue: object
|
||||
subject: string
|
||||
clicked_links: object[]
|
||||
}
|
||||
item?: NewsletterType
|
||||
loading: boolean
|
||||
}
|
||||
|
||||
@@ -93,7 +89,7 @@ const CampaignStatsPage = ({ match, history, location }: Props) => {
|
||||
return () => {
|
||||
showWPScreenOptions();
|
||||
};
|
||||
}, [match.params.id, loadItem]);
|
||||
}, [match.params.id, loadItem, state.item]);
|
||||
|
||||
const { item, loading } = state;
|
||||
const newsletter = item;
|
||||
@@ -122,13 +118,9 @@ const CampaignStatsPage = ({ match, history, location }: Props) => {
|
||||
/>
|
||||
|
||||
<div className="mailpoet_stat_triple-spaced">
|
||||
<div className="mailpoet_stat_info">
|
||||
<NewsletterStatsInfo newsletter={newsletter} />
|
||||
</div>
|
||||
<div className="mailpoet_stat_general">
|
||||
<NewsletterGeneralStats newsletter={newsletter} />
|
||||
</div>
|
||||
<div style={{ clear: 'both' }} />
|
||||
<NewsletterStatsInfo newsletter={newsletter} />
|
||||
|
||||
<NewsletterGeneralStats newsletter={newsletter} />
|
||||
</div>
|
||||
|
||||
<h2>{MailPoet.I18n.t('clickedLinks')}</h2>
|
||||
|
Reference in New Issue
Block a user