Display the unsubscribe reason to the user

[MAILPOET-2792]
This commit is contained in:
Pavel Dohnal
2020-06-18 11:08:41 +02:00
committed by Veljko V
parent 4e3b206734
commit 6e1cf96330
5 changed files with 92 additions and 20 deletions

View File

@@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import MailPoet from 'mailpoet'; import MailPoet from 'mailpoet';
import moment from 'moment';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Form from 'form/form.jsx'; import Form from 'form/form.jsx';
import ReactStringReplace from 'react-string-replace'; import ReactStringReplace from 'react-string-replace';
@@ -163,15 +164,48 @@ function beforeFormContent(subscriber) {
return undefined; return undefined;
} }
function afterFormContent() { function afterFormContent(values) {
return ( return (
<p className="description"> <>
<strong> {values?.unsubscribes?.map((unsubscribe) => {
{ MailPoet.I18n.t('tip') } const date = moment(unsubscribe.createdAt.date).format('dddd MMMM Do YYYY at h:mm:ss a');
</strong> let message;
{' '} if (unsubscribe.source === 'admin') {
{ MailPoet.I18n.t('customFieldsTip') } message = MailPoet.I18n.t('unsubcribedAdmin')
</p> .replace('%$1d', date)
.replace('%$2d', unsubscribe.meta);
} else if (unsubscribe.source === 'manage') {
message = MailPoet.I18n.t('unsubcribedManage').replace('%$1d', date);
} else if (unsubscribe.source === 'newsletter') {
message = ReactStringReplace(
MailPoet.I18n.t('unsubcribedNewsletter').replace('%$1d', date),
/\[link\]/g,
(match, i) => (
<a
key={i}
href={`admin.php?page=mailpoet-newsletter-editor&id=${unsubscribe.newsletterId}`}
>
{ unsubscribe.newsletterSubject }
</a>
)
);
} else {
message = MailPoet.I18n.t('unsubcribedUnknown').replace('%$1d', date);
}
return (
<p className="description" key={message}>
{message}
</p>
);
})}
<p className="description">
<strong>
{ MailPoet.I18n.t('tip') }
</strong>
{' '}
{ MailPoet.I18n.t('customFieldsTip') }
</p>
</>
); );
} }

View File

@@ -6,6 +6,7 @@ use MailPoet\API\JSON\Endpoint as APIEndpoint;
use MailPoet\API\JSON\Error as APIError; use MailPoet\API\JSON\Error as APIError;
use MailPoet\API\JSON\Response as APIResponse; use MailPoet\API\JSON\Response as APIResponse;
use MailPoet\Config\AccessControl; use MailPoet\Config\AccessControl;
use MailPoet\Entities\NewsletterEntity;
use MailPoet\Entities\StatisticsUnsubscribeEntity; use MailPoet\Entities\StatisticsUnsubscribeEntity;
use MailPoet\Entities\SubscriberEntity; use MailPoet\Entities\SubscriberEntity;
use MailPoet\Form\Util\FieldNameObfuscator; use MailPoet\Form\Util\FieldNameObfuscator;
@@ -19,6 +20,7 @@ use MailPoet\Newsletter\Scheduler\WelcomeScheduler;
use MailPoet\Segments\BulkAction; use MailPoet\Segments\BulkAction;
use MailPoet\Segments\SubscribersListings; use MailPoet\Segments\SubscribersListings;
use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsController;
use MailPoet\Statistics\StatisticsUnsubscribesRepository;
use MailPoet\Statistics\Track\Unsubscribes; use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscribers\ConfirmationEmailMailer; use MailPoet\Subscribers\ConfirmationEmailMailer;
use MailPoet\Subscribers\RequiredCustomFieldValidator; use MailPoet\Subscribers\RequiredCustomFieldValidator;
@@ -77,6 +79,9 @@ class Subscribers extends APIEndpoint {
/** @var Unsubscribes */ /** @var Unsubscribes */
private $unsubscribesTracker; private $unsubscribesTracker;
/** @var StatisticsUnsubscribesRepository */
private $statisticsUnsubscribesRepository;
public function __construct( public function __construct(
Listing\BulkActionController $bulkActionController, Listing\BulkActionController $bulkActionController,
SubscribersListings $subscribersListings, SubscribersListings $subscribersListings,
@@ -90,6 +95,7 @@ class Subscribers extends APIEndpoint {
ConfirmationEmailMailer $confirmationEmailMailer, ConfirmationEmailMailer $confirmationEmailMailer,
SubscriptionUrlFactory $subscriptionUrlFactory, SubscriptionUrlFactory $subscriptionUrlFactory,
Unsubscribes $unsubscribesTracker, Unsubscribes $unsubscribesTracker,
StatisticsUnsubscribesRepository $statisticsUnsubscribesRepository,
FieldNameObfuscator $fieldNameObfuscator FieldNameObfuscator $fieldNameObfuscator
) { ) {
$this->bulkActionController = $bulkActionController; $this->bulkActionController = $bulkActionController;
@@ -105,6 +111,7 @@ class Subscribers extends APIEndpoint {
$this->subscriptionUrlFactory = $subscriptionUrlFactory; $this->subscriptionUrlFactory = $subscriptionUrlFactory;
$this->fieldNameObfuscator = $fieldNameObfuscator; $this->fieldNameObfuscator = $fieldNameObfuscator;
$this->unsubscribesTracker = $unsubscribesTracker; $this->unsubscribesTracker = $unsubscribesTracker;
$this->statisticsUnsubscribesRepository = $statisticsUnsubscribesRepository;
} }
public function get($data = []) { public function get($data = []) {
@@ -115,12 +122,30 @@ class Subscribers extends APIEndpoint {
APIError::NOT_FOUND => WPFunctions::get()->__('This subscriber does not exist.', 'mailpoet'), APIError::NOT_FOUND => WPFunctions::get()->__('This subscriber does not exist.', 'mailpoet'),
]); ]);
} else { } else {
return $this->successResponse( $unsubscribes = $this->statisticsUnsubscribesRepository->findBy([
$subscriber 'subscriberId' => $id,
->withCustomFields() ], [
->withSubscriptions() 'createdAt' => 'desc',
->asArray() ]);
); $result = $subscriber
->withCustomFields()
->withSubscriptions()
->asArray();
$result['unsubscribes'] = [];
foreach ($unsubscribes as $unsubscribe) {
$mapped = [
'source' => $unsubscribe->getSource(),
'meta' => $unsubscribe->getMeta(),
'createdAt' => $unsubscribe->getCreatedAt(),
];
$newsletter = $unsubscribe->getNewsletter();
if ($newsletter instanceof NewsletterEntity) {
$mapped['newsletterId'] = $newsletter->getId();
$mapped['newsletterSubject'] = $newsletter->getSubject();
}
$result['unsubscribes'][] = $mapped;
}
return $this->successResponse($result);
} }
} }

