mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-24 19:33:02 +03:00
Add member's email status on member page (#15844)
closes TryGhost/Team#2270 - Show emails status depending on the reason email was blocked (spam/fail)
This commit is contained in:
parent
ab8f16ce79
commit
696cdea4d9
@ -64,35 +64,33 @@
|
||||
<p> Maximum: <b>500</b> characters. You’ve used
|
||||
{{gh-count-down-characters this.scratchMember.note 500}}</p>
|
||||
</GhFormGroup>
|
||||
{{#if this.hasSingleNewsletter}}
|
||||
{{#if (not-eq this.settings.editorDefaultEmailRecipients "disabled")}}
|
||||
<GhFormGroup @classNames="gh-members-subscribed-checkbox mb0">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<h4 class="gh-setting-title m">Subscribed to newsletter</h4>
|
||||
<p class="gh-setting-desc">If disabled, member will <em>not</em> receive newsletter emails</p>
|
||||
</div>
|
||||
<div class="for-switch">
|
||||
<label class="switch" for="subscribed-checkbox">
|
||||
<Input
|
||||
@checked={{this.member.subscribed}}
|
||||
@type="checkbox"
|
||||
id="subscribed-checkbox"
|
||||
name="subscribed"
|
||||
{{on "click" this.updateNewsletterPreference}}
|
||||
data-test-checkbox="member-subscribed"
|
||||
/>
|
||||
<span class="input-toggle-component"></span>
|
||||
</label>
|
||||
</div>
|
||||
{{#if this.canShowSingleNewsletter}}
|
||||
<GhFormGroup @classNames="gh-members-subscribed-checkbox mb0">
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<h4 class="gh-setting-title m">Subscribed to newsletter</h4>
|
||||
<p class="gh-setting-desc">If disabled, member will <em>not</em> receive newsletter emails</p>
|
||||
</div>
|
||||
</GhFormGroup>
|
||||
{{/if}}
|
||||
<div class="for-switch">
|
||||
<label class="switch" for="subscribed-checkbox">
|
||||
<Input
|
||||
@checked={{this.member.subscribed}}
|
||||
@type="checkbox"
|
||||
id="subscribed-checkbox"
|
||||
name="subscribed"
|
||||
{{on "click" this.updateNewsletterPreference}}
|
||||
data-test-checkbox="member-subscribed"
|
||||
/>
|
||||
<span class="input-toggle-component"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</GhFormGroup>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if this.hasMultipleNewsletters}}
|
||||
{{#if this.canShowMultipleNewsletters}}
|
||||
<Member::NewsletterPreference
|
||||
@member={{this.member}}
|
||||
@newsletters={{this.newslettersList}}
|
||||
|
@ -45,14 +45,6 @@ export default class extends Component {
|
||||
return hasAnActivePaidTier;
|
||||
}
|
||||
|
||||
get hasSingleNewsletter() {
|
||||
return this.newslettersList?.length === 1;
|
||||
}
|
||||
|
||||
get hasMultipleNewsletters() {
|
||||
return !!(this.newslettersList?.length > 1);
|
||||
}
|
||||
|
||||
get isCreatingComplimentary() {
|
||||
return this.args.isSaveRunning;
|
||||
}
|
||||
@ -124,6 +116,21 @@ export default class extends Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
get canShowSingleNewsletter() {
|
||||
return (
|
||||
this.newslettersList?.length === 1
|
||||
&& this.settings.editorDefaultEmailRecipients !== 'disabled'
|
||||
&& !this.feature.get('suppressionList')
|
||||
);
|
||||
}
|
||||
|
||||
get canShowMultipleNewsletters() {
|
||||
return (
|
||||
(this.newslettersList?.length > 1 || this.feature.get('suppressionList'))
|
||||
&& this.settings.editorDefaultEmailRecipients !== 'disabled'
|
||||
);
|
||||
}
|
||||
|
||||
@action
|
||||
updateNewsletterPreference(event) {
|
||||
if (!event.target.checked) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
<h4 class="gh-main-section-header small bn">Newsletters</h4>
|
||||
<div class="gh-main-section-content grey">
|
||||
<div class="gh-main-section-content grey {{if (feature "suppressionList") 'gh-member-newsletter-section'}}">
|
||||
<div class="gh-member-newsletters">
|
||||
{{#each this.newsletters as |newsletter|}}
|
||||
<div class="gh-member-newsletter-row">
|
||||
<div>
|
||||
<h4 class="gh-member-newsletter-title">{{newsletter.name}}</h4>
|
||||
</div>
|
||||
<div class="for-switch">
|
||||
<div class="for-switch {{if (and (feature "suppressionList") this.suppressionData.suppressed) 'disabled'}}">
|
||||
<label class="switch" for={{newsletter.forId}}>
|
||||
<Input
|
||||
@checked={{newsletter.subscribed}}
|
||||
@ -22,4 +22,34 @@
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
{{#if (and (feature "suppressionList") this.suppressionData.suppressed)}}
|
||||
<div class="gh-member-newsletter-footer red">
|
||||
{{#if (eq this.suppressionData.reason 'fail')}}
|
||||
{{svg-jar "event-email-delivery-failed" class="gh-member-newsletter-footer-icon"}}
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq this.suppressionData.reason 'spam')}}
|
||||
{{svg-jar "event-email-delivery-spam" class="gh-member-newsletter-footer-icon"}}
|
||||
{{/if}}
|
||||
|
||||
<div class="gh-member-newsletter-footer-text">
|
||||
{{#if (eq this.suppressionData.reason 'fail')}}
|
||||
Member email was suppressed due to it bouncing on {{this.suppressionData.date}}
|
||||
{{/if}}
|
||||
|
||||
{{#if (eq this.suppressionData.reason 'spam')}}
|
||||
Member email was suppressed due to a spam complaint on {{this.suppressionData.date}}
|
||||
{{/if}}
|
||||
|
||||
<a class="midgrey" href="javascript:void(0)" target="_blank" rel="noopener noreferrer">Learn more</a>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{#if (and (feature "suppressionList") (not this.suppressionData.suppressed))}}
|
||||
<div class="gh-member-newsletter-footer midgrey">
|
||||
If disabled, member will <i>not</i> receive newsletter emails
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Component from '@glimmer/component';
|
||||
import moment from 'moment-timezone';
|
||||
import {action} from '@ember/object';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
@ -26,6 +27,18 @@ export default class MembersNewsletterPreference extends Component {
|
||||
return [];
|
||||
}
|
||||
|
||||
get suppressionData() {
|
||||
const {emailSuppression} = this.args.member;
|
||||
const timestamp = emailSuppression?.info?.timestamp;
|
||||
const formattedDate = timestamp ? moment(new Date(timestamp)).format('D MMM YYYY') : null;
|
||||
|
||||
return {
|
||||
suppressed: emailSuppression?.suppressed,
|
||||
reason: emailSuppression?.info?.reason,
|
||||
date: formattedDate
|
||||
};
|
||||
}
|
||||
|
||||
@action
|
||||
updateNewsletterPreference(newsletter, event) {
|
||||
let updatedNewsletters = [];
|
||||
|
@ -115,12 +115,12 @@ export default class MembersEventsFetcher extends Resource {
|
||||
return;
|
||||
}
|
||||
const member = yield this.store.findRecord('member', memberId);
|
||||
if (member.email === 'spam@ghost.org') {
|
||||
if (member.email === 'spam@member.test') {
|
||||
this.data.unshift(mockData('email_delivered_event'));
|
||||
this.data.unshift(mockData('email_complaint_event'));
|
||||
}
|
||||
|
||||
if (member.email === 'fail@ghost.org') {
|
||||
if (member.email === 'fail@member.test') {
|
||||
this.data.unshift(mockData('email_failed_event'));
|
||||
}
|
||||
}
|
||||
@ -150,7 +150,7 @@ function mockData(eventType) {
|
||||
member: {
|
||||
id: '63737a1719675aed3b7cc988',
|
||||
uuid: '5c753e47-9f49-43ad-86d4-c5c0168519a2',
|
||||
email: 'spam@ghost.org',
|
||||
email: 'spam@member.test',
|
||||
status: 'free',
|
||||
name: 'Spam',
|
||||
expertise: null,
|
||||
|
@ -24,6 +24,7 @@ export default Model.extend(ValidationEngine, {
|
||||
|
||||
tiers: attr('member-tier'),
|
||||
newsletters: hasMany('newsletter', {embedded: 'always', async: false}),
|
||||
emailSuppression: attr(),
|
||||
|
||||
labels: hasMany('label', {embedded: 'always', async: false}),
|
||||
|
||||
|
@ -62,6 +62,7 @@ export default class FeatureService extends Service {
|
||||
@feature('sourceAttribution') sourceAttribution;
|
||||
@feature('lexicalEditor') lexicalEditor;
|
||||
@feature('audienceFeedback') audienceFeedback;
|
||||
@feature('suppressionList') suppressionList;
|
||||
|
||||
_user = null;
|
||||
|
||||
|
@ -1122,6 +1122,42 @@ textarea.gh-member-details-textarea {
|
||||
margin-bottom: 0!important;
|
||||
}
|
||||
|
||||
.gh-main-section-content.gh-member-newsletter-section {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.gh-member-newsletter-section .for-switch.disabled {
|
||||
opacity: 0.1;
|
||||
}
|
||||
|
||||
.gh-member-newsletter-footer-text {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.gh-member-newsletter-footer-text a {
|
||||
display: inline-block;
|
||||
text-decoration: underline;
|
||||
margin-left: 2px;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.gh-member-newsletter-footer {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
font-size: 1.25rem;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.gh-member-newsletter-footer-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.gh-member-newsletter-footer-icon [class*="__body"] {
|
||||
stroke: #95A1AD;
|
||||
}
|
||||
|
||||
.gh-member-feed-container {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
|
@ -1,5 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none">
|
||||
<path d="M14.412 18.978a1.22 1.22 0 0 1-1.163-.332l-2.414-2.404-2.592 1.34.1-3.843-3.036-3.035a1.219 1.219 0 0 1-.332-1.108 1.24 1.24 0 0 1 .82-.953L17.68 4.678a1.24 1.24 0 0 1 1.595 1.595l-1.307 3.919M18.917 4.926 8.339 13.743" stroke="#6C747D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path class="body" d="M14.412 18.978a1.22 1.22 0 0 1-1.163-.332l-2.414-2.404-2.592 1.34.1-3.843-3.036-3.035a1.219 1.219 0 0 1-.332-1.108 1.24 1.24 0 0 1 .82-.953L17.68 4.678a1.24 1.24 0 0 1 1.595 1.595l-1.307 3.919M18.917 4.926 8.339 13.743" stroke="#6C747D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M17.634 13.35v2.869" stroke="#F50B23" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="17.639" cy="18.75" r=".75" fill="#F50B23"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 580 B After Width: | Height: | Size: 593 B |
Loading…
Reference in New Issue
Block a user