Display the unsubscribe reason to the user
[MAILPOET-2792]
This commit is contained in:
@@ -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>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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() {
|
||||||
|
@@ -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'),
|
||||||
|
Reference in New Issue
Block a user