Ghost/ghost/admin/app/components/settings/members-email-labs/newsletter-management.js
Kevin Ansfield 2f849c431f Fixed newsletter list sometimes showing no newsletters
no issue

- depending on when the newsletter settings route is accessed we would sometimes show an empty newsletter list
- the problem stems from the use of a non-reactive fixed list of displayed newsletters where we manually update the list when we know the list should change. On initial load we were using `await store.findAll('newsletter')` then updating the displayed list, however the default behaviour for `store.findAll()` is to immediately return a live array - this doesn't work for our use-case because we'd then potentially update our displayed list from incomplete data
- added the `{reload: true}` option to the `findAll()` call to force a wait for the API request to finish before updating the displayed list of newsletters
2022-04-21 11:33:52 +01:00

153 lines
4.4 KiB
JavaScript

import Component from '@glimmer/component';
import ConfirmArchiveModal from '../../modals/edit-newsletter/confirm-archive';
import ConfirmUnarchiveModal from '../../modals/edit-newsletter/confirm-unarchive';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';
export default class NewsletterManagementComponent extends Component {
@service modals;
@service router;
@service store;
@tracked statusFilter = 'active';
@tracked filteredNewsletters = [];
statusFilters = ['active', 'archived'];
newsletters = this.store.peekAll('newsletter');
constructor() {
super(...arguments);
this.loadNewslettersTask.perform();
this.router.on('routeDidChange', this.handleNewRouteChange);
}
willDestroy() {
super.willDestroy(...arguments);
this.router.off('routeDidChange', this.handleNewRouteChange);
this.confirmArchiveModal?.close();
this.confirmUnarchiveModal?.close();
}
get activeNewsletters() {
return this.newsletters.filter(n => n.status === 'active');
}
get archivedNewsletters() {
return this.newsletters.filter(n => n.status === 'archived');
}
get displayingDefault() {
return this.statusFilter === 'active' && this.filteredNewsletters.length === 1;
}
@action
changeStatusFilter(status) {
this.statusFilter = status;
this.updateFilteredNewsletters();
}
@action
updateFilteredNewsletters() {
this.filteredNewsletters = this.newsletters.filter((n) => {
return n.status === this.statusFilter
&& !n.isNew
&& !n.isDestroyed;
});
}
@action
handleNewRouteChange(transition) {
// NOTE: this is necessary because ember-drag-drop has forced us into using
// an explicit tracked filteredNewsletters property rather than using a reactive
// getter that automatically displays newly added newsletters
if (transition.from.name === 'settings.members-email-labs.new-newsletter') {
this.updateFilteredNewsletters();
}
}
@action
archiveNewsletter(newsletter) {
this.confirmArchiveModal = this.modals.open(ConfirmArchiveModal, {
newsletter,
archiveNewsletterTask: this.archiveNewsletterTask
});
}
@task
*archiveNewsletterTask(newsletter) {
newsletter.status = 'archived';
const result = yield newsletter.save();
this.updateFilteredNewsletters();
this.confirmArchiveModal?.close();
return result;
}
@action
unarchiveNewsletter(newsletter) {
this.confirmUnarchiveModal = this.modals.open(ConfirmUnarchiveModal, {
newsletter,
unarchiveNewsletterTask: this.unarchiveNewsletterTask
});
}
@task
*unarchiveNewsletterTask(newsletter) {
newsletter.status = 'active';
const result = yield newsletter.save();
if (this.statusFilter === 'archived' && !this.archivedNewsletters.length) {
this.statusFilter = 'active';
}
this.updateFilteredNewsletters();
this.confirmUnarchiveModal?.close();
return result;
}
@task
*loadNewslettersTask() {
const newsletters = yield this.store.findAll('newsletter', {reload: true});
this.updateFilteredNewsletters();
return newsletters;
}
@task
*reorderNewslettersTask() {
// filteredNewsletters is the array that gets updated by <SortableObjects> whilst dragging.
// we only want to update ordering when _active_ newsletters are re-ordered to make sure
// archived newsletters don't end up with a lower sort order than active ones
if (this.statusFilter !== 'active') {
return;
}
// use filteredNewsletters rather than activeNewsletters so we're using'the ordered array
const activeNewsletters = this.filteredNewsletters;
const otherNewsletters = this.newsletters
.filter(n => !activeNewsletters.includes(n))
.sort(({sortOrder: a}, {sortOrder: b}) => b - a);
let sortOrder = 0;
for (const n of [...activeNewsletters, ...otherNewsletters]) {
n.sortOrder = sortOrder;
yield n.save();
sortOrder += 1;
}
}
}