mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 14:03:48 +03:00
40c78b6be6
refs https://github.com/TryGhost/Team/issues/1252 "Add complimentary subscription" doesn't make sense when there are no active tiers for site in member detail screen
191 lines
5.4 KiB
JavaScript
191 lines
5.4 KiB
JavaScript
import Component from '@glimmer/component';
|
|
import moment from 'moment';
|
|
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-decorators';
|
|
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 showMemberProductModal = false;
|
|
@tracked productsList;
|
|
|
|
get canShowStripeInfo() {
|
|
return !this.member.get('isNew') && this.membersUtils.isStripeEnabled;
|
|
}
|
|
|
|
get isAddComplimentaryAllowed() {
|
|
if (!this.membersUtils.isStripeEnabled) {
|
|
return false;
|
|
}
|
|
|
|
let products = this.member.get('products');
|
|
if (products && products.length > 0) {
|
|
return false;
|
|
}
|
|
|
|
if (this.feature.get('multipleProducts')) {
|
|
return !!this.productsList?.length;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
get products() {
|
|
let products = this.member.get('products') || [];
|
|
let subscriptions = this.member.get('subscriptions') || [];
|
|
let subscriptionData = subscriptions.filter((sub) => {
|
|
return !!sub.price;
|
|
}).map((sub) => {
|
|
return {
|
|
...sub,
|
|
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
|
|
};
|
|
});
|
|
|
|
for (let product of products) {
|
|
let productSubscriptions = subscriptionData.filter((subscription) => {
|
|
if (subscription.status === 'canceled') {
|
|
return false;
|
|
}
|
|
return subscription?.price?.product?.product_id === product.id;
|
|
});
|
|
product.subscriptions = productSubscriptions;
|
|
}
|
|
|
|
return products;
|
|
}
|
|
|
|
get customer() {
|
|
let firstSubscription = this.member.get('subscriptions').firstObject;
|
|
let customer = firstSubscription?.customer;
|
|
|
|
if (customer) {
|
|
return {
|
|
...customer,
|
|
startDate: firstSubscription?.startDate
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@action
|
|
setup() {
|
|
this.fetchProducts.perform();
|
|
}
|
|
|
|
get isCreatingComplimentary() {
|
|
return this.args.isSaveRunning;
|
|
}
|
|
|
|
@action
|
|
setProperty(property, value) {
|
|
this.args.setProperty(property, value);
|
|
}
|
|
|
|
@action
|
|
setLabels(labels) {
|
|
this.member.set('labels', labels);
|
|
}
|
|
|
|
@action
|
|
closeMemberProductModal() {
|
|
this.showMemberProductModal = false;
|
|
}
|
|
|
|
@action
|
|
cancelSubscription(subscriptionId) {
|
|
this.cancelSubscriptionTask.perform(subscriptionId);
|
|
}
|
|
|
|
@action
|
|
removeComplimentary(productId) {
|
|
this.removeComplimentaryTask.perform(productId);
|
|
}
|
|
|
|
@action
|
|
continueSubscription(subscriptionId) {
|
|
this.continueSubscriptionTask.perform(subscriptionId);
|
|
}
|
|
|
|
@action
|
|
addCompedSubscription() {
|
|
this.args.setProperty('comped', true);
|
|
this.args.saveMember();
|
|
}
|
|
|
|
@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(productId) {
|
|
let url = this.ghostPaths.url.api(`members/${this.member.get('id')}`);
|
|
let products = this.member.get('products') || [];
|
|
const updatedProducts = products.filter(product => product.id !== productId).map(product => ({id: product.id}));
|
|
|
|
let response = yield this.ajax.put(url, {
|
|
data: {
|
|
members: [{
|
|
id: this.member.get('id'),
|
|
email: this.member.get('email'),
|
|
products: updatedProducts
|
|
}]
|
|
}
|
|
});
|
|
|
|
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})
|
|
*fetchProducts() {
|
|
this.productsList = yield this.store.query('product', {filter: 'type:paid+active:true', include: 'monthly_price,yearly_price'});
|
|
}
|
|
}
|