mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 21:57:22 +01:00
409 lines
13 KiB
JavaScript
409 lines
13 KiB
JavaScript
import axios from 'axios'; // eslint-disable-line no-process-env
|
|
import pick from 'lodash/pick';
|
|
import moment from 'moment';
|
|
import subscriptionBlocks from '@/../../common/script/content/subscriptionBlocks';
|
|
import { mapState } from '@/libs/store';
|
|
import encodeParams from '@/libs/encodeParams';
|
|
import notificationsMixin from '@/mixins/notifications';
|
|
import { CONSTANTS, setLocalSetting } from '@/libs/userlocalManager';
|
|
import * as Analytics from '@/libs/analytics';
|
|
|
|
const STRIPE_PUB_KEY = import.meta.env.STRIPE_PUB_KEY;
|
|
|
|
let stripeInstance = null;
|
|
|
|
export default {
|
|
mixins: [notificationsMixin],
|
|
computed: {
|
|
...mapState({ user: 'user.data', credentials: 'credentials' }),
|
|
paypalCheckoutLink () {
|
|
return '/paypal/checkout';
|
|
},
|
|
paypalSubscriptionLink () {
|
|
return `/paypal/subscribe?sub=${this.subscriptionPlan}`;
|
|
},
|
|
paypalPurchaseLink () {
|
|
if (!this.subscription) {
|
|
this.subscription = {
|
|
key: 'basic_earned',
|
|
};
|
|
}
|
|
let couponString = '';
|
|
if (this.subscription.coupon) couponString = `&coupon=${this.subscription.coupon}`;
|
|
return `/paypal/subscribe?sub=${this.subscription.key}${couponString}`;
|
|
},
|
|
dateTerminated () {
|
|
if (!this.user.preferences || !this.user.preferences.dateFormat) {
|
|
return this.user.purchased.plan.dateTerminated;
|
|
}
|
|
return moment(this.user.purchased.plan.dateTerminated)
|
|
.format(this.user.preferences.dateFormat.toUpperCase());
|
|
},
|
|
renewalDate () {
|
|
const renewalDate = moment().add(1, 'months');
|
|
if (!this.user.preferences || !this.user.preferences.dateFormat) {
|
|
return renewalDate;
|
|
}
|
|
return renewalDate.format(this.user.preferences.dateFormat.toUpperCase());
|
|
},
|
|
},
|
|
methods: {
|
|
encodeGift (uuid, gift) {
|
|
gift.uuid = uuid;
|
|
const encodedString = JSON.stringify(gift);
|
|
return encodeURIComponent(encodedString);
|
|
},
|
|
openPaypalGift (giftData) {
|
|
if (!this.checkGemAmount(giftData)) return;
|
|
|
|
const gift = this.encodeGift(giftData.giftedTo, giftData.gift);
|
|
const url = `/paypal/checkout?gift=${gift}`;
|
|
|
|
this.openPaypal({
|
|
url,
|
|
type: `gift-${giftData.gift.type === 'gems' ? 'gems' : 'subscription'}`,
|
|
giftData,
|
|
});
|
|
},
|
|
openPaypal (data = {}) {
|
|
const {
|
|
type,
|
|
giftData,
|
|
gemsBlock,
|
|
sku,
|
|
g1g1,
|
|
} = data;
|
|
let { url } = data;
|
|
|
|
const appState = {
|
|
paymentMethod: 'paypal',
|
|
paymentCompleted: false,
|
|
paymentType: type,
|
|
};
|
|
|
|
if (type === 'gift-subscription') {
|
|
appState.g1g1 = g1g1;
|
|
}
|
|
|
|
if (type === 'subscription') {
|
|
appState.subscriptionKey = this.subscriptionPlan || this.subscription.key;
|
|
}
|
|
|
|
if (type.indexOf('gift-') === 0) {
|
|
appState.gift = giftData.gift;
|
|
appState.giftReceiver = giftData.receiverName;
|
|
}
|
|
|
|
if (type === 'gems') {
|
|
appState.gemsBlock = gemsBlock;
|
|
url += `?gemsBlock=${gemsBlock.key}`;
|
|
}
|
|
|
|
if (type === 'sku') {
|
|
appState.sku = sku;
|
|
url += `?sku=${sku}`;
|
|
}
|
|
|
|
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
|
|
window.open(url, '_blank');
|
|
|
|
function localStorageChangeHandled (e) {
|
|
if (e.key === 'saved-app-state') {
|
|
window.removeEventListener('storage', localStorageChangeHandled);
|
|
const newState = e.newValue ? JSON.parse(e.newValue) : {};
|
|
if (newState.paymentCompleted) window.location.reload(true);
|
|
}
|
|
}
|
|
|
|
// Listen for changes to local storage, indicating that the payment completed
|
|
window.addEventListener('storage', localStorageChangeHandled);
|
|
},
|
|
async redirectToStripe (data) {
|
|
if (!stripeInstance) {
|
|
stripeInstance = window.Stripe(STRIPE_PUB_KEY);
|
|
}
|
|
if (!this.checkGemAmount(data)) return;
|
|
|
|
let sub = false;
|
|
|
|
if (data.subscription) {
|
|
sub = data.subscription;
|
|
} else if (data.gift && data.gift.type === 'subscription') {
|
|
sub = data.gift.subscription.key;
|
|
}
|
|
|
|
sub = sub && subscriptionBlocks[sub];
|
|
|
|
let paymentType;
|
|
if (sub === false && !data.gift) paymentType = 'gems';
|
|
if (sub !== false && !data.gift) paymentType = 'subscription';
|
|
if (data.group || data.groupToCreate) paymentType = 'groupPlan';
|
|
if (data.gift && data.gift.type === 'gems') paymentType = 'gift-gems';
|
|
if (data.gift && data.gift.type === 'subscription') paymentType = 'gift-subscription';
|
|
if (data.sku) paymentType = 'sku';
|
|
|
|
let url = '/stripe/checkout-session';
|
|
const postData = {};
|
|
|
|
if (data.groupToCreate) {
|
|
url = '/api/v4/groups/create-plan';
|
|
postData.groupToCreate = data.groupToCreate;
|
|
postData.paymentType = 'Stripe';
|
|
}
|
|
|
|
if (data.gemsBlock) postData.gemsBlock = data.gemsBlock.key;
|
|
if (data.gift) {
|
|
data.gift.uuid = data.uuid;
|
|
postData.gift = data.gift;
|
|
}
|
|
if (data.subscription) postData.sub = sub.key;
|
|
if (data.coupon) postData.coupon = data.coupon;
|
|
if (data.groupId) postData.groupId = data.groupId;
|
|
if (data.demographics) postData.demographics = data.demographics;
|
|
if (data.sku) postData.sku = data.sku;
|
|
|
|
const response = await axios.post(url, postData);
|
|
|
|
const appState = {
|
|
paymentMethod: 'stripe',
|
|
paymentCompleted: false,
|
|
paymentType,
|
|
};
|
|
if (paymentType === 'gift-subscription') {
|
|
appState.g1g1 = data.g1g1;
|
|
}
|
|
if (paymentType === 'subscription') {
|
|
appState.subscriptionKey = sub.key;
|
|
} else if (paymentType === 'groupPlan') {
|
|
appState.subscriptionKey = sub.key;
|
|
|
|
// Handle new user signup
|
|
if (!this.$store.state.isUserLoggedIn) {
|
|
appState.newSignup = true;
|
|
}
|
|
|
|
if (data.groupToCreate) {
|
|
appState.newGroup = true;
|
|
appState.group = pick(response.data.data.group, ['_id', 'memberCount', 'name', 'type']);
|
|
} else {
|
|
appState.newGroup = false;
|
|
appState.group = pick(data.group, ['_id', 'memberCount', 'name', 'type']);
|
|
}
|
|
} else if (paymentType.indexOf('gift-') === 0) {
|
|
appState.gift = data.gift;
|
|
appState.giftReceiver = data.receiverName;
|
|
} else if (paymentType === 'gems') {
|
|
appState.gemsBlock = data.gemsBlock;
|
|
}
|
|
|
|
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
|
|
|
|
try {
|
|
const checkoutSessionResult = await stripeInstance.redirectToCheckout({
|
|
sessionId: response.data.data.sessionId,
|
|
});
|
|
if (checkoutSessionResult.error) {
|
|
console.error(checkoutSessionResult.error); // eslint-disable-line
|
|
alert(`Error while redirecting to Stripe: ${checkoutSessionResult.error.message}`);
|
|
throw checkoutSessionResult.error;
|
|
}
|
|
if (paymentType === 'groupPlan') {
|
|
Analytics.track({
|
|
hitType: 'event',
|
|
eventName: 'group plan create',
|
|
eventAction: 'group plan create',
|
|
eventCategory: 'behavior',
|
|
demographics: appState.newGroup.demographics,
|
|
type: appState.newGroup.type,
|
|
}, { trackOnClient: true });
|
|
}
|
|
} catch (err) {
|
|
console.error('Error while redirecting to Stripe', err); // eslint-disable-line
|
|
alert(`Error while redirecting to Stripe: ${err.message}`);
|
|
throw err;
|
|
}
|
|
},
|
|
async redirectToStripeEdit (config) {
|
|
if (!stripeInstance) {
|
|
stripeInstance = window.Stripe(STRIPE_PUB_KEY);
|
|
}
|
|
|
|
let groupId;
|
|
if (config && config.groupId) {
|
|
groupId = config.groupId;
|
|
}
|
|
|
|
const appState = {
|
|
paymentMethod: 'stripe',
|
|
isStripeEdit: true,
|
|
paymentCompleted: false,
|
|
paymentType: groupId ? 'groupPlan' : 'subscription',
|
|
groupId,
|
|
};
|
|
|
|
const response = await axios.post('/stripe/subscribe/edit', {
|
|
groupId,
|
|
});
|
|
|
|
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
|
|
|
|
try {
|
|
const checkoutSessionResult = await stripeInstance.redirectToCheckout({
|
|
sessionId: response.data.data.sessionId,
|
|
});
|
|
if (checkoutSessionResult.error) {
|
|
console.error(checkoutSessionResult.error); // eslint-disable-line
|
|
alert(`Error while redirecting to Stripe: ${checkoutSessionResult.error.message}`);
|
|
throw checkoutSessionResult.error;
|
|
}
|
|
} catch (err) {
|
|
console.error('Error while redirecting to Stripe', err); // eslint-disable-line
|
|
alert(`Error while redirecting to Stripe: ${err.message}`);
|
|
throw err;
|
|
}
|
|
},
|
|
checkGemAmount (data) {
|
|
const isGem = data && data.gift && data.gift.type === 'gems';
|
|
const notEnoughGem = isGem && (!data.gift.gems.amount || data.gift.gems.amount === 0);
|
|
if (notEnoughGem) {
|
|
this.error(this.$t('badAmountOfGemsToPurchase'), true);
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
amazonPaymentsInit (data) {
|
|
if (data.type !== 'single' && data.type !== 'subscription') return;
|
|
|
|
if (data.type === 'single') {
|
|
this.amazonPayments.gemsBlock = data.gemsBlock;
|
|
this.amazonPayments.sku = data.sku;
|
|
}
|
|
|
|
if (data.gift) {
|
|
if (data.gift.gems && data.gift.gems.amount && data.gift.gems.amount <= 0) return;
|
|
data.gift.uuid = data.giftedTo;
|
|
this.amazonPayments.giftReceiver = data.receiverName;
|
|
}
|
|
|
|
if (data.subscription) {
|
|
this.amazonPayments.subscription = data.subscription;
|
|
this.amazonPayments.coupon = data.coupon;
|
|
}
|
|
|
|
if (data.groupId) {
|
|
this.amazonPayments.groupId = data.groupId;
|
|
}
|
|
|
|
if (data.group) { // upgrading a group
|
|
this.amazonPayments.group = data.group;
|
|
}
|
|
|
|
if (data.groupToCreate) { // creating a group
|
|
this.amazonPayments.groupToCreate = data.groupToCreate;
|
|
}
|
|
|
|
if (data.demographics) { // sending demographics
|
|
this.amazonPayments.demographics = data.demographics;
|
|
}
|
|
|
|
this.amazonPayments.gift = data.gift;
|
|
this.amazonPayments.type = data.type;
|
|
},
|
|
amazonOnError (error) {
|
|
window.alert(error.getErrorMessage()); // eslint-disable-line no-alert
|
|
this.reset();
|
|
},
|
|
// Make sure the amazon session is reset between different sessions and after each purchase
|
|
amazonLogout () {
|
|
if (window.amazon && window.amazon.Login && typeof window.amazon.Login.logout === 'function') {
|
|
window.amazon.Login.logout();
|
|
}
|
|
},
|
|
reset () {
|
|
// @TODO: Ensure we are using all of these
|
|
// some vars are set in the payments mixin. We should try to edit in one place
|
|
this.amazonLogout();
|
|
|
|
this.amazonPayments.modal = null;
|
|
this.amazonPayments.type = null;
|
|
this.amazonPayments.loggedIn = false;
|
|
|
|
// Gift
|
|
this.amazonPayments.gift = null;
|
|
this.amazonPayments.giftReceiver = null;
|
|
|
|
this.amazonPayments.billingAgreementId = null;
|
|
this.amazonPayments.orderReferenceId = null;
|
|
this.amazonPayments.paymentSelected = false;
|
|
this.amazonPayments.recurringConsent = false;
|
|
this.amazonPayments.subscription = null;
|
|
this.amazonPayments.coupon = null;
|
|
this.amazonPayments.groupToCreate = null;
|
|
this.amazonPayments.group = null;
|
|
},
|
|
cancelSubscriptionConfirm (config) {
|
|
if (config.canCancel === false) return;
|
|
this.$root.$emit('habitica:cancel-subscription-confirm', config);
|
|
},
|
|
async cancelSubscription (config) {
|
|
this.loading = true;
|
|
|
|
let group;
|
|
if (config && config.group) {
|
|
group = config.group;
|
|
}
|
|
|
|
let paymentMethod = group
|
|
? group.purchased.plan.paymentMethod
|
|
: this.user.purchased.plan.paymentMethod;
|
|
paymentMethod = paymentMethod === 'Amazon Payments' ? 'amazon' : paymentMethod.toLowerCase();
|
|
|
|
const queryParams = {
|
|
noRedirect: true,
|
|
};
|
|
|
|
if (group) {
|
|
queryParams.groupId = group._id;
|
|
}
|
|
|
|
try {
|
|
const cancelUrl = `/${paymentMethod}/subscribe/cancel?${encodeParams(queryParams)}`;
|
|
await axios.get(cancelUrl);
|
|
|
|
if (!config || !config.group) {
|
|
await this.$store.dispatch('user:fetch', { forceLoad: true });
|
|
this.$root.$emit('habitica:subscription-canceled', {
|
|
dateTerminated: this.dateTerminated,
|
|
isGroup: false,
|
|
});
|
|
} else {
|
|
const appState = {
|
|
groupPlanCanceled: true,
|
|
};
|
|
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
|
|
window.location.reload(true);
|
|
}
|
|
|
|
this.loading = false;
|
|
} catch (e) {
|
|
window.alert(e.response.data.message); // eslint-disable-line no-alert
|
|
}
|
|
},
|
|
stripeGroup (options = { group: {}, upgrade: false }) {
|
|
const paymentData = {
|
|
subscription: 'group_monthly',
|
|
coupon: null,
|
|
};
|
|
|
|
if (options.upgrade && options.group._id) {
|
|
paymentData.groupId = options.group._id;
|
|
paymentData.group = options.group;
|
|
} else {
|
|
paymentData.groupToCreate = options.group;
|
|
}
|
|
|
|
this.redirectToStripe(paymentData);
|
|
},
|
|
},
|
|
};
|