Gift 1 Get 1 Promo 2018-19! (#10915)

* feat(subscription): promo banner in modal

* feat(subscription): promo banner on main page

* fix(banners): remove extraneous margin adjustment

* fix(banners): various

* feat(promotion): gift 1, get 1

* fix(promo): various

* chore(promo): add Bailey

* fix(promo): use different email template for promo beneficiary

* fix(promo): turns out Winter is meaningful
This commit is contained in:
Sabe Jones
2018-12-18 15:28:53 -06:00
committed by GitHub
parent bd1f6918ba
commit 8220199e49
18 changed files with 533 additions and 282 deletions

View File

@@ -209,7 +209,7 @@ describe('payments/index', () => {
await api.createSubscription(data);
let msg = '\`Hello recipient, sender has sent you 3 months of subscription!\`';
expect(user.sendMessage).to.be.calledOnce;
expect(user.sendMessage).to.be.calledTwice;
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
});
@@ -247,6 +247,77 @@ describe('payments/index', () => {
},
});
});
context('Winter 2018-19 Gift-1-Get-1 Promotion', async () => {
it('creates a gift subscription for purchaser and recipient if none exist', async () => {
await api.createSubscription(data);
expect(user.items.pets['Jackalope-RoyalPurple']).to.eql(5);
expect(user.purchased.plan.customerId).to.eql('Gift');
expect(user.purchased.plan.dateTerminated).to.exist;
expect(user.purchased.plan.dateUpdated).to.exist;
expect(user.purchased.plan.dateCreated).to.exist;
expect(recipient.items.pets['Jackalope-RoyalPurple']).to.eql(5);
expect(recipient.purchased.plan.customerId).to.eql('Gift');
expect(recipient.purchased.plan.dateTerminated).to.exist;
expect(recipient.purchased.plan.dateUpdated).to.exist;
expect(recipient.purchased.plan.dateCreated).to.exist;
});
it('adds extraMonths to existing subscription for purchaser and creates a gift subscription for recipient without sub', async () => {
user.purchased.plan = plan;
expect(user.purchased.plan.extraMonths).to.eql(0);
await api.createSubscription(data);
expect(user.purchased.plan.extraMonths).to.eql(3);
expect(recipient.items.pets['Jackalope-RoyalPurple']).to.eql(5);
expect(recipient.purchased.plan.customerId).to.eql('Gift');
expect(recipient.purchased.plan.dateTerminated).to.exist;
expect(recipient.purchased.plan.dateUpdated).to.exist;
expect(recipient.purchased.plan.dateCreated).to.exist;
});
it('adds extraMonths to existing subscription for recipient and creates a gift subscription for purchaser without sub', async () => {
recipient.purchased.plan = plan;
expect(recipient.purchased.plan.extraMonths).to.eql(0);
await api.createSubscription(data);
expect(recipient.purchased.plan.extraMonths).to.eql(3);
expect(user.items.pets['Jackalope-RoyalPurple']).to.eql(5);
expect(user.purchased.plan.customerId).to.eql('Gift');
expect(user.purchased.plan.dateTerminated).to.exist;
expect(user.purchased.plan.dateUpdated).to.exist;
expect(user.purchased.plan.dateCreated).to.exist;
});
it('adds extraMonths to existing subscriptions for purchaser and recipient', async () => {
user.purchased.plan = plan;
recipient.purchased.plan = plan;
expect(user.purchased.plan.extraMonths).to.eql(0);
expect(recipient.purchased.plan.extraMonths).to.eql(0);
await api.createSubscription(data);
expect(user.purchased.plan.extraMonths).to.eql(3);
expect(recipient.purchased.plan.extraMonths).to.eql(3);
});
it('sends a private message about the promotion', async () => {
await api.createSubscription(data);
let msg = '\`Hello sender, you received 3 months of subscription as part of our holiday gift-giving promotion!\`';
expect(user.sendMessage).to.be.calledTwice;
expect(user.sendMessage).to.be.calledWith(user, { senderMsg: msg });
});
});
});
context('Purchasing a subscription for self', () => {

View File

@@ -16,18 +16,24 @@ div
router-view(v-if="!isUserLoggedIn || isStaticPage")
template(v-else)
template(v-if="isUserLoaded")
div.resting-banner(v-show="showRestingBanner", ref="restingBanner")
.resting-banner(v-show="showRestingBanner", ref="restingBanner")
span.content
span.label.d-inline.d-sm-none {{ $t('innCheckOutBannerShort') }}
span.label.d-none.d-sm-inline {{ $t('innCheckOutBanner') }}
span.separator |
span.resume(@click="resumeDamage()") {{ $t('resumeDamage') }}
div.closepadding(@click="hideBanner()")
.closepadding(@click="hideBanner()")
span.svg-icon.inline.icon-10(aria-hidden="true", v-html="icons.close")
.g1g1-banner.d-flex.justify-content-center.align-items-center(v-if="!giftingHidden")
.svg-icon.svg-gifts.left-gift(v-html="icons.gifts")
router-link(:to="{name: 'subscription'}") {{ $t('g1g1Announcement') }}
.svg-icon.svg-gifts.right-gift(v-html="icons.gifts")
.closepadding(@click="hideGiftingBanner()")
span.svg-icon.inline.icon-10(aria-hidden="true", v-html="icons.close")
notifications-display
app-menu(:class='{"restingInn": showRestingBanner}' :style="{ marginTop: bannerHeight + 'px' }")
app-menu
.container-fluid
app-header(:class='{"restingInn": showRestingBanner}')
app-header
buyModal(
:item="selectedItemToBuy || {}",
:withPin="true",
@@ -50,6 +56,13 @@ div
<style lang='scss' scoped>
@import '~client/assets/scss/colors.scss';
#app {
height: calc(100% - 56px); /* 56px is the menu */
display: flex;
flex-direction: column;
min-height: 100vh;
}
#loading-screen-inapp {
#melior {
margin: 0 auto;
@@ -79,6 +92,46 @@ div
cursor: crosshair;
}
.container-fluid {
overflow-x: hidden;
flex: 1 0 auto;
}
.g1g1-banner {
width: 100%;
min-height: 2.5rem;
background-color: #34b5c1;
a {
color: $white;
text-decoration: none;
font-weight: bold;
}
.closepadding {
margin: 11px 24px;
display: inline-block;
position: relative;
right: 0;
top: 0;
cursor: pointer;
}
.left-gift {
margin: auto 1rem auto auto;
}
.right-gift {
margin: auto auto auto 1rem;
filter: FlipH;
transform: scaleX(-1);
}
.svg-gifts {
width: 4.6rem;
}
}
.notification {
border-radius: 1000px;
background-color: $green-10;
@@ -89,42 +142,10 @@ div
margin-bottom: .5em;
}
.container-fluid {
overflow-x: hidden;
flex: 1 0 auto;
}
#app {
height: calc(100% - 56px); /* 56px is the menu */
display: flex;
flex-direction: column;
min-height: 100vh;
}
</style>
<style lang='scss'>
@import '~client/assets/scss/colors.scss';
/* @TODO: The modal-open class is not being removed. Let's try this for now */
.modal {
overflow-y: scroll !important;
}
.modal-backdrop.show {
opacity: .9 !important;
background-color: $purple-100 !important;
}
/* Push progress bar above modals */
#nprogress .bar {
z-index: 1600 !important; /* Must stay above nav bar */
}
.resting-banner {
width: 100%;
min-height: 40px;
background-color: $blue-10;
position: fixed;
top: 0;
z-index: 1300;
display: flex;
@@ -140,14 +161,10 @@ div
.closepadding {
margin: 11px 24px;
display: inline-block;
position: absolute;
position: relative;
right: 0;
top: 0;
cursor: pointer;
span svg path {
stroke: $blue-500;
}
}
@media only screen and (max-width: 768px) {
@@ -170,6 +187,25 @@ div
}
</style>
<style lang='scss'>
@import '~client/assets/scss/colors.scss';
/* @TODO: The modal-open class is not being removed. Let's try this for now */
.modal {
overflow-y: scroll !important;
}
.modal-backdrop.show {
opacity: .9 !important;
background-color: $purple-100 !important;
}
/* Push progress bar above modals */
#nprogress .bar {
z-index: 1600 !important; /* Must stay above nav bar */
}
</style>
<script>
import axios from 'axios';
import { loadProgressBar } from 'axios-progress-bar';
@@ -189,8 +225,9 @@ import amazonPaymentsModal from 'client/components/payments/amazonModal';
import paymentsSuccessModal from 'client/components/payments/successModal';
import spellsMixin from 'client/mixins/spells';
import { CONSTANTS, getLocalSetting, removeLocalSetting } from 'client/libs/userlocalManager';
import { CONSTANTS, getLocalSetting, removeLocalSetting, setLocalSetting } from 'client/libs/userlocalManager';
import gifts from 'assets/svg/gifts.svg';
import svgClose from 'assets/svg/close.svg';
import bannedAccountModal from 'client/components/bannedAccountModal';
@@ -215,6 +252,7 @@ export default {
return {
icons: Object.freeze({
close: svgClose,
gifts,
}),
selectedItemToBuy: null,
selectedSpellToBuy: null,
@@ -226,6 +264,7 @@ export default {
currentTipNumber: 0,
bannerHidden: false,
bannerHeight: 0,
giftingHidden: getLocalSetting(CONSTANTS.keyConstants.GIFTING_BANNER_DISPLAY) === 'dismissed',
};
},
computed: {
@@ -423,14 +462,6 @@ export default {
this.hideLoadingScreen();
window.addEventListener('resize', this.setBannerOffset);
// Adjust the positioning of the header banners
this.$watch('showRestingBanner', () => {
this.$nextTick(() => {
this.setBannerOffset();
});
}, {immediate: true});
// Adjust the timezone offset
if (this.user.preferences.timezoneOffset !== this.browserTimezoneOffset) {
this.$store.dispatch('user:set', {
@@ -465,7 +496,6 @@ export default {
this.$root.$off('bv::show::modal');
this.$root.$off('buyModal::showItem');
this.$root.$off('selectMembersModal::showItem');
window.removeEventListener('resize', this.setBannerOffset);
},
mounted () {
// Remove the index.html loading screen and now show the inapp loading
@@ -624,22 +654,14 @@ export default {
},
hideBanner () {
this.bannerHidden = true;
this.setBannerOffset();
},
hideGiftingBanner () {
setLocalSetting(CONSTANTS.keyConstants.GIFTING_BANNER_DISPLAY, 'dismissed');
this.giftingHidden = true;
},
resumeDamage () {
this.$store.dispatch('user:sleep');
},
setBannerOffset () {
let contentPlacement = 0;
if (this.showRestingBanner && this.$refs.restingBanner !== undefined) {
contentPlacement = this.$refs.restingBanner.clientHeight;
}
this.bannerHeight = contentPlacement;
let smartBanner = document.getElementsByClassName('smartbanner')[0];
if (smartBanner !== undefined) {
smartBanner.style.top = `${contentPlacement}px`;
}
},
},
};
</script>

View File

@@ -1,6 +1,6 @@
.achievement-costumeContest6x {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1136px -438px;
background-position: -740px -420px;
width: 144px;
height: 156px;
}
@@ -34,6 +34,12 @@
width: 417px;
height: 147px;
}
.promo_g1g1 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1136px -867px;
width: 237px;
height: 150px;
}
.promo_ios {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -361px;
@@ -42,22 +48,34 @@
}
.promo_mystery_201811 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1136px -142px;
background-position: -1136px -571px;
width: 282px;
height: 147px;
}
.promo_piyo {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1136px -290px;
background-position: -1136px -719px;
width: 279px;
height: 147px;
}
.promo_studying {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1136px -142px;
width: 220px;
height: 232px;
}
.promo_take_this {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1281px -438px;
background-position: -1357px -142px;
width: 96px;
height: 69px;
}
.promo_todos {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1136px -375px;
width: 240px;
height: 195px;
}
.promo_turkey_day_2018 {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -871px;
@@ -90,7 +108,7 @@
}
.scene_veteran_pets {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -1136px -595px;
background-position: -740px -577px;
width: 242px;
height: 62px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

After

Width:  |  Height:  |  Size: 216 KiB

View File

@@ -1,5 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
<g fill="none" fill-rule="evenodd" stroke="#A5A1AC" stroke-width="2">
<g fill="none" fill-rule="evenodd" stroke="#FFF" stroke-width="2" opacity=".48">
<path d="M1 11L11 1M11 11L1 1"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 215 B

After

Width:  |  Height:  |  Size: 226 B

View File

@@ -0,0 +1,44 @@
<svg xmlns="http://www.w3.org/2000/svg" width="73" height="27" viewBox="0 0 73 27">
<g fill="none" fill-rule="evenodd">
<path fill="#8EEDF6" d="M4.333 9.757l2.166-.554-1.742-1.401-.554-2.166-1.401 1.742-2.166.554 1.742 1.4.554 2.167zM70.333 5.757l2.166-.554-1.742-1.401-.554-2.166-1.401 1.742-2.166.554 1.742 1.4.554 2.167zM37.147 5.518l2.573.428-1.202-2.315.428-2.574-2.315 1.202-2.574-.427 1.202 2.315-.427 2.573zM68.735 22.132l2.367 1.812.03-2.981 1.812-2.368-2.981-.03-2.368-1.812-.03 2.982-1.812 2.367zM33.676 23.656l1.839.305-.859-1.653.305-1.839-1.653.859-1.839-.305.859 1.653-.305 1.839zM10.695 25.362l.805 1.68.862-1.651 1.68-.804-1.651-.862-.804-1.681-.862 1.652-1.681.804z"/>
<path fill="#F8F9F9" d="M21.862 9.542l5.914-1.585 2.219 8.28-5.914 1.584z"/>
<path fill="#DDF3F3" d="M15.949 11.126l5.913-1.584 2.219 8.28-5.914 1.584z"/>
<path fill="#FFA624" d="M20.68 9.859l1.182-.317 2.219 8.28-1.183.316z"/>
<path fill="#FFBE5D" d="M21.862 9.542l1.183-.317 2.219 8.28-1.183.316z"/>
<path fill="#EE9109" d="M22.581 16.955l1.183-.317.317 1.183-1.183.317zM20.68 9.859l1.182-.317.317 1.183-1.182.317z"/>
<path fill="#C1E9E9" d="M15.949 11.126l4.73-1.267.318 1.183-4.732 1.267zM17.85 18.223l4.731-1.268.317 1.183-4.731 1.268z"/>
<path fill="#DDF3F3" d="M23.045 9.225l4.731-1.268.317 1.183-4.73 1.268zM24.947 16.322l4.73-1.268.318 1.183-4.731 1.267z"/>
<path fill="#FFA624" d="M23.764 16.638l1.183-.316.317 1.182-1.183.317zM21.862 9.542l1.183-.317.317 1.183-1.183.317z"/>
<g>
<path stroke="#FFA624" stroke-width="1.5" d="M21.737 3.348c-.295-1.038-1.009-2.02-2.008-2.204-1-.184-1.69.542-1.495 1.297.195.755.88.984 3.075 1.916.623.264.723.03.428-1.009z"/>
<path stroke="#FFBE5D" stroke-width="1.5" d="M24.307 3.71c.57-.918 1.527-1.664 2.538-1.565 1.012.098 1.475.986 1.08 1.658-.396.671-1.117.703-3.484.994-.672.083-.703-.17-.134-1.088z"/>
<path fill="#EE9109" d="M23.129 2.769c-1.968-.277-1.106 2.141-.317 2.252.79.111 2.285-1.976.317-2.252z"/>
<path fill="#F8F9F9" d="M22.862 4.665l7.276 1.022-.511 3.638-7.276-1.022z"/>
<path fill="#DDF3F3" d="M15.587 3.642l7.275 1.023-.51 3.638-7.276-1.023z"/>
<path fill="#FFBE5D" d="M20.437 4.324l4.85.682-.51 3.638-4.85-.682z"/>
<path fill="#FFA624" d="M20.437 4.324l2.425.341-.51 3.638-2.426-.341z"/>
<path fill="#FFA624" d="M22.862 4.665l2.426.34-.17 1.213-2.426-.34z"/>
<path fill="#EE9109" d="M20.437 4.324l2.425.341-.17 1.213-2.425-.341z"/>
<path fill="#C1E9E9" d="M15.246 6.068l4.85.681-.17 1.213-4.85-.682z"/>
<path fill="#DDF3F3" d="M24.947 7.431l4.85.682-.17 1.212-4.85-.681z"/>
</g>
<g>
<path stroke="#FFA624" stroke-width="1.5" d="M49.696 7.04c-.549-1.24-1.609-2.337-2.885-2.391-1.276-.054-2.007.969-1.632 1.874.374.905 1.266 1.071 4.16 1.847.822.22.905-.09.357-1.33z"/>
<path stroke="#FFBE5D" stroke-width="1.5" d="M52.956 7.04c.548-1.24 1.609-2.337 2.885-2.391 1.276-.054 2.007.969 1.632 1.874-.374.905-1.266 1.071-4.16 1.847-.822.22-.905-.09-.357-1.33z"/>
<path fill="#EE9109" d="M51.326 6.075c-2.497 0-1.002 2.858 0 2.858s2.497-2.858 0-2.858z"/>
<path fill="#F8F9F9" d="M51.326 8.481h9.23v4.616h-9.23z"/>
<path fill="#DDF3F3" d="M42.095 8.481h9.23v4.616h-9.23z"/>
<path fill="#FFBE5D" d="M48.249 8.481h6.154v4.616h-6.154z"/>
<path fill="#FFA624" d="M48.249 8.481h3.077v4.616h-3.077zM51.326 8.481h3.077v1.539h-3.077z"/>
<path fill="#EE9109" d="M48.249 8.481h3.077v1.539h-3.077z"/>
<path fill="#F8F9F9" d="M51.326 13.097h7.692v10.769h-7.692z"/>
<path fill="#DDF3F3" d="M43.634 13.097h7.692v10.769h-7.692z"/>
<path fill="#FFA624" d="M49.787 13.097h1.538v10.769h-1.538z"/>
<path fill="#FFBE5D" d="M51.326 13.097h1.538v10.769h-1.538z"/>
<path fill="#EE9109" d="M49.787 22.327h1.539v1.539h-1.539zM49.787 13.097h1.539v1.538h-1.539z"/>
<path fill="#C1E9E9" d="M43.634 13.097h6.153v1.538h-6.153zM42.095 11.558h6.154v1.539h-6.154zM43.634 22.327h6.153v1.539h-6.153z"/>
<path fill="#DDF3F3" d="M52.864 13.097h6.154v1.538h-6.154zM54.403 11.558h6.154v1.539h-6.154zM52.864 22.327h6.154v1.539h-6.154z"/>
<path fill="#FFA624" d="M51.326 22.327h1.538v1.539h-1.538zM51.326 13.097h1.538v1.538h-1.538z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -2,180 +2,172 @@
mixin featureBullet (text)
.row
.col-md-2.offset-1
.bubble.mx-auto
.svg-icon.check(v-html='icons.check')
.d-flex.bubble.justify-content-center.align-items-center
.svg-icon.check.mx-auto(v-html='icons.check')
.col-md-8.align-self-center
p=text
div(v-if='user')
b-modal(:hide-footer='true', :hide-header='true', :id='"buy-gems"', size='lg')
.container-fluid.purple-gradient
.gemfall
b-modal#buy-gems(:hide-footer='true', :id='"buy-gems"', size='lg')
.header-wrap(slot='modal-header')
.image-gemfall
.row
h2.text-invert.mx-auto {{ $t('support') }}
h2.header-invert.mx-auto {{ $t('support') }}
.row
.logo.svg-icon.mx-auto(v-html="icons.logo")
.container-fluid
.row
.col-6.offset-3.nav
.nav-item(@click='selectedPage = "subscribe"', :class="{active: selectedPage === 'subscribe'}") {{ $t('subscribe') }}
.nav-item(@click='selectedPage = "gems"', :class="{active: selectedPage === 'gems'}") {{ $t('buyGems') }}
div(v-show='selectedPage === "gems"')
div(v-if='hasSubscription')
.row.text-center
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
.row.text-center
.col-6.offset-3
p {{ $t("gemsPurchaseNote") }}
.d-flex.nav.justify-content-center
.nav-item.text-center(@click='selectedPage = "subscribe"', :class="{active: selectedPage === 'subscribe'}") {{ $t('subscribe') }}
.nav-item.text-center(@click='selectedPage = "gems"', :class="{active: selectedPage === 'gems'}") {{ $t('buyGems') }}
div(v-show='selectedPage === "gems"')
div(v-if='hasSubscription')
.row.text-center
h2.mx-auto.text-leadin {{ $t('gemBenefitLeadin') }}
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
.row.text-center
.col-6.offset-3
p {{ $t("gemsPurchaseNote") }}
.row.text-center
h2.mx-auto.text-leadin {{ $t('gemBenefitLeadin') }}
.row
.col
+featureBullet("{{ $t('gemBenefit1') }}")
+featureBullet("{{ $t('gemBenefit2') }}")
.col
+featureBullet("{{ $t('gemBenefit3') }}")
+featureBullet("{{ $t('gemBenefit4') }}")
.card-deck.gem-deck
.card.text-center.col-3(:class="{active: gemAmount === 20 }")
.card-img-top
.mx-auto(v-html='icons.twentyOneGems', style='"height: 55px; width: 47.5px; margin-top: 1.85em;"')
.card-body
.gem-count 20
.gem-text {{ $t('gems') }}
.divider
button.btn.btn-primary(@click='gemAmount === 20 ? gemAmount = 0 : gemAmount = 20') {{gemAmount === 20 ? $t('selected') : '$5.00'}}
.row.text-center
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
.card-deck
.card.text-center.payment-method(@click='showStripe({})')
.card-body
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
.card.text-center.payment-method
a.card-body.paypal(@click="openPaypal(paypalCheckoutLink, 'gems')")
img(src='~assets/images/paypal.png')
.card.text-center.payment-method(@click="amazonPaymentsInit({type: 'single'})")
.card-body.amazon
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('buyGemsSupportsDevs') }}
div(v-show='selectedPage === "subscribe"')
.g1g1-promo.d-flex.justify-content-center.align-items-center
.svg-icon.svg-gifts.left-gift(v-html="icons.gifts")
.text-center
strong.gift-text {{ $t('g1g1Announcement') }}
.gift-text {{ $t('g1g1Details') }}
.svg-icon.svg-gifts.right-gift(v-html="icons.gifts")
div(v-if='hasSubscription')
.row.text-center
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
.row.text-center
.col-10.offset-1
p(v-html='$t("subscriptionAlreadySubscribed1")')
div(v-if='!hasSubscription')
.row.text-center
h2.mx-auto.text-leadin {{ $t('subscriptionBenefitLeadin') }}
.row
.col
+featureBullet("{{ $t('gemBenefit1') }}")
+featureBullet("{{ $t('gemBenefit2') }}")
+featureBullet("{{ $t('subscriptionBenefit1') }}")
+featureBullet("{{ $t('subscriptionBenefit2') }}")
+featureBullet("{{ $t('subscriptionBenefit3') }}")
.col
+featureBullet("{{ $t('gemBenefit3') }}")
+featureBullet("{{ $t('gemBenefit4') }}")
.card-deck.gem-deck
//.card.text-center(:class="{active: gemAmount === 4}")
.card-img-top
.mx-auto(v-html='icons.fourGems', style='"height: 53px; width: 49.5px; margin-top: 2em;"')
.card-body
.gem-count 4
.gem-text {{ $t('gems') }}
.divider
button.btn.btn-primary(@click='gemAmount = 4') {{gemAmount === 4 ? $t('selected') : '$1.00'}}
.card.text-center.col-3(:class="{active: gemAmount === 20 }")
.card-img-top
.mx-auto(v-html='icons.twentyOneGems', style='"height: 55px; width: 47.5px; margin-top: 1.85em;"')
.card-body
.gem-count 20
.gem-text {{ $t('gems') }}
.divider
button.btn.btn-primary(@click='gemAmount === 20 ? gemAmount = 0 : gemAmount = 20') {{gemAmount === 20 ? $t('selected') : '$5.00'}}
//.card.text-center(:class="{active: gemAmount === 42}")
.card-img-top
.mx-auto(v-html='icons.fortyTwoGems', style='"height: 49.5px; width: 51px; margin-top: 1.9em;"')
.card-body
.gem-count 42
.gem-text {{ $t('gems') }}
.divider
button.btn.btn-primary(@click='gemAmount = 42') {{gemAmount === 42 ? $t('selected') : '$10.00'}}
//.card.text-center(:class="{active: gemAmount === 84}")
.card-img-top
.mx-auto(v-html='icons.eightyFourGems', style='"height: 65px; width: 67px; margin-top: 1em;"')
.card-body
.gem-count 84
.gem-text {{ $t('gems') }}
.divider
button.btn.btn-primary(@click='gemAmount = 84') {{gemAmount === 84 ? $t('selected') : '$20.00'}}
.row.text-center
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
+featureBullet("{{ $t('subscriptionBenefit4') }}")
+featureBullet("{{ $t('subscriptionBenefit5') }}")
+featureBullet("{{ $t('subscriptionBenefit6') }}")
.card-deck
.card.text-center.payment-method(@click='showStripe({})')
.card.text-center(:class='{active: subscriptionPlan === "basic_earned"}')
.card-body
.subscription-price
span.superscript $
span 5
span.superscript.muted .00
.small(v-once) {{ $t('everyMonth') }}
.divider
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:25})')
.spacer
button.btn.btn-primary(@click='subscriptionPlan = "basic_earned"') {{ subscriptionPlan === "basic_earned" ? $t('selected') : $t('select') }}
.card.text-center(:class='{active: subscriptionPlan === "basic_3mo"}')
.card-body
.subscription-price
span.superscript $
span 15
span.superscript.muted .00
.small(v-once) {{ $t('everyXMonths', {interval: 3}) }}
.divider
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:30})')
p.benefits(v-markdown='$t("receiveMysticHourglass")')
button.btn.btn-primary(@click='subscriptionPlan = "basic_3mo"') {{ subscriptionPlan === "basic_3mo" ? $t('selected') : $t('select') }}
.card.text-center(:class='{active: subscriptionPlan === "basic_6mo"}')
.card-body
.subscription-price
span.superscript $
span 30
span.superscript.muted .00
.small(v-once) {{ $t('everyXMonths', {interval: 6}) }}
.divider
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:35})')
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:2})')
button.btn.btn-primary(@click='subscriptionPlan = "basic_6mo"') {{ subscriptionPlan === "basic_6mo" ? $t('selected') : $t('select') }}
.card.text-center(:class='{active: subscriptionPlan === "basic_12mo"}')
.card-body
.subscription-price
span.superscript $
span 48
span.superscript.muted .00
.small(v-once) {{ $t('everyYear') }}
.divider
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:45})')
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:4})')
button.btn.btn-primary(@click='subscriptionPlan = "basic_12mo"') {{ subscriptionPlan === "basic_12mo" ? $t('selected') : $t('select') }}
.row.text-center(v-if='subscriptionPlan')
h2.mx-auto.text-payment(v-once) {{ $t('choosePaymentMethod') }}
.row.text-center
a.mx-auto(v-once) {{ $t('haveCouponCode') }}
.card-deck(v-if='subscriptionPlan')
.card.text-center.payment-method
.card-body(@click='showStripe({subscription: subscriptionPlan})')
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
.card.text-center.payment-method
a.card-body.paypal(@click="openPaypal(paypalCheckoutLink, 'gems')")
a.card-body.paypal(@click="openPaypal(paypalSubscriptionLink, 'subscription')")
img(src='~assets/images/paypal.png')
.card.text-center.payment-method(@click="amazonPaymentsInit({type: 'single'})")
.card-body.amazon
.card.text-center.payment-method
.card-body.amazon(@click="amazonPaymentsInit({type: 'subscription', subscription: subscriptionPlan})")
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('buyGemsSupportsDevs') }}
div(v-show='selectedPage === "subscribe"')
div(v-if='hasSubscription')
.row.text-center
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
.row.text-center
.col
p(v-html='$t("subscriptionAlreadySubscribed1")')
div(v-if='!hasSubscription')
.row.text-center
h2.mx-auto.text-leadin {{ $t('subscriptionBenefitLeadin') }}
.row
.col
+featureBullet("{{ $t('subscriptionBenefit1') }}")
+featureBullet("{{ $t('subscriptionBenefit2') }}")
+featureBullet("{{ $t('subscriptionBenefit3') }}")
.col
+featureBullet("{{ $t('subscriptionBenefit4') }}")
+featureBullet("{{ $t('subscriptionBenefit5') }}")
+featureBullet("{{ $t('subscriptionBenefit6') }}")
.card-deck
.card.text-center(:class='{active: subscriptionPlan === "basic_earned"}')
.card-body
.subscription-price
span.superscript $
span 5
span.superscript.muted .00
.small(v-once) {{ $t('everyMonth') }}
.divider
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:25})')
.spacer
button.btn.btn-primary(@click='subscriptionPlan = "basic_earned"') {{ subscriptionPlan === "basic_earned" ? $t('selected') : $t('select') }}
.card.text-center(:class='{active: subscriptionPlan === "basic_3mo"}')
.card-body
.subscription-price
span.superscript $
span 15
span.superscript.muted .00
.small(v-once) {{ $t('everyXMonths', {interval: 3}) }}
.divider
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:30})')
p.benefits(v-markdown='$t("receiveMysticHourglass")')
button.btn.btn-primary(@click='subscriptionPlan = "basic_3mo"') {{ subscriptionPlan === "basic_3mo" ? $t('selected') : $t('select') }}
.card.text-center(:class='{active: subscriptionPlan === "basic_6mo"}')
.card-body
.subscription-price
span.superscript $
span 30
span.superscript.muted .00
.small(v-once) {{ $t('everyXMonths', {interval: 6}) }}
.divider
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:35})')
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:2})')
button.btn.btn-primary(@click='subscriptionPlan = "basic_6mo"') {{ subscriptionPlan === "basic_6mo" ? $t('selected') : $t('select') }}
.card.text-center(:class='{active: subscriptionPlan === "basic_12mo"}')
.card-body
.subscription-price
span.superscript $
span 48
span.superscript.muted .00
.small(v-once) {{ $t('everyYear') }}
.divider
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:45})')
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:4})')
button.btn.btn-primary(@click='subscriptionPlan = "basic_12mo"') {{ subscriptionPlan === "basic_12mo" ? $t('selected') : $t('select') }}
.row.text-center(v-if='subscriptionPlan')
h2.mx-auto.text-payment(v-once) {{ $t('choosePaymentMethod') }}
.row.text-center
a.mx-auto(v-once) {{ $t('haveCouponCode') }}
.card-deck(v-if='subscriptionPlan')
.card.text-center.payment-method
.card-body(@click='showStripe({subscription: subscriptionPlan})')
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
.card.text-center.payment-method
a.card-body.paypal(@click="openPaypal(paypalSubscriptionLink, 'subscription')")
img(src='~assets/images/paypal.png')
.card.text-center.payment-method
.card-body.amazon(@click="amazonPaymentsInit({type: 'subscription', subscription: subscriptionPlan})")
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') }}
.col-6.offset-3 {{ $t('subscribeSupportsDevs') }}
</template>
<style lang="scss">
#buy-gems__BV_body_ {
#buy-gems .modal-body {
padding: 0;
}
#buy-gems .modal-content {
border-radius: 8px;
width: 824px;
}
#buy-gems .modal-header {
padding: 0;
border-bottom: 0px;
}
</style>
<style lang="scss" scoped>
@import '~client/assets/scss/colors.scss';
a.mx-auto {
color: #2995cd;
}
@@ -228,6 +220,11 @@
margin: 1em auto;
}
.g1g1-promo {
background-color: #34b5c1;
height: 3.75rem;
}
.gem-count {
font-family: Roboto;
font-size: 40px;
@@ -242,11 +239,40 @@
margin-bottom: 1em;
}
.gemfall {
.gift-text {
color: $white;
font-size: 14px;
}
.image-gemfall {
background: url(~assets/images/gemfall.png) center repeat-y;
height: 14em;
}
.svg-gifts {
width: 4.6rem;
}
.left-gift {
margin: auto 1rem auto 4.8rem;
}
.right-gift {
margin: auto 4.8rem auto 1rem;
filter: FlipH;
transform: scaleX(-1);
}
.header-wrap {
background-image: linear-gradient(74deg, #4f2a93, #6133b4);
height: 14em;
width: 100%;
color: #4e4a57;
padding: 0;
border-top-left-radius: 7px;
border-top-right-radius: 7px;
}
.logo {
width: 256px;
height: 56px;
@@ -258,19 +284,21 @@
.nav {
font-weight: bold;
height: 40px;
background-color: $gray-600;
}
.nav-item {
box-sizing: border-box;
display: inline-block;
font-size: 16px;
margin: 0 auto;
padding: 1.5em;
margin: 0rem;
padding: 1rem;
width: 7.5rem;
}
.nav-item:hover, .nav-item.active {
color: #4f2a93;
border-bottom: 2px solid #4f2a93;
border-bottom: 4px solid $purple-300;
cursor: pointer;
}
@@ -286,11 +314,6 @@
padding-top: 1.3em;
}
.purple-gradient {
background-image: linear-gradient(74deg, #4f2a93, #6133b4);
height: 14em;
}
.spacer {
height: 4em;
}
@@ -309,10 +332,11 @@
.svg-icon.check {
color: #bda8ff;
width: 1rem;
}
.text-invert {
margin: 1.6em;
.header-invert {
margin: 3rem auto 1.5rem;
color: #FFFFFF;
font-family: Roboto;
font-weight: normal;
@@ -320,9 +344,9 @@
}
.text-leadin {
margin: 1.6em;
font-weight: normal;
color: #4f2a93;
margin: 1rem;
font-weight: bold;
color: $purple-200;
}
.text-outtro {
@@ -346,6 +370,7 @@
import checkIcon from 'assets/svg/check.svg';
import creditCard from 'assets/svg/credit-card.svg';
import gifts from 'assets/svg/gifts.svg';
import heart from 'assets/svg/health.svg';
import logo from 'assets/svg/habitica-logo.svg';
@@ -381,6 +406,7 @@
check: checkIcon,
creditCard,
fourGems,
gifts,
heart,
twentyOneGems,
fortyTwoGems,

View File

@@ -31,11 +31,17 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
)
h3.panel-heading {{ $t('subscription') }}
.panel-body
.form-group
.radio(v-for='block in subscriptionBlocks', v-if="block.target !== 'group' && block.canSubscribe === true")
label
input(type="radio", name="subRadio", :value="block.key", v-model='gift.subscription.key')
| {{ $t('sendGiftSubscription', {price: block.price, months: block.months}) }}
.row
.col-md-4
.form-group
.radio(v-for='block in subscriptionBlocks', v-if="block.target !== 'group' && block.canSubscribe === true")
label
input(type="radio", name="subRadio", :value="block.key", v-model='gift.subscription.key')
| {{ $t('sendGiftSubscription', {price: block.price, months: block.months}) }}
.col-md-8
h4 {{ $t('winterPromoGiftHeader') }}
p {{ $t('winterPromoGiftDetails1') }}
p {{ $t('winterPromoGiftDetails2') }}
textarea.form-control(rows='3', v-model='gift.message', :placeholder="$t('sendGiftMessagePlaceholder')")
//include ../formatting-help

View File

@@ -90,6 +90,10 @@
li(v-once) {{ $t('giftSubscriptionText2') }}
li(v-once) {{ $t('giftSubscriptionText3') }}
h4(v-once) {{ $t('giftSubscriptionText4') }}
.col-6
h2 {{ $t('winterPromoGiftHeader') }}
p {{ $t('winterPromoGiftDetails1') }}
p {{ $t('winterPromoGiftDetails2') }}
</template>
<style scoped>

View File

@@ -12,6 +12,10 @@
z-index: 1400; // 1400 is above modal backgrounds
&-top-pos {
&-double {
top: 145px;
}
&-normal {
top: 65px;
}
@@ -26,6 +30,7 @@
<script>
import { mapState } from 'client/libs/store';
import notification from './notification';
import { CONSTANTS, getLocalSetting } from 'client/libs/userlocalManager';
export default {
components: {
@@ -39,7 +44,9 @@ export default {
notificationsTopPos () {
const base = 'notifications-top-pos-';
let modifier = '';
if (this.userSleeping) {
if (this.userSleeping && this.giftingShown) {
modifier = 'double';
} else if (this.userSleeping || this.giftingShown) {
modifier = 'sleeping';
} else {
modifier = 'normal';
@@ -47,5 +54,10 @@ export default {
return `${base}${modifier}`;
},
},
data () {
return {
giftingShown: getLocalSetting(CONSTANTS.keyConstants.GIFTING_BANNER_DISPLAY) !== 'dismissed',
};
},
};
</script>

View File

@@ -5,6 +5,7 @@ const CONSTANTS = {
EQUIPMENT_DRAWER_STATE: 'equipment-drawer-state',
CURRENT_EQUIPMENT_DRAWER_TAB: 'current-equipment-drawer-tab',
STABLE_SORT_STATE: 'stable-sort-state',
GIFTING_BANNER_DISPLAY: 'gifting-banner-display',
},
drawerStateValues: {
DRAWER_CLOSED: 'drawer-closed',

View File

@@ -143,7 +143,9 @@
"dateEndJanuary": "January 31",
"dateEndFebruary": "February 28",
"winterPromoGiftHeader": "GIFT A SUBSCRIPTION AND GET ONE FREE!",
"winterPromoGiftDetails1": "Until January 12th only, when you gift somebody a subscription, you get the same subscription for yourself for free!",
"winterPromoGiftDetails1": "Until January 15th only, when you gift somebody a subscription, you get the same subscription for yourself for free!",
"winterPromoGiftDetails2": "Please note that if you or your gift recipient already have a recurring subscription, the gifted subscription will only start after that subscription is cancelled or has expired. Thanks so much for your support! <3",
"discountBundle": "bundle"
"discountBundle": "bundle",
"g1g1Announcement": "Gift a Subscription, Get a Subscription Free event going on now!",
"g1g1Details": "Gift a sub to a friend from their profile and youll receive the same sub for free!"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -3,7 +3,7 @@ import { authWithHeaders } from '../../middlewares/auth';
let api = {};
// @TODO export this const, cannot export it from here because only routes are exported from controllers
const LAST_ANNOUNCEMENT_TITLE = 'NEW DISCOUNTED PET QUEST BUNDLE: BIRD BUDDIES!';
const LAST_ANNOUNCEMENT_TITLE = 'GIFT A SUBSCRIPTION, GET A SUBSCRIPTION! AND HABITICA BLOG POSTS';
const worldDmg = { // @TODO
bailey: false,
};
@@ -30,14 +30,26 @@ api.getNews = {
<div class="mr-3 ${baileyClass}"></div>
<div class="media-body">
<h1 class="align-self-center">${res.t('newStuff')}</h1>
<h2>12/11/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
<h2>12/18/2018 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
</div>
</div>
<hr/>
<p>If you're looking to add some pets to your Habitica stable, you're in luck! From now until December 31, you can purchase the Bird Buddies Pet Quest Bundle and receive the Rooster, Peacock, and Penguin quests, all for only 7 Gems! That's a discount of 5 Gems from the price of purchasing them separately. Check it out in the <a href='/shops/quests'>Quest Shop</a> today!</p>
<div class="small">Art by UncommonCriminal, Eevachu, PainterProphet, Lilith of Alfheim, Pfeffernusse, Draayder, Podcod, Fire Fire Fire, Pandoro, RBrinks, EmeraldOx, extrajordanary, melynnrose, Rattify, McCoyly, Breadstrings, and Darkly</div>
<div class="small mb-3">Writing by Elizabeth Queenan, Leephon, playgroundgiraffe, and Daniel the Bard</div>
<div class="promo_bird_buddies_bundle center-block"></div>
<div class="promo_g1g1 center-block"></div>
<h3>Gift a Subscription and Get One Free!</h3>
<p>In honor of the season of giving--and due to popular demand!--we're bringing back a very special promotion from today through January 15. Now when you gift somebody a subscription, you get the same subscription for yourself for free!</p>
<p>Subscribers get tons of perks every month, including exclusive items, the ability to buy Gems with Gold, a cute exclusive Jackalope Pet, and increased data history. Plus, it helps keep Habitica running :) To gift a subscription to someone, just open their profile and click the present icon in the upper right. You can open their profile by clicking their avatar in your party header or their name in chat.</p>
<p>This promotion is only available on <a href='https://habitica.com/'>the web</a> for now, but it will be coming to the Habitica mobile apps very soon.</p>
<p>Please note that this promotion only applies when you gift to another Habitican. If you or your gift recipient already have a recurring subscription, the gifted subscription will only start after that subscription is cancelled or has expired. Thanks so much for your support! <3</p>
<div class="small mb-3">by SabreCat and viirus</div>
<div class="promo_todos center-block"></div>
<h3>Wiki Feature: Habitican Shared Lists</h3>
<p>This month's <a href='https://habitica.wordpress.com/2018/12/12/habitican-shared-task-lists/' target='_blank'>featured Wiki article</a> is about Habitican Shared Lists! We hope that it will help you as you explore new possibilities for your task list. Be sure to check it out, and let us know what you think by reaching out on <a href='https://twitter.com/habitica' target='_blank'>Twitter</a>, <a href='http://blog.habitrpg.com' target='_blank'>Tumblr</a>, and <a href='https://facebook.com/habitica' target='_blank'>Facebook</a>.</p>
<div class="small mb-3">by shanaqui and the Wiki Wizards</div>
<div class="promo_studying center-block"></div>
<h3>Use Case and Guild Spotlights on Professionalization and Adulting Skills</h3>
<p>We've got new posts on the blog all about ways to use Habitica to help with all those pesky "grown-up" tasks! First, there's a <a href='https://habitica.wordpress.com/2018/12/18/professionalization-and-adulting-skills-guild-spotlight/' target='_blank'>Guild Spotlight</a> that highlights the Guilds that can help you as you explore ways to use Habitica to boost your adulting level. Next, we have a <a href='https://habitica.wordpress.com/2018/12/18/use-case-spotlight-professionalization-and-adulting-skills/' target='_blank'>Use Case Spotlight</a> with adulting and professionalization tips! These suggestions were submitted by Habiticans in the <a href='/groups/guild/1d3a10bf-60aa-4806-a38b-82d1084a59e6' target='_blank'>Use Case Spotlights Guild</a>.</p>
<p>Plus, we're collecting user submissions for the next Use Case Spotlight! How do you use Habitica to establish new habits? Well be featuring player-submitted examples in Use Case Spotlights on the Habitica Blog next month, so post your suggestions in the Use Case Spotlight Guild now. We look forward to learning more about how you use Habitica to improve your life and get things done!</p>
<div class="small mb-3">by shanaqui</div>
</div>
`,
});

View File

@@ -147,55 +147,88 @@ async function createSubscription (data) {
txnEmail(data.user, emailType);
}
analytics.trackPurchase({
uuid: data.user._id,
groupId,
itemPurchased,
sku: `${data.paymentMethod.toLowerCase()}-subscription`,
purchaseType,
paymentMethod: data.paymentMethod,
quantity: 1,
gift: Boolean(data.gift),
purchaseValue: block.price,
headers: data.headers,
});
if (!data.promo) {
analytics.trackPurchase({
uuid: data.user._id,
groupId,
itemPurchased,
sku: `${data.paymentMethod.toLowerCase()}-subscription`,
purchaseType,
paymentMethod: data.paymentMethod,
quantity: 1,
gift: Boolean(data.gift),
purchaseValue: block.price,
headers: data.headers,
});
}
if (!group) data.user.purchased.txnCount++;
if (!group && !data.promo) data.user.purchased.txnCount++;
if (data.gift) {
let byUserName = getUserInfo(data.user, ['name']).name;
// generate the message in both languages, so both users can understand it
let languages = [data.user.preferences.language, data.gift.member.preferences.language];
let senderMsg = shared.i18n.t('giftedSubscriptionFull', {
username: data.gift.member.profile.name,
sender: byUserName,
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
}, languages[0]);
senderMsg = `\`${senderMsg}\``;
if (data.promo) {
let senderMsg = shared.i18n.t(`giftedSubscription${data.promo}Promo`, {
username: data.gift.member.profile.name,
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
}, languages[0]);
let receiverMsg = shared.i18n.t('giftedSubscriptionFull', {
username: data.gift.member.profile.name,
sender: byUserName,
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
}, languages[1]);
receiverMsg = `\`${receiverMsg}\``;
senderMsg = `\`${senderMsg}\``;
data.user.sendMessage(data.gift.member, { senderMsg });
} else {
let senderMsg = shared.i18n.t('giftedSubscriptionFull', {
username: data.gift.member.profile.name,
sender: byUserName,
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
}, languages[0]);
senderMsg = `\`${senderMsg}\``;
if (data.gift.message) {
receiverMsg += ` ${data.gift.message}`;
senderMsg += ` ${data.gift.message}`;
let receiverMsg = shared.i18n.t('giftedSubscriptionFull', {
username: data.gift.member.profile.name,
sender: byUserName,
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
}, languages[1]);
receiverMsg = `\`${receiverMsg}\``;
if (data.gift.message) {
receiverMsg += ` ${data.gift.message}`;
senderMsg += ` ${data.gift.message}`;
}
data.user.sendMessage(data.gift.member, { receiverMsg, senderMsg, save: false });
}
data.user.sendMessage(data.gift.member, { receiverMsg, senderMsg, save: false });
if (data.gift.member.preferences.emailNotifications.giftedSubscription !== false) {
txnEmail(data.gift.member, 'gifted-subscription', [
{name: 'GIFTER', content: byUserName},
{name: 'X_MONTHS_SUBSCRIPTION', content: months},
]);
if (data.promo) {
txnEmail(data.gift.member, 'gift-one-get-one', [
{name: 'GIFTEE_USERNAME', content: data.promoUsername},
{name: 'X_MONTHS_SUBSCRIPTION', content: months},
]);
} else {
txnEmail(data.gift.member, 'gifted-subscription', [
{name: 'GIFTER', content: byUserName},
{name: 'X_MONTHS_SUBSCRIPTION', content: months},
]);
}
}
if (data.gift.member._id !== data.user._id) { // Only send push notifications if sending to a user other than yourself
if (data.gift.member._id !== data.user._id) { // If sending to a user other than yourself, don't push notify, and get bonus sub for self per holiday promo
let promoData = {
user: data.user,
gift: {
member: data.user,
subscription: {
key: data.gift.subscription.key,
},
},
paymentMethod: data.paymentMethod,
promo: 'Winter',
promoUsername: data.gift.member.auth.local.username,
};
await this.createSubscription(promoData);
if (data.gift.member.preferences.pushNotifications.giftedSubscription !== false) {
sendPushNotification(data.gift.member,
{

View File

@@ -90,7 +90,7 @@ function sendSubscriptionNotification ({
let text;
let timestamp = new Date();
if (recipient.id) {
text = `${buyer.name} ${buyer.id} ${buyer.email} bought a ${months}-month gift subscription for ${recipient.name} ${recipient.id} ${recipient.email} using ${paymentMethod} on ${timestamp}`;
text = `${buyer.name} ${buyer.id} ${buyer.email} bought a ${months}-month gift subscription for ${recipient.name} ${recipient.id} ${recipient.email} and got a promo using ${paymentMethod} on ${timestamp}`;
} else if (groupId) {
text = `${buyer.name} ${buyer.id} ${buyer.email} bought a 1-month recurring group-plan for ${groupId} using ${paymentMethod} on ${timestamp}`;
} else {