🐛 Fixed member count not showing in send email confirmation modal

closes https://github.com/TryGhost/Team/issues/738
refs https://github.com/TryGhost/Admin/pull/1972

- when we switched from the segment select back to checkboxes and label select we lost the automatic member counting which meant other parts of the publishing workflow had no counts
- fixed subscribed status counts shown in publish menu
- added the async count back to the confirm modal, taking full free/paid/specific query into account
- added total subscribed member count back to the draft publish menu so the email options can be disabled when no subscribed members exist
  - fixed missing disabled styling inside `<GhMembersRecipientSelect>`
This commit is contained in:
Kevin Ansfield 2021-06-08 13:07:16 +01:00
parent e44f18a412
commit 8f5e305721
7 changed files with 39 additions and 30 deletions

View File

@ -1,6 +1,6 @@
<div class="gh-publishmenu-send-to-option">
<p>Free members <span class="gh-publishmenu-emailcount">{{this.freeMemberCountLabel}}</span></p>
<div class="for-switch x-small" {{on "click" (fn this.toggleFilter "status:free")}}>
<div class="for-switch x-small {{if @disabled "disabled"}}" {{on "click" (fn this.toggleFilter "status:free")}}>
<label class="switch" for="send-email-to-free">
<input
id="send-email-to-free"
@ -17,7 +17,7 @@
{{#if this.isPaidAvailable}}
<div class="gh-publishmenu-send-to-option">
<p>Paid members <span class="gh-publishmenu-emailcount">{{this.paidMemberCountLabel}}</span></p>
<div class="for-switch x-small" {{on "click" (fn this.toggleFilter "status:-free")}}>
<div class="for-switch x-small {{if @disabled "disabled"}}" {{on "click" (fn this.toggleFilter "status:-free")}}>
<label class="switch" for="send-email-to-paid">
<input
id="send-email-to-paid"
@ -35,7 +35,7 @@
{{#if this.specificOptions}}
<div class="gh-publishmenu-send-to-option">
<p>Specific people</p>
<div class="for-switch x-small" {{on "click" this.toggleSpecificFilter}}>
<div class="for-switch x-small {{if @disabled "disabled"}}" {{on "click" this.toggleSpecificFilter}}>
<label class="switch" for="send-email-to-paid">
<input
id="send-email-to-paid"

View File

@ -157,10 +157,10 @@ export default class GhMembersRecipientSelect extends Component {
}
yield Promise.all([
this.store.query('member', {filter: 'subscribed:true,status:free', limit: 1}).then((res) => {
this.store.query('member', {filter: 'subscribed:true+status:free', limit: 1}).then((res) => {
this.freeMemberCount = res.meta.pagination.total;
}),
this.store.query('member', {filter: 'subscribed:true,status:-free', limit: 1}).then((res) => {
this.store.query('member', {filter: 'subscribed:true+status:-free', limit: 1}).then((res) => {
this.paidMemberCount = res.meta.pagination.total;
})
]);

View File

@ -30,7 +30,7 @@
</div>
{{#if this.canSendEmail}}
<div class="gh-publishmenu-section">
<div class="gh-publishmenu-section" {{did-insert (perform this.countTotalMembersTask)}}>
<div class="gh-publishmenu-email">
{{#if this.isSendingEmailLimited}}
<p class="gh-box gh-box-alert">{{html-safe this.sendingEmailLimitError}}</p>
@ -42,6 +42,7 @@
<GhMembersRecipientSelect
@filter={{this.recipientsFilter}}
@onChange={{this.setSendEmailWhenPublished}}
@disabled={{this.disableEmailOption}}
/>
</div>
</div>

View File

@ -3,12 +3,15 @@ import moment from 'moment';
import {computed} from '@ember/object';
import {isEmpty} from '@ember/utils';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
export default Component.extend({
feature: service(),
settings: service(),
config: service(),
feature: service(),
session: service(),
settings: service(),
store: service(),
post: null,
saveType: null,
@ -18,8 +21,9 @@ export default Component.extend({
'data-test-publishmenu-draft': true,
disableEmailOption: computed('memberCount', function () {
return (this.get('session.user.isOwnerOrAdmin') && this.memberCount === 0);
// TODO: remove owner or admin check when editors can count members
disableEmailOption: computed('totalMemberCount', 'countTotalMembersTask.isRunning', function () {
return this.get('session.user.isOwnerOrAdmin') && (this.totalMemberCount === 0 || this.countTotalMembersTask.isRunning);
}),
didInsertElement() {
@ -75,6 +79,15 @@ export default Component.extend({
}
},
countTotalMembersTask: task(function*() {
const user = yield this.session.user;
if (user.isOwnerOrAdmin) {
const result = yield this.store.query('member', {limit: 1, filter: 'subscribed:true'});
this.set('totalMemberCount', result.meta.pagination.total);
}
}),
// scheduled date 5 mins in the future to avoid immediate validation errors
_getMinDate() {
return moment.utc().add(5, 'minutes');

View File

@ -62,9 +62,7 @@
@modal="confirm-email-send"
@model={{hash
sendEmailWhenPublished=this.sendEmailWhenPublished
memberCount=this.memberCount
isScheduled=(eq this.saveType "schedule")
paidOnly=(eq this.post.visibility "paid")
retryEmailSend=this.retryEmailSend
}}
@confirm={{this.confirmEmailSend}}

View File

@ -4,8 +4,8 @@
</header>
<button class="close" title="Close" {{on "click" this.closeModal}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
<div class="modal-body" {{did-insert this.countPaidMembers}}>
{{#if this.countPaidMembersTask.isRunning}}
<div class="modal-body" {{did-insert this.countRecipients}}>
{{#if this.countRecipientsTask.isRunning}}
<div class="flex flex-column items-center">
<div class="gh-loading-spinner"></div>
</div>
@ -15,16 +15,16 @@
<strong>
{{#if (eq this.model.sendEmailWhenPublished 'status:-free')}}
{{!-- TODO: remove editor fallback once editors can query member counts --}}
{{if this.session.user.isEditor "all paid members" (gh-pluralize this.model.memberCount "paid member")}}
{{if this.session.user.isEditor "all paid members" (gh-pluralize this.memberCount "paid member")}}
{{else if (eq this.model.sendEmailWhenPublished 'status:free')}}
{{!-- TODO: remove editor fallback once editors can query member counts --}}
{{if this.session.user.isEditor "all free members" (gh-pluralize this.model.memberCount "free member")}}
{{if this.session.user.isEditor "all free members" (gh-pluralize this.memberCount "free member")}}
{{else if (eq this.model.sendEmailWhenPublished 'status:free,status:-free')}}
{{!-- TODO: remove editor fallback once editors can query member counts --}}
{{if this.session.user.isEditor "all members" (gh-pluralize this.model.memberCount "member")}}
{{if this.session.user.isEditor "all members" (gh-pluralize this.memberCount "member")}}
{{else}}
{{!-- TODO: remove editor fallback once editors can query member counts --}}
{{if this.session.user.isEditor "a custom members segment" (gh-pluralize this.model.memberCount "member")}}
{{if this.session.user.isEditor "a custom members segment" (gh-pluralize this.memberCount "member")}}
{{/if}}
</strong>
and will be published on your site{{#if this.model.isScheduled}} at the scheduled time{{/if}}. Sound good?
@ -37,7 +37,7 @@
<span>Cancel</span>
</button>
<GhTaskButton
@disabled={{this.countPaidMembersTask.isRunning}}
@disabled={{this.countRecipientsTask.isRunning}}
@buttonText={{if this.model.isScheduled "Schedule" "Publish and send"}}
@runningText={{if this.model.isScheduled "Scheduling..." "Publishing..."}}
@task={{this.confirmAndCheckErrorTask}}

View File

@ -8,8 +8,7 @@ export default ModalComponent.extend({
store: service(),
errorMessage: null,
paidMemberCount: null,
freeMemberCount: null,
memberCount: null,
// Allowed actions
confirm: () => {},
@ -19,25 +18,23 @@ export default ModalComponent.extend({
if (this.errorMessage) {
return this.retryEmailTask.perform();
} else {
if (!this.countPaidMembersTask.isRunning) {
if (!this.countRecipientsTask.isRunning) {
return this.confirmAndCheckErrorTask.perform();
}
}
}
},
countPaidMembers: action(function () {
countRecipients: action(function () {
// TODO: remove editor conditional once editors can query member counts
if (['free', 'paid'].includes(this.model.sendEmailWhenPublished) && !this.session.get('user.isEditor')) {
this.countPaidMembersTask.perform();
if (this.model.sendEmailWhenPublished && !this.session.get('user.isEditor')) {
this.countRecipientsTask.perform();
}
}),
countPaidMembersTask: task(function* () {
const result = yield this.store.query('member', {filter: 'subscribed:true+status:-free', limit: 1, page: 1});
this.set('paidMemberCount', result.meta.pagination.total);
const freeMemberCount = this.model.memberCount - result.meta.pagination.total;
this.set('freeMemberCount', freeMemberCount);
countRecipientsTask: task(function* () {
const result = yield this.store.query('member', {filter: `subscribed:true+(${this.model.sendEmailWhenPublished})`, limit: 1, page: 1});
this.set('memberCount', result.meta.pagination.total);
}),
confirmAndCheckErrorTask: task(function* () {