Merge branch 'release' into develop

This commit is contained in:
SabreCat
2017-12-15 05:37:04 +00:00
22 changed files with 473 additions and 311 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "habitica", "name": "habitica",
"version": "4.13.4", "version": "4.14.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@@ -1,7 +1,7 @@
{ {
"name": "habitica", "name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.", "description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.13.4", "version": "4.14.0",
"main": "./website/server/index.js", "main": "./website/server/index.js",
"dependencies": { "dependencies": {
"@slack/client": "^3.8.1", "@slack/client": "^3.8.1",

View File

@@ -191,7 +191,7 @@ describe('payments/index', () => {
await api.createSubscription(data); await api.createSubscription(data);
let msg = '\`Hello recipient, sender has sent you 3 months of subscription!\`'; 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 }); expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg });
}); });
@@ -229,6 +229,77 @@ describe('payments/index', () => {
}, },
}); });
}); });
context('Winter 2017-18 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', () => { context('Purchasing a subscription for self', () => {

View File

@@ -1,12 +1,30 @@
.promo_take_this { .promo_take_this {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -437px 0px; background-position: -741px -442px;
width: 114px; width: 114px;
height: 87px; height: 87px;
} }
.scene_calendar { .promo_winter_quests {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -741px 0px;
width: 141px;
height: 441px;
}
.promo_winter_retreat {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png'); background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px 0px; background-position: 0px 0px;
width: 740px;
height: 309px;
}
.promo_winter_subscriptions {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -437px -310px;
width: 237px;
height: 150px;
}
.scene_calendar {
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -310px;
width: 436px; width: 436px;
height: 368px; height: 368px;
} }

View File

@@ -1042,102 +1042,108 @@
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.quest_bundle_witchyFamiliars { .quest_bundle_winterQuests {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1035px -1603px; background-position: -1035px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_gem { .quest_bundle_witchyFamiliars {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1104px -1603px; background-position: -1104px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_opaquePotion { .shop_gem {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1173px -1603px; background-position: -1173px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_potion { .shop_opaquePotion {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1242px -1603px; background-position: -1242px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_seafoam { .shop_potion {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1311px -1603px; background-position: -1311px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_shinySeed { .shop_seafoam {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1380px -1603px; background-position: -1380px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_snowball { .shop_shinySeed {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1449px -1603px; background-position: -1449px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_spookySparkles { .shop_snowball {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1518px -1603px; background-position: -1518px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_mounts_MagicalBee-Base { .shop_spookySparkles {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1587px -1603px; background-position: -1587px -1603px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_mounts_Mammoth-Base { .shop_mounts_MagicalBee-Base {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px 0px; background-position: -1672px 0px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_mounts_MantisShrimp-Base { .shop_mounts_Mammoth-Base {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -69px; background-position: -1672px -69px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_mounts_Phoenix-Base { .shop_mounts_MantisShrimp-Base {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -138px; background-position: -1672px -138px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_pets_MagicalBee-Base { .shop_mounts_Phoenix-Base {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -207px; background-position: -1672px -207px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_pets_Mammoth-Base { .shop_pets_MagicalBee-Base {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -276px; background-position: -1672px -276px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_pets_MantisShrimp-Base { .shop_pets_Mammoth-Base {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -345px; background-position: -1672px -345px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_pets_Phoenix-Base { .shop_pets_MantisShrimp-Base {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -414px; background-position: -1672px -414px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.shop_pets_Phoenix-Base {
background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -483px;
width: 68px;
height: 68px;
}
.shop_backStab { .shop_backStab {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1468px -1121px; background-position: -1468px -1121px;
@@ -1236,91 +1242,91 @@
} }
.Pet_Egg_Armadillo { .Pet_Egg_Armadillo {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -1587px; background-position: 0px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Axolotl { .Pet_Egg_Axolotl {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: 0px -1672px; background-position: -69px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_BearCub { .Pet_Egg_BearCub {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -69px -1672px; background-position: -138px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Beetle { .Pet_Egg_Beetle {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -138px -1672px; background-position: -207px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Bunny { .Pet_Egg_Bunny {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -207px -1672px; background-position: -276px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Butterfly { .Pet_Egg_Butterfly {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -276px -1672px; background-position: -345px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Cactus { .Pet_Egg_Cactus {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -345px -1672px; background-position: -414px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Cheetah { .Pet_Egg_Cheetah {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -414px -1672px; background-position: -483px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Cow { .Pet_Egg_Cow {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -483px -1672px; background-position: -552px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Cuttlefish { .Pet_Egg_Cuttlefish {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -552px -1672px; background-position: -621px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Deer { .Pet_Egg_Deer {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -621px -1672px; background-position: -690px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Dragon { .Pet_Egg_Dragon {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -690px -1672px; background-position: -759px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Egg { .Pet_Egg_Egg {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -759px -1672px; background-position: -828px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Falcon { .Pet_Egg_Falcon {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -828px -1672px; background-position: -897px -1672px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Ferret { .Pet_Egg_Ferret {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -897px -1672px; background-position: -1672px -1587px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
@@ -1416,137 +1422,131 @@
} }
.Pet_Egg_Peacock { .Pet_Egg_Peacock {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1672px -483px; background-position: -1534px -828px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Penguin { .Pet_Egg_Penguin {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1534px -828px; background-position: -1148px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_PolarBear { .Pet_Egg_PolarBear {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1148px -1354px; background-position: -1079px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Rat { .Pet_Egg_Rat {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1079px -1354px; background-position: -1010px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Rock { .Pet_Egg_Rock {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1010px -1354px; background-position: -941px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Rooster { .Pet_Egg_Rooster {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -941px -1354px; background-position: -872px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Sabretooth { .Pet_Egg_Sabretooth {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -872px -1354px; background-position: -803px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Seahorse { .Pet_Egg_Seahorse {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -803px -1354px; background-position: -734px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Sheep { .Pet_Egg_Sheep {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -734px -1354px; background-position: -665px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Slime { .Pet_Egg_Slime {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -665px -1354px; background-position: -596px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Sloth { .Pet_Egg_Sloth {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -596px -1354px; background-position: -527px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Snail { .Pet_Egg_Snail {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -527px -1354px; background-position: -458px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Snake { .Pet_Egg_Snake {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -458px -1354px; background-position: -389px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Spider { .Pet_Egg_Spider {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -389px -1354px; background-position: -320px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_TRex { .Pet_Egg_TRex {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1455px -1237px; background-position: -1386px -1237px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_TigerCub { .Pet_Egg_TigerCub {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -320px -1354px; background-position: -251px -1354px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Treeling { .Pet_Egg_Treeling {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -251px -1354px; background-position: -1455px -1237px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Triceratops { .Pet_Egg_Triceratops {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1386px -1237px; background-position: -1317px -1237px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Turtle { .Pet_Egg_Turtle {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1317px -1237px; background-position: -1455px -1168px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Unicorn { .Pet_Egg_Unicorn {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1455px -1168px; background-position: -1386px -1168px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Whale { .Pet_Egg_Whale {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1386px -1168px; background-position: -1317px -1168px;
width: 68px; width: 68px;
height: 68px; height: 68px;
} }
.Pet_Egg_Wolf { .Pet_Egg_Wolf {
background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1317px -1168px;
width: 68px;
height: 68px;
}
.Pet_Egg_Yarn {
background-image: url('~assets/images/sprites/spritesmith-main-10.png'); background-image: url('~assets/images/sprites/spritesmith-main-10.png');
background-position: -1104px -1534px; background-position: -1104px -1534px;
width: 68px; width: 68px;

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 357 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 KiB

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 158 KiB

View File

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

View File

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

View File

@@ -4,11 +4,28 @@
.align-self-center.right-margin(:class='baileyClass') .align-self-center.right-margin(:class='baileyClass')
.media-body .media-body
h1.align-self-center(v-markdown='$t("newStuff")') h1.align-self-center(v-markdown='$t("newStuff")')
h2 12/13/2017 - BLOG POST: THE HABITICA PLANNER h2 12/15/2017 - NEW PET QUEST BUNDLE, GIFT-1-GET-1 SUBSCRIPTIONS, AND BEHIND THE SCENES BLOG
hr hr
p(v-markdown='"This month\'s [featured Wiki article](https://habitica.wordpress.com/2017/12/13/the-habitica-planner/) is about the Habitica Planner! We hope that it will help you as you find new ways to use Habitica for your task-management needs! Be sure to check it out, and let us know what you think by reaching out on [Twitter](https://twitter.com/habitica), [Tumblr](http://blog.habitrpg.com), and [Facebook](https://facebook.com/habitica)."') h3 New Discounted Pet Quest Bundle: Winter Quests
.small by Beffymaroo and the Wiki Wizards .media
.scene_calendar.center-block .media-body
p(v-markdown='"If you are looking to add some cold weather friends to your Habitica stable, you\'re in luck! From now until December 31, you can purchase the Winter Quest Bundle and receive the Trapper Santa, Find the Cub, 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 [Quest Shop](/shops/quests) today!"')
.small by Lemoness and SabreCat
.small Art by UncommonCriminal, Shaner, Eevachu, Pandoro, melynnrose, Breadstrings, Rattify, and PainterProphet
.small Writing by Lefnire, Leephon, and Daniel the Bard
.media
.promo_winter_subscriptions.left-margin
.media-body
h3 Gift a Subscription and Get One Free!
p In honor of the season of giving--and due to popular demand!--we're bringing back a very special promotion for the next month only. Now when you gift somebody a subscription, you get the same subscription for yourself for free!
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 on the present icon in the upper right.
.promo_winter_quests
p The special promotion will only run until January 12th, so if you've been curious about trying out a subscription, now's the time! Make a friend happy and use all your new gems to go questing together.
p 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
.small by SabreCat and Lemoness
h3 Behind the Scenes: Habitica's Winter Staff Retreat
p(v-markdown='"There\'s a new [Behind the Scenes post on the Habitica blog](https://habitica.wordpress.com/2017/12/14/behind-the-scenes-habiticas-winter-staff-retreat/) about our recent Staff Retreat. Check out some great photos and anecdotes from the trip, and learn a little more about the Habitica Team!"')
.promo_winter_retreat.center-block
br br
</template> </template>

View File

@@ -120,5 +120,8 @@
"dateEndAugust": "August 31", "dateEndAugust": "August 31",
"dateEndOctober": "October 31", "dateEndOctober": "October 31",
"dateEndNovember": "November 30", "dateEndNovember": "November 30",
"discountBundle": "bundle" "discountBundle": "bundle",
"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!",
"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"
} }

View File

@@ -637,5 +637,8 @@
"questYarnCompletion": "With a feeble swipe of a pin-riddled appendage and a weak roar, the Dread Yarnghetti finally unravels into a pile of yarn balls.<br><br>\"Take care of this yarn,\" shopkeeper @JinjooHat says, handing them to you. \"If you feed them and care for them properly, they'll grow into new and exciting projects that just might make your heart take flight…\"", "questYarnCompletion": "With a feeble swipe of a pin-riddled appendage and a weak roar, the Dread Yarnghetti finally unravels into a pile of yarn balls.<br><br>\"Take care of this yarn,\" shopkeeper @JinjooHat says, handing them to you. \"If you feed them and care for them properly, they'll grow into new and exciting projects that just might make your heart take flight…\"",
"questYarnBoss": "The Dread Yarnghetti", "questYarnBoss": "The Dread Yarnghetti",
"questYarnDropYarnEgg": "Yarn (Egg)", "questYarnDropYarnEgg": "Yarn (Egg)",
"questYarnUnlockText": "Unlocks purchasable Yarn eggs in the Market" "questYarnUnlockText": "Unlocks purchasable Yarn eggs in the Market",
"winterQuestsText": "Winter Quest Bundle",
"winterQuestsNotes": "Contains 'Trapper Santa', 'Find the Cub', and 'The Fowl Frost'. Available until December 31."
} }

View File

@@ -72,7 +72,7 @@
"APIToken": "API Token (this is a password - see warning above!)", "APIToken": "API Token (this is a password - see warning above!)",
"showAPIToken": "Show API Token", "showAPIToken": "Show API Token",
"hideAPIToken": "Hide API Token", "hideAPIToken": "Hide API Token",
"APITokenWarning": "If you need a new API Token (e.g., if you accidentally shared it), email <%= hrefTechAssistanceEmail %> with your User ID and current Token. Once it is reset you will need to re-authorize everything by logging out of the website and mobile app and by providing the new Token to any other Habitica tools that you use.", "APITokenWarning": "If you need a new API Token (e.g., if you accidentally shared it), email <%= hrefTechAssistanceEmail %> with your User ID and current Token. Once it is reset you will need to re-authorize everything by logging out of the website and mobile app and by providing the new Token to any other Habitica tools that you use.",
"thirdPartyApps": "Third Party Apps", "thirdPartyApps": "Third Party Apps",
"dataToolDesc": "A webpage that shows you certain information from your Habitica account, such as statistics about your tasks, equipment, and skills.", "dataToolDesc": "A webpage that shows you certain information from your Habitica account, such as statistics about your tasks, equipment, and skills.",
"beeminder": "Beeminder", "beeminder": "Beeminder",
@@ -118,6 +118,7 @@
"giftedSubscription": "Gifted Subscription", "giftedSubscription": "Gifted Subscription",
"giftedSubscriptionInfo": "<%= name %> gifted you a <%= months %> month subscription", "giftedSubscriptionInfo": "<%= name %> gifted you a <%= months %> month subscription",
"giftedSubscriptionFull": "Hello <%= username %>, <%= sender %> has sent you <%= monthCount %> months of subscription!", "giftedSubscriptionFull": "Hello <%= username %>, <%= sender %> has sent you <%= monthCount %> months of subscription!",
"giftedSubscriptionWinterPromo": "Hello <%= username %>, you received <%= monthCount %> months of subscription as part of our holiday gift-giving promotion!",
"invitedParty": "Invited To Party", "invitedParty": "Invited To Party",
"invitedGuild": "Invited To Guild", "invitedGuild": "Invited To Guild",
"importantAnnouncements": "Reminders to check in to complete tasks and receive prizes", "importantAnnouncements": "Reminders to check in to complete tasks and receive prizes",

View File

@@ -122,6 +122,21 @@ api.bundles = {
type: 'quests', type: 'quests',
value: 7, value: 7,
}, },
winterQuests: {
key: 'winterQuests',
text: t('winterQuestsText'),
notes: t('winterQuestsNotes'),
bundleKeys: [
'evilsanta',
'evilsanta2',
'penguin',
],
canBuy () {
return moment().isBetween('2017-12-14', '2018-01-01');
},
type: 'quests',
value: 7,
},
}; };
/* /*

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -365,47 +365,59 @@ api.createSubscription = async function createSubscription (data) {
txnEmail(data.user, emailType); txnEmail(data.user, emailType);
} }
analytics.trackPurchase({ if (!data.promo) {
uuid: data.user._id, analytics.trackPurchase({
groupId, uuid: data.user._id,
itemPurchased, groupId,
sku: `${data.paymentMethod.toLowerCase()}-subscription`, itemPurchased,
purchaseType, sku: `${data.paymentMethod.toLowerCase()}-subscription`,
paymentMethod: data.paymentMethod, purchaseType,
quantity: 1, paymentMethod: data.paymentMethod,
gift: Boolean(data.gift), quantity: 1,
purchaseValue: block.price, gift: Boolean(data.gift),
headers: data.headers, purchaseValue: block.price,
}); headers: data.headers,
});
}
if (!group) data.user.purchased.txnCount++; if (!group && !data.promo) data.user.purchased.txnCount++;
if (data.gift) { if (data.gift) {
let byUserName = getUserInfo(data.user, ['name']).name; let byUserName = getUserInfo(data.user, ['name']).name;
// generate the message in both languages, so both users can understand it // generate the message in both languages, so both users can understand it
let languages = [data.user.preferences.language, data.gift.member.preferences.language]; let languages = [data.user.preferences.language, data.gift.member.preferences.language];
let senderMsg = shared.i18n.t('giftedSubscriptionFull', { if (data.promo) {
username: data.gift.member.profile.name, let senderMsg = shared.i18n.t(`giftedSubscription${data.promo}Promo`, {
sender: byUserName, username: data.gift.member.profile.name,
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months, monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
}, languages[0]); }, languages[0]);
senderMsg = `\`${senderMsg}\``;
let receiverMsg = shared.i18n.t('giftedSubscriptionFull', { senderMsg = `\`${senderMsg}\``;
username: data.gift.member.profile.name, data.user.sendMessage(data.gift.member, { senderMsg });
sender: byUserName, } else {
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months, let senderMsg = shared.i18n.t('giftedSubscriptionFull', {
}, languages[1]); username: data.gift.member.profile.name,
receiverMsg = `\`${receiverMsg}\``; sender: byUserName,
monthCount: shared.content.subscriptionBlocks[data.gift.subscription.key].months,
}, languages[0]);
senderMsg = `\`${senderMsg}\``;
if (data.gift.message) { let receiverMsg = shared.i18n.t('giftedSubscriptionFull', {
receiverMsg += ` ${data.gift.message}`; username: data.gift.member.profile.name,
senderMsg += ` ${data.gift.message}`; 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 });
} }
data.user.sendMessage(data.gift.member, { receiverMsg, senderMsg });
if (data.gift.member.preferences.emailNotifications.giftedSubscription !== false) { if (data.gift.member.preferences.emailNotifications.giftedSubscription !== false) {
txnEmail(data.gift.member, 'gifted-subscription', [ txnEmail(data.gift.member, 'gifted-subscription', [
{name: 'GIFTER', content: byUserName}, {name: 'GIFTER', content: byUserName},
@@ -413,7 +425,12 @@ api.createSubscription = async function createSubscription (data) {
]); ]);
} }
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 = data;
promoData.gift.member = data.user;
promoData.promo = 'Winter';
await this.createSubscription(promoData);
if (data.gift.member.preferences.pushNotifications.giftedSubscription !== false) { if (data.gift.member.preferences.pushNotifications.giftedSubscription !== false) {
sendPushNotification(data.gift.member, sendPushNotification(data.gift.member,
{ {

View File

@@ -77,7 +77,7 @@ function sendSubscriptionNotification ({
let text; let text;
let timestamp = new Date(); let timestamp = new Date();
if (recipient.id) { 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) { } else if (groupId) {
text = `${buyer.name} ${buyer.id} ${buyer.email} bought a 1-month recurring group-plan for ${groupId} using ${paymentMethod} on ${timestamp}`; text = `${buyer.name} ${buyer.id} ${buyer.email} bought a 1-month recurring group-plan for ${groupId} using ${paymentMethod} on ${timestamp}`;
} else { } else {