Merge branch 'develop' into release
This commit is contained in:
@@ -12,6 +12,8 @@ div
|
||||
banned-account-modal
|
||||
amazon-payments-modal(v-if='!isStaticPage')
|
||||
payments-success-modal
|
||||
sub-cancel-modal-confirm(v-if='isUserLoaded')
|
||||
sub-canceled-modal(v-if='isUserLoaded')
|
||||
snackbars
|
||||
router-view(v-if="!isUserLoggedIn || isStaticPage")
|
||||
template(v-else)
|
||||
@@ -187,6 +189,8 @@ import notifications from 'client/mixins/notifications';
|
||||
import { setup as setupPayments } from 'client/libs/payments';
|
||||
import amazonPaymentsModal from 'client/components/payments/amazonModal';
|
||||
import paymentsSuccessModal from 'client/components/payments/successModal';
|
||||
import subCancelModalConfirm from 'client/components/payments/cancelModalConfirm';
|
||||
import subCanceledModal from 'client/components/payments/canceledModal';
|
||||
|
||||
import spellsMixin from 'client/mixins/spells';
|
||||
import { CONSTANTS, getLocalSetting, removeLocalSetting } from 'client/libs/userlocalManager';
|
||||
@@ -210,6 +214,8 @@ export default {
|
||||
amazonPaymentsModal,
|
||||
bannedAccountModal,
|
||||
paymentsSuccessModal,
|
||||
subCancelModalConfirm,
|
||||
subCanceledModal,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -123,3 +123,87 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#subscription-cancel-modal, #subscription-canceled-modal {
|
||||
.modal-content {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&.modal-hidden-footer .modal-body {
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
justify-content: center;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 0px;
|
||||
border-top-right-radius: 8px;
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom: none;
|
||||
background: $white;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
border-radius: 50%;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
background: $gray-700;
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
justify-content: center;
|
||||
border-top: none;
|
||||
|
||||
.small-text {
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding-top: 16px;
|
||||
padding-bottom: 24px;
|
||||
background: white;
|
||||
|
||||
.modal-body-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
|
||||
.btn.btn-primary {
|
||||
margin-top: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.cancel-text {
|
||||
color: $gray-50;
|
||||
line-height: 1.71;
|
||||
}
|
||||
|
||||
.details-block {
|
||||
background: $gray-700;
|
||||
border-radius: 4px;
|
||||
padding: 8px 24px;
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.auto-renew {
|
||||
margin-top: 16px;
|
||||
color: $orange-10;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="7" height="38" viewBox="0 0 7 38">
|
||||
<path fill="none" fill-rule="evenodd" stroke="#FFF" stroke-linecap="square" stroke-width="7" d="M3.5 4v17m0 12v1"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 209 B |
@@ -29,13 +29,14 @@
|
||||
.btn.btn-primary(v-if='!group.purchased.plan.dateTerminated && group.purchased.plan.paymentMethod === "Stripe"',
|
||||
@click='showStripeEdit({groupId: group.id})') {{ $t('subUpdateCard') }}
|
||||
.btn.btn-sm.btn-danger(v-if='!group.purchased.plan.dateTerminated',
|
||||
@click='cancelSubscription({group: group})') {{ $t('cancelGroupSub') }}
|
||||
@click='cancelSubscriptionConfirm({group: group})') {{ $t('cancelGroupSub') }}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import paymentsMixin from 'client/mixins/payments';
|
||||
import { CONSTANTS, getLocalSetting, removeLocalSetting } from 'client/libs/userlocalManager';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
@@ -45,8 +46,20 @@ export default {
|
||||
group: {},
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.loadGroup();
|
||||
async mounted () {
|
||||
await this.loadGroup();
|
||||
|
||||
let appState = getLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
||||
if (appState) {
|
||||
appState = JSON.parse(appState);
|
||||
if (appState.groupPlanCanceled) {
|
||||
removeLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
||||
this.$root.$emit('habitica:subscription-canceled', {
|
||||
dateTerminated: this.dateTerminated,
|
||||
isGroup: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
|
||||
@@ -400,7 +400,7 @@ export default {
|
||||
|
||||
// List of prompts for user on changes. Sounds like we may need a refactor here, but it is clean for now
|
||||
if (!this.user.flags.welcomed) {
|
||||
this.$store.state.avatarEditorOptions.editingUser = false;
|
||||
if (this.$store.state.avatarEditorOptions) this.$store.state.avatarEditorOptions.editingUser = false;
|
||||
return this.$root.$emit('bv::show::modal', 'avatar-modal');
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<template lang="pug">
|
||||
b-modal#subscription-cancel-modal(
|
||||
size='sm',
|
||||
:hideFooter="true",
|
||||
:modalClass="['modal-hidden-footer']"
|
||||
)
|
||||
div(slot="modal-header")
|
||||
.icon-container.warning-container.d-flex.align-items-center.justify-content-center
|
||||
.svg-icon.warning(v-html="icons.warning", v-once)
|
||||
.row
|
||||
.col-12.modal-body-col
|
||||
h2 {{ config && config.group ? $t('cancelGroupSub') : $t('cancelSub') }}
|
||||
span.cancel-text {{ config && config.group ? $t('confirmCancelGroupPlan') : $t('confirmCancelSub') }}
|
||||
button.btn.btn-danger.mt-4.mb-3(v-once, @click="close(); cancelSubscription(config)") {{ $t('cancelSub') }}
|
||||
a.standard-link(v-once, @click="close()") {{ $t('neverMind') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
#subscription-cancel-modal .modal-header {
|
||||
border-top: 8px solid $maroon-100;
|
||||
|
||||
.warning-container {
|
||||
background: $maroon-100;
|
||||
}
|
||||
|
||||
.warning {
|
||||
width: 7px;
|
||||
height: 38px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import warningIcon from 'assets/svg/exclamation.svg';
|
||||
import closeIcon from 'assets/svg/close.svg';
|
||||
import paymentsMixin from 'client/mixins/payments';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
warning: warningIcon,
|
||||
close: closeIcon,
|
||||
}),
|
||||
config: null,
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:cancel-subscription-confirm', (config) => {
|
||||
this.config = config;
|
||||
this.$root.$emit('bv::show::modal', 'subscription-cancel-modal');
|
||||
});
|
||||
},
|
||||
destroyed () {
|
||||
this.$root.$off('habitica:cancel-subscription-confirm');
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'subscription-cancel-modal');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,100 @@
|
||||
<template lang="pug">
|
||||
b-modal#subscription-canceled-modal(
|
||||
size='sm',
|
||||
:hideFooter="true",
|
||||
:modalClass="['modal-hidden-footer']"
|
||||
)
|
||||
div(slot="modal-header")
|
||||
.svg-icon.close(v-html="icons.close", v-once, @click="close()")
|
||||
.icon-container.check-container.d-flex.align-items-center.justify-content-center
|
||||
.svg-icon.check(v-html="icons.check", v-once)
|
||||
.row
|
||||
.col-12.modal-body-col
|
||||
h2 {{ $t(isGroup ? 'canceledGroupPlan' : 'subCanceledTitle') }}
|
||||
.details-block
|
||||
span
|
||||
| {{ $t('subWillBecomeInactive') }}
|
||||
br
|
||||
strong {{ isGroup ? groupDateTerminated : dateTerminated }}
|
||||
span.auto-renew.small-text(v-once) {{ $t('paymentCanceledDisputes') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
#subscription-canceled-modal .modal-header {
|
||||
border-top: 8px solid #1CA372;
|
||||
|
||||
.check-container {
|
||||
background: #1CA372;
|
||||
}
|
||||
|
||||
.check {
|
||||
width: 35.1px;
|
||||
height: 28px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 24px;
|
||||
right: 20px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: 878190;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#subscription-canceled-modal .modal-body {
|
||||
h2 {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.details-block {
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import checkIcon from 'assets/svg/check.svg';
|
||||
import closeIcon from 'assets/svg/close.svg';
|
||||
import paymentsMixin from 'client/mixins/payments';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
check: checkIcon,
|
||||
close: closeIcon,
|
||||
}),
|
||||
groupDateTerminated: null,
|
||||
isGroup: null,
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:subscription-canceled', ({dateTerminated, isGroup}) => {
|
||||
this.isGroup = isGroup;
|
||||
if (isGroup) {
|
||||
this.groupDateTerminated = dateTerminated;
|
||||
}
|
||||
this.$root.$emit('bv::show::modal', 'subscription-canceled-modal');
|
||||
});
|
||||
},
|
||||
destroyed () {
|
||||
this.$root.$off('habitica:subscription-canceled');
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'subscription-canceled-modal');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
div(v-if='hasSubscription')
|
||||
.btn.btn-primary(v-if='canEditCardDetails', @click='showStripeEdit()') {{ $t('subUpdateCard') }}
|
||||
.btn.btn-sm.btn-danger(v-if='canCancelSubscription && !loading', @click='cancelSubscription()') {{ $t('cancelSub') }}
|
||||
.btn.btn-sm.btn-danger(v-if='canCancelSubscription && !loading', @click='cancelSubscriptionConfirm()') {{ $t('cancelSub') }}
|
||||
small(v-if='!canCancelSubscription && !hasCanceledSubscription', v-html='getCancelSubInfo()')
|
||||
|
||||
.subscribe-pay(v-if='!hasSubscription || hasCanceledSubscription')
|
||||
@@ -104,7 +104,6 @@
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
import filter from 'lodash/filter';
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import min from 'lodash/min';
|
||||
@@ -235,10 +234,6 @@ export default {
|
||||
amount: this.numberOfMysticHourglasses,
|
||||
};
|
||||
},
|
||||
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());
|
||||
},
|
||||
canCancelSubscription () {
|
||||
return (
|
||||
this.user.purchased.plan.paymentMethod !== this.paymentMethods.GOOGLE &&
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
|
||||
.column-background {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 32px;
|
||||
|
||||
&.initial-description {
|
||||
|
||||
@@ -8,13 +8,14 @@ import notificationsMixin from 'client/mixins/notifications';
|
||||
import * as Analytics from 'client/libs/analytics';
|
||||
import { CONSTANTS, setLocalSetting } from 'client/libs/userlocalManager';
|
||||
import pick from 'lodash/pick';
|
||||
import moment from 'moment';
|
||||
|
||||
const habiticaUrl = `${location.protocol}//${location.host}`;
|
||||
|
||||
export default {
|
||||
mixins: [notificationsMixin],
|
||||
computed: {
|
||||
...mapState(['credentials']),
|
||||
...mapState({user: 'user.data', credentials: 'credentials'}),
|
||||
paypalCheckoutLink () {
|
||||
return '/paypal/checkout';
|
||||
},
|
||||
@@ -31,6 +32,10 @@ export default {
|
||||
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());
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
encodeGift (uuid, gift) {
|
||||
@@ -275,10 +280,10 @@ export default {
|
||||
this.amazonPayments.groupToCreate = null;
|
||||
this.amazonPayments.group = null;
|
||||
},
|
||||
cancelSubscriptionConfirm (config) {
|
||||
this.$root.$emit('habitica:cancel-subscription-confirm', config);
|
||||
},
|
||||
async cancelSubscription (config) {
|
||||
if (config && config.group && !confirm(this.$t('confirmCancelGroupPlan'))) return;
|
||||
if (!confirm(this.$t('sureCancelSub'))) return;
|
||||
|
||||
this.loading = true;
|
||||
|
||||
let group;
|
||||
@@ -286,18 +291,10 @@ export default {
|
||||
group = config.group;
|
||||
}
|
||||
|
||||
let paymentMethod = this.user.purchased.plan.paymentMethod;
|
||||
if (group) {
|
||||
paymentMethod = group.purchased.plan.paymentMethod;
|
||||
}
|
||||
let paymentMethod = group ? group.purchased.plan.paymentMethod : this.user.purchased.plan.paymentMethod;
|
||||
paymentMethod = paymentMethod === 'Amazon Payments' ? 'amazon' : paymentMethod.toLowerCase();
|
||||
|
||||
if (paymentMethod === 'Amazon Payments') {
|
||||
paymentMethod = 'amazon';
|
||||
} else {
|
||||
paymentMethod = paymentMethod.toLowerCase();
|
||||
}
|
||||
|
||||
let queryParams = {
|
||||
const queryParams = {
|
||||
noRedirect: true,
|
||||
};
|
||||
|
||||
@@ -309,9 +306,19 @@ export default {
|
||||
const cancelUrl = `/${paymentMethod}/subscribe/cancel?${encodeParams(queryParams)}`;
|
||||
await axios.get(cancelUrl);
|
||||
|
||||
alert(this.$t('paypalCanceled'));
|
||||
// @TODO: We should probably update the api to return the new sub data eventually.
|
||||
await this.$store.dispatch('user:fetch', {forceLoad: true});
|
||||
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) {
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
"continue": "Continue",
|
||||
"accept": "Accept",
|
||||
"reject": "Reject",
|
||||
"neverMind": "Never mind",
|
||||
"neverMind": "Nevermind",
|
||||
"buyMoreGems": "Buy More Gems",
|
||||
"notEnoughGems": "Not enough Gems",
|
||||
"alreadyHave": "Whoops! You already have this item. No need to buy it again!",
|
||||
|
||||
@@ -348,8 +348,8 @@
|
||||
"leaderCannotLeaveGroupWithActiveGroup": "A leader can not leave a group while the group has an active plan",
|
||||
"youHaveGroupPlan": "You have a free subscription because you are a member of a group that has a Group Plan. This will end when you are no longer in the group that has a Group Plan. Any months of extra subscription credit you have will be applied at the end of the Group Plan.",
|
||||
"cancelGroupSub": "Cancel Group Plan",
|
||||
"confirmCancelGroupPlan": "Are you sure you want to cancel the group plan and remove its benefits from all members, including their free subscriptions?",
|
||||
"canceledGroupPlan": "Canceled Group Plan",
|
||||
"confirmCancelGroupPlan": "Are you sure you want to cancel your Group Plan? All Group members will lose their subscription and benefits.",
|
||||
"canceledGroupPlan": "Group Plan Canceled",
|
||||
"groupPlanCanceled": "Group Plan will become inactive on",
|
||||
"purchasedGroupPlanPlanExtraMonths": "You have <%= months %> months of extra group plan credit.",
|
||||
"addManager": "Assign Manager",
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
"paymentYouSentSubscription": "You sent <strong><%= name %></strong> a <%= months %>-months Habitica subscription.",
|
||||
"paymentSubBilling": "Your subscription will be billed <strong>$<%= amount %></strong> every <strong><%= months %> months</strong>.",
|
||||
"paymentAutoRenew": "This subscription will auto-renew until it is canceled. If you need to cancel this subscription, you can do so from your settings.",
|
||||
"paymentCanceledDisputes": "We’ve sent a cancelation confirmation to your email. If you don’t see the email, please contact us to prevent future billing disputes.",
|
||||
"success": "Success!",
|
||||
|
||||
"classGear": "Class Gear",
|
||||
|
||||
@@ -69,8 +69,9 @@
|
||||
"notYetPlan": "Plan not yet available, but click to contact us and we'll keep you updated.",
|
||||
"contactUs": "Contact Us",
|
||||
"checkout": "Checkout",
|
||||
"sureCancelSub": "Are you sure you want to cancel your subscription?",
|
||||
"confirmCancelSub": "Are you sure you want to cancel your subscription? You will lose all of your subscription benefits.",
|
||||
"subCanceled": "Subscription will become inactive on",
|
||||
"subWillBecomeInactive": "Will become inactive",
|
||||
"buyGemsGoldTitle": "To Buy Gems with Gold",
|
||||
"becomeSubscriber": "Become a Subscriber",
|
||||
"subGemPop": "Because you subscribe to Habitica, you can purchase a number of Gems each month using Gold.",
|
||||
@@ -191,7 +192,7 @@
|
||||
"invalidCoupon": "Invalid coupon code.",
|
||||
"couponUsed": "Coupon code already used.",
|
||||
"couponCodeRequired": "The coupon code is required.",
|
||||
"paypalCanceled": "Your subscription has been canceled",
|
||||
"subCanceledTitle": "Subscription Canceled",
|
||||
"earnGemsMonthly": "Earn up to **<%= cap %> Gems** per month",
|
||||
"receiveMysticHourglass": "Receive a Mystic Hourglass!",
|
||||
"receiveMysticHourglasses": "Receive **<%= amount %> Mystic Hourglasses**!",
|
||||
|
||||
@@ -364,12 +364,14 @@ api.getUserChallenges = {
|
||||
$and: [{$or: orOptions}],
|
||||
};
|
||||
|
||||
if (owned && owned === 'not_owned') {
|
||||
query.$and.push({leader: {$ne: user._id}});
|
||||
}
|
||||
if (owned) {
|
||||
if (owned === 'not_owned') {
|
||||
query.$and = [{leader: {$ne: user._id}}];
|
||||
}
|
||||
|
||||
if (owned && owned === 'owned') {
|
||||
query.$and.push({leader: user._id});
|
||||
if (owned === 'owned') {
|
||||
query.$and = [{leader: user._id}];
|
||||
}
|
||||
}
|
||||
|
||||
if (req.query.search) {
|
||||
@@ -400,7 +402,6 @@ api.getUserChallenges = {
|
||||
// .populate('leader', nameFields)
|
||||
const challenges = await mongoQuery.exec();
|
||||
|
||||
|
||||
let resChals = challenges.map(challenge => challenge.toJSON());
|
||||
|
||||
resChals = _.orderBy(resChals, [challenge => {
|
||||
|
||||
Reference in New Issue
Block a user