Show congratulation page after first newsletter

[MAILPOET-1468]
This commit is contained in:
Pavel Dohnal
2018-10-31 13:36:03 +01:00
parent 6c8705f3c2
commit b9993da62c
16 changed files with 322 additions and 12 deletions

13
assets/js/src/loading.jsx Normal file
View File

@@ -0,0 +1,13 @@
import React from 'react';
function Loading() {
return (
<div className="mailpoet_loading">
<div className="mailpoet_modal_loading mailpoet_modal_loading_1" />
<div className="mailpoet_modal_loading mailpoet_modal_loading_2" />
<div className="mailpoet_modal_loading mailpoet_modal_loading_3" />
</div>
);
}
module.exports = Loading;

View File

@@ -87,7 +87,7 @@ define('modal', ['mailpoet', 'jquery'],
'<div class="mailpoet_popup_body clearfix"></div>' +
'</div>' +
'</div>',
loading: '<div id="mailpoet_loading" style="display:none;">' +
loading: '<div id="mailpoet_loading" class="mailpoet_loading" style="display:none;">' +
'<div id="mailpoet_modal_loading_1" class="mailpoet_modal_loading"></div>' +
'<div id="mailpoet_modal_loading_2" class="mailpoet_modal_loading"></div>' +
'<div id="mailpoet_modal_loading_3" class="mailpoet_modal_loading"></div>' +

View File

@@ -1,6 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, IndexRedirect, useRouterHistory } from 'react-router';
import { IndexRedirect, Route, Router, useRouterHistory } from 'react-router';
import { createHashHistory } from 'history';
import Hooks from 'wp-js-hooks';
import _ from 'underscore';
@@ -9,6 +9,7 @@ import PropTypes from 'prop-types';
import NewsletterTypes from 'newsletters/types.jsx';
import NewsletterTemplates from 'newsletters/templates.jsx';
import NewsletterSend from 'newsletters/send.jsx';
import NewsletterCongratulate from 'newsletters/send/congratulate/congratulate.jsx';
import NewsletterTypeStandard from 'newsletters/types/standard.jsx';
import NewsletterTypeNotification from 'newsletters/types/notification/notification.jsx';
import NewsletterTypeWelcome from 'newsletters/types/welcome/welcome.jsx';
@@ -89,6 +90,11 @@ if (container) {
path: 'template/:id',
component: NewsletterTemplates,
},
/* congratulate */
{
path: 'send/congratulate/:id',
component: NewsletterCongratulate,
},
/* Sending options */
{
path: 'send/:id',
@@ -98,7 +104,7 @@ if (container) {
routes = Hooks.applyFilters('mailpoet_newsletters_before_router', [...routes, ...getAutomaticEmailsRoutes()]);
const mailpoetListing = ReactDOM.render(( // eslint-disable-line react/no-render-return-value
window.mailpoet_listing = ReactDOM.render(( // eslint-disable-line react/no-render-return-value
<Router history={history}>
<Route path="/" component={App}>
<IndexRedirect to="standard" />
@@ -115,6 +121,4 @@ if (container) {
</Route>
</Router>
), container);
window.mailpoet_listing = mailpoetListing;
}

View File

@@ -162,6 +162,11 @@ const NewsletterSend = createReactClass({ // eslint-disable-line react/prefer-es
).done((response) => {
// save template in recently sent category
this.saveTemplate(newsletter, () => {
if (window.mailpoet_show_congratulate_after_first_newsletter) {
MailPoet.Modal.loading(false);
this.context.router.push(`/send/congratulate/${this.state.item.id}`);
return;
}
// redirect to listing based on newsletter type
this.context.router.push(Hooks.applyFilters('mailpoet_newsletters_send_server_request_response_redirect', `/${this.state.item.type || ''}`, this.state.item));
const customResponse = Hooks.applyFilters('mailpoet_newsletters_send_server_request_response', this.state.item, response);
@@ -205,6 +210,11 @@ const NewsletterSend = createReactClass({ // eslint-disable-line react/prefer-es
}).done((response) => {
// save template in recently sent category
this.saveTemplate(newsletter, () => {
if (window.mailpoet_show_congratulate_after_first_newsletter) {
MailPoet.Modal.loading(false);
this.context.router.push(`/send/congratulate/${this.state.item.id}`);
return;
}
// redirect to listing based on newsletter type
this.context.router.push(`/${this.state.item.type || ''}`);
const opts = this.state.item.options;

View File

@@ -0,0 +1,136 @@
import React from 'react';
import PropTypes from 'prop-types';
import MailPoet from 'mailpoet';
import moment from 'moment';
import Success from './success.jsx';
import Fail from './fail.jsx';
import Loading from './loading.jsx';
const SECONDS_WAITING_FOR_SUCCESS = 20;
const SECONDS_MINIMUIM_LOADING_SCREEN_DISPLAYED = 6;
function successPageClosed() {
return MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'settings',
action: 'set',
data: { show_congratulate_after_first_newsletter: false },
}).always(() => {
window.location = window.mailpoet_main_page;
});
}
function renderSuccess(newsletter, testingPassed) {
if (testingPassed) {
MailPoet.trackEvent('Cron testing done', {
'Cron is working': 'true',
});
}
return (<Success
illustrationImageUrl={window.mailpoet_congratulations_success_image}
successClicked={successPageClosed}
newsletter={newsletter}
/>);
}
function renderFail() {
MailPoet.trackEvent('Cron testing done', {
'Cron is working': 'false',
});
return (<Fail
failClicked={() => {
window.location = window.mailpoet_main_page;
}}
/>);
}
function renderLoading(showRichLoadingScreen) {
return (<Loading
illustrationImageUrl={window.mailpoet_congratulations_loading_image}
successClicked={successPageClosed}
showRichLoadingScreen={showRichLoadingScreen}
/>);
}
class Congratulate extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: true,
fail: false,
newsletter: null,
testingPassed: false,
timeStart: moment(),
minimumLoadingTimePassed: false,
};
this.tick = this.tick.bind(this);
}
componentDidMount() {
this.loadNewsletter(this.props.params.id);
this.tick();
}
componentWillReceiveProps(props) {
this.loadNewsletter(props.params.id);
}
tick() {
if (moment().subtract(SECONDS_WAITING_FOR_SUCCESS, 'second').isAfter(this.state.timeStart)) {
this.setState({ error: true, loading: false });
}
if (this.state.loading) {
this.loadNewsletter(this.props.params.id);
}
if (moment().subtract(SECONDS_MINIMUIM_LOADING_SCREEN_DISPLAYED, 'seconds').isAfter(this.state.timeStart)) {
this.setState({ minimumLoadingTimePassed: true });
}
if (this.state.loading || !this.state.minimumLoadingTimePassed) {
setTimeout(this.tick, 2000);
}
}
loadNewsletter(id) {
MailPoet.Ajax.post({
api_version: window.mailpoet_api_version,
endpoint: 'newsletters',
action: 'get',
data: {
id,
},
})
.done(response => this.newsletterLoaded(response.data));
}
newsletterLoaded(newsletter) {
if ((newsletter.type !== 'standard') || (newsletter.status === 'scheduled')) {
this.setState({ newsletter, loading: false, minimumLoadingTimePassed: true });
} else if ((newsletter.status === 'sent') || (newsletter.status === 'sending')) {
this.setState({ newsletter, loading: false, testingPassed: true });
} else {
this.setState({ newsletter });
}
}
renderContent() {
if (this.state.loading || !this.state.minimumLoadingTimePassed) {
return renderLoading(!!this.state.newsletter);
} else if (this.state.error) {
return renderFail();
}
return renderSuccess(this.state.newsletter, this.state.testingPassed);
}
render() {
return (<div className="newsletter_congratulate_page">{this.renderContent()}</div>);
}
}
Congratulate.propTypes = {
params: PropTypes.shape({
id: PropTypes.string.isRequired,
}).isRequired,
};
module.exports = Congratulate;

View File

@@ -0,0 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';
import ReactStringReplace from 'react-string-replace';
import MailPoet from '../../../mailpoet';
function Fail(props) {
return (
<div className="mailpoet_centered">
<h1>{MailPoet.I18n.t('congratulationsSendFailHeader')}</h1>
<p>
{ ReactStringReplace(
MailPoet.I18n.t('congratulationsSendFailExplain'),
/\[link\](.*?)\[\/link\]/g,
(match, i) => (
<a
key={i}
target="_blank"
rel="noopener noreferrer"
href="https://kb.mailpoet.com/article/231-sending-does-not-work"
>{ match }</a>
)
)
}
</p>
<button className="button" onClick={props.failClicked}>{MailPoet.I18n.t('close')}</button>
</div>
);
}
Fail.propTypes = {
failClicked: PropTypes.func.isRequired,
};
module.exports = Fail;

View File

@@ -0,0 +1,32 @@
import React from 'react';
import PropTypes from 'prop-types';
import MailPoet from '../../../mailpoet';
import LoadingDots from '../../../loading.jsx';
function renderRichData(showRichData, illustrationImageUrl) {
if (showRichData) {
return (
<div>
<h1 className="mailpoet_newsletter_loading_header">{MailPoet.I18n.t('congratulationsLoadingHeader')}</h1>
<img src={illustrationImageUrl} alt="" width="800px" height="266px" />
</div>
);
}
return (<div />);
}
function Loading(props) {
return (
<div className="mailpoet_newsletter_loading">
<LoadingDots />
{renderRichData(props.showRichLoadingScreen, props.illustrationImageUrl)}
</div>
);
}
Loading.propTypes = {
illustrationImageUrl: PropTypes.string.isRequired,
showRichLoadingScreen: PropTypes.bool.isRequired,
};
module.exports = Loading;

View File

@@ -0,0 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';
import MailPoet from '../../../mailpoet';
function renderHeader(newsletter) {
if (newsletter.type === 'welcome') {
return MailPoet.I18n.t('congratulationsWelcomeEmailSuccessHeader');
} else if (newsletter.type === 'notification') {
return MailPoet.I18n.t('congratulationsPostNotificationSuccessHeader');
} else if (newsletter.type === 'automatic') {
return MailPoet.I18n.t('congratulationsWooSuccessHeader');
} else if (newsletter.status === 'scheduled') {
return MailPoet.I18n.t('congratulationsScheduleSuccessHeader');
}
return MailPoet.I18n.t('congratulationsSendSuccessHeader');
}
function Success(props) {
return (
<div className="mailpoet_congratulate_success">
<h1>{renderHeader(props.newsletter)}</h1>
<img src={props.illustrationImageUrl} alt="" width="750" height="250" />
<button className="button" onClick={props.successClicked}>{MailPoet.I18n.t('close')}</button>
</div>
);
}
Success.propTypes = {
successClicked: PropTypes.func.isRequired,
illustrationImageUrl: PropTypes.string.isRequired,
newsletter: PropTypes.shape({
status: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
}).isRequired,
};
module.exports = Success;