View File

@@ -98,4 +98,11 @@ class StatisticsUnsubscribeEntity {
public function setMeta(string $meta) { public function setMeta(string $meta) {
$this->meta = $meta; $this->meta = $meta;
} }
/**
* @return string|null
*/
public function getMeta() {
return $this->meta;
}
} }

View File

@@ -22,6 +22,7 @@ use MailPoet\Models\SubscriberSegment;
use MailPoet\Segments\SubscribersListings; use MailPoet\Segments\SubscribersListings;
use MailPoet\Settings\SettingsController; use MailPoet\Settings\SettingsController;
use MailPoet\Settings\SettingsRepository; use MailPoet\Settings\SettingsRepository;
use MailPoet\Statistics\StatisticsUnsubscribesRepository;
use MailPoet\Statistics\Track\Unsubscribes; use MailPoet\Statistics\Track\Unsubscribes;
use MailPoet\Subscribers\ConfirmationEmailMailer; use MailPoet\Subscribers\ConfirmationEmailMailer;
use MailPoet\Subscribers\LinkTokens; use MailPoet\Subscribers\LinkTokens;
@@ -74,6 +75,7 @@ class SubscribersTest extends \MailPoetTest {
$container->get(ConfirmationEmailMailer::class), $container->get(ConfirmationEmailMailer::class),
new SubscriptionUrlFactory($wp, $settings, new LinkTokens), new SubscriptionUrlFactory($wp, $settings, new LinkTokens),
$container->get(Unsubscribes::class), $container->get(Unsubscribes::class),
$container->get(StatisticsUnsubscribesRepository::class),
$obfuscator $obfuscator
); );
$this->obfuscatedEmail = $obfuscator->obfuscate('email'); $this->obfuscatedEmail = $obfuscator->obfuscate('email');
@@ -135,12 +137,11 @@ class SubscribersTest extends \MailPoetTest {
$response = $this->endpoint->get(['id' => $this->subscriber1->id]); $response = $this->endpoint->get(['id' => $this->subscriber1->id]);
expect($response->status)->equals(APIResponse::STATUS_OK); expect($response->status)->equals(APIResponse::STATUS_OK);
expect($response->data)->equals( expect($response->data['id'])->equals($this->subscriber1->id);
Subscriber::findOne($this->subscriber1->id) expect($response->data['first_name'])->equals($this->subscriber1->first_name);
->withCustomFields() expect($response->data['email'])->equals($this->subscriber1->email);
->withSubscriptions() expect($response->data['unsubscribes'])->equals([]);
->asArray() expect($response->data['subscriptions'])->equals([]);
);
} }
public function testItCanSaveANewSubscriber() { public function testItCanSaveANewSubscriber() {

View File

@@ -89,6 +89,11 @@
'subscriberAdded': __('Subscriber was added successfully!'), 'subscriberAdded': __('Subscriber was added successfully!'),
'welcomeEmailTip': __('This subscriber will receive Welcome Emails if any are active for your lists.'), 'welcomeEmailTip': __('This subscriber will receive Welcome Emails if any are active for your lists.'),
'unsubcribedNewsletter': __('Unsubscribed at %$1d, from newsletter [link].'),
'unsubcribedManage': __('Unsubscribed at %$1d, using the Manage my Subscription page.'),
'unsubcribedAdmin': __('Unsubscribed at %$1d, by admin "%$2d".'),
'unsubcribedUnknown': __('Unsubscribed at %$1d, for an unknown reason.'),
'subscriber': __('Subscriber'), 'subscriber': __('Subscriber'),
'status': __('Status'), 'status': __('Status'),
'lists': __('Lists'), 'lists': __('Lists'),