From d6487d363031ccb40119aec9cd06c804cc62e88e Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Thu, 31 Mar 2022 11:06:21 +0100 Subject: [PATCH] Created labs versions of members-email settings code refs https://github.com/TryGhost/Team/issues/1441 - duplicated route/controller/template and component to `-labs` versions so larger changes and refactors can be made without affecting the GA code - added redirect for `/settings/members-email -> /settings/members-email-labs` when `multipleNewsletters` flag is enabled - cleaned up multiple-newsletters related code from the non-labs component --- .../settings/members-email-labs.hbs | 237 +++++++ .../components/settings/members-email-labs.js | 246 +++++++ .../app/components/settings/members-email.hbs | 616 ++++++------------ .../app/components/settings/members-email.js | 21 - .../settings/members-email-labs.js | 74 +++ ghost/admin/app/router.js | 1 + .../app/routes/settings/members-email-labs.js | 43 ++ .../app/routes/settings/members-email.js | 7 +- .../templates/settings/members-email-labs.hbs | 48 ++ .../settings/members-email-labs-test.js | 48 ++ .../acceptance/settings/members-email-test.js | 7 +- 11 files changed, 897 insertions(+), 451 deletions(-) create mode 100644 ghost/admin/app/components/settings/members-email-labs.hbs create mode 100644 ghost/admin/app/components/settings/members-email-labs.js create mode 100644 ghost/admin/app/controllers/settings/members-email-labs.js create mode 100644 ghost/admin/app/routes/settings/members-email-labs.js create mode 100644 ghost/admin/app/templates/settings/members-email-labs.hbs create mode 100644 ghost/admin/tests/acceptance/settings/members-email-labs-test.js diff --git a/ghost/admin/app/components/settings/members-email-labs.hbs b/ghost/admin/app/components/settings/members-email-labs.hbs new file mode 100644 index 0000000000..ae1b0e5892 --- /dev/null +++ b/ghost/admin/app/components/settings/members-email-labs.hbs @@ -0,0 +1,237 @@ +
+
+
+
+
+

Enable newsletter sending

+

Newsletter features are active, posts can be sent by email

