From f1c8af662f77c11e6977776bf74e7e665b89b531 Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 9 Feb 2022 21:40:32 +0000 Subject: [PATCH] Refactored modal for bulk unsubscribing members refs https://github.com/TryGhost/Team/issues/559 Members controller was becoming bloated and difficult to follow due to catering for many different concerns. - converted old modal to newer promise-modal style - pulled full bulk unsubscribing logic out of the members controller and into the modal so logic is contained in one place --- .../modals/members/bulk-unsubscribe.hbs | 80 +++++++++++++++++++ .../modals/members/bulk-unsubscribe.js | 55 +++++++++++++ ghost/admin/app/controllers/members.js | 63 ++++----------- ghost/admin/app/templates/members.hbs | 2 +- 4 files changed, 153 insertions(+), 47 deletions(-) create mode 100644 ghost/admin/app/components/modals/members/bulk-unsubscribe.hbs create mode 100644 ghost/admin/app/components/modals/members/bulk-unsubscribe.js diff --git a/ghost/admin/app/components/modals/members/bulk-unsubscribe.hbs b/ghost/admin/app/components/modals/members/bulk-unsubscribe.hbs new file mode 100644 index 0000000000..73ab8cebeb --- /dev/null +++ b/ghost/admin/app/components/modals/members/bulk-unsubscribe.hbs @@ -0,0 +1,80 @@ + \ No newline at end of file diff --git a/ghost/admin/app/components/modals/members/bulk-unsubscribe.js b/ghost/admin/app/components/modals/members/bulk-unsubscribe.js new file mode 100644 index 0000000000..187e43f5cc --- /dev/null +++ b/ghost/admin/app/components/modals/members/bulk-unsubscribe.js @@ -0,0 +1,55 @@ +import Component from '@glimmer/component'; +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 MembersBulkUnsubscribeModal extends Component { + @service ajax; + @service ghostPaths; + + @tracked error; + @tracked response; + + get isDisabled() { + return !this.args.data.query; + } + + get hasRun() { + return !!(this.error || this.response); + } + + @action + setLabel(label) { + this.selectedLabel = label; + } + + @task({drop: true}) + *bulkUnsubscribeTask() { + try { + const query = new URLSearchParams(this.args.data.query); + const removeLabelUrl = `${this.ghostPaths.url.api('members/bulk')}?${query}`; + const response = yield this.ajax.put(removeLabelUrl, { + data: { + bulk: { + action: 'unsubscribe', + meta: {} + } + } + }); + + this.args.data.onComplete?.(); + + this.response = response?.bulk?.meta; + + return true; + } catch (e) { + if (e.payload?.errors) { + this.error = e.payload.errors[0].message; + } else { + this.error = 'An unknown error occurred. Please try again.'; + } + throw e; + } + } +} diff --git a/ghost/admin/app/controllers/members.js b/ghost/admin/app/controllers/members.js index 8d40cdc214..b06600c9fb 100644 --- a/ghost/admin/app/controllers/members.js +++ b/ghost/admin/app/controllers/members.js @@ -53,7 +53,6 @@ export default class MembersController extends Controller { @tracked orderParam = null; @tracked modalLabel = null; @tracked showLabelModal = false; - @tracked showUnsubscribeMembersModal = false; @tracked filters = A([]); @tracked softFilters = A([]); @@ -301,11 +300,7 @@ export default class MembersController extends Controller { bulkAddLabel() { this.modals.open('modals/members/bulk-add-label', { query: this.getApiQueryObject(), - onComplete: () => { - // reset and reload - this.store.unloadAll('member'); - this.reload(); - } + onComplete: this.resetAndReloadMembers }); } @@ -313,20 +308,30 @@ export default class MembersController extends Controller { bulkRemoveLabel() { this.modals.open('modals/members/bulk-remove-label', { query: this.getApiQueryObject(), - onComplete: () => { - // reset and reload - this.store.unloadAll('member'); - this.reload(); - } + onComplete: this.resetAndReloadMembers }); } + @action + bulkUnsubscribe() { + this.modals.open('modals/members/bulk-unsubscribe', { + query: this.getApiQueryObject(), + onComplete: this.resetAndReloadMembers + }); + } + + @action + resetAndReloadMembers() { + this.store.unloadAll('member'); + this.reload(); + } + @action bulkDelete() { this.modals.open('modals/members/bulk-delete', { query: this.getApiQueryObject(), onComplete: () => { - // reset and reload + // reset, clear filters, and reload list and counts this.store.unloadAll('member'); this.router.transitionTo('members.index', {queryParams: Object.assign(resetQueryParams('members.index'))}); this.membersStats.invalidate(); @@ -340,16 +345,6 @@ export default class MembersController extends Controller { this.paidParam = paid.value; } - @action - toggleUnsubscribeMembersModal() { - this.showUnsubscribeMembersModal = !this.showUnsubscribeMembersModal; - } - - @action - unsubscribeMembers() { - return this.unsubscribeMembersTask.perform(); - } - // Tasks ------------------------------------------------------------------- @task({restartable: true}) @@ -416,30 +411,6 @@ export default class MembersController extends Controller { }); } - @task({drop: true}) - *unsubscribeMembersTask() { - const query = new URLSearchParams(this.getApiQueryObject()); - const unsubscribeUrl = `${this.ghostPaths.url.api('members/bulk')}?${query}`; - // response contains details of which members failed to be unsubscribe - const response = yield this.ajax.put(unsubscribeUrl, { - data: { - bulk: { - action: 'unsubscribe', - meta: {} - } - } - }); - - // reset and reload - this.store.unloadAll('member'); - this.reload(); - - this.membersStats.invalidate(); - this.membersStats.fetchCounts(); - - return response?.bulk?.meta; - } - // Internal ---------------------------------------------------------------- resetFilters(params) { diff --git a/ghost/admin/app/templates/members.hbs b/ghost/admin/app/templates/members.hbs index e3c2d06900..83bd885ab1 100644 --- a/ghost/admin/app/templates/members.hbs +++ b/ghost/admin/app/templates/members.hbs @@ -79,7 +79,7 @@
  • -