Show re-engagement emails notice after saving

[MAILPOET-3743]
This commit is contained in:
Brezo Cordero
2021-10-20 20:57:59 -05:00
committed by Veljko V
parent 0c72f41b8d
commit 21b9ae9f2e
9 changed files with 151 additions and 5 deletions

View File

@ -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();

View File

@ -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' };
} }

View File

@ -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;

View File

@ -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,
}; };
} }

View File

@ -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;
}

View File

@ -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[] }

View File

@ -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',
];
}
} }

View File

@ -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)')

View File

@ -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 sites emails with…', 'Transational emails settings title'), 'transactionalTitle': _x('Send all sites 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'),