mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 21:57:22 +01:00
Sept 18 fixes (#9051)
* Added hover state to buy buttons * Translated profile * Fixed sending private message from member modal * Added payment functions * Added translation to home page * Fixed translation * Some front page styles * Fixed inbox sorting and searching * Added seasonals * Fixed buy gem modal conflict * Fixed paypal link * Fixed footer style crossover * Fixed quest update * Fixed sanity
This commit is contained in:
@@ -59,7 +59,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("shirt", specialShirtKeys)', @click='unlock(`shirt.${specialShirtKeys.join(",shirt.")}`)') $t('purchaseAll')
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("shirt", specialShirtKeys)', @click='unlock(`shirt.${specialShirtKeys.join(",shirt.")}`)') {{ $t('purchaseAll') }}
|
||||
#skin.section.customize-section(v-if='activeTopPage === "skin"')
|
||||
.row.sub-menu.col-6.offset-3.text-center
|
||||
.col-6.offset-3.text-center.sub-menu-item(:class='{active: activeSubPage === "color"}')
|
||||
@@ -69,26 +69,17 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.option(v-for='option in ["ddc994", "f5a76e", "ea8349", "c06534", "98461a", "915533", "c3e1dc", "6bd049"]',
|
||||
:class='{active: user.preferences.skin === option}')
|
||||
.skin.sprite.customize-option(:class="`skin_${option}`", @click='set({"preferences.skin": option})')
|
||||
.row(v-if='editing')
|
||||
.row(v-if='editing && set.key !== "undefined"', v-for='set in seasonalSkins')
|
||||
.col-12.customize-options
|
||||
.option(v-for='option in rainbowSkins',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
//h3(v-if='!hideSet(set)') {{$t(set.key)}}
|
||||
.option(v-for='option in set.options',
|
||||
:class='{active: option.active, locked: option.locked, hide: option.hide}')
|
||||
.skin.sprite.customize-option(:class="`skin_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("skin", rainbowSkinKeys)', @click='unlock(`skin.${rainbowSkinKeys.join(",skin.")}`)') $t('purchaseAll')
|
||||
.row(v-if='editing')
|
||||
.col-12.customize-options
|
||||
.option(v-for='option in animalSkins',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.skin.sprite.customize-option(:class="`skin_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("skin", animalSkinKeys)', @click='unlock(`skin.${animalSkinKeys.join(",skin.")}`)') $t('purchaseAll')
|
||||
button.btn.btn-secondary.purchase-all(v-if='!hideSet(set) && !userOwnsSet("skin", set.keys)', @click='unlock(`skin.${set.keys.join(",skin.")}`)') {{ $t('purchaseAll') }}
|
||||
#hair.section.customize-section(v-if='activeTopPage === "hair"')
|
||||
.row.sub-menu.col-6.offset-3.text-center
|
||||
.col-2.offset-1.text-center.sub-menu-item(@click='changeSubPage("color")', :class='{active: activeSubPage === "color"}')
|
||||
@@ -101,20 +92,33 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
strong(v-once) {{$t('ponytail')}}
|
||||
.col-2.text-center.sub-menu-item(@click='changeSubPage("facialhair")', :class='{active: activeSubPage === "facialhair"}', v-if='editing')
|
||||
strong(v-once) {{$t('facialhair')}}
|
||||
#hair-color.row(v-if='activeSubPage === "color"')
|
||||
.col-12.customize-options
|
||||
.option(v-for='option in ["white", "brown", "blond", "red", "black"]',
|
||||
:class='{active: user.preferences.hair.color === option}')
|
||||
.color-bangs.sprite.customize-option(:class="`hair_bangs_1_${option}`", @click='set({"preferences.hair.color": option})')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in premiumHairColors',
|
||||
:class='{active: option.active === option, locked: option.locked}')
|
||||
.color-bangs.sprite.customize-option(:class="`hair_bangs_1_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", premiumHairColorKeys, "color")', @click='unlock(`hair.color.${premiumHairColorKeys.join(",hair.color.")}`)') $t('purchaseAll')
|
||||
#hair-color.section.customize-section(v-if='activeSubPage === "color"')
|
||||
.row
|
||||
.col-12.customize-options
|
||||
.option(v-for='option in ["white", "brown", "blond", "red", "black"]',
|
||||
:class='{active: user.preferences.hair.color === option}')
|
||||
.color-bangs.sprite.customize-option(:class="`hair_bangs_1_${option}`", @click='set({"preferences.hair.color": option})')
|
||||
//.row(v-if='editing')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in premiumHairColors',
|
||||
:class='{active: option.active === option, locked: option.locked}')
|
||||
.color-bangs.sprite.customize-option(:class="`hair_bangs_1_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", premiumHairColorKeys, "color")', @click='unlock(`hair.color.${premiumHairColorKeys.join(",hair.color.")}`)') {{ $t('purchaseAll') }}
|
||||
.row(v-if='editing && set.key !== "undefined"', v-for='set in seasonalHairColors')
|
||||
.col-12.customize-options
|
||||
//h3(v-if='!hideSet(set)') {{set.text}}
|
||||
.option(v-for='option in set.options',
|
||||
:class='{active: option.active, locked: option.locked, hide: option.hide}')
|
||||
.skin.sprite.customize-option(:class="`hair_bangs_1_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!hideSet(set) && !userOwnsSet("hair", set.keys, "color")', @click='unlock(`hair.color.${set.keys.join(",hair.color.")}`)') {{ $t('purchaseAll') }}
|
||||
#style.row(v-if='activeSubPage === "style"')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in baseHair3',
|
||||
@@ -124,7 +128,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair3Keys, "base")', @click='unlock(`hair.base.${baseHair3Keys.join(",hair.base.")}`)') $t('purchaseAll')
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair3Keys, "base")', @click='unlock(`hair.base.${baseHair3Keys.join(",hair.base.")}`)') {{ $t('purchaseAll') }}
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in baseHair4',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
@@ -133,7 +137,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair4Keys, "base")', @click='unlock(`hair.base.${baseHair4Keys.join(",hair.base.")}`)') $t('purchaseAll')
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair4Keys, "base")', @click='unlock(`hair.base.${baseHair4Keys.join(",hair.base.")}`)') {{ $t('purchaseAll') }}
|
||||
#bangs.row(v-if='activeSubPage === "bangs"')
|
||||
.col-12.customize-options
|
||||
.head_0.option(@click='set({"preferences.hair.bangs": 0})',
|
||||
@@ -155,7 +159,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair2Keys, "base")', @click='unlock(`hair.base.${baseHair2Keys.join(",hair.base.")}`)') $t('purchaseAll')
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair2Keys, "base")', @click='unlock(`hair.base.${baseHair2Keys.join(",hair.base.")}`)') {{ $t('purchaseAll') }}
|
||||
#facialhair.row(v-if='activeSubPage === "facialhair"')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in baseHair5',
|
||||
@@ -165,7 +169,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair5Keys, "beard")', @click='unlock(`hair.beard.${baseHair5Keys.join(",hair.beard.")}`)') $t('purchaseAll')
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair5Keys, "beard")', @click='unlock(`hair.beard.${baseHair5Keys.join(",hair.beard.")}`)') {{ $t('purchaseAll') }}
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in baseHair6',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
@@ -174,7 +178,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair6Keys, "mustache")', @click='unlock(`hair.mustache.${baseHair6Keys.join(",hair.mustache.")}`)') $t('purchaseAll')
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair6Keys, "mustache")', @click='unlock(`hair.mustache.${baseHair6Keys.join(",hair.mustache.")}`)') {{ $t('purchaseAll') }}
|
||||
#extra.section.container.customize-section(v-if='activeTopPage === "extra"')
|
||||
.row.sub-menu.col-6.offset-3.text-center
|
||||
.col-4.text-center.sub-menu-item(@click='changeSubPage("glasses")', :class='{active: activeSubPage === "glasses"}')
|
||||
@@ -200,7 +204,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!animalEarsOwned', @click='unlock(animalEarsUnlockString)') $t('purchaseAll')
|
||||
button.btn.btn-secondary.purchase-all(v-if='!animalEarsOwned', @click='unlock(animalEarsUnlockString)') {{ $t('purchaseAll') }}
|
||||
#wheelchairs.row(v-if='activeSubPage === "wheelchair"')
|
||||
.col-12.customize-options.weelchairs
|
||||
.option(@click='set({"preferences.chair": "none"})', :class='{active: user.preferences.chair === "none"}')
|
||||
@@ -508,6 +512,10 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
}
|
||||
|
||||
.option.hide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.customize-options .option {
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
@@ -756,14 +764,18 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
import map from 'lodash/map';
|
||||
import get from 'lodash/get';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import avatar from './avatar';
|
||||
import { getBackgroundShopSets } from '../../common/script/libs/shops';
|
||||
import unlock from '../../common/script/ops/unlock';
|
||||
import guide from 'client/mixins/guide';
|
||||
import notifications from 'client/mixins/notifications';
|
||||
import appearance from 'common/script/content/appearance';
|
||||
import appearanceSets from 'common/script/content/appearance/sets';
|
||||
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
|
||||
@@ -777,6 +789,9 @@ import gem from 'assets/svg/gem.svg';
|
||||
import pin from 'assets/svg/pin.svg';
|
||||
import isPinned from 'common/script/libs/isPinned';
|
||||
|
||||
const skinsBySet = groupBy(appearance.skin, 'set.key');
|
||||
const hairColorBySet = groupBy(appearance.hair.color, 'set.key');
|
||||
|
||||
let tasksByCategory = {
|
||||
work: [
|
||||
{
|
||||
@@ -1029,6 +1044,70 @@ export default {
|
||||
});
|
||||
return options;
|
||||
},
|
||||
seasonalSkins () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
|
||||
let seasonalSkins = [];
|
||||
for (let key in skinsBySet) {
|
||||
let set = skinsBySet[key];
|
||||
|
||||
let keys = set.map(item => {
|
||||
return item.key;
|
||||
});
|
||||
|
||||
let options = keys.map(optionKey => {
|
||||
return this.mapKeysToOption(optionKey, 'skin', '', key);
|
||||
});
|
||||
|
||||
let text = this.$t(key);
|
||||
if (appearanceSets[key] && appearanceSets[key].text) {
|
||||
text = appearanceSets[key].text();
|
||||
}
|
||||
|
||||
let compiledSet = {
|
||||
key,
|
||||
options,
|
||||
keys,
|
||||
text,
|
||||
};
|
||||
seasonalSkins.push(compiledSet);
|
||||
}
|
||||
|
||||
return seasonalSkins;
|
||||
},
|
||||
seasonalHairColors () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
|
||||
let seasonalHairColors = [];
|
||||
for (let key in hairColorBySet) {
|
||||
let set = hairColorBySet[key];
|
||||
|
||||
let keys = set.map(item => {
|
||||
return item.key;
|
||||
});
|
||||
|
||||
let options = keys.map(optionKey => {
|
||||
return this.mapKeysToOption(optionKey, 'hair', 'color', key);
|
||||
});
|
||||
|
||||
let text = this.$t(key);
|
||||
if (appearanceSets[key] && appearanceSets[key].text) {
|
||||
text = appearanceSets[key].text();
|
||||
}
|
||||
|
||||
let compiledSet = {
|
||||
key,
|
||||
options,
|
||||
keys,
|
||||
text,
|
||||
};
|
||||
seasonalHairColors.push(compiledSet);
|
||||
}
|
||||
|
||||
return seasonalHairColors;
|
||||
},
|
||||
premiumHairColors () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
@@ -1117,6 +1196,9 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
hideSet (set) {
|
||||
return moment(appearanceSets[set.key].availableUntil).isBefore(moment());
|
||||
},
|
||||
purchase (type, key) {
|
||||
this.$store.dispatch('shops:purchase', {
|
||||
type,
|
||||
@@ -1124,16 +1206,22 @@ export default {
|
||||
});
|
||||
this.backgroundUpdate = new Date();
|
||||
},
|
||||
mapKeysToOption (key, type, subType) {
|
||||
mapKeysToOption (key, type, subType, set) {
|
||||
let userPreference = subType ? this.user.preferences[type][subType] : this.user.preferences[type];
|
||||
let userPurchased = subType ? this.user.purchased[type][subType] : this.user.purchased[type];
|
||||
let locked = !userPurchased || !userPurchased[key];
|
||||
let pathKey = subType ? `${type}.${subType}` : `${type}`;
|
||||
let hide = false;
|
||||
|
||||
if (set && appearanceSets[set]) {
|
||||
if (locked) hide = moment(appearanceSets[set].availableUntil).isBefore(moment());
|
||||
}
|
||||
|
||||
let option = {};
|
||||
option.key = key;
|
||||
option.active = userPreference === key;
|
||||
option.locked = locked;
|
||||
option.hide = hide;
|
||||
option.click = () => {
|
||||
return locked ? this.unlock(`${pathKey}.${key}`) : this.set({[`preferences.${pathKey}`]: key});
|
||||
};
|
||||
|
||||
@@ -234,7 +234,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
sendMessage () {
|
||||
this.userIdToMessage = this.user._id;
|
||||
this.$store.state.userIdToMessage = this.user._id;
|
||||
this.$root.$emit('show::modal', 'private-message');
|
||||
},
|
||||
async getMembers () {
|
||||
|
||||
@@ -170,7 +170,7 @@ export default {
|
||||
const response = await this.$store.dispatch('guilds:inviteToQuest', {groupId: this.group._id, key});
|
||||
const quest = response.data.data;
|
||||
|
||||
this.$store.party.data.quest = quest;
|
||||
this.$store.state.party.data.quest = quest;
|
||||
this.$root.$emit('hide::modal', 'start-quest-modal');
|
||||
},
|
||||
},
|
||||
|
||||
@@ -30,39 +30,39 @@
|
||||
.col
|
||||
+featureBullet("{{ $t('gemBenefit3') }}")
|
||||
+featureBullet("{{ $t('gemBenefit4') }}")
|
||||
.card-deck
|
||||
.card.text-center
|
||||
.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 $.99
|
||||
.card.text-center
|
||||
button.btn.btn-primary(@click='gemAmount = 4') {{gemAmount === 4 ? $t('selected') : '$1.00'}}
|
||||
.card.text-center.col-3(:class="{active: gemAmount === 21}")
|
||||
.card-img-top
|
||||
.mx-auto(v-html='icons.twentyOneGems', style='"height: 55px; width: 47.5px; margin-top: 1.85em;"')
|
||||
.card-body
|
||||
.gem-count 21
|
||||
.gem-text {{ $t('gems') }}
|
||||
.divider
|
||||
button.btn.btn-primary $4.99
|
||||
.card.text-center
|
||||
button.btn.btn-primary(@click='gemAmount = 21') {{gemAmount === 21 ? $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 $9.99
|
||||
.card.text-center
|
||||
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 $19.99
|
||||
button.btn.btn-primary(@click='gemAmount = 84') {{gemAmount === 84 ? $t('selected') : '$20.00'}}
|
||||
.row.text-center
|
||||
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
|
||||
.card-deck
|
||||
@@ -100,63 +100,63 @@
|
||||
+featureBullet("{{ $t('subscriptionBenefit5') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit6') }}")
|
||||
.card-deck
|
||||
.card.text-center
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_earned"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 4
|
||||
span.superscript.muted .99
|
||||
span 5
|
||||
span.superscript.muted .00
|
||||
.small {{ $t('everyMonth') }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:25})')
|
||||
.spacer
|
||||
button.btn.btn-primary {{ $t('select') }}
|
||||
.card.text-center
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_earned"') {{ subscriptionPlan === "basic_earned" ? $t('select') : $t('selected') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_3mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 14
|
||||
span.superscript.muted .99
|
||||
span 15
|
||||
span.superscript.muted .00
|
||||
.small {{ $t('everyXMonths', {interval: 3}) }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:30})')
|
||||
p.benefits(v-markdown='$t("receiveMysticHourglass")')
|
||||
button.btn.btn-primary {{ $t('select') }}
|
||||
.card.text-center
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_3mo"') {{ subscriptionPlan === "basic_3mo" ? $t('select') : $t('selected') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_6mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 29
|
||||
span.superscript.muted .99
|
||||
span 30
|
||||
span.superscript.muted .00
|
||||
.small {{ $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 {{ $t('select') }}
|
||||
.card.text-center
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_6mo"') {{ subscriptionPlan === "basic_6mo" ? $t('select') : $t('selected') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_12mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 47
|
||||
span.superscript.muted .99
|
||||
span 48
|
||||
span.superscript.muted .00
|
||||
.small {{ $t('everyYear') }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:45})')
|
||||
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:4})')
|
||||
button.btn.btn-primary {{ $t('select') }}
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_12mo"') {{ subscriptionPlan === "basic_12mo" ? $t('select') : $t('selected') }}
|
||||
.row.text-center
|
||||
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
|
||||
.row.text-center
|
||||
a.mx-auto {{ $t('haveCouponCode') }}
|
||||
.card-deck
|
||||
.card.text-center.payment-method
|
||||
.card-body(@click='showStripe({})')
|
||||
.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(:href='paypalCheckoutLink', target='_blank')
|
||||
a.card-body.paypal(:href='paypalSubscriptionLink', target='_blank')
|
||||
img(src='~assets/images/paypal.png')
|
||||
.card.text-center.payment-method
|
||||
.card-body.amazon(@click="amazonPaymentsInit({type: 'single'})")
|
||||
.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;"')
|
||||
@@ -198,12 +198,24 @@
|
||||
border: solid 2px #e1e0e3;
|
||||
}
|
||||
|
||||
.gem-deck {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 1em;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
}
|
||||
|
||||
.card.active {
|
||||
border-color: #24cc8f;
|
||||
button {
|
||||
background-color: #24cc8f;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 80%;
|
||||
height: 1px;
|
||||
@@ -261,6 +273,10 @@
|
||||
background-color: #e1e0e3;
|
||||
}
|
||||
|
||||
.payment-method:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.paypal {
|
||||
padding-top: 1.3em;
|
||||
}
|
||||
@@ -369,6 +385,8 @@
|
||||
fortyTwoGems,
|
||||
eightyFourGems,
|
||||
}),
|
||||
gemAmount: 0,
|
||||
subscriptionPlan: '',
|
||||
selectedPage: 'subscribe',
|
||||
amazonPayments: {},
|
||||
planGemLimits,
|
||||
|
||||
@@ -21,7 +21,6 @@ import notifications from 'client/mixins/notifications';
|
||||
|
||||
export default {
|
||||
mixins: [notifications],
|
||||
props: ['userIdToMessage'],
|
||||
components: {
|
||||
bModal,
|
||||
},
|
||||
@@ -29,8 +28,19 @@ export default {
|
||||
return {
|
||||
privateMessage: '',
|
||||
loading: false,
|
||||
userIdToMessage: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
userIdToMessageStore () {
|
||||
return this.$store.state.userIdToMessage;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
userIdToMessageStore () {
|
||||
this.userIdToMessage = this.userIdToMessageStore;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async sendPrivateMessage () {
|
||||
if (!this.privateMessage || !this.userIdToMessage) return;
|
||||
@@ -45,6 +55,8 @@ export default {
|
||||
this.loading = false;
|
||||
|
||||
this.text(this.$t('messageSentAlert'));
|
||||
|
||||
this.privateMessage = '';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
a.purchase(:href='paypalPurchaseLink', :disabled='!subscription.key', target='_blank')
|
||||
img(src='https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png', :alt="$t('paypal')")
|
||||
.col-md-4
|
||||
a.purchase(@click="amazonPaymentsInit({type: 'subscription', subscription:subscription.key, coupon:subscription.coupon})")
|
||||
a.btn.btn-secondary.purchase(@click="amazonPaymentsInit({type: 'subscription', subscription:subscription.key, coupon:subscription.coupon})")
|
||||
img(src='https://payments.amazon.com/gp/cba/button', :alt="$t('amazonPayments')")
|
||||
|
||||
.row
|
||||
@@ -153,12 +153,6 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
paypalPurchaseLink () {
|
||||
let couponString = '';
|
||||
if (this.subscription.coupon) couponString = `&coupon=${this.subscription.coupon}`;
|
||||
return `/paypal/subscribe?_id=${this.user._id}&apiToken=${this.user.apiToken}&sub=${this.subscription.key}${couponString}`;
|
||||
// @TODO don't put API Token in URL parameters
|
||||
},
|
||||
subscriptionBlocksOrdered () {
|
||||
let subscriptions = filter(subscriptionBlocks, (o) => {
|
||||
return o.discount !== true;
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
.row
|
||||
.col-6
|
||||
img(src='~assets/images/home/home-main@3x.png', width='357px')
|
||||
h1 Motivate yourself to achieve your goals.
|
||||
p.section-main It's time to have fun when you get things done! Join over 2 million Habiticans and improve your life one task at a time.
|
||||
h1 {{$t('motivateYourself')}}
|
||||
p.section-main {{$t('timeToGetThingsDone')}}
|
||||
.col-6
|
||||
h3.text-center Sign Up For Free
|
||||
h3.text-center {{$t('singUpForFree')}}
|
||||
div.text-center
|
||||
button.social-button(@click='socialAuth("facebook")')
|
||||
.svg-icon.social-icon(v-html="icons.facebookIcon")
|
||||
@@ -21,14 +21,14 @@
|
||||
.svg-icon.social-icon(v-html="icons.googleIcon")
|
||||
span {{$t('signUpWithSocial', {social: 'Google'})}}
|
||||
.strike
|
||||
span OR
|
||||
span {{$t('or')}}
|
||||
.form
|
||||
input.form-control(type='text', placeholder='Login Name', v-model='username', :class='{"input-valid": username.length > 0}')
|
||||
input.form-control(type='email', placeholder='Email', v-model='email', :class='{"input-invalid": emailInvalid, "input-valid": emailValid}')
|
||||
input.form-control(type='password', placeholder='Password', v-model='password', :class='{"input-valid": password.length > 0}')
|
||||
input.form-control(type='password', placeholder='Confirm Password', v-model='passwordConfirm', :class='{"input-invalid": passwordConfirmInvalid, "input-valid": passwordConfirmValid}')
|
||||
p.form-text(v-once, v-html="$t('termsAndAgreement')")
|
||||
button.sign-up(@click='register()') Sign Up
|
||||
button.sign-up(@click='register()') {{$t('signup')}}
|
||||
.col-12
|
||||
.spacer.svg-icon(v-html='icons.spacer')
|
||||
|
||||
@@ -38,21 +38,21 @@
|
||||
.container
|
||||
.row
|
||||
.col-6.offset-3.text-center
|
||||
h2 Gamify Your Life
|
||||
p.section-main Habitica is a free habit-building and productivity app that treats your real life like a game. With in-game rewards and punishments to motivate you and a strong social network to inspire you, Habitica can help you achieve your goals to become healthy, hard-working, and happy.
|
||||
h2 {{$t('gamifyYourLife')}}
|
||||
p.section-main {{$t('aboutHabitica')}}
|
||||
.row
|
||||
.col-4
|
||||
img.track-habits(src='~assets/images/home/track-habits@3x.png', width='354px', height='228px')
|
||||
strong Track Your Habits and Goals
|
||||
p Stay accountable by tracking and managing your Habits, Daily goals, and To-Do list with Habitica’s easy-to-use mobile apps and web interface.
|
||||
strong {{$t('trackYourGoals')}}
|
||||
p {{$t('trackYourGoalsDesc')}}
|
||||
.col-4
|
||||
img(src='~assets/images/home/earn-rewards@3x.png', width='316px', height='244px')
|
||||
strong Earn Rewards for Your Goals
|
||||
p Check off tasks to level up your Avatar and unlock in-game features such as battle armor, mysterious pets, magic skills, and even quests!
|
||||
strong {{$t('earnRewards')}}
|
||||
p {{$t('earnRewardsDesc')}}
|
||||
.col-4
|
||||
img(src='~assets/images/home/battle-monsters@3x.png', width='303px', height='244px')
|
||||
strong Battle Monsters with Friends
|
||||
p Fight monsters with other Habiticans! Use the Gold that you earn to buy in-game or custom rewards, like watching an episode of your favorite TV show.
|
||||
strong {{$t('battleMonsters')}}
|
||||
p {{$t('battleMonstersDesc')}}
|
||||
.col-12
|
||||
.spacer.svg-icon(v-html='icons.spacer')
|
||||
|
||||
@@ -60,20 +60,20 @@
|
||||
.container.text-center
|
||||
.row
|
||||
.col-12
|
||||
h2 Players Use Habitica to Improve
|
||||
h2 {{$t('playersUseToImprove')}}
|
||||
.row
|
||||
.col-4
|
||||
img(src='~assets/images/home/health-fitness@3x.png', width='300px', height='300px')
|
||||
strong Health and Fitness
|
||||
p Never motivated to floss? Can't seem to get to the gym? Habitica finally makes it fun to get healthy.
|
||||
strong {{$t('healthAndFitness')}}
|
||||
p {{$t('healthAndFitnessDesc')}}
|
||||
.col-4
|
||||
img(src='~assets/images/home/school-work@3x.png', width='300px', height='300px')
|
||||
strong School and Work
|
||||
p Whether you're preparing a report for your teacher or your boss, it's easy to keep track of your progress as you tackle your toughest tasks.
|
||||
strong {{$t('schoolAndWork')}}
|
||||
p {{$t('schoolAndWorkDesc')}}
|
||||
.col-4
|
||||
img(src='~assets/images/home/much-more@3x.png', width='300px', height='300px')
|
||||
strong And much, much more!
|
||||
p Our fully customizable task list means that you can shape Habitica to fit your personal goals. Work on creative projects, emphasize self-care, or pursue a different dream -- it's all up to you.
|
||||
strong {{$t('muchmuchMore')}}
|
||||
p {{$t('muchmuchMoreDesc')}}
|
||||
.col-12
|
||||
.spacer.svg-icon(v-html='icons.spacer')
|
||||
.container-fluid
|
||||
@@ -85,8 +85,8 @@
|
||||
.col-6
|
||||
.iphones.svg-icon(v-html='icons.iphones')
|
||||
.col-6.text-column
|
||||
h2 Level Up Anywhere
|
||||
p Our mobile apps make it simple to keep track of your tasks on-the-go. Accomplish your goals with a single tap, no matter where you are.
|
||||
h2 {{ $t('levelUpAnywhere') }}
|
||||
p {{ $t('levelUpAnywhereDesc') }}
|
||||
a.app.svg-icon(v-html='icons.googlePlay', href='https://play.google.com/store/apps/details?id=com.habitrpg.android.habitica', target='_blank')
|
||||
a.app.svg-icon(v-html='icons.iosAppStore', href='https://itunes.apple.com/us/app/habitica-gamified-task-manager/id994882113?mt=8', target='_blank')
|
||||
.container-fluid
|
||||
@@ -95,13 +95,13 @@
|
||||
#call-to-action.purple-4
|
||||
.container.featured
|
||||
.row.text-center
|
||||
h3.col-12 Join over 2,000,000 people having fun while accomplishing their goals!
|
||||
h3.col-12 {{ $t('joinMany') }}
|
||||
.row
|
||||
.col-12.text-center
|
||||
button.btn.btn-primary.join-button(@click='playButtonClick()') Join Habitica Today
|
||||
button.btn.btn-primary.join-button(@click='playButtonClick()') {{ $t('joinToday') }}
|
||||
.row.featured
|
||||
.col-12.text-center
|
||||
strong Featured in
|
||||
strong {{ $t('featuredIn') }}
|
||||
.container-fluid.featured
|
||||
.row
|
||||
.col-12
|
||||
@@ -115,11 +115,6 @@
|
||||
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/discover-logo.png', alt="$t(altAttrDiscover)")
|
||||
.container-fluid
|
||||
.seamless_stars_varied_opacity_repeat
|
||||
|
||||
#bottom-wrap.purple-4
|
||||
#bottom-background
|
||||
.seamless_mountains_demo_repeat
|
||||
.midground_foreground_extended2
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -240,13 +235,19 @@
|
||||
.social-button {
|
||||
border-radius: 2px;
|
||||
border: solid 2px #bda8ff;
|
||||
width: 206px;
|
||||
height: 40px;
|
||||
width: 48%;
|
||||
min-height: 40px;
|
||||
padding: .5em;
|
||||
background: transparent;
|
||||
margin-right: .5em;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.social-button:hover {
|
||||
cursor: pointer;
|
||||
border-color: #fff;
|
||||
}
|
||||
|
||||
.social-icon {
|
||||
margin-right: 1em;
|
||||
width: 18px;
|
||||
@@ -290,17 +291,28 @@
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.form {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
}
|
||||
|
||||
input {
|
||||
margin-bottom: 1em;
|
||||
border-radius: 2px;
|
||||
background-color: #432874;
|
||||
border-color: #432874;
|
||||
color: $purple-400;
|
||||
border: solid 2px transparent;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border: solid 2px #9a62ff;
|
||||
color: #fff;
|
||||
background-color: #36205d;
|
||||
}
|
||||
|
||||
input:hover {
|
||||
background-color: #36205d;
|
||||
}
|
||||
|
||||
button.sign-up {
|
||||
@@ -469,33 +481,6 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#bottom-wrap {
|
||||
padding-top: 10em;
|
||||
}
|
||||
|
||||
#bottom-background {
|
||||
position: relative;
|
||||
|
||||
.seamless_mountains_demo_repeat {
|
||||
background-image: url('~assets/images/auth/seamless_mountains_demo.png');
|
||||
background-repeat: repeat-x;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.midground_foreground_extended2 {
|
||||
background-image: url('~assets/images/auth/midground_foreground_extended2.png');
|
||||
position: relative;
|
||||
width: 1500px;
|
||||
max-width: 100%;
|
||||
height: 150px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -7,11 +7,20 @@
|
||||
|
||||
#purple-footer
|
||||
app-footer
|
||||
|
||||
#bottom-wrap.purple-4
|
||||
#bottom-background
|
||||
.seamless_mountains_demo_repeat
|
||||
.midground_foreground_extended2
|
||||
</template>
|
||||
|
||||
<style lang='scss'>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.purple-4 {
|
||||
background-color: #271b3d;
|
||||
}
|
||||
|
||||
#purple-footer {
|
||||
background-color: #271b3d;
|
||||
|
||||
@@ -34,6 +43,33 @@
|
||||
}
|
||||
}
|
||||
|
||||
#bottom-wrap {
|
||||
padding-top: 10em;
|
||||
}
|
||||
|
||||
#bottom-background {
|
||||
position: relative;
|
||||
|
||||
.seamless_mountains_demo_repeat {
|
||||
background-image: url('~assets/images/auth/seamless_mountains_demo.png');
|
||||
background-repeat: repeat-x;
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.midground_foreground_extended2 {
|
||||
background-image: url('~assets/images/auth/midground_foreground_extended2.png');
|
||||
position: relative;
|
||||
width: 1500px;
|
||||
max-width: 100%;
|
||||
height: 150px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.static-wrapper {
|
||||
.container-fluid {
|
||||
margin: 5em 2em 2em 2em;
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
h4(v-once) {{$t('emptyMessagesLine1')}}
|
||||
p(v-once) {{$t('emptyMessagesLine2')}}
|
||||
.conversations(v-if='filtersConversations.length > 0')
|
||||
.conversation(v-for='conversation in conversations', @click='selectConversation(conversation.key)',
|
||||
.conversation(v-for='conversation in filtersConversations', @click='selectConversation(conversation.key)',
|
||||
:class="{active: selectedConversation === conversation.key}")
|
||||
div
|
||||
span(:class="userLevelStyle(conversation)") {{conversation.name}}
|
||||
@@ -213,6 +213,11 @@ export default {
|
||||
conversations[userId].date = message.timestamp;
|
||||
}
|
||||
|
||||
conversations = sortBy(conversations, [(o) => {
|
||||
return moment(o.date).toDate();
|
||||
}]);
|
||||
conversations = conversations.reverse();
|
||||
|
||||
return conversations;
|
||||
},
|
||||
currentMessages () {
|
||||
@@ -220,7 +225,7 @@ export default {
|
||||
return this.conversations[this.selectedConversation].messages;
|
||||
},
|
||||
filtersConversations () {
|
||||
if (!this.search) return Object.values(this.conversations);
|
||||
if (!this.search) return this.conversations;
|
||||
return filter(this.conversations, (conversation) => {
|
||||
return conversation.name.toLowerCase().indexOf(this.search.toLowerCase()) !== -1;
|
||||
});
|
||||
|
||||
@@ -20,46 +20,46 @@ div
|
||||
member-details(:member="user")
|
||||
.row
|
||||
.col-6.offset-3.text-center.nav
|
||||
.nav-item(@click='selectedPage = "profile"', :class="{active: selectedPage === 'profile'}") Profile
|
||||
.nav-item(@click='selectedPage = "stats"', :class="{active: selectedPage === 'stats'}") Stats
|
||||
.nav-item(@click='selectedPage = "achievements"', :class="{active: selectedPage === 'achievements'}") Achievements
|
||||
.nav-item(@click='selectedPage = "profile"', :class="{active: selectedPage === 'profile'}") {{ $t('profile') }}
|
||||
.nav-item(@click='selectedPage = "stats"', :class="{active: selectedPage === 'stats'}") {{ $t('stats') }}
|
||||
.nav-item(@click='selectedPage = "achievements"', :class="{active: selectedPage === 'achievements'}") {{ $t('achievements') }}
|
||||
#userProfile.standard-page(v-show='selectedPage === "profile"', v-if='user.profile')
|
||||
.row
|
||||
.col-8
|
||||
.header
|
||||
h1 {{user.profile.name}}
|
||||
h4
|
||||
strong User Id:
|
||||
strong {{ $t('userId') }}:
|
||||
| {{user._id}}
|
||||
.col-4
|
||||
button.btn.btn-secondary(v-if='user._id === userLoggedIn._id', @click='editing = !editing') Edit
|
||||
button.btn.btn-secondary(v-if='user._id === userLoggedIn._id', @click='editing = !editing') {{ $t('edit') }}
|
||||
.row(v-if='!editing')
|
||||
.col-8
|
||||
.about
|
||||
h2 About
|
||||
h2 {{ $t('about') }}
|
||||
p(v-markdown='user.profile.blurb')
|
||||
.photo
|
||||
h2 Photo
|
||||
h2 {{ $t('photo') }}
|
||||
img.img-rendering-auto(v-if='user.profile.imageUrl', :src='user.profile.imageUrl')
|
||||
|
||||
.col-4
|
||||
.info
|
||||
h2 info
|
||||
h2 {{ $t('info') }}
|
||||
div
|
||||
strong Joined:
|
||||
strong {{ $t('joined') }}:
|
||||
| {{user.auth.timestamps.created}}
|
||||
div
|
||||
strong Total Log Ins:
|
||||
strong {{ $t('totalLogins') }}:
|
||||
span {{ $t('totalCheckins', {count: user.loginIncentives}) }}
|
||||
div
|
||||
| {{getProgressDisplay()}}
|
||||
.progress
|
||||
.progress-bar(role='progressbar', :aria-valuenow='incentivesProgress', aria-valuemin='0', aria-valuemax='100', :style='{width: incentivesProgress + "%"}')
|
||||
span.sr-only {{ incentivesProgress }}% Complete
|
||||
span.sr-only {{ incentivesProgress }}% {{$t('complete')}}
|
||||
// @TODO: Implement in V2 .social
|
||||
|
||||
.row(v-if='editing')
|
||||
h1 Edit Profile
|
||||
h1 {{$t('editProfile')}}
|
||||
.col-12
|
||||
.alert.alert-info.alert-sm(v-html='$t("communityGuidelinesWarning", managerEmail)')
|
||||
|
||||
@@ -87,7 +87,6 @@ div
|
||||
.col-12.text-center
|
||||
button.btn.btn-primary(@click='save()') {{ $t("save") }}
|
||||
button.btn.btn-warning(@click='editing = false') {{ $t("cancel") }}
|
||||
|
||||
#achievements.standard-page.container(v-show='selectedPage === "achievements"', v-if='user.achievements')
|
||||
.row(v-for='(category, key) in achievements')
|
||||
h2.col-12.text-center {{ $t(key+'Achievs') }}
|
||||
@@ -107,94 +106,93 @@ div
|
||||
.row
|
||||
.col-6(v-if='user.achievements.challenges')
|
||||
.achievement-icon.achievement-alien
|
||||
h2.text-center Challeges Won
|
||||
h2.text-center {{$t('challengesWon')}}
|
||||
div(v-for='chal in user.achievements.challenges')
|
||||
span {{chal}}
|
||||
hr
|
||||
.col-6(v-if='user.achievements.quests')
|
||||
.achievement-icon.achievement-karaoke
|
||||
h2.text-center Quests Completed
|
||||
h2.text-center {{$t('questsCompleted')}}
|
||||
div(v-for='(value, key) in user.achievements.quests')
|
||||
span {{ content.quests[key].text() }}
|
||||
span {{ value }}
|
||||
|
||||
#stats.standard-page(v-show='selectedPage === "stats"', v-if='user.preferences')
|
||||
.row
|
||||
.col-6
|
||||
h2.text-center Equipment
|
||||
.col-6 {{$t('equipment')}}
|
||||
h2.text-center
|
||||
.well
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.eyewear}')
|
||||
div(:class="`shop_${equippedItems.eyewear}`")
|
||||
h3 Eyewear
|
||||
h3 {{$t('eyewear')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.head}')
|
||||
div(:class="`shop_${equippedItems.head}`")
|
||||
h3 Head Gear
|
||||
h3 {{$t('headGear')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.headAccessory}')
|
||||
div(:class="`shop_${equippedItems.headAccessory}`")
|
||||
h3 Head Access.
|
||||
h3 {{$t('headAccess')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.backAccessory}')
|
||||
div(:class="`shop_${equippedItems.backAccessory}`")
|
||||
h3 Back Access.
|
||||
h3 {{$t('backAccess')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.armor}')
|
||||
div(:class="`shop_${equippedItems.armor}`")
|
||||
h3 Armor
|
||||
h3 {{$t('armor')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.bodyAccessory}')
|
||||
div(:class="`shop_${equippedItems.bodyAccessory}`")
|
||||
h3 Body Access.
|
||||
h3 {{$t('bodyAccess')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.weapon}')
|
||||
div(:class="`shop_${equippedItems.weapon}`")
|
||||
h3 Main-Hand
|
||||
h3 {{$t('mainHand')}}
|
||||
.col-4.item-wrapper
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.shield}')
|
||||
div(:class="`shop_${equippedItems.shield}`")
|
||||
h3 Off-Hand
|
||||
h3 {{$t('offHand')}}
|
||||
.col-6
|
||||
h2.text-center Costume
|
||||
h2.text-center {{$t('costume')}}
|
||||
.well
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.eyewear}')
|
||||
div(:class="`shop_${costumeItems.eyewear}`")
|
||||
h3 Eyewear
|
||||
h3 {{$t('eyewear')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.head}')
|
||||
div(:class="`shop_${costumeItems.head}`")
|
||||
h3 Head Gear
|
||||
h3 {{$t('headGear')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.headAccessory}')
|
||||
div(:class="`shop_${costumeItems.headAccessory}`")
|
||||
h3 Head Access.
|
||||
h3 {{$t('headAccess')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.backAccessory}')
|
||||
div(:class="`shop_${costumeItems.backAccessory}`")
|
||||
h3 Back Access.
|
||||
h3 {{$t('backAccess')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.armor}')
|
||||
div(:class="`shop_${costumeItems.armor}`")
|
||||
h3 Armor
|
||||
h3 {{$t('armor')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.bodyAccessory}')
|
||||
div(:class="`shop_${costumeItems.bodyAccessory}`")
|
||||
h3 Body Access.
|
||||
h3 {{$t('bodyAccess')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.weapon}')
|
||||
div(:class="`shop_${costumeItems.weapon}`")
|
||||
h3 Main-Hand
|
||||
h3 {{$t('mainHand')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: user.preferences.background}')
|
||||
div(:class="user.preferences.background")
|
||||
h3 Background
|
||||
h3 {{$t('background')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.shield}')
|
||||
div(:class="`shop_${costumeItems.shield}`")
|
||||
h3 Off-Hand
|
||||
h3 {{$t('offHand')}}
|
||||
.row.pet-mount-row
|
||||
.col-6
|
||||
h2.text-center(v-once) {{ $t('pets') }}
|
||||
@@ -230,7 +228,7 @@ div
|
||||
span {{ mountMasterProgress(user.items.mounts) }}
|
||||
#attributes.row
|
||||
hr.col-12
|
||||
h2.col-12 Attributes
|
||||
h2.col-12 {{$t('attributes')}}
|
||||
.col-6(v-for="(statInfo, stat) in stats")
|
||||
.row.col-12.stats-column
|
||||
.col-4.attribute-label
|
||||
@@ -241,31 +239,33 @@ div
|
||||
.col-6
|
||||
ul.bonus-stats
|
||||
li
|
||||
strong Level:
|
||||
strong {{$t('level')}}:
|
||||
| {{statsComputed.levelBonus[stat]}}
|
||||
li
|
||||
strong Equipment:
|
||||
strong {{$t('equipment')}}:
|
||||
| {{statsComputed.gearBonus[stat]}}
|
||||
li
|
||||
strong Class:
|
||||
strong {{$t('class')}}:
|
||||
| {{statsComputed.classBonus[stat]}}
|
||||
li
|
||||
strong Allocated:
|
||||
strong {{$t('allocated')}}:
|
||||
| {{user.stats[stat]}}
|
||||
li
|
||||
strong Buffs:
|
||||
strong {{$t('buffs')}}:
|
||||
| {{user.stats.buffs[stat]}}
|
||||
#allocation(v-if='user._id === userLoggedIn._id')
|
||||
.row.title-row
|
||||
.col-6
|
||||
h3(v-if='userLevel100Plus', v-once, v-html="$t('noMoreAllocate')")
|
||||
h3(v-if='user.stats.points || userLevel100Plus')
|
||||
| Points Available
|
||||
| {{$t('pointsAvailable')}}
|
||||
.counter.badge(v-if='user.stats.points || userLevel100Plus')
|
||||
| {{user.stats.points}}
|
||||
.col-6
|
||||
.float-right
|
||||
toggle-switch(:label="$t('autoAllocation')", v-model='user.preferences.automaticAllocation', @change='userset({"preferences.automaticAllocation": Boolean(user.preferences.automaticAllocation), "preferences.allocationMode": "taskbased"})')
|
||||
toggle-switch(:label="$t('autoAllocation')",
|
||||
v-model='user.preferences.automaticAllocation',
|
||||
@change='userset({"preferences.automaticAllocation": Boolean(user.preferences.automaticAllocation), "preferences.allocationMode": "taskbased"})')
|
||||
|
||||
.row
|
||||
.col-3(v-for='(statInfo, stat) in allocateStatsList')
|
||||
@@ -273,10 +273,10 @@ div
|
||||
.col-12
|
||||
div(:class='stat') {{ $t(stats[stat].title) }}
|
||||
.number {{ user.stats[stat] }}
|
||||
.points pts
|
||||
.points {{$t('pts')}}
|
||||
.col-4
|
||||
.up(v-if='user.stats.points', @click='allocate(stat)')
|
||||
private-message-modal(:userIdToMessage='userIdToMessage')
|
||||
private-message-modal
|
||||
send-gems-modal(:userReceivingGems='userReceivingGems')
|
||||
</template>
|
||||
|
||||
@@ -686,7 +686,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
sendMessage () {
|
||||
this.userIdToMessage = this.user._id;
|
||||
this.$store.state.userIdToMessage = this.user._id;
|
||||
this.$root.$emit('show::modal', 'private-message');
|
||||
},
|
||||
getProgressDisplay () {
|
||||
|
||||
@@ -2,8 +2,10 @@ import axios from 'axios';
|
||||
|
||||
let AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
||||
let API_TOKEN = '';
|
||||
let API_ID = '';
|
||||
if (AUTH_SETTINGS) {
|
||||
AUTH_SETTINGS = JSON.parse(AUTH_SETTINGS);
|
||||
API_ID = AUTH_SETTINGS.auth.apiId;
|
||||
API_TOKEN = AUTH_SETTINGS.auth.apiToken;
|
||||
}
|
||||
|
||||
@@ -15,7 +17,16 @@ let StripeCheckout = window.StripeCheckout;
|
||||
export default {
|
||||
computed: {
|
||||
paypalCheckoutLink () {
|
||||
return `/paypal/checkout?_id=${this.user._id}&apiToken=${API_TOKEN}`;
|
||||
return `/paypal/checkout?_id=${API_ID}&apiToken=${API_TOKEN}`;
|
||||
},
|
||||
paypalSubscriptionLink () {
|
||||
return `/paypal/subscribe?_id=${API_ID}&apiToken=${API_TOKEN}&sub=${this.subscriptionPlan}`;
|
||||
},
|
||||
paypalPurchaseLink () {
|
||||
if (!this.subscription) return '';
|
||||
let couponString = '';
|
||||
if (this.subscription.coupon) couponString = `&coupon=${this.subscription.coupon}`;
|
||||
return `/paypal/subscribe?_id=${API_ID}&apiToken=${API_TOKEN}&sub=${this.subscription.key}${couponString}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -122,6 +122,7 @@ export default function () {
|
||||
notificationStore: [],
|
||||
modalStack: [],
|
||||
afterLoginRedirect: '',
|
||||
userIdToMessage: '',
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -199,5 +199,25 @@
|
||||
"invalidAttribute": "\"<%= attr %>\" is not a valid attribute.",
|
||||
"notEnoughAttrPoints": "You don't have enough attribute points.",
|
||||
"style": "Style",
|
||||
"facialhair": "Facial"
|
||||
"facialhair": "Facial",
|
||||
"photo": "Photo",
|
||||
"info": "Info",
|
||||
"joined": "Joined",
|
||||
"totalLogins": "Total Log Ins",
|
||||
"editProfile": "Edit Profile",
|
||||
"challengesWon": "Challeges Won",
|
||||
"questsCompleted": "Quests Completed",
|
||||
"equipment": "Equipment",
|
||||
"costume": "Costume",
|
||||
"headGear": "Head Gear",
|
||||
"headAccess": "Head Access.",
|
||||
"backAccess": "Back Access.",
|
||||
"bodyAccess": "Body Access.",
|
||||
"mainHand": "Main-Hand",
|
||||
"offHand": "Off-Hand",
|
||||
"level": "Level",
|
||||
"allocated": "Allocated",
|
||||
"buffs": "Buffs",
|
||||
"pointsAvailable": "Points Available",
|
||||
"pts": "pts"
|
||||
}
|
||||
|
||||
@@ -282,5 +282,30 @@
|
||||
"confirmPasswordPlaceholder": "Make sure it's the same password!",
|
||||
"joinHabitica": "Join Habitica",
|
||||
"alreadyHaveAccountLogin": "Already have a Habitica account? <strong>Log in.</strong>",
|
||||
"dontHaveAccountSignup": "Don’t have a Habitica account? <strong>Sign up.</strong>"
|
||||
"dontHaveAccountSignup": "Don’t have a Habitica account? <strong>Sign up.</strong>",
|
||||
"motivateYourself": "Motivate yourself to achieve your goals.",
|
||||
"timeToGetThingsDone": "It's time to have fun when you get things done! Join over 2 million Habiticans and improve your life one task at a time.",
|
||||
"singUpForFree": "Sign Up For Free",
|
||||
"or": "OR",
|
||||
"gamifyYourLife": "Gamify Your Life",
|
||||
"aboutHabitica": "Habitica is a free habit-building and productivity app that treats your real life like a game. With in-game rewards and punishments to motivate you and a strong social network to inspire you, Habitica can help you achieve your goals to become healthy, hard-working, and happy.",
|
||||
"trackYourGoals": "Track Your Habits and Goals",
|
||||
"trackYourGoalsDesc": "Stay accountable by tracking and managing your Habits, Daily goals, and To-Do list with Habitica’s easy-to-use mobile apps and web interface.",
|
||||
"earnRewards": "Earn Rewards for Your Goals",
|
||||
"earnRewardsDesc": "Check off tasks to level up your Avatar and unlock in-game features such as battle armor, mysterious pets, magic skills, and even quests!",
|
||||
"battleMonsters": "Battle Monsters with Friends",
|
||||
"battleMonstersDesc": "Fight monsters with other Habiticans! Use the Gold that you earn to buy in-game or custom rewards, like watching an episode of your favorite TV show.",
|
||||
"playersUseToImprove": "Players Use Habitica to Improve",
|
||||
"healthAndFitness": "Health and Fitness",
|
||||
"healthAndFitnessDesc": "Never motivated to floss? Can't seem to get to the gym? Habitica finally makes it fun to get healthy.",
|
||||
"schoolAndWork": "School and Work",
|
||||
"schoolAndWorkDesc": "Whether you're preparing a report for your teacher or your boss, it's easy to keep track of your progress as you tackle your toughest tasks.",
|
||||
"muchmuchMore": "And much, much more!",
|
||||
"muchmuchMoreDesc": "Our fully customizable task list means that you can shape Habitica to fit your personal goals. Work on creative projects, emphasize self-care, or pursue a different dream -- it's all up to you.",
|
||||
"levelUpAnywhere": "Level Up Anywhere",
|
||||
"levelUpAnywhereDesc": "Our mobile apps make it simple to keep track of your tasks on-the-go. Accomplish your goals with a single tap, no matter where you are.",
|
||||
"joinMany": "Join over 2,000,000 people having fun while accomplishing their goals!",
|
||||
"joinToday": "Join Habitica Today",
|
||||
"featuredIn": "Featured in",
|
||||
"signup": "Sign Up"
|
||||
}
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
"subscriberItemText": "Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month. See the wiki's 'Mystery Item' page for more information.",
|
||||
"all": "All",
|
||||
"none": "None",
|
||||
"or": "Or",
|
||||
"and": "and",
|
||||
"loginSuccess": "Login successful!",
|
||||
"youSure": "Are you sure?",
|
||||
@@ -279,5 +278,6 @@
|
||||
"messages": "Messages",
|
||||
"emptyMessagesLine1": "You don't have any messages",
|
||||
"emptyMessagesLine2": "Send a message to start a conversation!",
|
||||
"letsgo": "Let's Go!"
|
||||
"letsgo": "Let's Go!",
|
||||
"selected": "Selected"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user