Ghost/ghost/admin/app/services/members-count-cache.js
Kevin Ansfield 7c4674507e Switched members-count-fetcher to use members-count-cache
no issue

In the new publish flow we use `{{members-count-fetcher}}` to show member counts as needed in the template without needing to worry about manually fetching counts in the backing classes. However, when switching between states in the flow the count would be re-requested resulting in some glitchy looking async count rendering. By changing `{{members-count-fetcher}}` to use our `members-count-cache` service internally we reduce the likelihood of an async count being triggered when switching between publish flow states.

- updated `members-count-cache` service methods to work with filter strings or full query objects
- switched `members-count-fetcher` resource to use `members-count-cache` in place of directly querying the store
2022-05-05 11:18:49 +01:00

92 lines
2.7 KiB
JavaScript

import Service, {inject as service} from '@ember/service';
import moment from 'moment';
import {action} from '@ember/object';
import {ghPluralize} from 'ghost-admin/helpers/gh-pluralize';
import {task} from 'ember-concurrency';
export default class MembersCountCacheService extends Service {
@service session;
@service store;
cache = {};
@action
async count(query) {
if (typeof query === 'string') {
query = {filter: query};
}
const cacheKey = JSON.stringify(query);
const cachedValue = this.cache[cacheKey];
if (cachedValue && moment().diff(cachedValue.time, 'seconds') <= 60) {
return cachedValue.count;
}
const count = this._countMembersTask.perform(query);
this.cache[cacheKey] = {count, time: moment()};
return count;
}
@action
async countString(filter = '', {knownCount} = {}) {
const user = this.session.user;
const basicFilter = filter.replace(/^newsletters\.status:active\+\((.*)\)$/, '$1');
const filterParts = basicFilter.split(',');
const isFree = filterParts.length === 1 && filterParts[0] === 'status:free';
const isPaid = filterParts.length === 1 && filterParts[0] === 'status:-free';
const isAll = !filter || (filterParts.includes('status:free') && filterParts.includes('status:-free'));
// editors don't have permission to browse members so can't retrieve a count
// TODO: remove when editors have relevant permissions or we have a different way of fetching counts
if (user.isEditor && knownCount === undefined) {
if (isFree) {
return 'all free members';
}
if (isPaid) {
return 'all paid members';
}
if (isAll) {
return 'all members';
}
return 'a custom members segment';
}
const recipientCount = knownCount !== undefined ? knownCount : await this.count(filter);
if (isFree) {
return ghPluralize(recipientCount, 'free member');
}
if (isPaid) {
return ghPluralize(recipientCount, 'paid member');
}
return ghPluralize(recipientCount, 'member');
}
@action
clear() {
this.cache = {};
}
@task
*_countMembersTask(query) {
if (!query) {
return 0;
}
try {
const result = yield this.store.query('member', {...query, limit: 1, page: 1});
return result.meta.pagination.total;
} catch (e) {
console.error(e); // eslint-disable-line
return 0;
}
}
}