mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-30 01:42:29 +03:00
848b2d82a1
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.
248 lines
7.5 KiB
JavaScript
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);
|
|
}
|
|
}
|
|
}
|