+
+
+ +
+
+
+
+
+ +{{#if this.emailNewsletterEnabled}} +
+
+

Newsletters

+ {{#if (not-eq this.archivedNewsletterCount 0)}} +
+
+ {{!-- + {{#if type.name}}{{type.name}}{{else}}Unknown type{{/if}} + --}} + Active + {{svg-jar "arrow-down-small" class="w2"}} +
+
+ {{/if}} +
+
+
+ {{#each this.newsletters.newsletters as |newsletter|}} + {{#if (eq newsletter.status "active")}} +
+ {{svg-jar "grab" class="grab-newsletter"}} +
+

+ {{newsletter.name}} +

+

+ {{newsletter.description}} +

+
+
+
+

{{newsletter.members.total}}

+

Subscribers

+
+
+

{{newsletter.posts.total}}

+

Posts sent

+
+
+
+ {{#if (eq this.activeNewsletterCount 1)}} + + {{else}} + + + + {{svg-jar "dotdotdot"}} + + + + +
  • + +
  • +
  • + +
  • +
    +
    + {{/if}} +
    +
    + {{/if}} + {{/each}} +
    +
    + +
    + +
    +

    General settings

    +
    +
    +
    +
    +

    Default newsletter recipients

    +

    When you publish new content, who do you usually want to send it to?

    +
    + +
    +
    + {{#liquid-if this.defaultRecipientsOpen}} + {{#if (gt this.activeNewsletterCount 1)}} +
    + +
    +
    +
    + +
    + +
    +
    + {{else}} +
    + +
    + {{/if}} + {{/liquid-if}} +
    +
    + + {{#unless this.config.mailgunIsConfigured}} +
    +
    +
    +

    Mailgun configuration

    +

    The Mailgun API is used for bulk email newsletter delivery. Why is this required?

    +
    + +
    +
    + {{#liquid-if this.membersEmailOpen}} +
    + +
    + + +
    + + {{region.flag}} {{region.name}} + +
    +
    + + + + +
    +

    Find your Mailgun region and domain + here +

    +
    + + + +

    Find your Mailgun API keys + here +

    +
    +
    + {{/liquid-if}} +
    +
    + {{/unless}} + +
    +
    +
    +

    Enable newsletter open-rate

    +

    Track how many members are reading your emails

    +
    +
    + +
    +
    +
    +
    +
    +{{/if}} \ No newline at end of file diff --git a/ghost/admin/app/components/settings/members-email-labs.js b/ghost/admin/app/components/settings/members-email-labs.js new file mode 100644 index 0000000000..004bb78596 --- /dev/null +++ b/ghost/admin/app/components/settings/members-email-labs.js @@ -0,0 +1,246 @@ +import Component from '@ember/component'; +import classic from 'ember-classic-decorator'; +import {action, computed} from '@ember/object'; +import {inject as service} from '@ember/service'; +import {task} from 'ember-concurrency'; + +const US = {flag: 'πŸ‡ΊπŸ‡Έ', name: 'US', baseUrl: 'https://api.mailgun.net/v3'}; +const EU = {flag: 'πŸ‡ͺπŸ‡Ί', name: 'EU', baseUrl: 'https://api.eu.mailgun.net/v3'}; + +@classic +export default class MembersEmailLabs extends Component { + @service config; + @service ghostPaths; + @service ajax; + @service settings; + @service newsletters; + + replyAddresses = null; + recipientsSelectValue = null; + showFromAddressConfirmation = false; + showEmailDesignSettings = false; + + @computed('settings.editorDefaultEmailRecipients') + get emailNewsletterEnabled() { + return this.get('settings.editorDefaultEmailRecipients') !== 'disabled'; + } + + @computed('recipientsSelectValue') + get emailPreviewVisible() { + return this.recipientsSelectValue !== 'none'; + } + + @computed('settings.membersReplyAddress') + get selectedReplyAddress() { + return this.replyAddresses.findBy('value', this.get('settings.membersReplyAddress')); + } + + @computed('fromAddress') + get disableUpdateFromAddressButton() { + const savedFromAddress = this.get('settings.membersFromAddress') || ''; + if (!savedFromAddress.includes('@') && this.config.emailDomain) { + return !this.fromAddress || (this.fromAddress === `${savedFromAddress}@${this.config.emailDomain}`); + } + return !this.fromAddress || (this.fromAddress === savedFromAddress); + } + + @computed('settings.mailgunBaseUrl') + get mailgunRegion() { + if (!this.settings.get('mailgunBaseUrl')) { + return US; + } + + return [US, EU].find((region) => { + return region.baseUrl === this.settings.get('mailgunBaseUrl'); + }); + } + + @computed('settings.{mailgunBaseUrl,mailgunApiKey,mailgunDomain}') + get mailgunSettings() { + return { + apiKey: this.get('settings.mailgunApiKey') || '', + domain: this.get('settings.mailgunDomain') || '', + baseUrl: this.get('settings.mailgunBaseUrl') || '' + }; + } + + @computed('newsletters.newsletters.@each.status') + get activeNewsletterCount() { + return this.newsletters.newsletters.filter(n => n.status === 'active').length; + } + + @computed('newsletters.newsletters.@each.status') + get archivedNewsletterCount() { + return this.newsletters.newsletters.filter(n => n.status === 'archived').length; + } + + init() { + super.init(...arguments); + this.set('mailgunRegions', [US, EU]); + this.set('replyAddresses', [ + { + label: 'Newsletter email address (' + this.fromAddress + ')', + value: 'newsletter' + }, + { + label: 'Support email address (' + this.supportAddress + ')', + value: 'support' + } + ]); + + // set recipientsSelectValue as a static property because within this + // component's lifecycle it's not always derived from the settings values. + // e.g. can be set to "segment" when the filter is empty which is not derivable + // from settings as it would equate to "none" + this.set('recipientsSelectValue', this._getDerivedRecipientsSelectValue()); + } + + @action + toggleFromAddressConfirmation() { + this.toggleProperty('showFromAddressConfirmation'); + } + + @action + closeEmailDesignSettings() { + this.set('showEmailDesignSettings', false); + } + + @action + setMailgunDomain(event) { + this.set('settings.mailgunDomain', event.target.value); + if (!this.get('settings.mailgunBaseUrl')) { + this.set('settings.mailgunBaseUrl', this.mailgunRegion.baseUrl); + } + } + + @action + setMailgunApiKey(event) { + this.set('settings.mailgunApiKey', event.target.value); + if (!this.get('settings.mailgunBaseUrl')) { + this.set('settings.mailgunBaseUrl', this.mailgunRegion.baseUrl); + } + } + + @action + setMailgunRegion(region) { + this.set('settings.mailgunBaseUrl', region.baseUrl); + } + + @action + setFromAddress(fromAddress) { + this.setEmailAddress('fromAddress', fromAddress); + } + + @action + toggleEmailTrackOpens(event) { + if (event) { + event.preventDefault(); + } + this.set('settings.emailTrackOpens', !this.settings.get('emailTrackOpens')); + } + + @action + toggleEmailNewsletterEnabled(event) { + if (event) { + event.preventDefault(); + } + + const newsletterEnabled = !this.emailNewsletterEnabled; + + if (newsletterEnabled) { + this.set('settings.editorDefaultEmailRecipients', 'visibility'); + } else { + this.set('settings.editorDefaultEmailRecipients', 'disabled'); + this.set('settings.editorDefaultEmailRecipientsFilter', null); + } + + this.set('recipientsSelectValue', this._getDerivedRecipientsSelectValue()); + } + + @action + setReplyAddress(event) { + const newReplyAddress = event.value; + + this.set('settings.membersReplyAddress', newReplyAddress); + } + + @action + setDefaultEmailRecipients(value) { + // Update the underlying setting properties to match the selected recipients option + + if (['visibility', 'disabled'].includes(value)) { + this.settings.set('editorDefaultEmailRecipients', value); + this.settings.set('editorDefaultEmailRecipientsFilter', null); + } else { + this.settings.set('editorDefaultEmailRecipients', 'filter'); + } + + if (value === 'all-members') { + this.settings.set('editorDefaultEmailRecipientsFilter', 'status:free,status:-free'); + } + + if (value === 'paid-only') { + this.settings.set('editorDefaultEmailRecipientsFilter', 'status:-free'); + } + + if (value === 'none') { + this.settings.set('editorDefaultEmailRecipientsFilter', null); + } + + // Update the value used to display the selected recipients option explicitly + // because it's local non-derived state + this.set('recipientsSelectValue', value); + } + + @action + setDefaultEmailRecipientsFilter(filter) { + this.settings.set('editorDefaultEmailRecipientsFilter', filter); + } + + @action + archiveNewsletter(id) { + this.newsletters.archive(id); + } + + @action + addNewsletter() { + this.newsletters.add(); + } + + @(task(function* () { + let url = this.get('ghostPaths.url').api('/settings/members/email'); + try { + const response = yield this.ajax.post(url, { + data: { + email: this.fromAddress, + type: 'fromAddressUpdate' + } + }); + this.toggleProperty('showFromAddressConfirmation'); + return response; + } catch (e) { + // Failed to send email, retry + return false; + } + }).drop()) + updateFromAddress; + + _getDerivedRecipientsSelectValue() { + const defaultEmailRecipients = this.settings.get('editorDefaultEmailRecipients'); + const defaultEmailRecipientsFilter = this.settings.get('editorDefaultEmailRecipientsFilter'); + + if (defaultEmailRecipients === 'filter') { + if (defaultEmailRecipientsFilter === 'status:free,status:-free') { + return 'all-members'; + } else if (defaultEmailRecipientsFilter === 'status:-free') { + return 'paid-only'; + } else if (defaultEmailRecipientsFilter === null) { + return 'none'; + } else { + return 'segment'; + } + } + + return defaultEmailRecipients; + } +} diff --git a/ghost/admin/app/components/settings/members-email.hbs b/ghost/admin/app/components/settings/members-email.hbs index dec69e0b05..e99946d5e4 100644 --- a/ghost/admin/app/components/settings/members-email.hbs +++ b/ghost/admin/app/components/settings/members-email.hbs @@ -1,224 +1,121 @@ -{{#if (feature "multipleNewsletters")}} -
    +
    +
    +
    +
    +
    +

    Enable newsletter sending

    +

    Newsletter features are active, posts can be sent by email

    +
    +
    + +
    +
    +
    +
    +
    + +{{#if this.emailNewsletterEnabled}} + +
    -

    Enable newsletter sending

    -

    Newsletter features are active, posts can be sent by email

    -
    -
    - +

    Email design

    +

    Customize the look and feel of your newsletters

    +
    - {{#if this.emailNewsletterEnabled}} -
    -
    -

    Newsletters

    - {{#if (not-eq this.archivedNewsletterCount 0)}} -
    -
    - {{!-- - {{#if type.name}}{{type.name}}{{else}}Unknown type{{/if}} - --}} - Active - {{svg-jar "arrow-down-small" class="w2"}} -
    -
    - {{/if}} -
    -
    -
    - {{#each this.newsletters.newsletters as |newsletter|}} - {{#if (eq newsletter.status "active")}} -
    - {{svg-jar "grab" class="grab-newsletter"}} -
    -

    - {{newsletter.name}} -

    -

    - {{newsletter.description}} -

    -
    -
    -
    -

    {{newsletter.members.total}}

    -

    Subscribers

    -
    -
    -

    {{newsletter.posts.total}}

    -

    Posts sent

    -
    -
    -
    - {{#if (eq this.activeNewsletterCount 1)}} - - {{else}} - - - - {{svg-jar "dotdotdot"}} - - - - -
  • - -
  • -
  • - -
  • -
    -
    - {{/if}} -
    -
    - {{/if}} - {{/each}} -
    -
    - -
    +
    -
    -

    General settings

    +
    +
    -
    +

    Default newsletter recipients

    When you publish new content, who do you usually want to send it to?

    - +
    + +
    +
    +
    +
    +
    +
    +

    Email addresses

    +

    Contact information used for newsletters and member login emails

    +
    +
    - {{#liquid-if this.defaultRecipientsOpen}} - {{#if (gt this.activeNewsletterCount 1)}} -
    - -
    -
    -
    - -
    - + + +
    + +
    -
    - {{else}} -
    - -
    - {{/if}} +

    The address your newsletter posts are sent from

    + + {{#if this.showFromAddressConfirmation}} +
    + {{svg-jar "check-circle" class="w4 h4 mr1 stroke-green-d1"}} Check your inbox and confirm before saving your settings +
    + {{/if}} +
    + + + + {{one-way-select this.selectedReplyAddress + id="reply-address" + name="reply-address" + options=(readonly this.replyAddresses) + optionValuePath="value" + optionLabelPath="label" + update=(action "setReplyAddress") + }} + {{svg-jar "arrow-down-small"}} + +
    +

    Where you receive responses to newsletters

    + {{#if (eq this.settings.membersReplyAddress "support")}} + Change support email address + {{/if}} +
    +
    {{/liquid-if}}
    - - {{#unless this.config.mailgunIsConfigured}} -
    -
    -
    -

    Mailgun configuration

    -

    The Mailgun API is used for bulk email newsletter delivery. Why is this required?

    -
    - -
    -
    - {{#liquid-if this.membersEmailOpen}} -
    - -
    - - -
    - - {{region.flag}} {{region.name}} - -
    -
    - - - - -
    -

    Find your Mailgun region and domain - here -

    -
    - - - -

    Find your Mailgun API keys - here -

    -
    -
    - {{/liquid-if}} -
    -
    - {{/unless}} - +
    +
    @@ -234,253 +131,116 @@
    -
    - {{/if}} -{{else}} -
    -
    -
    -
    -
    -

    Enable newsletter sending

    -

    Newsletter features are active, posts can be sent by email

    -
    -
    - -
    +
    +
    +

    Preview

    +
    +
    +
    Ready to {{#if this.emailPreviewVisible}} publish & send {{else}} publish {{/if}}{{svg-jar "arrow-down"}} this post?
    +
    +
    +
    +
    +
    +
    Set it live now
    +
    +
    +
    +
    +
    +
    Schedule it for later
    +
    +
    +
    + {{#if this.emailPreviewVisible}} +
    +
    +
    + +
    + +
    +
    +
    +
    + {{/if}} +
    - {{#if this.emailNewsletterEnabled}} - -
    + {{#unless this.config.mailgunIsConfigured}} +
    +
    +

    Advanced

    -

    Email design

    -

    Customize the look and feel of your newsletters

    +

    Mailgun configuration

    +

    The Mailgun API is used for bulk email newsletter delivery. Why is this required?

    - +
    -
    -
    -
    - -
    - -
    -
    -
    -
    -
    -
    -

    Default newsletter recipients

    -

    When you publish new content, who do you usually want to send it to?

    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Email addresses

    -

    Contact information used for newsletters and member login emails

    -
    - -
    -
    - {{#liquid-if this.membersFromOpen}} -
    - - -
    - - -
    -

    The address your newsletter posts are sent from

    -
    - {{#if this.showFromAddressConfirmation}} -
    - {{svg-jar "check-circle" class="w4 h4 mr1 stroke-green-d1"}} Check your inbox and confirm before saving your settings -
    - {{/if}} -
    - - - - {{one-way-select this.selectedReplyAddress - id="reply-address" - name="reply-address" - options=(readonly this.replyAddresses) - optionValuePath="value" - optionLabelPath="label" - update=(action "setReplyAddress") - }} - {{svg-jar "arrow-down-small"}} - -
    -

    Where you receive responses to newsletters

    - {{#if (eq this.settings.membersReplyAddress "support")}} - Change support email address - {{/if}} -
    -
    - {{/liquid-if}} -
    -
    -
    -
    -
    -
    -
    -

    Enable newsletter open-rate

    -

    Track how many members are reading your emails

    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Preview

    -
    -
    -
    Ready to {{#if this.emailPreviewVisible}} publish & send {{else}} publish {{/if}}{{svg-jar "arrow-down"}} this post?
    -
    -
    -
    -
    -
    -
    Set it live now
    -
    -
    -
    -
    -
    -
    Schedule it for later
    -
    -
    -
    - {{#if this.emailPreviewVisible}} -
    -
    -
    - -
    - +
    + {{#liquid-if this.membersEmailOpen}} +
    + +
    + + +
    + + {{region.flag}} {{region.name}} +
    -
    +
    + + + +
    -
    - {{/if}} -
    +

    Find your Mailgun region and domain + here +

    + + + + +

    Find your Mailgun API keys + here +

    +
    +
    + {{/liquid-if}}
    + {{/unless}} - {{#unless this.config.mailgunIsConfigured}} -
    -
    -

    Advanced

    -
    -
    -
    -
    -

    Mailgun configuration

    -

    The Mailgun API is used for bulk email newsletter delivery. Why is this required?

    -
    - -
    -
    - {{#liquid-if this.membersEmailOpen}} -
    - -
    - - -
    - - {{region.flag}} {{region.name}} - -
    -
    - - - - -
    -

    Find your Mailgun region and domain - here -

    -
    - - - -

    Find your Mailgun API keys - here -

    -
    -
    - {{/liquid-if}} -
    -
    -
    -
    - {{/unless}} - - {{/if}} {{/if}} \ No newline at end of file diff --git a/ghost/admin/app/components/settings/members-email.js b/ghost/admin/app/components/settings/members-email.js index beb2295ae1..29fdb147a4 100644 --- a/ghost/admin/app/components/settings/members-email.js +++ b/ghost/admin/app/components/settings/members-email.js @@ -13,7 +13,6 @@ export default class MembersEmail extends Component { @service ghostPaths; @service ajax; @service settings; - @service newsletters; replyAddresses = null; recipientsSelectValue = null; @@ -64,16 +63,6 @@ export default class MembersEmail extends Component { }; } - @computed('newsletters.newsletters.@each.status') - get activeNewsletterCount() { - return this.newsletters.newsletters.filter(n => n.status === 'active').length; - } - - @computed('newsletters.newsletters.@each.status') - get archivedNewsletterCount() { - return this.newsletters.newsletters.filter(n => n.status === 'archived').length; - } - init() { super.init(...arguments); this.set('mailgunRegions', [US, EU]); @@ -197,16 +186,6 @@ export default class MembersEmail extends Component { this.settings.set('editorDefaultEmailRecipientsFilter', filter); } - @action - archiveNewsletter(id) { - this.newsletters.archive(id); - } - - @action - addNewsletter() { - this.newsletters.add(); - } - @(task(function* () { let url = this.get('ghostPaths.url').api('/settings/members/email'); try { diff --git a/ghost/admin/app/controllers/settings/members-email-labs.js b/ghost/admin/app/controllers/settings/members-email-labs.js new file mode 100644 index 0000000000..2d9ca0d864 --- /dev/null +++ b/ghost/admin/app/controllers/settings/members-email-labs.js @@ -0,0 +1,74 @@ +import Controller from '@ember/controller'; +import {action} from '@ember/object'; +import {inject as service} from '@ember/service'; +import {task} from 'ember-concurrency'; +import {tracked} from '@glimmer/tracking'; + +export default class MembersEmailLabsController extends Controller { + @service config; + @service session; + @service settings; + + queryParams = ['showEmailDesignSettings']; + + // from/supportAddress are set here so that they can be reset to saved values on save + // to avoid it looking like they've been saved when they have a separate update process + @tracked fromAddress = ''; + @tracked supportAddress = ''; + + @tracked showEmailDesignSettings = false; + @tracked showLeaveSettingsModal = false; + + @action + setEmailAddress(property, email) { + this[property] = email; + } + + @action + toggleEmailDesignSettings() { + this.showEmailDesignSettings = !this.showEmailDesignSettings; + } + + leaveRoute(transition) { + if (this.settings.get('hasDirtyAttributes')) { + transition.abort(); + this.leaveSettingsTransition = transition; + this.showLeaveSettingsModal = true; + } + this.showEmailDesignSettings = false; + } + + @action + async confirmLeave() { + this.settings.rollbackAttributes(); + this.showLeaveSettingsModal = false; + this.leaveSettingsTransition.retry(); + } + + @action + cancelLeave() { + this.showLeaveSettingsModal = false; + this.leaveSettingsTransition = null; + } + + parseEmailAddress(address) { + const emailAddress = address || 'noreply'; + // Adds default domain as site domain + if (emailAddress.indexOf('@') < 0 && this.config.emailDomain) { + return `${emailAddress}@${this.config.emailDomain}`; + } + return emailAddress; + } + + resetEmailAddresses() { + this.fromAddress = this.parseEmailAddress(this.settings.get('membersFromAddress')); + this.supportAddress = this.parseEmailAddress(this.settings.get('membersSupportAddress')); + } + + @task({drop: true}) + *saveSettings() { + const response = yield this.settings.save(); + this.resetEmailAddresses(); + return response; + } +} diff --git a/ghost/admin/app/router.js b/ghost/admin/app/router.js index c6a2094772..02b35fbd95 100644 --- a/ghost/admin/app/router.js +++ b/ghost/admin/app/router.js @@ -43,6 +43,7 @@ Router.map(function () { this.route('settings.general', {path: '/settings/general'}); this.route('settings.membership', {path: '/settings/members'}); this.route('settings.members-email', {path: '/settings/members-email'}); + this.route('settings.members-email-labs', {path: '/settings/members-email-labs'}); this.route('settings.code-injection', {path: '/settings/code-injection'}); this.route('settings.design', {path: '/settings/design'}, function () { diff --git a/ghost/admin/app/routes/settings/members-email-labs.js b/ghost/admin/app/routes/settings/members-email-labs.js new file mode 100644 index 0000000000..1fe472ea14 --- /dev/null +++ b/ghost/admin/app/routes/settings/members-email-labs.js @@ -0,0 +1,43 @@ +import AdminRoute from 'ghost-admin/routes/admin'; +import {action} from '@ember/object'; +import {inject as service} from '@ember/service'; + +export default class MembersEmailLabsRoute extends AdminRoute { + @service feature; + @service notifications; + @service settings; + + beforeModel(transition) { + super.beforeModel(...arguments); + + if (!this.feature.multipleNewsletters) { + return this.transitionTo('settings.members-email'); + } + + if (transition.to.queryParams?.fromAddressUpdate === 'success') { + this.notifications.showAlert( + `Newsletter email address has been updated`, + {type: 'success', key: 'members.settings.from-address.updated'} + ); + } + } + + model() { + return this.settings.reload(); + } + + setupController(controller) { + controller.resetEmailAddresses(); + } + + @action + willTransition(transition) { + return this.controller.leaveRoute(transition); + } + + buildRouteInfoMetadata() { + return { + titleToken: 'Settings - Email newsletter' + }; + } +} diff --git a/ghost/admin/app/routes/settings/members-email.js b/ghost/admin/app/routes/settings/members-email.js index 577ca529ce..c9bffb0701 100644 --- a/ghost/admin/app/routes/settings/members-email.js +++ b/ghost/admin/app/routes/settings/members-email.js @@ -3,12 +3,17 @@ import {action} from '@ember/object'; import {inject as service} from '@ember/service'; export default class MembersEmailRoute extends AdminRoute { + @service feature; @service notifications; @service settings; beforeModel(transition) { super.beforeModel(...arguments); + if (this.feature.multipleNewsletters) { + return this.transitionTo('settings.members-email-labs'); + } + if (transition.to.queryParams?.fromAddressUpdate === 'success') { this.notifications.showAlert( `Newsletter email address has been updated`, @@ -32,7 +37,7 @@ export default class MembersEmailRoute extends AdminRoute { buildRouteInfoMetadata() { return { - titleToken: 'Settings - Members' + titleToken: 'Settings - Email newsletter' }; } } diff --git a/ghost/admin/app/templates/settings/members-email-labs.hbs b/ghost/admin/app/templates/settings/members-email-labs.hbs new file mode 100644 index 0000000000..e472b005f5 --- /dev/null +++ b/ghost/admin/app/templates/settings/members-email-labs.hbs @@ -0,0 +1,48 @@ +
    + +

    + Settings + {{svg-jar "arrow-right"}} + Email newsletter +

    +
    + +
    +
    + +
    +
    + +
    +
    + + {{#if this.showLeaveSettingsModal}} + + {{/if}} +
    + +{{#if this.showEmailDesignSettings}} + + + +{{/if}} \ No newline at end of file diff --git a/ghost/admin/tests/acceptance/settings/members-email-labs-test.js b/ghost/admin/tests/acceptance/settings/members-email-labs-test.js new file mode 100644 index 0000000000..e179d1e22d --- /dev/null +++ b/ghost/admin/tests/acceptance/settings/members-email-labs-test.js @@ -0,0 +1,48 @@ +import {authenticateSession} from 'ember-simple-auth/test-support'; +import {click, currentURL, find} from '@ember/test-helpers'; +import {disableLabsFlag, enableLabsFlag} from '../../helpers/labs-flag'; +import {expect} from 'chai'; +import {setupApplicationTest} from 'ember-mocha'; +import {setupMirage} from 'ember-cli-mirage/test-support'; +import {visit} from '../../helpers/visit'; + +describe('Acceptance: Settings - Members email (multipleNewsletters)', function () { + const hooks = setupApplicationTest(); + setupMirage(hooks); + + beforeEach(async function () { + this.server.loadFixtures('configs'); + + const role = this.server.create('role', {name: 'Owner'}); + this.server.create('user', {roles: [role]}); + + enableLabsFlag(this.server, 'multipleNewsletters'); + + return await authenticateSession(); + }); + + it('without flag - redirects labs to original', async function () { + disableLabsFlag(this.server, 'multipleNewsletters'); + await visit('/settings/members-email-labs'); + expect(currentURL()).to.equal('/settings/members-email'); + }); + + it('with flag - redirects original to labs', async function () { + await visit('/settings/members-email'); + expect(currentURL()).to.equal('/settings/members-email-labs'); + }); + + it('can manage open rate tracking', async function () { + this.server.db.settings.update({key: 'email_track_opens'}, {value: 'true'}); + + await visit('/settings/members-email-labs'); + expect(find('[data-test-checkbox="email-track-opens"]')).to.be.checked; + + await click('label[for="email-track-opens"]'); + expect(find('[data-test-checkbox="email-track-opens"]')).to.not.be.checked; + + await click('[data-test-button="save-members-settings"]'); + + expect(this.server.db.settings.findBy({key: 'email_track_opens'}).value).to.equal(false); + }); +}); diff --git a/ghost/admin/tests/acceptance/settings/members-email-test.js b/ghost/admin/tests/acceptance/settings/members-email-test.js index b896dcb215..9adf009050 100644 --- a/ghost/admin/tests/acceptance/settings/members-email-test.js +++ b/ghost/admin/tests/acceptance/settings/members-email-test.js @@ -1,5 +1,5 @@ import {authenticateSession} from 'ember-simple-auth/test-support'; -import {click, find} from '@ember/test-helpers'; +import {click, currentURL, find} from '@ember/test-helpers'; import {expect} from 'chai'; import {setupApplicationTest} from 'ember-mocha'; import {setupMirage} from 'ember-cli-mirage/test-support'; @@ -18,6 +18,11 @@ describe('Acceptance: Settings - Members email', function () { return await authenticateSession(); }); + it('loads non-labs route', async function () { + await visit('/settings/members-email'); + expect(currentURL()).to.equal('/settings/members-email'); + }); + it('can manage open rate tracking', async function () { this.server.db.settings.update({key: 'email_track_opens'}, {value: 'true'});