mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
✨ Allowed domain change for members "from" address (#1597)
refs TryGhost/Ghost#11414 - Restructures member settings in labs, from address gets its own section - Removes explicit site domain for fromAddress as we allow updating the full address - Adds new CTA to trigger magic link for updating members from address - Adds new confirmation modal for email sent to new from address - Adds notification banner for from address update redirect link
This commit is contained in:
parent
3ed7434b73
commit
01e72dc991
11 changed files with 173 additions and 66 deletions
|
@ -2,5 +2,5 @@
|
|||
{{message.message}}
|
||||
</div>
|
||||
<button class="gh-alert-close" {{action "closeNotification"}} data-test-button="close-notification">
|
||||
{{svg-jar "close"}}<span class="hidden">Close</span>
|
||||
{{svg-jar "close-stroke"}}<span class="hidden">Close</span>
|
||||
</button>
|
||||
|
|
|
@ -219,30 +219,57 @@
|
|||
<section class="bb b--whitegrey pa5">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<h4 class="gh-setting-title">Email settings</h4>
|
||||
<p class="gh-setting-desc pa0 ma0">Customise signup, signin and subscription emails</p>
|
||||
<h4 class="gh-setting-title">From address</h4>
|
||||
<p class="gh-setting-desc pa0 ma0">The email address your members receive newsletters from</p>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="gh-btn" {{action (toggle "membersEmailOpen" this)}} data-test-toggle-membersemail><span>{{if this.membersEmailOpen "Close" "Expand"}}</span></button>
|
||||
<button type="button" class="gh-btn" {{action (toggle "membersFromOpen" this)}} data-test-toggle-membersFrom><span>{{if this.membersFromOpen "Close" "Expand"}}</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#liquid-if this.membersEmailOpen}}
|
||||
{{#liquid-if this.membersFromOpen}}
|
||||
<div class="flex flex-column w-100 w-50-l flex mt8">
|
||||
<GhFormGroup>
|
||||
<label class="fw6 f8">From Address</label>
|
||||
<div class="flex items-center justify-center mt1 gh-input-group">
|
||||
<div class="flex items-center justify-center mt1">
|
||||
<GhTextInput
|
||||
@value={{readonly this.subscriptionSettings.fromAddress}}
|
||||
@input={{action "setSubscriptionSettings" "fromAddress"}}
|
||||
@class="w20"
|
||||
/>
|
||||
<span class="gh-input-append"> @{{this.blogDomain}}</span>
|
||||
<GhTaskButton
|
||||
@buttonText="Update from address"
|
||||
@runningText="Sending..."
|
||||
@successText="Confirmation Email Sent"
|
||||
@task={{this.updateFromAddress}}
|
||||
@class="gh-btn gh-btn-icon gh-btn-textfield-group ml2"
|
||||
data-test-button="update-from-address"
|
||||
/>
|
||||
</div>
|
||||
<div class="f8 fw4 midgrey mt1">Your members will receive system emails from this address</div>
|
||||
</GhFormGroup>
|
||||
|
||||
{{#if this.showFromAddressConfirmation}}
|
||||
<div class="flex items-center green-d1 nt3 lh-1">
|
||||
{{svg-jar "check-circle" class="w4 h4 mr1 stroke-green-d1"}} <span class="nudge-left--2">Check your inbox and click the link to confirm</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/liquid-if}}
|
||||
</section>
|
||||
{{#unless this.hasBulkEmailConfig}}
|
||||
<section class="bb b--whitegrey pa5">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<h4 class="gh-setting-title">Mailgun settings</h4>
|
||||
<p class="gh-setting-desc pa0 ma0">Customise signup, signin and subscription emails</p>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="gh-btn" {{action (toggle "membersEmailOpen" this)}} data-test-toggle-membersemail>
|
||||
<span>{{if this.membersEmailOpen "Close" "Expand"}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#liquid-if this.membersEmailOpen}}
|
||||
<div class="flex flex-column w-100 w-50-l flex mt8">
|
||||
<div class="flex items-center">
|
||||
<GhFormGroup @class="gh-labs-mailgun-region">
|
||||
<label class="fw6 f8">Mailgun region</label>
|
||||
|
@ -285,8 +312,8 @@
|
|||
Find your Mailgun API keys here »
|
||||
</a>
|
||||
</GhFormGroup>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/liquid-if}}
|
||||
</section>
|
||||
{{/unless}}
|
||||
</div>
|
|
@ -3,6 +3,7 @@ import {computed} from '@ember/object';
|
|||
import {reads} from '@ember/object/computed';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {set} from '@ember/object';
|
||||
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'};
|
||||
|
@ -30,8 +31,10 @@ export default Component.extend({
|
|||
config: service(),
|
||||
mediaQueries: service(),
|
||||
ghostPaths: service(),
|
||||
ajax: service(),
|
||||
|
||||
currencies: null,
|
||||
showFromAddressConfirmation: false,
|
||||
|
||||
// passed in actions
|
||||
setMembersSubscriptionSettings() {},
|
||||
|
@ -45,6 +48,10 @@ export default Component.extend({
|
|||
return CURRENCIES.findBy('value', this.get('subscriptionSettings.stripeConfig.plans.monthly.currency'));
|
||||
}),
|
||||
|
||||
disableUpdateFromAddressButton: computed('subscriptionSettings.fromAddress', function () {
|
||||
return (this.originalFromAddress === this.get('subscriptionSettings.fromAddress'));
|
||||
}),
|
||||
|
||||
mailgunRegion: computed('settings.bulkEmailSettings.baseUrl', function () {
|
||||
if (!this.settings.get('bulkEmailSettings.baseUrl')) {
|
||||
return US;
|
||||
|
@ -103,6 +110,10 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
actions: {
|
||||
toggleFromAddressConfirmation() {
|
||||
this.toggleProperty('showFromAddressConfirmation');
|
||||
},
|
||||
|
||||
setDefaultContentVisibility(value) {
|
||||
this.setDefaultContentVisibility(value);
|
||||
},
|
||||
|
@ -183,6 +194,22 @@ export default Component.extend({
|
|||
}
|
||||
},
|
||||
|
||||
updateFromAddress: task(function* () {
|
||||
let url = this.get('ghostPaths.url').api('/settings/members/email');
|
||||
try {
|
||||
const response = yield this.ajax.post(url, {
|
||||
data: {
|
||||
from_address: this.subscriptionSettings.fromAddress
|
||||
}
|
||||
});
|
||||
this.toggleProperty('showFromAddressConfirmation');
|
||||
return response;
|
||||
} catch (e) {
|
||||
// Failed to send email, retry
|
||||
return false;
|
||||
}
|
||||
}).drop(),
|
||||
|
||||
get stripeConnectAuthUrl() {
|
||||
return this.ghostPaths.url.api('members/stripe_connect');
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<header class="modal-header">
|
||||
<h1>Check your Inbox</h1>
|
||||
</header>
|
||||
<a class="close" href="" role="button" title="Close" {{action "closeModal"}}>{{svg-jar "close"}}<span class="hidden">Close</span></a>
|
||||
|
||||
<div class="modal-body">
|
||||
We have sent an email to confirm you own <b>{{this.fromAddress}}</b>.
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button {{action "closeModal"}} class="gh-btn"><span>Close</span></button>
|
||||
</div>
|
|
@ -0,0 +1,8 @@
|
|||
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||
import {alias} from '@ember/object/computed';
|
||||
|
||||
export default ModalComponent.extend({
|
||||
|
||||
confirm() {},
|
||||
fromAddress: alias('model.fromAddress')
|
||||
});
|
|
@ -42,6 +42,8 @@ export default Controller.extend({
|
|||
session: service(),
|
||||
settings: service(),
|
||||
|
||||
queryParams: ['fromAddressUpdate'],
|
||||
fromAddressUpdate: null,
|
||||
importErrors: null,
|
||||
importSuccessful: false,
|
||||
showDeleteAllModal: false,
|
||||
|
@ -250,5 +252,6 @@ export default Controller.extend({
|
|||
reset() {
|
||||
this.set('importErrors', null);
|
||||
this.set('importSuccessful', false);
|
||||
this.set('fromAddressUpdate', null);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -4,6 +4,12 @@ import {inject as service} from '@ember/service';
|
|||
|
||||
export default AuthenticatedRoute.extend(CurrentUserSettings, {
|
||||
settings: service(),
|
||||
notifications: service(),
|
||||
queryParams: {
|
||||
fromAddressUpdate: {
|
||||
replace: true
|
||||
}
|
||||
},
|
||||
|
||||
beforeModel() {
|
||||
this._super(...arguments);
|
||||
|
@ -16,6 +22,15 @@ export default AuthenticatedRoute.extend(CurrentUserSettings, {
|
|||
return this.settings.reload();
|
||||
},
|
||||
|
||||
setupController(controller) {
|
||||
if (controller.fromAddressUpdate === 'success') {
|
||||
this.notifications.showAlert(
|
||||
`Done! Newsletter “From address” has been updated`.htmlSafe(),
|
||||
{type: 'success', key: 'members.settings.from-address.updated'}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
resetController(controller, isExiting) {
|
||||
if (isExiting) {
|
||||
controller.reset();
|
||||
|
|
|
@ -203,7 +203,7 @@
|
|||
.gh-alert-content {
|
||||
font-size: 1.4rem;
|
||||
line-height: 1.3em;
|
||||
font-weight: 300;
|
||||
font-weight: 400;
|
||||
user-select: text;
|
||||
}
|
||||
|
||||
|
@ -216,14 +216,14 @@
|
|||
.gh-alert-close {
|
||||
flex-shrink: 0;
|
||||
margin-left: 20px;
|
||||
padding: 5px;
|
||||
padding: 4px;
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
}
|
||||
|
||||
.gh-alert-close svg {
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
height: 12px;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.gh-alert-close:hover {
|
||||
|
|
|
@ -320,6 +320,10 @@ fieldset[disabled] .gh-btn {
|
|||
fill: color-mod(var(--midgrey) l(+15%));
|
||||
}
|
||||
|
||||
.gh-btn:not(.gh-btn-blue):not(.gh-btn-green) svg.gh-icon-spinner rect {
|
||||
fill: color-mod(var(--midgrey) l(-7%));
|
||||
}
|
||||
|
||||
.gh-btn-icon-right svg,
|
||||
svg.gh-btn-icon-right {
|
||||
margin-left: 0.5em;
|
||||
|
@ -374,6 +378,11 @@ svg.gh-btn-icon-right {
|
|||
box-shadow: none;
|
||||
}
|
||||
|
||||
.gh-btn-textfield-group span {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/* Button Variations
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
:root {
|
||||
--lh-1-0: 1.0em;
|
||||
--lh-1-1: 1.1em;
|
||||
--lh-1-3: 1.333em;
|
||||
--lh-1-4: 1.4em;
|
||||
|
@ -15,6 +16,7 @@
|
|||
--lh-2-0: 2.0em;
|
||||
}
|
||||
|
||||
.lh-1 { line-height: var(--lh-1-0); }
|
||||
.lh-solid { line-height: var(--lh-1-1); }
|
||||
.lh-heading { line-height: var(--lh-1-3); }
|
||||
.lh-title { line-height: var(--lh-1-4); }
|
||||
|
@ -24,6 +26,7 @@
|
|||
.lh-zero { line-height: 0; }
|
||||
|
||||
@media (--breakpoint-not-small) {
|
||||
.lh-1-ns { line-height: var(--lh-1-0); }
|
||||
.lh-solid-ns { line-height: var(--lh-1-1); }
|
||||
.lh-heading-ns { line-height: var(--lh-1-3); }
|
||||
.lh-title-ns { line-height: var(--lh-1-4); }
|
||||
|
@ -34,6 +37,7 @@
|
|||
}
|
||||
|
||||
@media (--breakpoint-medium) {
|
||||
.lh-1-m { line-height: var(--lh-1-0); }
|
||||
.lh-solid-m { line-height: var(--lh-1-1); }
|
||||
.lh-heading-m { line-height: var(--lh-1-3); }
|
||||
.lh-title-m { line-height: var(--lh-1-4); }
|
||||
|
@ -44,6 +48,7 @@
|
|||
}
|
||||
|
||||
@media (--breakpoint-large) {
|
||||
.lh-1-l { line-height: var(--lh-1-0); }
|
||||
.lh-solid-l { line-height: var(--lh-1-1); }
|
||||
.lh-heading-l { line-height: var(--lh-1-3); }
|
||||
.lh-title-l { line-height: var(--lh-1-4); }
|
||||
|
|
1
ghost/admin/public/assets/icons/close-stroke.svg
Normal file
1
ghost/admin/public/assets/icons/close-stroke.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style>.a{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px;}</style></defs><title>close</title><line class="a" x1="0.75" y1="23.249" x2="23.25" y2="0.749"/><line class="a" x1="23.25" y1="23.249" x2="0.75" y2="0.749"/></svg>
|
After Width: | Height: | Size: 332 B |
Loading…
Add table
Reference in a new issue