✨ Added new support and reply-to address for members
no issue - Adds 2 new email address fields for members in email settings section - support address and reply-to address - Support address - Is used for member auth emails as well as in themes and Portal for allowing members to contact support. - Reply-to address - Is used to set `reply-to` address for newsletter emails that allows configuring where member's reply to emails will go - Disabled from address update for empty value - Updated success toast message and copy for from/support address update - Changed section title + description for email addresses - Added "public" to support email description
This commit is contained in:
parent
4955b0d3f5
commit
301fdde0f7
|
@ -140,6 +140,20 @@
|
|||
{{/if}}
|
||||
</section>
|
||||
|
||||
{{#if this.config.enableDeveloperExperiments}}
|
||||
<section class="bb b--whitegrey pa5">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<h4 class="gh-setting-title">Portal settings</h4>
|
||||
<p class="gh-setting-desc pa0 ma0">Customize members modal signup flow</p>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="gh-btn" {{action (toggle "showMembersModalSettings" this)}} data-test-toggle-membersFrom><span> Customize </span></button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
<section class="bb b--whitegrey pa5">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
|
@ -270,8 +284,8 @@
|
|||
<section class="bb b--whitegrey pa5">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<h4 class="gh-setting-title">From address</h4>
|
||||
<p class="gh-setting-desc pa0 ma0">The email address your members receive newsletters from</p>
|
||||
<h4 class="gh-setting-title">Email addresses</h4>
|
||||
<p class="gh-setting-desc pa0 ma0">Contact information used for newsletters and member login emails</p>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="gh-btn" {{action (toggle "membersFromOpen" this)}} data-test-toggle-membersFrom><span>{{if this.membersFromOpen "Close" "Expand"}}</span></button>
|
||||
|
@ -279,46 +293,91 @@
|
|||
</div>
|
||||
|
||||
{{#liquid-if this.membersFromOpen}}
|
||||
<div class="flex flex-column w-100 w-50-l flex mt8">
|
||||
<div class="mt8">
|
||||
<GhFormGroup>
|
||||
<label class="fw6 f8">Support email address</label>
|
||||
<div class="flex items-center justify-center mt1">
|
||||
<GhTextInput
|
||||
@value={{readonly this.supportAddress}}
|
||||
@input={{action "setSupportAddress" value="target.value"}}
|
||||
@class="gh-labs-members-emailinput"
|
||||
/>
|
||||
<GhTaskButton
|
||||
@buttonText="Update support address"
|
||||
@runningText="Sending..."
|
||||
@successText="Confirmation Email Sent"
|
||||
@disabled={{this.disableUpdateSupportAddressButton}}
|
||||
@task={{this.updateSupportAddress}}
|
||||
@class="gh-btn gh-btn-icon gh-btn-textfield-group gh-labs-members-emaildropdown"
|
||||
data-test-button="update-support-address"
|
||||
/>
|
||||
</div>
|
||||
</GhFormGroup>
|
||||
<div class="nt5 mb5">
|
||||
<span class="mt1 fw4 f8 midgrey">
|
||||
How members can reach you for help with their account (public)
|
||||
</span>
|
||||
</div>
|
||||
{{#if this.showSupportAddressConfirmation}}
|
||||
<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>
|
||||
<div class="mt8">
|
||||
<GhFormGroup>
|
||||
<label class="fw6 f8">Newsletter email address</label>
|
||||
<div class="flex items-center justify-center mt1">
|
||||
<GhTextInput
|
||||
@value={{readonly this.fromAddress}}
|
||||
@input={{action "setFromAddress" value="target.value"}}
|
||||
@class="w20"
|
||||
@class="gh-labs-members-emailinput"
|
||||
/>
|
||||
<GhTaskButton
|
||||
@buttonText="Update from address"
|
||||
@buttonText="Update newsletter address"
|
||||
@runningText="Sending..."
|
||||
@successText="Confirmation Email Sent"
|
||||
@disabled={{this.disableUpdateFromAddressButton}}
|
||||
@task={{this.updateFromAddress}}
|
||||
@class="gh-btn gh-btn-icon gh-btn-textfield-group ml2"
|
||||
@class="gh-btn gh-btn-icon gh-btn-textfield-group gh-labs-members-emaildropdown"
|
||||
data-test-button="update-from-address"
|
||||
/>
|
||||
</div>
|
||||
</GhFormGroup>
|
||||
<div class="nt5 mb5">
|
||||
<span class="mt1 fw4 f8 midgrey">
|
||||
The address your newsletter posts are sent from
|
||||
</span>
|
||||
</div>
|
||||
{{#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>
|
||||
{{#if this.config.enableDeveloperExperiments}}
|
||||
<section class="bb b--whitegrey pa5">
|
||||
<div class="flex justify-between">
|
||||
<div>
|
||||
<h4 class="gh-setting-title">Portal settings</h4>
|
||||
<p class="gh-setting-desc pa0 ma0">Customize members modal signup flow</p>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" class="gh-btn" {{action (toggle "showMembersModalSettings" this)}} data-test-toggle-membersFrom><span> Customize </span></button>
|
||||
<div class="mt8">
|
||||
<GhFormGroup @class="for-select gh-labs-members-defaultemaildd">
|
||||
<label class="fw6 f8" for="reply-address">Newsletter replies go to</label>
|
||||
<span class="gh-select mt1">
|
||||
{{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"}}
|
||||
</span>
|
||||
</GhFormGroup>
|
||||
<div class="nt5 mb5">
|
||||
<span class="mt1 fw4 f8 midgrey">
|
||||
Where you receive responses to newsletters
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{/if}}
|
||||
{{/liquid-if}}
|
||||
</section>
|
||||
{{#unless this.mailgunIsConfigured}}
|
||||
<section class="bb b--whitegrey pa5">
|
||||
<div class="flex justify-between">
|
||||
|
|
|
@ -28,6 +28,17 @@ const CURRENCIES = [
|
|||
}
|
||||
];
|
||||
|
||||
const REPLY_ADDRESSES = [
|
||||
{
|
||||
label: 'Newsletter email address',
|
||||
value: 'newsletter'
|
||||
},
|
||||
{
|
||||
label: 'Support email address',
|
||||
value: 'support'
|
||||
}
|
||||
];
|
||||
|
||||
export default Component.extend({
|
||||
feature: service(),
|
||||
config: service(),
|
||||
|
@ -37,7 +48,9 @@ export default Component.extend({
|
|||
settings: service(),
|
||||
|
||||
currencies: null,
|
||||
replyAddresses: null,
|
||||
showFromAddressConfirmation: false,
|
||||
showSupportAddressConfirmation: false,
|
||||
showMembersModalSettings: false,
|
||||
stripePlanInvalidAmount: false,
|
||||
_scratchStripeYearlyAmount: null,
|
||||
|
@ -63,6 +76,10 @@ export default Component.extend({
|
|||
stripeConnectAccountName: reads('settings.stripeConnectDisplayName'),
|
||||
stripeConnectLivemode: reads('settings.stripeConnectLivemode'),
|
||||
|
||||
selectedReplyAddress: computed('settings.membersReplyAddress', function () {
|
||||
return REPLY_ADDRESSES.findBy('value', this.get('settings.membersReplyAddress'));
|
||||
}),
|
||||
|
||||
selectedCurrency: computed('stripePlans.monthly.currency', function () {
|
||||
return CURRENCIES.findBy('value', this.get('stripePlans.monthly.currency'));
|
||||
}),
|
||||
|
@ -70,9 +87,17 @@ export default Component.extend({
|
|||
disableUpdateFromAddressButton: computed('fromAddress', function () {
|
||||
const savedFromAddress = this.get('settings.membersFromAddress') || '';
|
||||
if (!savedFromAddress.includes('@') && this.blogDomain) {
|
||||
return (this.fromAddress === `${savedFromAddress}@${this.blogDomain}`);
|
||||
return !this.fromAddress || (this.fromAddress === `${savedFromAddress}@${this.blogDomain}`);
|
||||
}
|
||||
return (this.fromAddress === savedFromAddress);
|
||||
return !this.fromAddress || (this.fromAddress === savedFromAddress);
|
||||
}),
|
||||
|
||||
disableUpdateSupportAddressButton: computed('supportAddress', function () {
|
||||
const savedSupportAddress = this.get('settings.membersSupportAddress') || '';
|
||||
if (!savedSupportAddress.includes('@') && this.blogDomain) {
|
||||
return !this.supportAddress || (this.supportAddress === `${savedSupportAddress}@${this.blogDomain}`);
|
||||
}
|
||||
return !this.supportAddress || (this.supportAddress === savedSupportAddress);
|
||||
}),
|
||||
|
||||
blogDomain: computed('config.blogDomain', function () {
|
||||
|
@ -120,6 +145,7 @@ export default Component.extend({
|
|||
this._super(...arguments);
|
||||
this.set('mailgunRegions', [US, EU]);
|
||||
this.set('currencies', CURRENCIES);
|
||||
this.set('replyAddresses', REPLY_ADDRESSES);
|
||||
},
|
||||
|
||||
actions: {
|
||||
|
@ -159,7 +185,11 @@ export default Component.extend({
|
|||
},
|
||||
|
||||
setFromAddress(fromAddress) {
|
||||
this.setFromAddress(fromAddress);
|
||||
this.setEmailAddress('fromAddress', fromAddress);
|
||||
},
|
||||
|
||||
setSupportAddress(supportAddress) {
|
||||
this.setEmailAddress('supportAddress', supportAddress);
|
||||
},
|
||||
|
||||
toggleSelfSignup() {
|
||||
|
@ -245,6 +275,12 @@ export default Component.extend({
|
|||
this.set('settings.stripePlans', updatedPlans);
|
||||
},
|
||||
|
||||
setReplyAddress(event) {
|
||||
const newReplyAddress = event.value;
|
||||
|
||||
this.set('settings.membersReplyAddress', newReplyAddress);
|
||||
},
|
||||
|
||||
setStripeConnectIntegrationToken(event) {
|
||||
this.set('settings.stripeProductName', this.get('settings.title'));
|
||||
this.setStripeConnectIntegrationTokenSetting(event.target.value);
|
||||
|
@ -322,7 +358,8 @@ export default Component.extend({
|
|||
try {
|
||||
const response = yield this.ajax.post(url, {
|
||||
data: {
|
||||
from_address: this.fromAddress
|
||||
email: this.fromAddress,
|
||||
type: 'fromAddressUpdate'
|
||||
}
|
||||
});
|
||||
this.toggleProperty('showFromAddressConfirmation');
|
||||
|
@ -333,6 +370,23 @@ export default Component.extend({
|
|||
}
|
||||
}).drop(),
|
||||
|
||||
updateSupportAddress: task(function* () {
|
||||
let url = this.get('ghostPaths.url').api('/settings/members/email');
|
||||
try {
|
||||
const response = yield this.ajax.post(url, {
|
||||
data: {
|
||||
email: this.supportAddress,
|
||||
type: 'supportAddressUpdate'
|
||||
}
|
||||
});
|
||||
this.toggleProperty('showSupportAddressConfirmation');
|
||||
return response;
|
||||
} catch (e) {
|
||||
// Failed to send email, retry
|
||||
return false;
|
||||
}
|
||||
}).drop(),
|
||||
|
||||
get liveStripeConnectAuthUrl() {
|
||||
return this.ghostPaths.url.api('members/stripe_connect') + '?mode=live';
|
||||
},
|
||||
|
|
|
@ -43,8 +43,9 @@ export default Controller.extend({
|
|||
session: service(),
|
||||
settings: service(),
|
||||
|
||||
queryParams: ['fromAddressUpdate'],
|
||||
queryParams: ['fromAddressUpdate', 'supportAddressUpdate'],
|
||||
fromAddressUpdate: null,
|
||||
supportAddressUpdate: null,
|
||||
importErrors: null,
|
||||
importSuccessful: false,
|
||||
showDeleteAllModal: false,
|
||||
|
@ -72,7 +73,11 @@ export default Controller.extend({
|
|||
},
|
||||
|
||||
fromAddress: computed(function () {
|
||||
return this.parseFromAddress();
|
||||
return this.parseEmailAddress(this.settings.get('membersFromAddress'));
|
||||
}),
|
||||
|
||||
supportAddress: computed(function () {
|
||||
return this.parseEmailAddress(this.settings.get('membersSupportAddress'));
|
||||
}),
|
||||
|
||||
blogDomain: computed('config.blogDomain', function () {
|
||||
|
@ -184,8 +189,8 @@ export default Controller.extend({
|
|||
this.set('settings.stripeConnectIntegrationToken', stripeConnectIntegrationToken);
|
||||
},
|
||||
|
||||
setFromAddress(fromAddress) {
|
||||
this.set('fromAddress', fromAddress);
|
||||
setEmailAddress(type, emailAddress) {
|
||||
this.set(type, emailAddress);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -230,19 +235,20 @@ export default Controller.extend({
|
|||
return RSVP.resolve();
|
||||
},
|
||||
|
||||
parseFromAddress() {
|
||||
const fromAddress = this.settings.get('membersFromAddress') || 'noreply';
|
||||
parseEmailAddress(address) {
|
||||
const emailAddress = address || 'noreply';
|
||||
// Adds default domain as site domain
|
||||
if (fromAddress.indexOf('@') < 0 && this.blogDomain) {
|
||||
return `${fromAddress}@${this.blogDomain}`;
|
||||
if (emailAddress.indexOf('@') < 0 && this.blogDomain) {
|
||||
return `${emailAddress}@${this.blogDomain}`;
|
||||
}
|
||||
return fromAddress;
|
||||
return emailAddress;
|
||||
},
|
||||
|
||||
saveSettings: task(function* () {
|
||||
const response = yield this.settings.save();
|
||||
// Reset from address value on save
|
||||
this.set('fromAddress', this.parseFromAddress());
|
||||
this.set('fromAddress', this.parseEmailAddress(this.settings.get('membersFromAddress')));
|
||||
this.set('supportAddress', this.parseEmailAddress(this.settings.get('membersSupportAddress')));
|
||||
return response;
|
||||
}).drop(),
|
||||
|
||||
|
@ -272,6 +278,7 @@ export default Controller.extend({
|
|||
this.set('importErrors', null);
|
||||
this.set('importSuccessful', false);
|
||||
this.set('fromAddressUpdate', null);
|
||||
this.set('supportAddressUpdate', null);
|
||||
// stripeConnectIntegrationToken is not a persisted value so we don't want
|
||||
// to keep it around across transitions
|
||||
this.settings.set('stripeConnectIntegrationToken', undefined);
|
||||
|
|
|
@ -55,6 +55,8 @@ export default Model.extend(ValidationEngine, {
|
|||
defaultContentVisibility: attr('string'),
|
||||
membersAllowFreeSignup: attr('boolean'),
|
||||
membersFromAddress: attr('string'),
|
||||
membersSupportAddress: attr('string'),
|
||||
membersReplyAddress: attr('string'),
|
||||
stripeProductName: attr('string'),
|
||||
stripeSecretKey: attr('string'),
|
||||
stripePublishableKey: attr('string'),
|
||||
|
|
|
@ -8,6 +8,9 @@ export default AuthenticatedRoute.extend(CurrentUserSettings, {
|
|||
queryParams: {
|
||||
fromAddressUpdate: {
|
||||
replace: true
|
||||
},
|
||||
supportAddressUpdate: {
|
||||
replace: true
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -25,9 +28,14 @@ export default AuthenticatedRoute.extend(CurrentUserSettings, {
|
|||
setupController(controller) {
|
||||
if (controller.fromAddressUpdate === 'success') {
|
||||
this.notifications.showAlert(
|
||||
`Done! Newsletter “From address” has been updated`.htmlSafe(),
|
||||
`Newsletter email address has been updated`.htmlSafe(),
|
||||
{type: 'success', key: 'members.settings.from-address.updated'}
|
||||
);
|
||||
} else if (controller.supportAddressUpdate === 'success') {
|
||||
this.notifications.showAlert(
|
||||
`Support email address has been updated`.htmlSafe(),
|
||||
{type: 'success', key: 'members.settings.support-address.updated'}
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -47,7 +47,8 @@
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
/* Members */
|
||||
/* Members settings */
|
||||
/* ------------------------------------------------ */
|
||||
|
||||
.gh-labs-members-radio {
|
||||
cursor: pointer;
|
||||
|
@ -171,6 +172,19 @@
|
|||
}
|
||||
}
|
||||
|
||||
.gh-labs-members-emailinput {
|
||||
|
||||
}
|
||||
|
||||
.gh-labs-members-emaildropdown {
|
||||
min-width: 192px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.gh-labs-members-defaultemaildd {
|
||||
padding-right: 200px;
|
||||
}
|
||||
|
||||
.gh-labs-mailgun-region {
|
||||
width: 140px !important;
|
||||
margin-right: 12px;
|
||||
|
|
|
@ -28,9 +28,10 @@
|
|||
<GhMembersLabSetting
|
||||
@settings={{this.settings}}
|
||||
@fromAddress={{this.fromAddress}}
|
||||
@supportAddress={{this.supportAddress}}
|
||||
@setDefaultContentVisibility={{action "setDefaultContentVisibility"}}
|
||||
@setStripeConnectIntegrationTokenSetting={{action "setStripeConnectIntegrationTokenSetting"}}
|
||||
@setFromAddress={{action "setFromAddress"}}
|
||||
@setEmailAddress={{action "setEmailAddress"}}
|
||||
/>
|
||||
<div class="mt5 pl5 pr5 pb5">
|
||||
<GhTaskButton @buttonText="Save members settings"
|
||||
|
|
Loading…
Reference in New Issue