Show re-engagement emails notice after saving
[MAILPOET-3743]
This commit is contained in:
@ -3,12 +3,38 @@ import MailPoet from 'mailpoet';
|
|||||||
import Button from 'common/button/button';
|
import Button from 'common/button/button';
|
||||||
import { useAction, useSelector } from 'settings/store/hooks';
|
import { useAction, useSelector } from 'settings/store/hooks';
|
||||||
import { GlobalContext } from 'context';
|
import { GlobalContext } from 'context';
|
||||||
|
import ReactStringReplace from 'react-string-replace';
|
||||||
|
|
||||||
|
const showReEngagementNotice = (action, showError, showSuccess) => {
|
||||||
|
if (action === 'deactivate') {
|
||||||
|
showError(<p>{MailPoet.I18n.t('re-engagementDisabledNotice')}</p>, { scroll: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action === 'reactivate') {
|
||||||
|
const reEngagementReactivatedNotice = ReactStringReplace(
|
||||||
|
MailPoet.I18n.t('re-engagementReactivatedNotice'),
|
||||||
|
/\[link\](.*?)\[\/link\]/g,
|
||||||
|
(match) => (
|
||||||
|
<a
|
||||||
|
key="reEngagementEmailsTabLink"
|
||||||
|
href="?page=mailpoet-newsletters#/re_engagement"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
{match}
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
showSuccess(<p>{reEngagementReactivatedNotice}</p>, { scroll: true });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const [clicked, setClicked] = React.useState(false);
|
const [clicked, setClicked] = React.useState(false);
|
||||||
const isSaving = useSelector('isSaving')();
|
const isSaving = useSelector('isSaving')();
|
||||||
const hasError = useSelector('hasErrorFlag')();
|
const hasError = useSelector('hasErrorFlag')();
|
||||||
const error = useSelector('getSavingError')();
|
const error = useSelector('getSavingError')();
|
||||||
|
const hasReEngagementNotice = useSelector('hasReEngagementNotice')();
|
||||||
|
const reEngagementAction = useSelector('getReEngagementAction')();
|
||||||
const save = useAction('saveSettings');
|
const save = useAction('saveSettings');
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const { notices } = React.useContext<any>(GlobalContext);
|
const { notices } = React.useContext<any>(GlobalContext);
|
||||||
@ -17,9 +43,14 @@ export default () => {
|
|||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (clicked && !isSaving) {
|
if (clicked && !isSaving) {
|
||||||
if (error) showError(error.map((err) => <p>{err}</p>), { scroll: true });
|
if (error) showError(error.map((err) => <p>{err}</p>), { scroll: true });
|
||||||
else showSuccess(<p>{MailPoet.I18n.t('settingsSaved')}</p>, { scroll: true });
|
else {
|
||||||
|
showSuccess(<p>{MailPoet.I18n.t('settingsSaved')}</p>, { scroll: true });
|
||||||
|
if (hasReEngagementNotice) {
|
||||||
|
showReEngagementNotice(reEngagementAction, showError, showSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [clicked, error, isSaving, showError, showSuccess]);
|
}, [clicked, error, isSaving, showError, showSuccess, hasReEngagementNotice, reEngagementAction]);
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
setClicked(true);
|
setClicked(true);
|
||||||
save();
|
save();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { select } from '@wordpress/data';
|
import { select } from '@wordpress/data';
|
||||||
|
|
||||||
import { STORE_NAME } from 'settings/store';
|
import { STORE_NAME } from 'settings/store';
|
||||||
import { Action } from 'settings/store/types';
|
import { Action, ReEngagement } from 'settings/store/types';
|
||||||
import { updateKeyActivationState } from './mss_and_premium';
|
import { updateKeyActivationState } from './mss_and_premium';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@ -18,6 +18,10 @@ export function setErrorFlag(value: boolean): Action {
|
|||||||
return { type: 'SET_ERROR_FLAG', value };
|
return { type: 'SET_ERROR_FLAG', value };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setReEngagement(value: ReEngagement): Action {
|
||||||
|
return { type: 'SET_RE_ENGAGEMENT_NOTICE', value };
|
||||||
|
}
|
||||||
|
|
||||||
export function* saveSettings() {
|
export function* saveSettings() {
|
||||||
yield { type: 'SAVE_STARTED' };
|
yield { type: 'SAVE_STARTED' };
|
||||||
const data = select(STORE_NAME).getSettings();
|
const data = select(STORE_NAME).getSettings();
|
||||||
@ -41,6 +45,7 @@ export function* saveSettings() {
|
|||||||
fromAddressModalCanBeShown: false,
|
fromAddressModalCanBeShown: false,
|
||||||
});
|
});
|
||||||
yield setSettings(res.data);
|
yield setSettings(res.data);
|
||||||
|
yield setReEngagement(res.meta);
|
||||||
return { type: 'SAVE_DONE' };
|
return { type: 'SAVE_DONE' };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,11 @@ export default function createReducer(defaultValue: State) {
|
|||||||
return { ...state, save: { inProgress: false, error: null } };
|
return { ...state, save: { inProgress: false, error: null } };
|
||||||
case 'SAVE_FAILED':
|
case 'SAVE_FAILED':
|
||||||
return { ...state, save: { inProgress: false, error: action.error } };
|
return { ...state, save: { inProgress: false, error: action.error } };
|
||||||
|
case 'SET_RE_ENGAGEMENT_NOTICE':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
reEngagement: { showNotice: action.value.showNotice, action: action.value.action },
|
||||||
|
};
|
||||||
case 'UPDATE_KEY_ACTIVATION_STATE':
|
case 'UPDATE_KEY_ACTIVATION_STATE':
|
||||||
keyActivation = { ...state.keyActivation, ...action.fields };
|
keyActivation = { ...state.keyActivation, ...action.fields };
|
||||||
keyActivation.isKeyValid = null;
|
keyActivation.isKeyValid = null;
|
||||||
|
@ -70,7 +70,11 @@ export default function makeDefaultState(window: any): State {
|
|||||||
state: TestEmailState.NONE,
|
state: TestEmailState.NONE,
|
||||||
error: null,
|
error: null,
|
||||||
};
|
};
|
||||||
|
const reEngagement = {
|
||||||
|
showNotice: false,
|
||||||
|
action: null,
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
data, flags, save, keyActivation, segments, pages, paths, hosts, testEmail,
|
data, flags, save, keyActivation, segments, pages, paths, hosts, testEmail, reEngagement,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -89,3 +89,11 @@ export function getSendGridOptions(state: State) {
|
|||||||
export function getTestEmailState(state: State) {
|
export function getTestEmailState(state: State) {
|
||||||
return state.testEmail;
|
return state.testEmail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function hasReEngagementNotice(state: State): boolean {
|
||||||
|
return state.reEngagement.showNotice;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getReEngagementAction(state: State) {
|
||||||
|
return state.reEngagement.action;
|
||||||
|
}
|
||||||
|
@ -218,6 +218,11 @@ export type KeyActivationState = {
|
|||||||
activationUrl?: string;
|
activationUrl?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ReEngagement = {
|
||||||
|
showNotice: boolean;
|
||||||
|
action?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export enum TestEmailState {
|
export enum TestEmailState {
|
||||||
SENDING,
|
SENDING,
|
||||||
NONE,
|
NONE,
|
||||||
@ -250,6 +255,7 @@ export type State = {
|
|||||||
};
|
};
|
||||||
keyActivation: KeyActivationState;
|
keyActivation: KeyActivationState;
|
||||||
hosts: Hosts;
|
hosts: Hosts;
|
||||||
|
reEngagement: ReEngagement;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Action =
|
export type Action =
|
||||||
@ -262,6 +268,7 @@ export type Action =
|
|||||||
| { type: 'SAVE_DONE' }
|
| { type: 'SAVE_DONE' }
|
||||||
| { type: 'SAVE_FAILED'; error: string[] }
|
| { type: 'SAVE_FAILED'; error: string[] }
|
||||||
| { type: 'UPDATE_KEY_ACTIVATION_STATE'; fields: Partial<KeyActivationState> }
|
| { type: 'UPDATE_KEY_ACTIVATION_STATE'; fields: Partial<KeyActivationState> }
|
||||||
|
| { type: 'SET_RE_ENGAGEMENT_NOTICE'; value: ReEngagement }
|
||||||
| { type: 'START_TEST_EMAIL_SENDING' }
|
| { type: 'START_TEST_EMAIL_SENDING' }
|
||||||
| { type: 'TEST_EMAIL_SUCCESS' }
|
| { type: 'TEST_EMAIL_SUCCESS' }
|
||||||
| { type: 'TEST_EMAIL_FAILED'; error: string[] }
|
| { type: 'TEST_EMAIL_FAILED'; error: string[] }
|
||||||
|
@ -9,9 +9,11 @@ use MailPoet\Config\ServicesChecker;
|
|||||||
use MailPoet\Cron\Workers\InactiveSubscribers;
|
use MailPoet\Cron\Workers\InactiveSubscribers;
|
||||||
use MailPoet\Cron\Workers\SubscribersEngagementScore;
|
use MailPoet\Cron\Workers\SubscribersEngagementScore;
|
||||||
use MailPoet\Cron\Workers\WooCommerceSync;
|
use MailPoet\Cron\Workers\WooCommerceSync;
|
||||||
|
use MailPoet\Entities\NewsletterEntity;
|
||||||
use MailPoet\Entities\ScheduledTaskEntity;
|
use MailPoet\Entities\ScheduledTaskEntity;
|
||||||
use MailPoet\Form\FormMessageController;
|
use MailPoet\Form\FormMessageController;
|
||||||
use MailPoet\Mailer\MailerLog;
|
use MailPoet\Mailer\MailerLog;
|
||||||
|
use MailPoet\Newsletter\NewslettersRepository;
|
||||||
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
use MailPoet\Newsletter\Sending\ScheduledTasksRepository;
|
||||||
use MailPoet\Segments\SegmentsRepository;
|
use MailPoet\Segments\SegmentsRepository;
|
||||||
use MailPoet\Services\AuthorizedEmailsController;
|
use MailPoet\Services\AuthorizedEmailsController;
|
||||||
@ -65,6 +67,8 @@ class Settings extends APIEndpoint {
|
|||||||
public $permissions = [
|
public $permissions = [
|
||||||
'global' => AccessControl::PERMISSION_MANAGE_SETTINGS,
|
'global' => AccessControl::PERMISSION_MANAGE_SETTINGS,
|
||||||
];
|
];
|
||||||
|
/** @var NewslettersRepository */
|
||||||
|
private $newsletterRepository;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
SettingsController $settings,
|
SettingsController $settings,
|
||||||
@ -73,6 +77,7 @@ class Settings extends APIEndpoint {
|
|||||||
TransactionalEmails $wcTransactionalEmails,
|
TransactionalEmails $wcTransactionalEmails,
|
||||||
WPFunctions $wp,
|
WPFunctions $wp,
|
||||||
EntityManager $entityManager,
|
EntityManager $entityManager,
|
||||||
|
NewslettersRepository $newslettersRepository,
|
||||||
StatisticsOpensRepository $statisticsOpensRepository,
|
StatisticsOpensRepository $statisticsOpensRepository,
|
||||||
ScheduledTasksRepository $scheduledTasksRepository,
|
ScheduledTasksRepository $scheduledTasksRepository,
|
||||||
FormMessageController $messageController,
|
FormMessageController $messageController,
|
||||||
@ -87,6 +92,7 @@ class Settings extends APIEndpoint {
|
|||||||
$this->servicesChecker = $servicesChecker;
|
$this->servicesChecker = $servicesChecker;
|
||||||
$this->wp = $wp;
|
$this->wp = $wp;
|
||||||
$this->entityManager = $entityManager;
|
$this->entityManager = $entityManager;
|
||||||
|
$this->newsletterRepository = $newslettersRepository;
|
||||||
$this->statisticsOpensRepository = $statisticsOpensRepository;
|
$this->statisticsOpensRepository = $statisticsOpensRepository;
|
||||||
$this->scheduledTasksRepository = $scheduledTasksRepository;
|
$this->scheduledTasksRepository = $scheduledTasksRepository;
|
||||||
$this->messageController = $messageController;
|
$this->messageController = $messageController;
|
||||||
@ -107,6 +113,7 @@ class Settings extends APIEndpoint {
|
|||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
$oldSettings = $this->settings->getAll();
|
$oldSettings = $this->settings->getAll();
|
||||||
|
$meta = [];
|
||||||
$signupConfirmation = $this->settings->get('signup_confirmation.enabled');
|
$signupConfirmation = $this->settings->get('signup_confirmation.enabled');
|
||||||
foreach ($settings as $name => $value) {
|
foreach ($settings as $name => $value) {
|
||||||
$this->settings->set($name, $value);
|
$this->settings->set($name, $value);
|
||||||
@ -123,7 +130,19 @@ class Settings extends APIEndpoint {
|
|||||||
if ($signupConfirmation !== $this->settings->get('signup_confirmation.enabled')) {
|
if ($signupConfirmation !== $this->settings->get('signup_confirmation.enabled')) {
|
||||||
$this->messageController->updateSuccessMessages();
|
$this->messageController->updateSuccessMessages();
|
||||||
}
|
}
|
||||||
return $this->successResponse($this->settings->getAll());
|
|
||||||
|
// Tracking and re-engagement Emails
|
||||||
|
$meta['showNotice'] = false;
|
||||||
|
if ($oldSettings['tracking'] !== $this->settings->get('tracking') ) {
|
||||||
|
try {
|
||||||
|
$meta = $this->updateReEngagementEmailStatus($this->settings->get('tracking'));
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->badRequest([
|
||||||
|
APIError::UNKNOWN => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->successResponse($this->settings->getAll(), $meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,4 +282,50 @@ class Settings extends APIEndpoint {
|
|||||||
$this->subscribersCountsController->removeRedundancyFromStatisticsCache();
|
$this->subscribersCountsController->removeRedundancyFromStatisticsCache();
|
||||||
return $this->successResponse();
|
return $this->successResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function updateReEngagementEmailStatus($newTracking): array {
|
||||||
|
if (!empty($newTracking['enabled']) && $newTracking['enabled'] === "1" ) {
|
||||||
|
return $this->reactivateReEngagementEmails();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return $this->deactivateReEngagementEmails();
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
throw new \Exception(
|
||||||
|
__('Unable to deactivate re-engagement emails: ' . $e->getMessage()), 'mailpoet');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws \Exception
|
||||||
|
*/
|
||||||
|
public function deactivateReEngagementEmails(): array {
|
||||||
|
$reEngagementEmails = $this->newsletterRepository->findActiveByTypes(([NewsletterEntity::TYPE_RE_ENGAGEMENT]));
|
||||||
|
if (!$reEngagementEmails) {
|
||||||
|
return [
|
||||||
|
'showNotice' => false,
|
||||||
|
'action' => 'deactivate',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($reEngagementEmails as $reEngagementEmail) {
|
||||||
|
$reEngagementEmail->setStatus(NewsletterEntity::STATUS_DRAFT);
|
||||||
|
$this->entityManager->persist($reEngagementEmail);
|
||||||
|
$this->entityManager->flush();
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
'showNotice' => true,
|
||||||
|
'action' => 'deactivate',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reactivateReEngagementEmails(): array {
|
||||||
|
$draftReEngagementEmails = $this->newsletterRepository->findDraftByTypes(([NewsletterEntity::TYPE_RE_ENGAGEMENT]));
|
||||||
|
return [
|
||||||
|
'showNotice' => !!$draftReEngagementEmails,
|
||||||
|
'action' => 'reactivate',
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,25 @@ class NewslettersRepository extends Repository {
|
|||||||
->getResult();
|
->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string[] $types
|
||||||
|
* @return NewsletterEntity[]
|
||||||
|
*/
|
||||||
|
public function findDraftByTypes($types) {
|
||||||
|
return $this->entityManager
|
||||||
|
->createQueryBuilder()
|
||||||
|
->select('n')
|
||||||
|
->from(NewsletterEntity::class, 'n')
|
||||||
|
->where('n.status = :status')
|
||||||
|
->setParameter(':status', NewsletterEntity::STATUS_DRAFT)
|
||||||
|
->andWhere('n.deletedAt is null')
|
||||||
|
->andWhere('n.type IN (:types)')
|
||||||
|
->setParameter('types', $types)
|
||||||
|
->orderBy('n.subject')
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
public function getStandardNewsletterSentCount(DateTimeInterface $since): int {
|
public function getStandardNewsletterSentCount(DateTimeInterface $since): int {
|
||||||
return (int)$this->doctrineRepository->createQueryBuilder('n')
|
return (int)$this->doctrineRepository->createQueryBuilder('n')
|
||||||
->select('COUNT(n)')
|
->select('COUNT(n)')
|
||||||
|
@ -129,6 +129,8 @@
|
|||||||
'trackingTitle': __('Open and click tracking'),
|
'trackingTitle': __('Open and click tracking'),
|
||||||
'trackingDescription': __('Enable or disable open and click tracking.'),
|
'trackingDescription': __('Enable or disable open and click tracking.'),
|
||||||
're-engagementDisabledBecauseTrackingIs': __('Note: re-engagement emails are disabled when tracking is disabled.'),
|
're-engagementDisabledBecauseTrackingIs': __('Note: re-engagement emails are disabled when tracking is disabled.'),
|
||||||
|
're-engagementDisabledNotice': __('Re-engagement emails were deactivated.'),
|
||||||
|
're-engagementReactivatedNotice': __('Re-engagement emails are now enabled. Dont forget to [link]activate them[/link].'),
|
||||||
'transactionalTitle': _x('Send all site’s emails with…', 'Transational emails settings title'),
|
'transactionalTitle': _x('Send all site’s emails with…', 'Transational emails settings title'),
|
||||||
'transactionalDescription': _x('Choose which method to send all your WordPress emails (e.g. password reset, new registration, WooCommerce invoices, etc.).', 'Transational emails settings description'),
|
'transactionalDescription': _x('Choose which method to send all your WordPress emails (e.g. password reset, new registration, WooCommerce invoices, etc.).', 'Transational emails settings description'),
|
||||||
'transactionalLink': _x('Read more.', 'Transactional emails settings link'),
|
'transactionalLink': _x('Read more.', 'Transactional emails settings link'),
|
||||||
|
Reference in New Issue
Block a user