Merge branch 'release' into develop

This commit is contained in:
Sabe Jones 2020-04-14 14:50:46 -05:00
commit 1e1c058d82
17 changed files with 151 additions and 109 deletions

2
package-lock.json generated
View file

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

View file

@ -1,7 +1,7 @@
{
"name": "habitica",
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
"version": "4.140.0",
"version": "4.140.3",
"main": "./website/server/index.js",
"dependencies": {
"@babel/core": "^7.9.0",

View file

@ -1,6 +1,6 @@
.promo_april_fools_2020 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -433px -337px;
background-position: -445px -184px;
width: 423px;
height: 147px;
}
@ -12,19 +12,31 @@
}
.promo_egg_quest {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -648px;
background-position: -355px -648px;
width: 354px;
height: 147px;
}
.promo_mystery_202004 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -355px -648px;
background-position: -875px 0px;
width: 282px;
height: 147px;
}
.promo_pastel_skin_hair {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: 0px -648px;
width: 354px;
height: 147px;
}
.customize-option.promo_pastel_skin_hair {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -25px -663px;
width: 60px;
height: 60px;
}
.promo_seasonal_shop_spring {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -638px -648px;
background-position: -875px -299px;
width: 162px;
height: 138px;
}
@ -48,13 +60,13 @@
}
.promo_spring_potions_2020 {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -445px -184px;
background-position: -433px -337px;
width: 423px;
height: 147px;
}
.promo_take_this {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -875px -151px;
background-position: -1026px -148px;
width: 96px;
height: 69px;
}
@ -66,7 +78,7 @@
}
.scene_meditation {
background-image: url('~@/assets/images/sprites/spritesmith-largeSprites-0.png');
background-position: -875px 0px;
background-position: -875px -148px;
width: 150px;
height: 150px;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 96 KiB

View file

@ -11,6 +11,12 @@
<span slot="popoverContent">
<strong v-if="item.key === 'gem' && gemsLeft === 0">{{ $t('maxBuyGems') }}</strong>
<h4 class="popover-content-title">{{ item.text }}</h4>
<div
v-if="item.event"
class="mt-2"
>
{{ limitedString }}
</div>
</span>
<template
slot="itemBadge"
@ -26,14 +32,15 @@
import _filter from 'lodash/filter';
import _sortBy from 'lodash/sortBy';
import _map from 'lodash/map';
import moment from 'moment';
import { mapState } from '@/libs/store';
import pinUtils from '@/mixins/pinUtils';
import planGemLimits from '@/../../common/script/libs/planGemLimits';
import seasonalShopConfig from '@/../../common/script/libs/shops-seasonal.config';
import ShopItem from '../shopItem';
import CategoryItem from './categoryItem';
export default {
components: {
CategoryItem,
@ -53,6 +60,9 @@ export default {
return planGemLimits.convCap
+ this.user.purchased.plan.consecutive.gemCapExtra - this.user.purchased.plan.gemsBought;
},
limitedString () {
return this.$t('limitedOffer', { date: moment(seasonalShopConfig.dateRange.end).format('LL') });
},
sortedMarketItems () {
let result = _map(this.category.items, e => ({
...e,

View file

@ -82,6 +82,16 @@
>
<questDialogDrops :item="item" />
</div>
<div
v-if="item.event"
class="limitedTime"
>
<span
class="svg-icon inline icon-16 clock-icon"
v-html="icons.clock"
></span>
<span class="limitedString">{{ limitedString }}</span>
</div>
<div
slot="modal-footer"
class="clearfix"
@ -121,6 +131,9 @@
margin: 33px auto auto;
}
.modal-body {
padding-bottom: 0px;
}
.questInfo {
width: 70%;
@ -208,6 +221,27 @@
}
}
.limitedTime {
height: 32px;
background-color: $purple-300;
width: calc(100% + 30px);
margin: 0 -15px; // the modal content has its own padding
font-size: 12px;
line-height: 1.33;
text-align: center;
color: $white;
display: flex;
align-items: center;
justify-content: center;
.limitedString {
height: 16px;
margin-left: 8px;
}
}
.notEnough {
pointer-events: none;
opacity: 0.55;
@ -247,14 +281,17 @@
</style>
<script>
import moment from 'moment';
import { mapState } from '@/libs/store';
import seasonalShopConfig from '@/../../common/script/libs/shops-seasonal.config';
import svgClock from '@/assets/svg/clock.svg';
import svgClose from '@/assets/svg/close.svg';
import svgGold from '@/assets/svg/gold.svg';
import svgGem from '@/assets/svg/gem.svg';
import svgPin from '@/assets/svg/pin.svg';
import svgExperience from '@/assets/svg/experience.svg';
import svgGem from '@/assets/svg/gem.svg';
import svgGold from '@/assets/svg/gold.svg';
import svgHourglasses from '@/assets/svg/hourglass.svg';
import svgPin from '@/assets/svg/pin.svg';
import BalanceInfo from '../balanceInfo.vue';
import currencyMixin from '../_currencyMixin';
@ -286,12 +323,13 @@ export default {
data () {
return {
icons: Object.freeze({
clock: svgClock,
close: svgClose,
gold: svgGold,
gem: svgGem,
pin: svgPin,
experience: svgExperience,
gem: svgGem,
gold: svgGold,
hourglass: svgHourglasses,
pin: svgPin,
}),
isPinned: false,
@ -319,6 +357,9 @@ export default {
if (this.priceType === 'hourglasses') return this.icons.hourglass;
return this.icons.gem;
},
limitedString () {
return this.$t('limitedOffer', { date: moment(seasonalShopConfig.dateRange.end).format('LL') });
},
},
watch: {
item: function itemChanged () {

View file

@ -299,7 +299,10 @@
<span slot="popoverContent">
<div class="questPopover">
<h4 class="popover-content-title">{{ item.text }}</h4>
<questInfo :quest="item" />
<questInfo
:quest="item"
:popoverVersion="true"
/>
</div>
</span>
<template

View file

@ -1,40 +1,43 @@
<template>
<div
class="row"
:class="{'small-version': smallVersion}"
>
<div>
<div
v-if="quest.collect"
class="table-row"
class="row"
>
<dt>{{ $t('collect') + ':' }}</dt>
<dd>
<div
v-for="(collect, key) of quest.collect"
:key="key"
>
<span>{{ collect.count }} {{ getCollectText(collect) }}</span>
</div>
</dd>
<div
v-if="quest.collect"
class="table-row"
>
<dt>{{ $t('collect') + ':' }}</dt>
<dd>
<div
v-for="(collect, key) of quest.collect"
:key="key"
>
<span>{{ collect.count }} {{ getCollectText(collect) }}</span>
</div>
</dd>
</div>
<div
v-if="quest.boss"
class="table-row"
>
<dt>{{ $t('bossHP') + ':' }}</dt>
<dd>{{ quest.boss.hp }}</dd>
</div>
<div class="table-row">
<dt>{{ $t('difficulty') + ':' }}</dt>
<dd>
<div
v-for="star of stars()"
:key="star"
class="svg-icon inline icon-16"
v-html="icons[star]"
></div>
</dd>
</div>
</div>
<div
v-if="quest.boss"
class="table-row"
>
<dt>{{ $t('bossHP') + ':' }}</dt>
<dd>{{ quest.boss.hp }}</dd>
</div>
<div class="table-row">
<dt>{{ $t('difficulty') + ':' }}</dt>
<dd>
<div
v-for="star of stars()"
:key="star"
class="svg-icon inline"
:class="smallVersion ? 'icon-12' : 'icon-16'"
v-html="icons[star]"
></div>
</dd>
<div v-if="quest.event && popoverVersion">
{{ limitedString }}
</div>
</div>
</template>
@ -115,16 +118,20 @@ dt {
</style>
<script>
import moment from 'moment';
import svgStar from '@/assets/svg/difficulty-star.svg';
import svgStarHalf from '@/assets/svg/difficulty-star-half.svg';
import svgStarEmpty from '@/assets/svg/difficulty-star-empty.svg';
import seasonalShopConfig from '@/../../common/script/libs/shops-seasonal.config';
export default {
props: {
quest: {
type: Object,
},
smallVersion: {
popoverVersion: {
type: Boolean,
default: false,
},
@ -146,6 +153,9 @@ export default {
return 1;
},
limitedString () {
return this.$t('limitedOffer', { date: moment(seasonalShopConfig.dateRange.end).format('LL') });
},
},
methods: {
stars () {

View file

@ -104,7 +104,7 @@
</div>
<div
v-if="item.event"
class="mt-4"
:class="item.purchaseType === 'gear' ? 'mt-4' : 'mt-2'"
>
{{ limitedString }}
</div>

View file

@ -11,7 +11,7 @@ export default prefill({
pastelHairColors: { setPrice: 5, availableUntil: '2016-01-01' },
rainbowHairColors: { setPrice: 5, text: t('rainbowColors') },
shimmerHairColors: {
setPrice: 5, availableFrom: '2019-04-09', availableUntil: '2019-05-02', text: t('shimmerColors'),
setPrice: 5, availableFrom: '2020-04-14', availableUntil: '2020-05-02', text: t('shimmerColors'),
},
hauntedHairColors: {
setPrice: 5, availableFrom: '2019-10-08', availableUntil: '2019-11-02', text: t('hauntedColors'),
@ -22,7 +22,7 @@ export default prefill({
rainbowSkins: { setPrice: 5, text: t('rainbowSkins') },
animalSkins: { setPrice: 5, text: t('animalSkins') },
pastelSkins: {
setPrice: 5, availableFrom: '2019-04-09', availableUntil: '2019-05-02', text: t('pastelSkins'),
setPrice: 5, availableFrom: '2020-04-14', availableUntil: '2020-05-02', text: t('pastelSkins'),
},
spookySkins: { setPrice: 5, availableUntil: '2016-01-01', text: t('spookySkins') },
supernaturalSkins: {

View file

@ -3,6 +3,9 @@ import defaults from 'lodash/defaults';
import each from 'lodash/each';
import moment from 'moment';
import t from './translation';
import {
EVENTS,
} from './constants';
function hasQuestAchievementFunction (key) {
return user => user.achievements.quests
@ -70,6 +73,7 @@ const premium = {
value: 2,
text: t('hatchingPotionShimmer'),
limited: true,
event: EVENTS.spring2020,
_addlNotes: t('eventAvailabilityReturning', {
availableDate: t('dateEndMarch'),
previousDate: t('marchYYYY', { year: 2018 }),
@ -205,6 +209,7 @@ const premium = {
value: 2,
text: t('hatchingPotionCelestial'),
limited: true,
event: EVENTS.spring2020,
_addlNotes: t('eventAvailabilityReturning', {
availableDate: t('dateEndMarch'),
previousDate: t('marchYYYY', { year: 2019 }),
@ -271,6 +276,7 @@ const premium = {
value: 2,
text: t('hatchingPotionBirchBark'),
limited: true,
event: EVENTS.spring2020,
canBuy () {
return moment().isBefore('2020-05-02');
},
@ -284,6 +290,7 @@ const wacky = {
Veggie: {
text: t('hatchingPotionVeggie'),
limited: true,
event: EVENTS.spring2020,
_addlNotes: t('eventAvailabilityReturning', {
availableDate: t('dateEndMarch'),
previousDate: t('marchYYYY', { year: 2019 }),

View file

@ -4,6 +4,7 @@ import moment from 'moment';
import sortBy from 'lodash/sortBy';
import t from './translation';
import {
EVENTS,
USER_CAN_OWN_QUEST_CATEGORIES,
} from './constants';
@ -3584,6 +3585,7 @@ const quests = {
completion: t('questWaffleCompletion'),
value: 4,
category: 'hatchingPotion',
event: EVENTS.spring2020,
boss: {
name: t('questWaffleBoss'),
hp: 500,

View file

@ -24,7 +24,7 @@ const featuredItems = {
path: 'premiumHatchingPotions.Celestial',
},
{
type: 'hatchingPotions',
type: 'premiumHatchingPotion',
path: 'hatchingPotions.Veggie',
},
];

View file

@ -94,6 +94,7 @@ export default function getItemInfo (user, type, item, officialPinnedItems, lang
purchaseType: 'hatchingPotions',
path: item.wacky ? `wackyHatchingPotions.${item.key}` : `premiumHatchingPotions.${item.key}`,
pinType: 'premiumHatchingPotion',
event: item.event,
};
break;
case 'food':
@ -133,6 +134,7 @@ export default function getItemInfo (user, type, item, officialPinnedItems, lang
notes: item.notes(language),
addlNotes: item.addlNotes ? item.addlNotes(language) : null,
group: item.group,
event: item.event,
value: item.goldValue ? item.goldValue : item.value,
locked,
previous: content.quests[item.previous]

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -4,7 +4,7 @@ const api = {};
// @TODO export this const, cannot export it from here because only routes are exported from
// controllers
const LAST_ANNOUNCEMENT_TITLE = 'CONFECTION HATCHING POTION QUEST, APRIL FOOL BLOG POST, AND SHINY SEEDS!';
const LAST_ANNOUNCEMENT_TITLE = 'SHIMMER HAIR COLORS AND PASTEL SKIN SET!';
const worldDmg = { // @TODO
bailey: false,
};
@ -31,63 +31,18 @@ api.getNews = {
<div class="mr-3 ${baileyClass}"></div>
<div class="media-body">
<h1 class="align-self-center">${res.t('newStuff')}</h1>
<h2>4/7/2020 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
<h2>4/14/2020 - ${LAST_ANNOUNCEMENT_TITLE}</h2>
</div>
</div>
<hr/>
<h3>April Fool's Challenge Winners and Blog Post!</h3>
<div class="promo_pastel_skin_hair center-block"></div>
<p>
The winners of the April Fool's Social Media Challenge have been selected!
Congratulations to Silvercat17, RaidingPartyGames, Pangdood, Spacehawk, and VixiMonster!
The Seasonal Edition Shimmer Hair Colors and Pastel Skin Set are now available for
purchase in the User menu > Edit Avatar! These skin sets will only be available to
purchase until April 30th, and then they will disappear from the shop until next
Spring Fling. If you buy them, though, you will have access to them year-round!
</p>
<p>
Thank you to everyone who shared their awesome pics with their dessert pets! You can see
a fun <a href='https://habitica.wordpress.com/2020/04/07/taking-the-cake-dessert-pet-pics-from-habiticas-april-fools-celebration/'
target='_blank'>recap of the shenanigans on our blog</a>. Stay tuned to see what wacky antics the Fool gets up to next year!
</p>
<div class="promo_april_fools_2020 center-block"></div>
<h3>Confection Magic Hatching Potion Quest!</h3>
<p>
Oh, no! Just as Habiticans were going back to daily life, missing their cute dessert
pets, it looks like some kind of syrupy monstrosity has emerged to threaten the land!
</p>
<p>
Can you help the April Fool save Habitica from the Awful Waffle? Join the battle, and
earn special Confection Magic Hatching potions by completing your everyday tasks.
</p>
<p>
You can purchase the limited Confection Magic Hatching Potion Quest from the <a
href='/shops/quests'>Quest Shop</a> between now and April 30! Each quest completion
awards participants three potions each. Confection pets do not have mount forms, so keep
that in mind when you're purchasing!
</p>
<p>
Garden Potions have also returned, if you prefer a healthier treat! You can find them in
<a href='/shops/market'>the Market</a> until April 30. Keep in mind that Garden pets also
do not have mount forms when deciding how many to purchase.
</p>
<p>
After they're gone, it will be at least a year before the Confection Magic Hatching
Potion Quest or the Garden Magic Potions are available again, so be sure to get them now!
</p>
<div class="small mb-3">by Beffymaroo, Piyo, Viirus, and SabreCat</div>
<div class="promo_shiny_seeds center-block"></div>
<h3>Shiny Seeds</h3>
<p>
Throw a Shiny Seed at your friends and they will turn into a cheerful flower until their
next cron! You can buy the Seeds in the <a href='/shops/seasonal'>Seasonal Shop</a> with
Gold. Plus, if you get transformed by a Shiny Seed, you'll receive the Agricultural
Friends badge!
</p>
<p>
Don't want to be a flower? Just buy some Petal-Free Potion from your Rewards column to
reverse it.
</p>
<p>
Shiny Seeds will be available in the <a href='/shops/seasonal'>Seasonal Shop</a> until
April 30th!
</p>
<div class="small mb-3">by Lemoness</div>
<div class="small mb-3">by Lemoness and McCoyly</div>
</div>
`,
});

View file

@ -22,7 +22,7 @@ function sendWebhook (webhook, body, user) {
logger.error(webhookErr, {
extraMessage: 'Error while sending a webhook request.',
userId: user._id,
webhook,
webhookId: webhook.id,
});
let _failuresReset = false;