Files
habitica/website/client/components/settings/subscription.vue
Keith Holliday a317b351be Sept 23 fixes (#9074)
* Discover challenges

* Fixed hero loading

* Moved add task button

* Fixed bailey showing

* Added logs for bad sub data

* Fixed blurb editing

* Added confirmation for deleteing message

* Reset invite modals on invite

* fixed group member sorting

* Fixed chat time styles

* Fixed hover on liked

* Fixed like count

* Added reverse

* Fixed editing party

* Added leader conditions

* Added search

* Added loading

* Reset members when leaving party

* Rounded pending

* Fixed overflow on collecting quests

* Added to invite friends

* Hid summary from party

* Fixed button styles

* Fixed button class

* Removed okay button

* Fixed renav for profile modal

* Added subscription back to menu

* Fixed static link

* Added daily due setting

* Added local auth adding

* Fixed centering of text

* Removed message locally

* Added count for new message

* Added style fix for profile pet

* Fixed achievement popovers

* Fixed white boxes

* Added plain color backgrounds

* fixed challenge mutability

* Fixed challenge editing

* Added notation for large numbers

* Add color text to guild sizes

* Removed membership filters from discover challenges

* Added invites to group

* Cmd + enter send message

* Made leader clickable

* Updated group validation

* Added cancelling autocomplete

* Added mention icon

* Added removing member

* Removed extra string
2017-09-25 13:02:12 -05:00

306 lines
11 KiB
Vue

<template lang="pug">
.standard-page
amazon-payments-modal(:amazon-payments='amazonPayments')
h1 {{ $t('subscription') }}
.row
.col-6
h2 {{ $t('benefits') }}
ul
li
span.hint(:popover="$t('buyGemsGoldText', {gemCostTranslation})",
popover-trigger='mouseenter',
popover-placement='right') {{ $t('buyGemsGold') }}
span.badge.badge-success(v-if='subscription.key !== "basic_earned"') {{ $t('buyGemsGoldCap', buyGemsGoldCap) }}
li
span.hint(:popover="$t('retainHistoryText')", popover-trigger='mouseenter', popover-placement='right') {{ $t('retainHistory') }}
li
span.hint(:popover="$t('doubleDropsText')", popover-trigger='mouseenter', popover-placement='right') {{ $t('doubleDrops') }}
li
span.hint(:popover="$t('mysteryItemText')", popover-trigger='mouseenter', popover-placement='right') {{ $t('mysteryItem') }}
div(v-if='subscription.key !== "basic_earned"')
.badge.badge-success {{ $t('mysticHourglass', mysticHourglass) }}
.small.muted {{ $t('mysticHourglassText') }}
li
span.hint(:popover="$t('exclusiveJackalopePetText')", popover-trigger='mouseenter', popover-placement='right') {{ $t('exclusiveJackalopePet') }}
li
span.hint(:popover="$t('supportDevsText')", popover-trigger='mouseenter', popover-placement='right') {{ $t('supportDevs') }}
.col-6
h2 Plan
table.table.alert.alert-info(v-if='hasSubscription')
tr(v-if='hasCanceledSubscription'): td.alert.alert-warning
span.noninteractive-button.btn-danger {{ $t('canceledSubscription') }}
i.glyphicon.glyphicon-time
| {{ $t('subCanceled') }} &nbsp;
strong {{user.purchased.plan.dateTerminated | date}}
tr(v-if='!hasCanceledSubscription'): td
h4 {{ $t('subscribed') }}
p(v-if='hasPlan && !hasGroupPlan') {{ $t('purchasedPlanId', {purchasedPlanIdInfo}) }}
p(v-if='hasGroupPlan') {{ $t('youHaveGroupPlan') }}
tr(v-if='user.purchased.plan.extraMonths'): td
span.glyphicon.glyphicon-credit-card
| &nbsp; {{ $t('purchasedPlanExtraMonths', {purchasedPlanExtraMonthsDetails}) }}
tr(v-if='hasConsecutiveSubscription'): td
span.glyphicon.glyphicon-forward
| &nbsp; {{ $t('consecutiveSubscription') }}
ul.list-unstyled
li {{ $t('consecutiveMonths') }} {{user.purchased.plan.consecutive.count + user.purchased.plan.consecutive.offset}}
li {{ $t('gemCapExtra') }} {{user.purchased.plan.consecutive.gemCapExtra}}
li {{ $t('mysticHourglasses') }} {{user.purchased.plan.consecutive.trinkets}}
div(v-if='!hasSubscription || hasCanceledSubscription')
h4(v-if='hasCanceledSubscription') {{ $t("resubscribe") }}
.form-group.reduce-top-margin
.radio(v-for='block in subscriptionBlocksOrdered', v-if="block.target !== 'group' && block.canSubscribe === true")
label
input(type="radio", name="subRadio", :value="block.key", v-model='subscription.key')
span(v-if='block.original')
span.label.label-success.line-through
| ${{block.original }}
| {{ $t('subscriptionRateText', {price: block.price, months: block.months}) }}
span(v-if='!block.original')
| {{ $t('subscriptionRateText', {price: block.price, months: block.months}) }}
.form-inline
.form-group
input.form-control(type='text', v-model='subscription.coupon', :placeholder="$t('couponPlaceholder')")
.form-group
button.btn.btn-primary(type='button', @click='applyCoupon(subscription.coupon)') {{ $t("apply") }}
div(v-if='hasSubscription')
.btn.btn-primary(v-if='canEditCardDetails', @click='showStripeEdit()') {{ $t('subUpdateCard') }}
.btn.btn-sm.btn-danger(v-if='canCancelSubscription', @click='cancelSubscription()') {{ $t('cancelSub') }}
small(v-if='!canCancelSubscription', v-html='getCancelSubInfo()')
.subscribe-pay(v-if='!hasSubscription || hasCanceledSubscription')
h3 {{ $t('subscribeUsing') }}
.row.text-center
.col-md-4
button.purchase.btn.btn-primary(@click='showStripe({subscription:subscription.key, coupon:subscription.coupon})', :disabled='!subscription.key') {{ $t('card') }}
.col-md-4
a.purchase(:href='paypalPurchaseLink', :disabled='!subscription.key', target='_blank')
img(src='https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png', :alt="$t('paypal')")
.col-md-4
a.btn.btn-secondary.purchase(@click="amazonPaymentsInit({type: 'subscription', subscription:subscription.key, coupon:subscription.coupon})")
img(src='https://payments.amazon.com/gp/cba/button', :alt="$t('amazonPayments')")
.row
.col-6
h2 {{ $t('giftSubscription') }}
ol
li {{ $t('giftSubscriptionText1') }}
li {{ $t('giftSubscriptionText2') }}
li {{ $t('giftSubscriptionText3') }}
h4 {{ $t('giftSubscriptionText4') }}
</template>
<style scoped>
.badge.badge-success {
color: #fff;
}
.subscribe-pay {
margin-top: 1em;
}
</style>
<script>
import axios from 'axios';
import moment from 'moment';
import filter from 'lodash/filter';
import sortBy from 'lodash/sortBy';
import min from 'lodash/min';
import { mapState } from 'client/libs/store';
import encodeParams from 'client/libs/encodeParams';
import subscriptionBlocks from '../../../common/script/content/subscriptionBlocks';
import planGemLimits from '../../../common/script/libs/planGemLimits';
import amazonPaymentsModal from '../payments/amazonModal';
import paymentsMixin from '../../mixins/payments';
export default {
mixins: [paymentsMixin],
components: {
amazonPaymentsModal,
},
data () {
return {
gemCostTranslation: {
gemCost: planGemLimits.convRate,
gemLimit: planGemLimits.convRate,
},
subscription: {
key: 'basic_earned',
},
amazonPayments: {},
paymentMethods: {
AMAZON_PAYMENTS: 'Amazon Payments',
STRIPE: 'Stripe',
GOOGLE: 'Google',
APPLE: 'Apple',
PAYPAL: 'Paypal',
GIFT: 'Gift',
},
};
},
filters: {
date (value) {
if (!value) return '';
return moment(value);
// return moment(value).format(this.user.preferences.dateFormat); // @TODO make that work (`TypeError: this is undefined`)
},
},
computed: {
...mapState({user: 'user.data', credentials: 'credentials'}),
subscriptionBlocksOrdered () {
let subscriptions = filter(subscriptionBlocks, (o) => {
return o.discount !== true;
});
return sortBy(subscriptions, [(o) => {
return o.months;
}]);
},
purchasedPlanIdInfo () {
if (!this.subscriptionBlocks[this.user.purchased.plan.planId]) {
// @TODO: find which subs are in the common
console.log(this.subscriptionBlocks[this.user.purchased.plan.planId]); // eslint-disable-line
return {
price: 0,
months: 0,
plan: '',
};
}
return {
price: this.subscriptionBlocks[this.user.purchased.plan.planId].price,
months: this.subscriptionBlocks[this.user.purchased.plan.planId].months,
plan: this.user.purchased.plan.paymentMethod,
};
},
subscriptionBlocks () {
return subscriptionBlocks;
},
canEditCardDetails () {
return Boolean(
!this.hasCanceledSubscription &&
this.user.purchased.plan.paymentMethod === this.paymentMethods.STRIPE
);
},
hasSubscription () {
return Boolean(this.user.purchased.plan.customerId);
},
hasCanceledSubscription () {
return (
this.hasSubscription &&
Boolean(this.user.purchased.plan.dateTerminated)
);
},
hasPlan () {
return Boolean(this.user.purchased.plan.planId);
},
hasGroupPlan () {
return this.user.purchased.plan.customerId === 'group-plan';
},
hasConsecutiveSubscription () {
return Boolean(this.user.purchased.plan.consecutive.count) || Boolean(this.user.purchased.plan.consecutive.offset);
},
purchasedPlanExtraMonthsDetails () {
return {
months: this.user.purchased.plan.extraMonths.toFixed(2),
};
},
buyGemsGoldCap () {
return {
amount: min(this.gemGoldCap),
};
},
gemGoldCap () {
let baseCap = 25;
let gemCapIncrement = 5;
let capIncrementThreshold = 3;
let gemCapExtra = this.user.purchased.plan.consecutive.gemCapExtra;
let blocks = subscriptionBlocks[this.subscription.key].months / capIncrementThreshold;
let flooredBlocks = Math.floor(blocks);
let userTotalDropCap = baseCap + gemCapExtra + flooredBlocks * gemCapIncrement;
let maxDropCap = 50;
return [userTotalDropCap, maxDropCap];
},
numberOfMysticHourglasses () {
let numberOfHourglasses = subscriptionBlocks[this.subscription.key].months / 3;
return Math.floor(numberOfHourglasses);
},
mysticHourglass () {
return {
amount: this.numberOfMysticHourglasses,
};
},
},
methods: {
async applyCoupon (coupon) {
let response = await axios.get(`/api/v3/coupons/validate/${coupon}`);
if (!response.data.valid) {
// Notification.error(env.t('invalidCoupon'), true);
return;
}
// Notification.text("Coupon applied!");
let subs = subscriptionBlocks;
subs.basic_6mo.discount = true;
subs.google_6mo.discount = false;
},
canCancelSubscription () {
return (
this.user.purchased.plan.paymentMethod !== this.paymentMethods.GOOGLE &&
this.user.purchased.plan.paymentMethod !== this.paymentMethods.APPLE &&
!this.hasCanceledSubscription &&
!this.hasGroupPlan
);
},
async cancelSubscription (config) {
if (config && config.group && !confirm(this.$t('confirmCancelGroupPlan'))) return;
if (!confirm(this.$t('sureCancelSub'))) return;
let group;
if (config && config.group) {
group = config.group;
}
let paymentMethod = this.user.purchased.plan.paymentMethod;
if (group) {
paymentMethod = group.purchased.plan.paymentMethod;
}
if (paymentMethod === 'Amazon Payments') {
paymentMethod = 'amazon';
} else {
paymentMethod = paymentMethod.toLowerCase();
}
let queryParams = {
_id: this.user._id,
apiToken: this.credentials.API_TOKEN,
noRedirect: true,
};
if (group) {
queryParams.groupId = group._id;
}
let cancelUrl = `/${paymentMethod}/subscribe/cancel?${encodeParams(queryParams)}`;
await axios.get(cancelUrl);
// Success
alert(this.$t('paypalCanceled'));
this.$router.push('/');
},
getCancelSubInfo () {
return this.$t(`cancelSubInfo${this.user.purchased.plan.paymentMethod}`);
},
},
};
</script>