mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 21:57:22 +01:00
new client 2017 09 19 various fixes: subscriptions, streaks, etc (#9047)
* remove excess brace on settings > subscription screen * prevent User icon > Settings > Subscription page from crashing when subscription has termination date * stop subscription modal from pitching subscription to a subscriber * change placeholder text from Username to Login Name for consistency with other login/register forms * fix test for POST-tasks_user -- streak and dateCompleted weren't being tested correctly * prevent tag selector from appearing in edit screen for a challenge's own tasks * restore Restore Streak when editing a user's Dailies (including their own copies of Challenge and Group Plan Dailies) * remove failing streak test
This commit is contained in:
@@ -131,7 +131,7 @@ describe('POST /tasks/user', () => {
|
|||||||
expect(task.updatedAt).not.to.equal('tomorrow');
|
expect(task.updatedAt).not.to.equal('tomorrow');
|
||||||
expect(task.challenge).not.to.equal('no');
|
expect(task.challenge).not.to.equal('no');
|
||||||
expect(task.completed).to.equal(false);
|
expect(task.completed).to.equal(false);
|
||||||
expect(task.streak).not.to.equal('never');
|
expect(task.dateCompleted).not.to.equal('never');
|
||||||
expect(task.value).not.to.equal(324);
|
expect(task.value).not.to.equal(324);
|
||||||
expect(task.yesterDaily).to.equal(true);
|
expect(task.yesterDaily).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -81,80 +81,87 @@
|
|||||||
.col-6.offset-3 {{ $t('buyGemsSupportsDevs') }}
|
.col-6.offset-3 {{ $t('buyGemsSupportsDevs') }}
|
||||||
|
|
||||||
div(v-show='selectedPage === "subscribe"')
|
div(v-show='selectedPage === "subscribe"')
|
||||||
.row.text-center
|
div(v-if='hasSubscription')
|
||||||
h2.mx-auto.text-leadin {{ $t('subscriptionBenefitLeadin') }}
|
.row.text-center
|
||||||
.row
|
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
|
||||||
.col
|
.row.text-center
|
||||||
+featureBullet("{{ $t('subscriptionBenefit1') }}")
|
.col
|
||||||
+featureBullet("{{ $t('subscriptionBenefit2') }}")
|
p(v-html='$t("subscriptionAlreadySubscribed1")')
|
||||||
+featureBullet("{{ $t('subscriptionBenefit3') }}")
|
div(v-if='!hasSubscription')
|
||||||
.col
|
.row.text-center
|
||||||
+featureBullet("{{ $t('subscriptionBenefit4') }}")
|
h2.mx-auto.text-leadin {{ $t('subscriptionBenefitLeadin') }}
|
||||||
+featureBullet("{{ $t('subscriptionBenefit5') }}")
|
.row
|
||||||
+featureBullet("{{ $t('subscriptionBenefit6') }}")
|
.col
|
||||||
.card-deck
|
+featureBullet("{{ $t('subscriptionBenefit1') }}")
|
||||||
.card.text-center
|
+featureBullet("{{ $t('subscriptionBenefit2') }}")
|
||||||
.card-body
|
+featureBullet("{{ $t('subscriptionBenefit3') }}")
|
||||||
.subscription-price
|
.col
|
||||||
span.superscript $
|
+featureBullet("{{ $t('subscriptionBenefit4') }}")
|
||||||
span 4
|
+featureBullet("{{ $t('subscriptionBenefit5') }}")
|
||||||
span.superscript.muted .99
|
+featureBullet("{{ $t('subscriptionBenefit6') }}")
|
||||||
.small {{ $t('everyMonth') }}
|
.card-deck
|
||||||
.divider
|
.card.text-center
|
||||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:25})')
|
.card-body
|
||||||
.spacer
|
.subscription-price
|
||||||
button.btn.btn-primary {{ $t('select') }}
|
span.superscript $
|
||||||
.card.text-center
|
span 4
|
||||||
.card-body
|
span.superscript.muted .99
|
||||||
.subscription-price
|
.small {{ $t('everyMonth') }}
|
||||||
span.superscript $
|
.divider
|
||||||
span 14
|
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:25})')
|
||||||
span.superscript.muted .99
|
.spacer
|
||||||
.small {{ $t('everyXMonths', {interval: 3}) }}
|
button.btn.btn-primary {{ $t('select') }}
|
||||||
.divider
|
.card.text-center
|
||||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:30})')
|
.card-body
|
||||||
p.benefits(v-markdown='$t("receiveMysticHourglass")')
|
.subscription-price
|
||||||
button.btn.btn-primary {{ $t('select') }}
|
span.superscript $
|
||||||
.card.text-center
|
span 14
|
||||||
.card-body
|
span.superscript.muted .99
|
||||||
.subscription-price
|
.small {{ $t('everyXMonths', {interval: 3}) }}
|
||||||
span.superscript $
|
.divider
|
||||||
span 29
|
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:30})')
|
||||||
span.superscript.muted .99
|
p.benefits(v-markdown='$t("receiveMysticHourglass")')
|
||||||
.small {{ $t('everyXMonths', {interval: 6}) }}
|
button.btn.btn-primary {{ $t('select') }}
|
||||||
.divider
|
.card.text-center
|
||||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:35})')
|
.card-body
|
||||||
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:2})')
|
.subscription-price
|
||||||
button.btn.btn-primary {{ $t('select') }}
|
span.superscript $
|
||||||
.card.text-center
|
span 29
|
||||||
.card-body
|
span.superscript.muted .99
|
||||||
.subscription-price
|
.small {{ $t('everyXMonths', {interval: 6}) }}
|
||||||
span.superscript $
|
.divider
|
||||||
span 47
|
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:35})')
|
||||||
span.superscript.muted .99
|
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:2})')
|
||||||
.small {{ $t('everyYear') }}
|
button.btn.btn-primary {{ $t('select') }}
|
||||||
.divider
|
.card.text-center
|
||||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:45})')
|
.card-body
|
||||||
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:4})')
|
.subscription-price
|
||||||
button.btn.btn-primary {{ $t('select') }}
|
span.superscript $
|
||||||
.row.text-center
|
span 47
|
||||||
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
|
span.superscript.muted .99
|
||||||
.row.text-center
|
.small {{ $t('everyYear') }}
|
||||||
a.mx-auto {{ $t('haveCouponCode') }}
|
.divider
|
||||||
.card-deck
|
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:45})')
|
||||||
.card.text-center.payment-method
|
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:4})')
|
||||||
.card-body(@click='showStripe({})')
|
button.btn.btn-primary {{ $t('select') }}
|
||||||
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
|
.row.text-center
|
||||||
.card.text-center.payment-method
|
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
|
||||||
a.card-body.paypal(:href='paypalCheckoutLink', target='_blank')
|
.row.text-center
|
||||||
img(src='~assets/images/paypal.png')
|
a.mx-auto {{ $t('haveCouponCode') }}
|
||||||
.card.text-center.payment-method
|
.card-deck
|
||||||
.card-body.amazon(@click="amazonPaymentsInit({type: 'single'})")
|
.card.text-center.payment-method
|
||||||
img(src='~assets/images/amazon-payments.png')
|
.card-body(@click='showStripe({})')
|
||||||
.row.text-center
|
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
|
||||||
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
|
.card.text-center.payment-method
|
||||||
.row.text-center.text-outtro
|
a.card-body.paypal(:href='paypalCheckoutLink', target='_blank')
|
||||||
.col-6.offset-3 {{ $t('subscribeSupportsDevs') }}
|
img(src='~assets/images/paypal.png')
|
||||||
|
.card.text-center.payment-method
|
||||||
|
.card-body.amazon(@click="amazonPaymentsInit({type: 'single'})")
|
||||||
|
img(src='~assets/images/amazon-payments.png')
|
||||||
|
.row.text-center
|
||||||
|
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
|
||||||
|
.row.text-center.text-outtro
|
||||||
|
.col-6.offset-3 {{ $t('subscribeSupportsDevs') }}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@@ -340,6 +347,9 @@
|
|||||||
startingPageOption () {
|
startingPageOption () {
|
||||||
return this.$store.state.gemModalOptions.startingPage;
|
return this.$store.state.gemModalOptions.startingPage;
|
||||||
},
|
},
|
||||||
|
hasSubscription () {
|
||||||
|
return Boolean(this.user.purchased.plan.customerId);
|
||||||
|
},
|
||||||
userReachedGemCap () {
|
userReachedGemCap () {
|
||||||
return this.user.purchased.plan.customerId && this.user.purchased.plan.gemsBought >= this.user.purchased.plan.consecutive.gemCapExtra + this.planGemLimits.convCap;
|
return this.user.purchased.plan.customerId && this.user.purchased.plan.gemsBought >= this.user.purchased.plan.consecutive.gemCapExtra + this.planGemLimits.convCap;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
tr(v-if='hasCanceledSubscription'): td.alert.alert-warning
|
tr(v-if='hasCanceledSubscription'): td.alert.alert-warning
|
||||||
span.noninteractive-button.btn-danger {{ $t('canceledSubscription') }}
|
span.noninteractive-button.btn-danger {{ $t('canceledSubscription') }}
|
||||||
i.glyphicon.glyphicon-time
|
i.glyphicon.glyphicon-time
|
||||||
| {{ $t('subCanceled') }}
|
| {{ $t('subCanceled') }}
|
||||||
strong {{user.purchased.plan.dateTerminated | date}}
|
strong {{user.purchased.plan.dateTerminated | date}}
|
||||||
tr(v-if='!hasCanceledSubscription'): td
|
tr(v-if='!hasCanceledSubscription'): td
|
||||||
h4 {{ $t('subscribed') }}
|
h4 {{ $t('subscribed') }}
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
| {{ $t('consecutiveSubscription') }}
|
| {{ $t('consecutiveSubscription') }}
|
||||||
ul.list-unstyled
|
ul.list-unstyled
|
||||||
li {{ $t('consecutiveMonths') }} {{user.purchased.plan.consecutive.count + user.purchased.plan.consecutive.offset}}
|
li {{ $t('consecutiveMonths') }} {{user.purchased.plan.consecutive.count + user.purchased.plan.consecutive.offset}}
|
||||||
li {{ $t('gemCapExtra') }}} {{user.purchased.plan.consecutive.gemCapExtra}}
|
li {{ $t('gemCapExtra') }} {{user.purchased.plan.consecutive.gemCapExtra}}
|
||||||
li {{ $t('mysticHourglasses') }} {{user.purchased.plan.consecutive.trinkets}}
|
li {{ $t('mysticHourglasses') }} {{user.purchased.plan.consecutive.trinkets}}
|
||||||
|
|
||||||
div(v-if='!hasSubscription || hasCanceledSubscription')
|
div(v-if='!hasSubscription || hasCanceledSubscription')
|
||||||
@@ -147,7 +147,8 @@ export default {
|
|||||||
filters: {
|
filters: {
|
||||||
date (value) {
|
date (value) {
|
||||||
if (!value) return '';
|
if (!value) return '';
|
||||||
return moment(value).formate(this.user.preferences.dateFormat);
|
return moment(value);
|
||||||
|
// return moment(value).format(this.user.preferences.dateFormat); // @TODO make that work (`TypeError: this is undefined`)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -156,6 +157,7 @@ export default {
|
|||||||
let couponString = '';
|
let couponString = '';
|
||||||
if (this.subscription.coupon) couponString = `&coupon=${this.subscription.coupon}`;
|
if (this.subscription.coupon) couponString = `&coupon=${this.subscription.coupon}`;
|
||||||
return `/paypal/subscribe?_id=${this.user._id}&apiToken=${this.user.apiToken}&sub=${this.subscription.key}${couponString}`;
|
return `/paypal/subscribe?_id=${this.user._id}&apiToken=${this.user.apiToken}&sub=${this.subscription.key}${couponString}`;
|
||||||
|
// @TODO don't put API Token in URL parameters
|
||||||
},
|
},
|
||||||
subscriptionBlocksOrdered () {
|
subscriptionBlocksOrdered () {
|
||||||
let subscriptions = filter(subscriptionBlocks, (o) => {
|
let subscriptions = filter(subscriptionBlocks, (o) => {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
.strike
|
.strike
|
||||||
span OR
|
span OR
|
||||||
.form
|
.form
|
||||||
input.form-control(type='text', placeholder='Username', v-model='username', :class='{"input-valid": username.length > 0}')
|
input.form-control(type='text', placeholder='Login Name', v-model='username', :class='{"input-valid": username.length > 0}')
|
||||||
input.form-control(type='email', placeholder='Email', v-model='email', :class='{"input-invalid": emailInvalid, "input-valid": emailValid}')
|
input.form-control(type='email', placeholder='Email', v-model='email', :class='{"input-invalid": emailInvalid, "input-valid": emailValid}')
|
||||||
input.form-control(type='password', placeholder='Password', v-model='password', :class='{"input-valid": password.length > 0}')
|
input.form-control(type='password', placeholder='Password', v-model='password', :class='{"input-valid": password.length > 0}')
|
||||||
input.form-control(type='password', placeholder='Confirm Password', v-model='passwordConfirm', :class='{"input-invalid": passwordConfirmInvalid, "input-valid": passwordConfirmValid}')
|
input.form-control(type='password', placeholder='Confirm Password', v-model='passwordConfirm', :class='{"input-invalid": passwordConfirmInvalid, "input-valid": passwordConfirmValid}')
|
||||||
|
|||||||
@@ -117,7 +117,7 @@
|
|||||||
span.custom-control-indicator
|
span.custom-control-indicator
|
||||||
span.custom-control-description {{ $t('dayOfWeek') }}
|
span.custom-control-description {{ $t('dayOfWeek') }}
|
||||||
|
|
||||||
.option
|
.option(v-if="task.userId")
|
||||||
label(v-once) {{ $t('tags') }}
|
label(v-once) {{ $t('tags') }}
|
||||||
.category-wrap(@click="showTagsSelect = !showTagsSelect")
|
.category-wrap(@click="showTagsSelect = !showTagsSelect")
|
||||||
span.category-select(v-if='task.tags && task.tags.length === 0') {{$t('none')}}
|
span.category-select(v-if='task.tags && task.tags.length === 0') {{$t('none')}}
|
||||||
@@ -135,12 +135,18 @@
|
|||||||
span.custom-control-description(v-once) {{ tag.name }}
|
span.custom-control-description(v-once) {{ tag.name }}
|
||||||
.row
|
.row
|
||||||
button.btn.btn-primary(@click="showTagsSelect = !showTagsSelect") {{$t('close')}}
|
button.btn.btn-primary(@click="showTagsSelect = !showTagsSelect") {{$t('close')}}
|
||||||
|
|
||||||
.option(v-if="task.type === 'habit'")
|
.option(v-if="task.type === 'habit'")
|
||||||
label(v-once) {{ $t('resetStreak') }}
|
label(v-once) {{ $t('resetStreak') }}
|
||||||
b-dropdown(:text="$t(task.frequency)")
|
b-dropdown(:text="$t(task.frequency)")
|
||||||
b-dropdown-item(v-for="frequency in ['daily', 'weekly', 'monthly']", :key="frequency", @click="task.frequency = frequency", :class="{active: task.frequency === frequency}")
|
b-dropdown-item(v-for="frequency in ['daily', 'weekly', 'monthly']", :key="frequency", @click="task.frequency = frequency", :class="{active: task.frequency === frequency}")
|
||||||
| {{ $t(frequency) }}
|
| {{ $t(frequency) }}
|
||||||
|
|
||||||
|
.option(v-if="task.type === 'daily' && task.userId")
|
||||||
|
.form-group
|
||||||
|
label(v-once) {{ $t('restoreStreak') }}
|
||||||
|
input(type="number", v-model="task.streak", min="0", required)
|
||||||
|
|
||||||
.option.group-options(v-if='groupId')
|
.option.group-options(v-if='groupId')
|
||||||
label(v-once) Assigned To
|
label(v-once) Assigned To
|
||||||
.category-wrap(@click="showAssignedSelect = !showAssignedSelect")
|
.category-wrap(@click="showAssignedSelect = !showAssignedSelect")
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
"manageSub": "Click to manage subscription",
|
"manageSub": "Click to manage subscription",
|
||||||
"cancelSub": "Cancel Subscription",
|
"cancelSub": "Cancel Subscription",
|
||||||
"cancelSubInfoGoogle": "Please go to the \"Account\" > \"Subscriptions\" section of the Google Play Store app to cancel your subscription or to see your subscription's termination date if you have already cancelled it. This screen is not able to show you whether your subscription has been cancelled.",
|
"cancelSubInfoGoogle": "Please go to the \"Account\" > \"Subscriptions\" section of the Google Play Store app to cancel your subscription or to see your subscription's termination date if you have already cancelled it. This screen is not able to show you whether your subscription has been cancelled.",
|
||||||
"cancelSubInfoApple": "Please follow <a href=\"https://support.apple.com/en-us/HT202039\">Apple’s official instructions</a> to cancel your subscription or to see your subscription's termination date if you have already cancelled it. This screen is not able to show you whether your subscription has been cancelled.",
|
"cancelSubInfoApple": "Please follow <a href=\"https://support.apple.com/en-us/HT202039\">Apple's official instructions</a> to cancel your subscription or to see your subscription's termination date if you have already cancelled it. This screen is not able to show you whether your subscription has been cancelled.",
|
||||||
"canceledSubscription": "Canceled Subscription",
|
"canceledSubscription": "Canceled Subscription",
|
||||||
"cancelingSubscription": "Canceling the subscription",
|
"cancelingSubscription": "Canceling the subscription",
|
||||||
"adminSub": "Administrator Subscriptions",
|
"adminSub": "Administrator Subscriptions",
|
||||||
@@ -199,5 +199,7 @@
|
|||||||
"subscriptionBenefit5": "Receive the exclusive Royal Purple Jackalope pet!",
|
"subscriptionBenefit5": "Receive the exclusive Royal Purple Jackalope pet!",
|
||||||
"subscriptionBenefit6": "Earn Mystic Hourglasses for use in the Time Travelers' Shop!",
|
"subscriptionBenefit6": "Earn Mystic Hourglasses for use in the Time Travelers' Shop!",
|
||||||
"haveCouponCode": "Do you have a coupon code?",
|
"haveCouponCode": "Do you have a coupon code?",
|
||||||
|
"subscriptionAlreadySubscribedLeadIn": "Thanks for subscribing!",
|
||||||
|
"subscriptionAlreadySubscribed1": "To see your subscription details and cancel, renew, or change your subscription, please go to <a href='/user/settings/subscription'>User icon > Settings > Subscription</a>.",
|
||||||
"purchaseAll": "Purchase All"
|
"purchaseAll": "Purchase All"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user