Add engagement score into segment list

[MAILPOET-3533]
This commit is contained in:
Jan Lysý
2021-05-04 12:20:28 +02:00
committed by Veljko V
parent 3eb245da76
commit f4ce284e5c
6 changed files with 69 additions and 1 deletions

View File

@ -5,10 +5,12 @@ import classNames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Listing from 'listing/listing.jsx'; import Listing from 'listing/listing.jsx';
import { ListingsEngagementScore } from '../subscribers/listings_engagement_score';
const isWPUsersSegment = (segment) => segment.type === 'wp_users'; const isWPUsersSegment = (segment) => segment.type === 'wp_users';
const isWooCommerceCustomersSegment = (segment) => segment.type === 'woocommerce_users'; const isWooCommerceCustomersSegment = (segment) => segment.type === 'woocommerce_users';
const isSpecialSegment = (segmt) => isWPUsersSegment(segmt) || isWooCommerceCustomersSegment(segmt); const isSpecialSegment = (segmt) => isWPUsersSegment(segmt) || isWooCommerceCustomersSegment(segmt);
const mailpoetTrackingEnabled = (!!(window.mailpoet_tracking_enabled));
const columns = [ const columns = [
{ {
@ -20,6 +22,11 @@ const columns = [
name: 'description', name: 'description',
label: MailPoet.I18n.t('description'), label: MailPoet.I18n.t('description'),
}, },
{
name: 'average_subscriber_score',
label: MailPoet.I18n.t('averageScore'),
display: mailpoetTrackingEnabled,
},
{ {
name: 'subscribed', name: 'subscribed',
label: MailPoet.I18n.t('subscribed'), label: MailPoet.I18n.t('subscribed'),
@ -263,6 +270,16 @@ class SegmentList extends React.Component {
<td data-colname={MailPoet.I18n.t('description')}> <td data-colname={MailPoet.I18n.t('description')}>
<abbr>{ segment.description }</abbr> <abbr>{ segment.description }</abbr>
</td> </td>
{ (mailpoetTrackingEnabled === true) ? (
<td className="column mailpoet-listing-stats-column" data-colname={MailPoet.I18n.t('averageScore')}>
<div className="mailpoet-listing-stats">
<ListingsEngagementScore
id={segment.id}
engagementScore={segment.average_engagement_score}
/>
</div>
</td>
) : null }
<td className="mailpoet-hide-on-mobile" data-colname={MailPoet.I18n.t('subscribed')}> <td className="mailpoet-hide-on-mobile" data-colname={MailPoet.I18n.t('subscribed')}>
<abbr>{ subscribed.toLocaleString() }</abbr> <abbr>{ subscribed.toLocaleString() }</abbr>
</td> </td>

View File

@ -32,6 +32,7 @@ class SegmentsResponseBuilder {
'created_at' => $segment->getCreatedAt()->format(self::DATE_FORMAT), 'created_at' => $segment->getCreatedAt()->format(self::DATE_FORMAT),
'updated_at' => $segment->getUpdatedAt()->format(self::DATE_FORMAT), 'updated_at' => $segment->getUpdatedAt()->format(self::DATE_FORMAT),
'deleted_at' => ($deletedAt = $segment->getDeletedAt()) ? $deletedAt->format(self::DATE_FORMAT) : null, 'deleted_at' => ($deletedAt = $segment->getDeletedAt()) ? $deletedAt->format(self::DATE_FORMAT) : null,
'average_engagement_score' => $segment->getAverageEngagementScore(),
]; ];
} }

View File

@ -9,6 +9,7 @@ use MailPoet\Listing\PageLimit;
use MailPoet\Models\Newsletter; use MailPoet\Models\Newsletter;
use MailPoet\Segments\SegmentDependencyValidator; use MailPoet\Segments\SegmentDependencyValidator;
use MailPoet\Services\Bridge; use MailPoet\Services\Bridge;
use MailPoet\Settings\SettingsController;
use MailPoet\Util\License\Features\Subscribers as SubscribersFeature; use MailPoet\Util\License\Features\Subscribers as SubscribersFeature;
use MailPoet\WooCommerce\Helper as WooCommerceHelper; use MailPoet\WooCommerce\Helper as WooCommerceHelper;
use MailPoet\WP\AutocompletePostListLoader as WPPostListLoader; use MailPoet\WP\AutocompletePostListLoader as WPPostListLoader;
@ -36,6 +37,9 @@ class Segments {
/** @var WPPostListLoader */ /** @var WPPostListLoader */
private $wpPostListLoader; private $wpPostListLoader;
/** @var SettingsController */
private $settings;
/** @var SegmentDependencyValidator */ /** @var SegmentDependencyValidator */
private $segmentDependencyValidator; private $segmentDependencyValidator;
@ -47,6 +51,7 @@ class Segments {
WooCommerceHelper $woocommerceHelper, WooCommerceHelper $woocommerceHelper,
WPPostListLoader $wpPostListLoader, WPPostListLoader $wpPostListLoader,
SubscribersFeature $subscribersFeature, SubscribersFeature $subscribersFeature,
SettingsController $settings,
SegmentDependencyValidator $segmentDependencyValidator SegmentDependencyValidator $segmentDependencyValidator
) { ) {
$this->pageRenderer = $pageRenderer; $this->pageRenderer = $pageRenderer;
@ -56,6 +61,7 @@ class Segments {
$this->wp = $wp; $this->wp = $wp;
$this->woocommerceHelper = $woocommerceHelper; $this->woocommerceHelper = $woocommerceHelper;
$this->wpPostListLoader = $wpPostListLoader; $this->wpPostListLoader = $wpPostListLoader;
$this->settings = $settings;
$this->segmentDependencyValidator = $segmentDependencyValidator; $this->segmentDependencyValidator = $segmentDependencyValidator;
} }
@ -102,6 +108,7 @@ class Segments {
); );
$wooCurrencySymbol = $this->woocommerceHelper->isWooCommerceActive() ? $this->woocommerceHelper->getWoocommerceCurrencySymbol() : ''; $wooCurrencySymbol = $this->woocommerceHelper->isWooCommerceActive() ? $this->woocommerceHelper->getWoocommerceCurrencySymbol() : '';
$data['woocommerce_currency_symbol'] = html_entity_decode($wooCurrencySymbol); $data['woocommerce_currency_symbol'] = html_entity_decode($wooCurrencySymbol);
$data['tracking_enabled'] = $this->settings->get('tracking.enabled');
$this->pageRenderer->displayPage('segments.html', $data); $this->pageRenderer->displayPage('segments.html', $data);
} }

View File

@ -54,6 +54,18 @@ class SegmentEntity {
*/ */
private $dynamicFilters; private $dynamicFilters;
/**
* @ORM\Column(type="float", nullable=true)
* @var float|null
*/
private $averageEngagementScore;
/**
* @ORM\Column(type="datetimetz", nullable=true)
* @var \DateTimeInterface|null
*/
private $averageEngagementScoreUpdatedAt;
public function __construct(string $name, string $type, string $description) { public function __construct(string $name, string $type, string $description) {
$this->name = $name; $this->name = $name;
$this->type = $type; $this->type = $type;
@ -122,4 +134,20 @@ class SegmentEntity {
public function isStatic(): bool { public function isStatic(): bool {
return in_array($this->getType(), [self::TYPE_DEFAULT, self::TYPE_WP_USERS, self::TYPE_WC_USERS], true); return in_array($this->getType(), [self::TYPE_DEFAULT, self::TYPE_WP_USERS, self::TYPE_WC_USERS], true);
} }
public function getAverageEngagementScore(): ?float {
return $this->averageEngagementScore;
}
public function setAverageEngagementScore(?float $averageEngagementScore): void {
$this->averageEngagementScore = $averageEngagementScore;
}
public function getAverageEngagementScoreUpdatedAt(): ?\DateTimeInterface {
return $this->averageEngagementScoreUpdatedAt;
}
public function setAverageEngagementScoreUpdatedAt(?\DateTimeInterface $averageEngagementScoreUpdatedAt): void {
$this->averageEngagementScoreUpdatedAt = $averageEngagementScoreUpdatedAt;
}
} }

View File

@ -24,7 +24,7 @@ class SegmentListingRepository extends ListingRepository {
} }
protected function applySelectClause(QueryBuilder $queryBuilder) { protected function applySelectClause(QueryBuilder $queryBuilder) {
$queryBuilder->select("PARTIAL s.{id,name,type,description,createdAt,updatedAt,deletedAt}"); $queryBuilder->select("PARTIAL s.{id,name,type,description,createdAt,updatedAt,deletedAt,averageEngagementScore}");
} }
protected function applyFromClause(QueryBuilder $queryBuilder) { protected function applyFromClause(QueryBuilder $queryBuilder) {

View File

@ -31,6 +31,7 @@
var mailpoet_can_use_woocommerce_subscriptions = <%= json_encode(can_use_woocommerce_subscriptions) %>; var mailpoet_can_use_woocommerce_subscriptions = <%= json_encode(can_use_woocommerce_subscriptions) %>;
var mailpoet_woocommerce_currency_symbol = <%= json_encode(woocommerce_currency_symbol) %>; var mailpoet_woocommerce_currency_symbol = <%= json_encode(woocommerce_currency_symbol) %>;
var mailpoet_woocommerce_countries = <%= json_encode(woocommerce_countries) %>; var mailpoet_woocommerce_countries = <%= json_encode(woocommerce_countries) %>;
var mailpoet_tracking_enabled = <%= json_encode(tracking_enabled) %>;
</script> </script>
<% endblock %> <% endblock %>
@ -85,6 +86,7 @@
'save': __('Save'), 'save': __('Save'),
'trashAndDisable': __('Trash and disable'), 'trashAndDisable': __('Trash and disable'),
'restoreAndEnable': __('Restore and enable'), 'restoreAndEnable': __('Restore and enable'),
'averageScore': __('Average Score'),
'previousPage': __('Previous page'), 'previousPage': __('Previous page'),
'firstPage': __('First page'), 'firstPage': __('First page'),
@ -195,5 +197,18 @@
'dynamicSegmentSizeIsCalculated': __('Calculating segment size…'), 'dynamicSegmentSizeIsCalculated': __('Calculating segment size…'),
'dynamicSegmentSizeCalculatingTimeout': __('Segment size calculation has timed out. You can still save the segment.'), 'dynamicSegmentSizeCalculatingTimeout': __('Segment size calculation has timed out. You can still save the segment.'),
'dynamicSegmentSize': __('This segment has %$1d subscribers.'), 'dynamicSegmentSize': __('This segment has %$1d subscribers.'),
'unknownBadgeName': __('Unknown'),
'unknownBadgeTooltip': __('Not enough data.'),
'tooltipUnknown': __('Fewer than 3 emails sent'),
'excellentBadgeName': __('Excellent'),
'excellentBadgeTooltip': __('Congrats!'),
'tooltipExcellent': __('Above 50%'),
'goodBadgeName': __('Good'),
'goodBadgeTooltip': __('Good stuff.'),
'tooltipGood': __('between 20 and 50%'),
'averageBadgeName': __('Low'),
'averageBadgeTooltip': __('Something to improve.'),
'tooltipAverage': __('between 0 and 20%'),
}) %> }) %>
<% endblock %> <% endblock %>