Merge branch 'develop' into release

This commit is contained in:
Sabe Jones
2019-05-09 14:32:14 -05:00
15 changed files with 318 additions and 39 deletions
+6
View File
@@ -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 {
+84
View File
@@ -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'}),
+1 -1
View File
@@ -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 {
+25 -18
View File
@@ -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) {
+1 -1
View File
@@ -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!",
+2 -2
View File
@@ -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",
+1
View File
@@ -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": "Weve sent a cancelation confirmation to your email. If you dont see the email, please contact us to prevent future billing disputes.",
"success": "Success!",
"classGear": "Class Gear",
+3 -2
View File
@@ -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 => {