Ghost/ghost/admin/app/components/gh-member-settings-form.js
Simon Backx 848b2d82a1
Cleaned up suppressionList feature flag (#16736)
no issue

This pull request removes the `suppressionList` feature flag and all its
dependencies from the codebase. It makes the suppression list feature
the default and consistent behavior for all email events and
newsletters. It simplifies the UI, logic, and data related to email
events and newsletters. It affects several files in the
`ghost/admin/app`, `ghost/core/core`, and `ghost/members-api`
directories.
2023-05-04 14:47:04 +02:00

248 lines
7.5 KiB
JavaScript

import Component from '@glimmer/component';
import moment from 'moment-timezone';
import {action} from '@ember/object';
import {getNonDecimal, getSymbol} from 'ghost-admin/utils/currency';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';
export default class extends Component {
@service membersUtils;
@service ghostPaths;
@service ajax;
@service store;
@service feature;
@service settings;
constructor(...args) {
super(...args);
this.member = this.args.member;
this.scratchMember = this.args.scratchMember;
}
@tracked showMemberTierModal = false;
@tracked tiersList;
@tracked newslettersList;
get isAddComplimentaryAllowed() {
if (!this.membersUtils.paidMembersEnabled) {
return false;
}
if (this.member.get('isNew')) {
return false;
}
if (this.member.get('tiers')?.length > 0) {
return false;
}
// complimentary subscriptions are assigned to tiers so it only
// makes sense to show the "add complimentary" buttons when there's a
// tier to assign the complimentary subscription to
const hasAnActivePaidTier = !!this.tiersList?.length;
return hasAnActivePaidTier;
}
get isCreatingComplimentary() {
return this.args.isSaveRunning;
}
get tiers() {
let subscriptions = this.member.get('subscriptions') || [];
// Create the tiers from `subscriptions.price.tier`
let tiers = subscriptions
.map(subscription => (subscription.tier || subscription.price.tier))
.filter((value, index, self) => {
// Deduplicate by taking the first object by `id`
return typeof value.id !== 'undefined' && self.findIndex(element => (element.tier_id || element.id) === (value.tier_id || value.id)) === index;
});
let subscriptionData = subscriptions.filter((sub) => {
return !!sub.price;
}).map((sub) => {
const data = {
...sub,
attribution: {
...sub.attribution,
referrerSource: sub.attribution?.referrer_source || 'Unknown',
referrerMedium: sub.attribution?.referrer_medium || '-'
},
startDate: sub.start_date ? moment(sub.start_date).format('D MMM YYYY') : '-',
validUntil: sub.current_period_end ? moment(sub.current_period_end).format('D MMM YYYY') : '-',
cancellationReason: sub.cancellation_reason,
price: {
...sub.price,
currencySymbol: getSymbol(sub.price.currency),
nonDecimalAmount: getNonDecimal(sub.price.amount)
},
isComplimentary: !sub.id
};
if (sub.trial_end_at) {
const inTrialMode = moment(sub.trial_end_at).isAfter(new Date(), 'day');
if (inTrialMode) {
data.trialUntil = moment(sub.trial_end_at).format('D MMM YYYY');
}
}
if (!sub.id && sub.tier?.expiry_at) {
data.compExpiry = moment(sub.tier.expiry_at).format('D MMM YYYY');
}
return data;
});
return tiers.map((tier) => {
let tierSubscriptions = subscriptionData.filter((subscription) => {
return subscription?.price?.tier?.tier_id === (tier.tier_id || tier.id);
});
return {
...tier,
subscriptions: tierSubscriptions
};
});
}
get customer() {
let firstSubscription = this.member.get('subscriptions').firstObject;
let customer = firstSubscription?.customer;
if (customer) {
return {
...customer,
startDate: firstSubscription?.startDate
};
}
return null;
}
get canShowMultipleNewsletters() {
return (
this.settings.editorDefaultEmailRecipients !== 'disabled'
);
}
@action
updateNewsletterPreference(event) {
if (!event.target.checked) {
this.member.set('newsletters', []);
} else if (this.newslettersList.firstObject) {
const newsletter = this.newslettersList.firstObject;
this.member.set('newsletters', [newsletter]);
}
}
@action
setup() {
this.fetchTiers.perform();
this.fetchNewsletters.perform();
}
@action
setProperty(property, value) {
this.args.setProperty(property, value);
}
@action
updateProperty(event){
this.args.setProperty(event.currentTarget.name, event.target.value);
}
@action
setLabels(labels) {
this.member.set('labels', labels);
}
@action
setMemberNewsletters(newsletters) {
this.member.set('newsletters', newsletters);
}
@action
closeMemberTierModal() {
this.showMemberTierModal = false;
}
@action
cancelSubscription(subscriptionId) {
this.cancelSubscriptionTask.perform(subscriptionId);
}
@action
removeComplimentary(tierId) {
this.removeComplimentaryTask.perform(tierId);
}
@action
continueSubscription(subscriptionId) {
this.continueSubscriptionTask.perform(subscriptionId);
}
@task({drop: true})
*cancelSubscriptionTask(subscriptionId) {
let url = this.ghostPaths.url.api('members', this.member.get('id'), 'subscriptions', subscriptionId);
let response = yield this.ajax.put(url, {
data: {
cancel_at_period_end: true
}
});
this.store.pushPayload('member', response);
return response;
}
@task({drop: true})
*removeComplimentaryTask(tierId) {
let url = this.ghostPaths.url.api(`members/${this.member.get('id')}`);
let tiers = this.member.get('tiers') || [];
const updatedTiers = tiers
.filter(tier => tier.id !== tierId)
.map(tier => ({id: tier.id}));
let response = yield this.ajax.put(url, {
data: {
members: [{
id: this.member.get('id'),
email: this.member.get('email'),
tiers: updatedTiers
}]
}
});
this.store.pushPayload('member', response);
return response;
}
@task({drop: true})
*continueSubscriptionTask(subscriptionId) {
let url = this.ghostPaths.url.api('members', this.member.get('id'), 'subscriptions', subscriptionId);
let response = yield this.ajax.put(url, {
data: {
cancel_at_period_end: false
}
});
this.store.pushPayload('member', response);
return response;
}
@task({drop: true})
*fetchTiers() {
this.tiersList = yield this.store.query('tier', {filter: 'type:paid+active:true', include: 'monthly_price,yearly_price'});
}
@task({drop: true})
*fetchNewsletters() {
this.newslettersList = yield this.store.query('newsletter', {filter: 'status:active'});
if (this.member.get('isNew')) {
const defaultNewsletters = this.newslettersList.filter((newsletter) => {
return newsletter.subscribeOnSignup && newsletter.visibility === 'members';
});
this.setMemberNewsletters(defaultNewsletters);
}
}
}