diff --git a/assets/css/src/in-app-announcements.styl b/assets/css/src/in-app-announcements.styl
index 170d7e31e0..210fdb7f31 100644
--- a/assets/css/src/in-app-announcements.styl
+++ b/assets/css/src/in-app-announcements.styl
@@ -26,3 +26,16 @@
100%
-moz-box-shadow: 0 0 0 0 rgba(255, 83, 1, 0)
box-shadow: 0 0 0 0 rgba(255, 83, 1, 0)
+
+.mailpoet_in_app_announcement_free_welcome_emails
+ text-align: center
+ h2
+ font-size: 28px
+ img
+ width: 640px
+ margin-top: -20px
+
+.mailpoet_in_app_announcement_free_welcome_emails_dot
+ position: relative
+ top: -3px
+ left: 8px
diff --git a/assets/img/in_app_announcements/hello-illustration-for-welcome-emails.png b/assets/img/in_app_announcements/hello-illustration-for-welcome-emails.png
new file mode 100644
index 0000000000..49f6928759
Binary files /dev/null and b/assets/img/in_app_announcements/hello-illustration-for-welcome-emails.png differ
diff --git a/assets/js/src/in_app_announcements/in_app_announcement.jsx b/assets/js/src/in_app_announcements/in_app_announcement.jsx
index 56238e3d39..96832b0a42 100644
--- a/assets/js/src/in_app_announcements/in_app_announcement.jsx
+++ b/assets/js/src/in_app_announcements/in_app_announcement.jsx
@@ -1,25 +1,80 @@
import React from 'react';
+import MailPoet from 'mailpoet';
import InAppAnnouncementDot from './in_app_announcement_dot.jsx';
-const InAppAnnouncement = (props) => {
- if (props.newUser !== null &&
- window.mailpoet_is_new_user !== props.newUser
- ) {
- return null;
+class InAppAnnouncement extends React.Component {
+ constructor(props) {
+ super(props);
+ this.saveDisplayed = this.saveDisplayed.bind(this);
+
+ this.state = {
+ announcementsSettings: window.mailpoet_in_app_announcements || null,
+ };
}
- if (props.validUntil < (new Date().getTime() / 1000)) {
- return null;
+ saveDisplayed() {
+ const settings = Object.assign({}, this.state.announcementsSettings);
+ settings.displayed.push(this.props.showOnlyOnceSlug);
+ return MailPoet.Ajax.post({
+ api_version: window.mailpoet_api_version,
+ endpoint: 'settings',
+ action: 'set',
+ data: { in_app_announcements: settings },
+ }).always(() => (this.setState({ announcementsSettings: settings })));
}
- return (
-
- {props.children}
- );
+ render() {
+ if (this.props.showToNewUser !== null &&
+ window.mailpoet_is_new_user !== this.props.showToNewUser
+ ) {
+ return null;
+ }
+
+ if (this.props.validUntil !== null
+ && this.props.validUntil < new Date()
+ ) {
+ return null;
+ }
+
+ if (this.props.showToPremiumUser !== null &&
+ window.mailpoet_premium_active !== this.props.showToPremiumUser
+ ) {
+ return null;
+ }
+
+ if (this.props.showOnlyOnceSlug &&
+ this.state.announcementsSettings.displayed.includes(this.props.showOnlyOnceSlug)
+ ) {
+ return null;
+ }
+
+ return (
+ {
+ if (!this.props.showOnlyOnceSlug) { return; }
+ this.saveDisplayed();
+ }}
+ >
+ {this.props.children}
+
+ );
+ }
+}
+
+const validateBooleanWithWindowDependency = (props, propName, componentName, windowProperty) => {
+ const propValue = props[propName];
+ if (propValue !== null && propValue !== true && propValue !== false) {
+ return new Error(`Invalid property in ${componentName}. newUser must be of type boolean`);
+ }
+ if (propValue !== null && typeof window[windowProperty] === 'undefined') {
+ return new Error(
+ `Missing data for evaluation of ${componentName} display condition. ${propName} requires window.${windowProperty}`
+ );
+ }
+ return null;
};
InAppAnnouncement.propTypes = {
@@ -27,14 +82,27 @@ InAppAnnouncement.propTypes = {
height: React.PropTypes.string,
className: React.PropTypes.string,
children: React.PropTypes.element.isRequired,
- validUntil: React.PropTypes.number,
- newUser: (props, propName, componentName) => {
+ validUntil: React.PropTypes.instanceOf(Date),
+ showToNewUser: (props, propName, componentName) => (
+ validateBooleanWithWindowDependency(props, propName, componentName, 'mailpoet_is_new_user')
+ ),
+ showToPremiumUser: (props, propName, componentName) => (
+ validateBooleanWithWindowDependency(props, propName, componentName, 'mailpoet_premium_active')
+ ),
+ showOnlyOnceSlug: (props, propName, componentName) => {
const propValue = props[propName];
- if (propValue !== null && propValue !== true && propValue !== false) {
- return new Error(`Invalid property in ${componentName}. newUser must be of type boolean`);
+ if (propValue !== null && typeof propValue !== 'string') {
+ return new Error(`Invalid property in ${componentName}. ${propName} must be of type string`);
}
- if (typeof window.mailpoet_is_new_user === 'undefined') {
- return new Error(`Missing data for evaluation of ${componentName} display condition. ${propName} requires window.mailpoet_is_new_user`);
+ if (propValue === null) {
+ return null;
+ }
+ if (
+ typeof window.mailpoet_in_app_announcements === 'undefined'
+ ) {
+ return new Error(
+ `Missing data for evaluation of ${componentName} display condition. ${propName} requires window.mailpoet_in_app_announcements`
+ );
}
return null;
},
@@ -45,7 +113,9 @@ InAppAnnouncement.defaultProps = {
height: '600px',
className: null,
validUntil: null,
- newUser: null,
+ showToNewUser: null,
+ showToPremiumUser: null,
+ showOnlyOnceSlug: null,
};
module.exports = InAppAnnouncement;
diff --git a/assets/js/src/in_app_announcements/in_app_announcement_dot.jsx b/assets/js/src/in_app_announcements/in_app_announcement_dot.jsx
index 83edc8404b..8241efc448 100644
--- a/assets/js/src/in_app_announcements/in_app_announcement_dot.jsx
+++ b/assets/js/src/in_app_announcements/in_app_announcement_dot.jsx
@@ -14,21 +14,24 @@ const InAppAnnouncementDot = props => (
width: props.width,
height: props.height,
});
+ if (props.onUserTrigger) props.onUserTrigger();
}}
/>
);
InAppAnnouncementDot.propTypes = {
+ children: React.PropTypes.element.isRequired,
width: React.PropTypes.string,
height: React.PropTypes.string,
className: React.PropTypes.string,
- children: React.PropTypes.element.isRequired,
+ onUserTrigger: React.PropTypes.func,
};
InAppAnnouncementDot.defaultProps = {
width: 'auto',
height: 'auto',
className: null,
+ onUserTrigger: null,
};
module.exports = InAppAnnouncementDot;
diff --git a/assets/js/src/newsletters/listings/heading.jsx b/assets/js/src/newsletters/listings/heading.jsx
index 54df9f61e8..9ed6c09cdd 100644
--- a/assets/js/src/newsletters/listings/heading.jsx
+++ b/assets/js/src/newsletters/listings/heading.jsx
@@ -1,6 +1,7 @@
import React from 'react';
import { Link } from 'react-router';
import MailPoet from 'mailpoet';
+import InAppAnnoucement from 'in_app_announcements/in_app_announcement.jsx';
const ListingHeading = () => (
@@ -17,6 +18,23 @@ const ListingHeading = () => (
>
{MailPoet.I18n.t('new')}
+
+
+
{MailPoet.I18n.t('freeWelcomeEmailsHeading')}
+

+
{MailPoet.I18n.t('freeWelcomeEmailsParagraph')}
+
+
);
diff --git a/lib/Models/Setting.php b/lib/Models/Setting.php
index efcc2ccfae..d962270762 100644
--- a/lib/Models/Setting.php
+++ b/lib/Models/Setting.php
@@ -53,7 +53,10 @@ class Setting extends Model {
),
'analytics' => array(
'enabled' => false,
- )
+ ),
+ 'in_app_announcements' => [
+ 'displayed' => []
+ ],
);
}
diff --git a/views/newsletters.html b/views/newsletters.html
index 88af5cff15..0c5688d4d9 100644
--- a/views/newsletters.html
+++ b/views/newsletters.html
@@ -17,6 +17,8 @@
var mailpoet_tracking_enabled = <%= json_encode(tracking_enabled) %>;
var mailpoet_premium_active = <%= json_encode(premium_plugin_active) %>;
var mailpoet_automatic_emails = <%= json_encode(automatic_emails) %>;
+ var mailpoet_in_app_announcements = mailpoet_settings.in_app_announcements;
+ var mailpoet_free_welcome_emails_image = '<%= image_url('in_app_announcements/hello-illustration-for-welcome-emails.png') %>';
<% set newUser = (is_new_user == true) ? 'true' : 'false' %>
var mailpoet_is_new_user = <%= newUser %>;
@@ -297,6 +299,9 @@
'introBack': _x('Back', 'A label on a button'),
'introSkip': _x('Skip', 'A label on a button'),
'introDone': _x('Done', 'A label on a button'),
+
+ 'freeWelcomeEmailsHeading': __('Welcome Emails are now free for everyone'),
+ 'freeWelcomeEmailsParagraph': __('Say “Hello!” automatically to all your new subscribers. They’ll appreciate the extra touch.'),
}) %>
<% endblock %>