mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-25 20:03:12 +03:00
Switched delete member modal to new modal pattern (#15467)
refs https://github.com/TryGhost/Team/issues/1734 refs https://github.com/TryGhost/Team/issues/559 refs https://github.com/TryGhost/Ghost/issues/14101 - switches to newer modal patterns ready for later Ember upgrades
This commit is contained in:
parent
63b1e4e8ad
commit
ac67475605
37
ghost/admin/app/components/members/modals/delete-member.hbs
Normal file
37
ghost/admin/app/components/members/modals/delete-member.hbs
Normal file
@ -0,0 +1,37 @@
|
||||
<div class="modal-content" data-test-modal="delete-member">
|
||||
<header class="modal-header">
|
||||
<h1>Delete member account</h1>
|
||||
</header>
|
||||
<button type="button" class="close" title="Close" {{on "click" (fn @close false)}}>{{svg-jar "close"}}<span class="hidden">Close</span></button>
|
||||
|
||||
<div class="modal-body">
|
||||
<p class="mb6">
|
||||
Permanently delete <strong>{{@data.member.email}}</strong> from Ghost.
|
||||
</p>
|
||||
|
||||
{{#if this.hasActiveStripeSubscriptions}}
|
||||
<div class="flex justify-between">
|
||||
<div class="form-group for-checkbox gh-member-cancelstripe-checkbox">
|
||||
<label class="checkbox">
|
||||
<input
|
||||
class="gh-input"
|
||||
type="checkbox"
|
||||
checked={{this.shouldCancelSubscriptions}}
|
||||
{{on "click" (toggle "toggleShouldCancelSubscriptions" this)}}
|
||||
/>
|
||||
<span class="input-toggle-component"></span>
|
||||
<div>
|
||||
<h4>Also cancel subscription in Stripe</h4>
|
||||
<p>If disabled, the member’s premium subscription will continue</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="gh-btn" type="button" {{on "click" (fn @close false)}}><span>Cancel</span></button>
|
||||
<GhTaskButton @buttonText={{if this.shouldCancelSubscriptions "Delete member + Cancel subscription" "Delete member"}} @successText="Deleted" @task={{this.deleteMemberTask}} @class="gh-btn gh-btn-red gh-btn-icon" />
|
||||
</div>
|
||||
</div>
|
47
ghost/admin/app/components/members/modals/delete-member.js
Normal file
47
ghost/admin/app/components/members/modals/delete-member.js
Normal file
@ -0,0 +1,47 @@
|
||||
import Component from '@glimmer/component';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
import {tracked} from '@glimmer/tracking';
|
||||
|
||||
export default class DeleteMemberModal extends Component {
|
||||
@service notifications;
|
||||
|
||||
@tracked shouldCancelSubscriptions = false;
|
||||
|
||||
get member() {
|
||||
return this.args.data.member;
|
||||
}
|
||||
|
||||
get hasActiveStripeMigrations() {
|
||||
const subscriptions = this.member.get('subscriptions');
|
||||
|
||||
if (!subscriptions || subscriptions.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const firstActiveStripeSubscription = subscriptions.find((subscription) => {
|
||||
return ['active', 'trialing', 'unpaid', 'past_due'].includes(subscription.status);
|
||||
});
|
||||
|
||||
return firstActiveStripeSubscription !== undefined;
|
||||
}
|
||||
|
||||
@task({drop: true})
|
||||
*deleteMemberTask() {
|
||||
const options = {
|
||||
adapterOptions: {
|
||||
cancel: this.shouldCancelSubscriptions
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
yield this.member.destroyRecord(options);
|
||||
this.args.data.afterDelete?.();
|
||||
this.args.close(true);
|
||||
} catch (e) {
|
||||
this.notifications.showAPIError(e, {key: 'member.delete'});
|
||||
this.args.close(false);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
<header class="modal-header">
|
||||
<h1>Delete member account</h1>
|
||||
</header>
|
||||
<a class="close" href="" role="button" title="Close" {{action "closeModal"}}>{{svg-jar "close"}}<span class="hidden">Close</span></a>
|
||||
|
||||
<div class="modal-body">
|
||||
<p class="mb6">
|
||||
Permanently delete <strong>{{this.member.email}}</strong> from Ghost.
|
||||
</p>
|
||||
|
||||
{{#if this.hasActiveStripeSubscriptions}}
|
||||
<div class="flex justify-between">
|
||||
<div class="form-group for-checkbox gh-member-cancelstripe-checkbox">
|
||||
<label class="checkbox">
|
||||
<input
|
||||
class="gh-input"
|
||||
type="checkbox"
|
||||
checked={{this.shouldCancelSubscriptions}}
|
||||
{{on "click" (action "toggleShouldCancelSubscriptions")}}
|
||||
/>
|
||||
<span class="input-toggle-component"></span>
|
||||
<div>
|
||||
<h4>Also cancel subscription in Stripe</h4>
|
||||
<p>If disabled, the member’s premium subscription will continue</p>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="gh-btn" type="button" {{action "closeModal"}}><span>Cancel</span></button>
|
||||
<GhTaskButton @buttonText={{if this.shouldCancelSubscriptions "Delete member + Cancel subscription" "Delete member"}} @successText="Deleted" @task={{this.deleteMember}} @class="gh-btn gh-btn-red gh-btn-icon" />
|
||||
</div>
|
@ -1,51 +0,0 @@
|
||||
import ModalComponent from 'ghost-admin/components/modal-base';
|
||||
import {alias, reads} from '@ember/object/computed';
|
||||
import {computed} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
import {task} from 'ember-concurrency';
|
||||
|
||||
export default ModalComponent.extend({
|
||||
membersStats: service(),
|
||||
|
||||
shouldCancelSubscriptions: false,
|
||||
|
||||
// Allowed actions
|
||||
confirm: () => {},
|
||||
|
||||
member: alias('model'),
|
||||
|
||||
cancelSubscriptions: reads('shouldCancelSubscriptions'),
|
||||
|
||||
hasActiveStripeSubscriptions: computed('member', function () {
|
||||
let subscriptions = this.member.get('subscriptions');
|
||||
|
||||
if (!subscriptions || subscriptions.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let firstActiveStripeSubscription = subscriptions.find((subscription) => {
|
||||
return ['active', 'trialing', 'unpaid', 'past_due'].includes(subscription.status);
|
||||
});
|
||||
|
||||
return firstActiveStripeSubscription !== undefined;
|
||||
}),
|
||||
|
||||
actions: {
|
||||
confirm() {
|
||||
this.deleteMember.perform();
|
||||
},
|
||||
|
||||
toggleShouldCancelSubscriptions() {
|
||||
this.set('shouldCancelSubscriptions', !this.shouldCancelSubscriptions);
|
||||
}
|
||||
},
|
||||
|
||||
deleteMember: task(function* () {
|
||||
try {
|
||||
yield this.confirm(this.shouldCancelSubscriptions);
|
||||
this.membersStats.invalidate();
|
||||
} finally {
|
||||
this.send('closeModal');
|
||||
}
|
||||
}).drop()
|
||||
});
|
@ -1,4 +1,5 @@
|
||||
import Controller, {inject as controller} from '@ember/controller';
|
||||
import DeleteMemberModal from '../components/members/modals/delete-member';
|
||||
import EmberObject, {action, defineProperty} from '@ember/object';
|
||||
import boundOneWay from 'ghost-admin/utils/bound-one-way';
|
||||
import moment from 'moment-timezone';
|
||||
@ -13,12 +14,12 @@ export default class MemberController extends Controller {
|
||||
@service session;
|
||||
@service dropdown;
|
||||
@service membersStats;
|
||||
@service modals;
|
||||
@service notifications;
|
||||
@service router;
|
||||
@service store;
|
||||
|
||||
@tracked isLoading = false;
|
||||
@tracked showDeleteMemberModal = false;
|
||||
@tracked showImpersonateMemberModal = false;
|
||||
@tracked modalLabel = null;
|
||||
@tracked showLabelModal = false;
|
||||
@ -34,6 +35,10 @@ export default class MemberController extends Controller {
|
||||
return this.model;
|
||||
}
|
||||
|
||||
set member(member) {
|
||||
this.model = member;
|
||||
}
|
||||
|
||||
get labelModalData() {
|
||||
let label = this.modalLabel;
|
||||
let labels = this.availableLabels;
|
||||
@ -56,10 +61,6 @@ export default class MemberController extends Controller {
|
||||
return options;
|
||||
}
|
||||
|
||||
set member(member) {
|
||||
this.model = member;
|
||||
}
|
||||
|
||||
get scratchMember() {
|
||||
let scratchMember = EmberObject.create({member: this.member});
|
||||
SCRATCH_PROPS.forEach(prop => defineProperty(scratchMember, prop, boundOneWay(`member.${prop}`)));
|
||||
@ -97,8 +98,15 @@ export default class MemberController extends Controller {
|
||||
}
|
||||
|
||||
@action
|
||||
toggleDeleteMemberModal() {
|
||||
this.showDeleteMemberModal = !this.showDeleteMemberModal;
|
||||
confirmDeleteMember() {
|
||||
this.modals.open(DeleteMemberModal, {
|
||||
member: this.member,
|
||||
afterDelete: () => {
|
||||
this.membersStats.invalidate();
|
||||
this.members.refreshData();
|
||||
this.transitionToRoute('members');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@action
|
||||
@ -116,22 +124,6 @@ export default class MemberController extends Controller {
|
||||
return this.saveTask.perform();
|
||||
}
|
||||
|
||||
@action
|
||||
deleteMember(cancelSubscriptions = false) {
|
||||
let options = {
|
||||
adapterOptions: {
|
||||
cancel: cancelSubscriptions
|
||||
}
|
||||
};
|
||||
return this.member.destroyRecord(options).then(() => {
|
||||
this.members.refreshData();
|
||||
this.transitionToRoute('members');
|
||||
return;
|
||||
}, (error) => {
|
||||
return this.notifications.showAPIError(error, {key: 'member.delete'});
|
||||
});
|
||||
}
|
||||
|
||||
// Tasks -------------------------------------------------------------------
|
||||
|
||||
@task({drop: true})
|
||||
|
@ -39,7 +39,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="mr2"
|
||||
{{on "click" this.toggleDeleteMemberModal}}
|
||||
{{on "click" this.confirmDeleteMember}}
|
||||
data-test-button="delete-member"
|
||||
>
|
||||
<span class="red">Delete member</span>
|
||||
@ -68,15 +68,6 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{{#if this.showDeleteMemberModal}}
|
||||
<GhFullscreenModal
|
||||
@modal="delete-member"
|
||||
@model={{this.member}}
|
||||
@confirm={{this.deleteMember}}
|
||||
@close={{this.toggleDeleteMemberModal}}
|
||||
@modifier="action wide" />
|
||||
{{/if}}
|
||||
|
||||
{{#if this.showImpersonateMemberModal}}
|
||||
<GhFullscreenModal
|
||||
@modal="impersonate-member"
|
||||
|
Loading…
Reference in New Issue
Block a user