mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 14:17:22 +01:00
Beard and mustache facial hairs now can be bought as a full set for 5 gems (#10338)
* Purchasing All Facial Hairs Fixed * Notifications z-index fixed * Notifications z-index fixed x2 * Z-indexes fixed, facial hairs buying corrected * isPurchaseAllNeeded refactored * isPurchaseAllNeeded is more generic now * Linting Passed
This commit is contained in:
committed by
Matteo Pagliazzi
parent
128ec5a1b1
commit
6c64a1cd8c
@@ -163,32 +163,27 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
||||
:class='{active: user.preferences.hair.bangs === option}')
|
||||
.bangs.sprite.customize-option(:class="`hair_bangs_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.bangs": option})')
|
||||
#facialhair.row(v-if='activeSubPage === "facialhair"')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.head_0.option(@click='set({"preferences.hair.beard": 0})', :class="[{ active: user.preferences.hair.beard === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
|
||||
.option(v-for='option in baseHair5',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.base.sprite.customize-option(:class="`hair_beard_${option.key}_${user.preferences.hair.color}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center(v-if='!userOwnsSet("hair", baseHair5Keys, "beard")')
|
||||
.gem-lock
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 5
|
||||
button.btn.btn-secondary.purchase-all(@click='unlock(`hair.beard.${baseHair5Keys.join(",hair.beard.")}`)') {{ $t('purchaseAll') }}
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.head_0.option(@click='set({"preferences.hair.mustache": 0})', :class="[{ active: user.preferences.hair.mustache === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
|
||||
.option(v-for='option in baseHair6',
|
||||
.option(v-for='option in baseHair5',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.base.sprite.customize-option(:class="`hair_mustache_${option.key}_${user.preferences.hair.color}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center(v-if='!userOwnsSet("hair", baseHair6Keys, "mustache")')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.head_0.option(@click='set({"preferences.hair.beard": 0})', :class="[{ active: user.preferences.hair.beard === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
|
||||
.option(v-for='option in baseHair6',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.base.sprite.customize-option(:class="`hair_beard_${option.key}_${user.preferences.hair.color}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center(v-if="isPurchaseAllNeeded('hair', ['baseHair5', 'baseHair6'], ['mustache', 'beard'])")
|
||||
.gem-lock
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 5
|
||||
button.btn.btn-secondary.purchase-all(@click='unlock(`hair.mustache.${baseHair6Keys.join(",hair.mustache.")}`)') {{ $t('purchaseAll') }}
|
||||
button.btn.btn-secondary.purchase-all(@click='unlock(`hair.mustache.${baseHair5Keys.join(",hair.mustache.")},hair.beard.${baseHair6Keys.join(",hair.beard.")}`)') {{ $t('purchaseAll') }}
|
||||
#extra.section.container.customize-section(v-if='activeTopPage === "extra"')
|
||||
.row.sub-menu
|
||||
.col-3.offset-1.text-center.sub-menu-item(@click='changeSubPage("glasses")', :class='{active: activeSubPage === "glasses"}')
|
||||
@@ -1010,8 +1005,8 @@ export default {
|
||||
baseHair2Keys: [2, 4, 5, 6, 7, 8],
|
||||
baseHair3Keys: [9, 10, 11, 12, 13, 14],
|
||||
baseHair4Keys: [15, 16, 17, 18, 19, 20],
|
||||
baseHair5Keys: [1, 2, 3],
|
||||
baseHair6Keys: [1, 2],
|
||||
baseHair5Keys: [1, 2],
|
||||
baseHair6Keys: [1, 2, 3],
|
||||
animalEarsKeys: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
|
||||
icons: Object.freeze({
|
||||
logoPurple,
|
||||
@@ -1228,7 +1223,7 @@ export default {
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair5Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'beard');
|
||||
return this.mapKeysToOption(key, 'hair', 'mustache');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
@@ -1237,7 +1232,7 @@ export default {
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair6Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'mustache');
|
||||
return this.mapKeysToOption(key, 'hair', 'beard');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
@@ -1335,6 +1330,68 @@ export default {
|
||||
|
||||
return owns;
|
||||
},
|
||||
/**
|
||||
* Allows you to find out whether you need the "Purchase All" button or not. If there are more than 2 unpurchased items, returns true, otherwise returns false.
|
||||
* @param {string} category - The selected category.
|
||||
* @param {string[]} keySets - The items keySets.
|
||||
* @param {string[]} [types] - The items types (subcategories). Optional.
|
||||
* @returns {boolean} - Determines whether the "Purchase All" button is needed (true) or not (false).
|
||||
*/
|
||||
isPurchaseAllNeeded (category, keySets, types) {
|
||||
const purchasedItemsLengths = [];
|
||||
// If item types are specified, count them
|
||||
if (types && types.length > 0) {
|
||||
// Types can be undefined, so we must check them.
|
||||
types.forEach((type) => {
|
||||
if (this.user.purchased[category][type]) {
|
||||
purchasedItemsLengths
|
||||
.push(Object.keys(this.user.purchased[category][type]).length);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
let purchasedItemsCounter = 0;
|
||||
|
||||
// If types are not specified, recursively
|
||||
// search for purchased items in the category
|
||||
const findPurchasedItems = (item) => {
|
||||
if (typeof item === 'object') {
|
||||
Object.values(item)
|
||||
.forEach((innerItem) => {
|
||||
if (typeof innerItem === 'boolean' && innerItem === true) {
|
||||
purchasedItemsCounter += 1;
|
||||
}
|
||||
return findPurchasedItems(innerItem);
|
||||
});
|
||||
}
|
||||
return purchasedItemsCounter;
|
||||
};
|
||||
|
||||
findPurchasedItems(this.user.purchased[category]);
|
||||
if (purchasedItemsCounter > 0) {
|
||||
purchasedItemsLengths.push(purchasedItemsCounter);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't need to count the key sets (below)
|
||||
// if there are no purchased items at all.
|
||||
if (purchasedItemsLengths.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const allItemsLengths = [];
|
||||
// Key sets must be specify correctly.
|
||||
keySets.forEach((keySet) => {
|
||||
allItemsLengths.push(Object.keys(this[keySet]).length);
|
||||
});
|
||||
|
||||
// Simply sum all the length values and
|
||||
// write them into variables for the convenience.
|
||||
const allItems = allItemsLengths.reduce((acc, val) => acc + val);
|
||||
const purchasedItems = purchasedItemsLengths.reduce((acc, val) => acc + val);
|
||||
|
||||
const unpurchasedItems = allItems - purchasedItems;
|
||||
return unpurchasedItems > 2;
|
||||
},
|
||||
prev () {
|
||||
this.modalPage -= 1;
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ div
|
||||
inbox-modal
|
||||
creator-intro
|
||||
profile
|
||||
b-navbar.navbar.navbar-inverse.fixed-top.navbar-expand-lg(type="dark")
|
||||
b-navbar.navbar.navbar-inverse.fixed-top.navbar-expand-lg(type="dark", :class="navbarZIndexClass")
|
||||
.navbar-header
|
||||
.logo.svg-icon.d-none.d-xl-block(v-html="icons.logo")
|
||||
.svg-icon.gryphon.d-md-block.d-none.d-xl-none
|
||||
@@ -145,7 +145,16 @@ div
|
||||
padding-right: 12.5px;
|
||||
height: 56px;
|
||||
box-shadow: 0 1px 2px 0 rgba($black, 0.24);
|
||||
z-index: 1042; // To stay above snakbar notifications and modals
|
||||
}
|
||||
|
||||
.navbar-z-index {
|
||||
&-normal {
|
||||
z-index: 1080;
|
||||
}
|
||||
|
||||
&-modal {
|
||||
z-index: 1035;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-header {
|
||||
@@ -327,7 +336,14 @@ export default {
|
||||
user: 'user.data',
|
||||
userHourglasses: 'user.data.purchased.plan.consecutive.trinkets',
|
||||
groupPlans: 'groupPlans',
|
||||
modalStack: 'modalStack',
|
||||
}),
|
||||
navbarZIndexClass () {
|
||||
if (this.modalStack.length > 0) {
|
||||
return 'navbar-z-index-modal';
|
||||
}
|
||||
return 'navbar-z-index-normal';
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.getUserGroupPlans();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template lang="pug">
|
||||
.notifications
|
||||
div(v-for='notification in notifications', :key='notification.uuid')
|
||||
.notifications(:class="notificationsTopPos")
|
||||
div(v-for='notification in notificationStore', :key='notification.uuid')
|
||||
notification(:notification='notification')
|
||||
</template>
|
||||
|
||||
@@ -8,13 +8,23 @@
|
||||
.notifications {
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
top: 65px;
|
||||
width: 350px;
|
||||
z-index: 1041; // 1041 is above modal backgrounds
|
||||
z-index: 1070; // 1070 is above modal backgrounds
|
||||
|
||||
&-top-pos {
|
||||
&-normal {
|
||||
top: 65px;
|
||||
}
|
||||
|
||||
&-sleeping {
|
||||
top: 105px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'client/libs/store';
|
||||
import notification from './notification';
|
||||
|
||||
export default {
|
||||
@@ -22,8 +32,19 @@ export default {
|
||||
notification,
|
||||
},
|
||||
computed: {
|
||||
notifications () {
|
||||
return this.$store.state.notificationStore;
|
||||
...mapState({
|
||||
notificationStore: 'notificationStore',
|
||||
userSleeping: 'user.data.preferences.sleep',
|
||||
}),
|
||||
notificationsTopPos () {
|
||||
const base = 'notifications-top-pos-';
|
||||
let modifier = '';
|
||||
if (this.userSleeping) {
|
||||
modifier = 'sleeping';
|
||||
} else {
|
||||
modifier = 'normal';
|
||||
}
|
||||
return `${base}${modifier}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user