mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-18 07:07:35 +01:00
new client misc fixes (#9033)
* show quests and open quest dialog on click * extract questDialogContent/Drops to separate components & use those in startQuestModal & buyQuestModal * fix market search * remove & readd pinned gear on revive * remove listener once destroyed
This commit is contained in:
@@ -3,43 +3,20 @@
|
||||
.left-panel.content
|
||||
h3.text-center Quests
|
||||
.row
|
||||
.col-4.quest-col(v-for='(value, key, index) in user.items.quests', @click='selectQuest(key)', :class="{selected: key === selectedQuest}", v-if='value > 0')
|
||||
.col-4.quest-col(v-for='(value, key, index) in user.items.quests', @click='selectQuest({key})', :class="{selected: key === selectedQuest}", v-if='value > 0')
|
||||
.quest-wrapper
|
||||
.quest(:class="'inventory_quest_scroll_' + key")
|
||||
.row
|
||||
.col-10.offset-1.text-center
|
||||
span.description Can’t find a quest to start? Try checking out the Quest Shop in the Market for new releases!
|
||||
span.description(v-once) {{ $t('noQuestToStart') }}
|
||||
div(v-if='questData')
|
||||
.quest-image(:class="'quest_' + questData.key")
|
||||
h2.text-center {{questData.text()}}
|
||||
//- span by: Keith Holliday @TODO: Add author
|
||||
p(v-html="questData.notes()")
|
||||
div.quest-details
|
||||
div(v-if=' questData.collect')
|
||||
Strong {{$t('collect')}}:
|
||||
span(v-for="(value, key, index) in questData.collect")
|
||||
| {{$t('collectionItems', { number: questData.collect[key].count, items: questData.collect[key].text() })}}
|
||||
div
|
||||
Strong {{$t('difficulty')}}:
|
||||
span
|
||||
.svg-icon.difficulty-star(v-html="icons.difficultyStarIcon")
|
||||
questDialogContent(:item="questData")
|
||||
div.text-center
|
||||
button.btn.btn-primary(@click='questInit()') {{$t('inviteToPartyOrQuest')}}
|
||||
div.text-center
|
||||
p {{$t('inviteInformation')}}
|
||||
.side-panel(v-if='questData')
|
||||
h4.text-center {{$t('rewards')}}
|
||||
.box
|
||||
.svg-icon.rewards-icon(v-html="icons.starIcon")
|
||||
strong {{questData.drop.exp}} {{$t('experience')}}
|
||||
.box
|
||||
.svg-icon.rewards-icon(v-html="icons.goldIcon")
|
||||
strong {{questData.drop.gp}} {{$t('gold')}}
|
||||
h4.text-center(v-if='questData.drop.items') {{$t('questOwnerRewards')}}
|
||||
.box(v-for='item in questData.drop.items')
|
||||
.rewards-icon(v-if='item.type === "quest"', :class="'quest_' + item.key")
|
||||
.drop-rewards-icon(v-if='item.type === "gear"', :class="'shop_' + item.key")
|
||||
strong.quest-reward-text {{item.text()}}
|
||||
questDialogDrops(:item="questData")
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@@ -54,11 +31,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.quest-image {
|
||||
margin: 0 auto;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
|
||||
.quest-details {
|
||||
margin: 0 auto;
|
||||
@@ -96,7 +69,7 @@
|
||||
|
||||
.quest-col .quest-wrapper {
|
||||
background: $white;
|
||||
padding: .7em;
|
||||
padding: .2em;
|
||||
margin-bottom: 1em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
@@ -109,52 +82,18 @@
|
||||
}
|
||||
|
||||
.side-panel {
|
||||
background: #edecee;
|
||||
position: absolute;
|
||||
height: 460px;
|
||||
width: 320px;
|
||||
top: 2.5em;
|
||||
left: 35em;
|
||||
right: -350px;
|
||||
top: 25px;
|
||||
border-radius: 8px;
|
||||
background-color: $gray-600;
|
||||
box-shadow: 0 2px 16px 0 rgba(26, 24, 29, 0.32);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
width: 364px;
|
||||
z-index: -1;
|
||||
padding-top: 1em;
|
||||
border-radius: 4px;
|
||||
|
||||
.drop-rewards-icon {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.rewards-icon {
|
||||
float: left;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
|
||||
svg {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.quest-reward-text {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.box {
|
||||
width: 220px;
|
||||
height: 64px;
|
||||
border-radius: 2px;
|
||||
background-color: #ffffff;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 1em;
|
||||
padding: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
.difficulty-star {
|
||||
width: 20px;
|
||||
display: inline-block;
|
||||
vertical-align: bottom;
|
||||
height: 93%;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -174,10 +113,16 @@ import starIcon from 'assets/svg/star.svg';
|
||||
import goldIcon from 'assets/svg/gold.svg';
|
||||
import difficultyStarIcon from 'assets/svg/difficulty-star.svg';
|
||||
|
||||
|
||||
import questDialogDrops from '../shops/quests/questDialogDrops';
|
||||
import questDialogContent from '../shops/quests/questDialogContent';
|
||||
|
||||
export default {
|
||||
props: ['group'],
|
||||
components: {
|
||||
bModal,
|
||||
questDialogDrops,
|
||||
questDialogContent,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -198,6 +143,11 @@ export default {
|
||||
mounted () {
|
||||
let questKeys = Object.keys(this.user.items.quests);
|
||||
this.selectedQuest = questKeys[0];
|
||||
|
||||
this.$root.$on('selectQuest', this.selectQuest);
|
||||
},
|
||||
destroyed () {
|
||||
this.$root.$off('selectQuest', this.selectQuest);
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
@@ -207,8 +157,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
selectQuest (quest) {
|
||||
this.selectedQuest = quest;
|
||||
this.selectedQuest = quest.key;
|
||||
},
|
||||
|
||||
async questInit () {
|
||||
Analytics.updateUser({
|
||||
partyID: this.group._id,
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
)
|
||||
template(slot="popoverContent", scope="context")
|
||||
h4.popover-content-title {{ context.item.text }}
|
||||
.popover-content-text {{ context.item.notes }}
|
||||
.popover-content-text(v-html="context.item.notes")
|
||||
template(slot="itemBadge", scope="context")
|
||||
countBadge(
|
||||
:show="true",
|
||||
@@ -145,6 +145,10 @@
|
||||
@change="resetSpell($event)",
|
||||
@memberSelected="memberSelected($event)",
|
||||
)
|
||||
|
||||
startQuestModal(
|
||||
group="user.party"
|
||||
)
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -184,6 +188,8 @@ import CountBadge from 'client/components/ui/countBadge';
|
||||
import SelectMembersModal from 'client/components/selectMembersModal';
|
||||
import HatchedPetDialog from '../stable/hatchedPetDialog';
|
||||
|
||||
import startQuestModal from '../../groups/startQuestModal';
|
||||
|
||||
import createAnimal from 'client/libs/createAnimal';
|
||||
|
||||
import moment from 'moment';
|
||||
@@ -198,6 +204,7 @@ const groups = [
|
||||
['hatchingPotions', 'Pet_HatchingPotion_'],
|
||||
['food', 'Pet_Food_'],
|
||||
['special', 'inventory_special_', allowedSpecialItems],
|
||||
['quests', 'inventory_quest_scroll_'],
|
||||
].map(([group, classPrefix, allowedItems]) => {
|
||||
return {
|
||||
key: group,
|
||||
@@ -221,6 +228,7 @@ export default {
|
||||
HatchedPetDialog,
|
||||
CountBadge,
|
||||
SelectMembersModal,
|
||||
startQuestModal,
|
||||
},
|
||||
directives: {
|
||||
drag: DragDropDirective,
|
||||
@@ -403,6 +411,10 @@ export default {
|
||||
} else {
|
||||
this.selectedSpell = item;
|
||||
}
|
||||
} else if (groupKey === 'quests') {
|
||||
this.$root.$emit('show::modal', 'start-quest-modal');
|
||||
|
||||
this.$root.$emit('selectQuest', item);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -642,7 +642,7 @@ export default {
|
||||
}
|
||||
|
||||
if (searchBy) {
|
||||
let foundPosition = gear.text().toLowerCase().indexOf(searchBy);
|
||||
let foundPosition = gear.text.toLowerCase().indexOf(searchBy);
|
||||
if (foundPosition === -1) {
|
||||
return false;
|
||||
}
|
||||
@@ -672,7 +672,7 @@ export default {
|
||||
}
|
||||
|
||||
if (searchBy) {
|
||||
let foundPosition = item.text().toLowerCase().indexOf(searchBy);
|
||||
let foundPosition = item.text.toLowerCase().indexOf(searchBy);
|
||||
if (foundPosition === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
div.content(v-if="item != null")
|
||||
|
||||
div.inner-content
|
||||
slot(name="item", :item="item")
|
||||
|
||||
h4.title {{ itemText }}
|
||||
div.text(v-html="itemNotes")
|
||||
|
||||
questInfo.questInfo(:quest="item")
|
||||
questDialogContent(:item="item")
|
||||
|
||||
div
|
||||
span.svg-icon.inline.icon-32(aria-hidden="true", v-html="(priceType === 'gems') ? icons.gem : icons.gold")
|
||||
@@ -42,17 +37,7 @@
|
||||
) {{ $t('buyNow') }}
|
||||
|
||||
div.right-sidebar(v-if="item.drop")
|
||||
h3(v-once) {{ $t('rewards') }}
|
||||
div.reward-item
|
||||
span.svg-icon.inline.icon(v-html="icons.experience")
|
||||
span.reward-text {{ $t('amountExperience', { amount: item.drop.exp }) }}
|
||||
div.reward-item(v-if="item.drop.gp != 0")
|
||||
span.svg-icon.inline.icon(v-html="icons.gold")
|
||||
span.reward-text {{ $t('amountGold', { amount: item.drop.gp }) }}
|
||||
div.reward-item(v-for="drop in item.drop.items")
|
||||
span.icon
|
||||
div(:class="getDropIcon(drop)")
|
||||
span.reward-text {{ getDropName(drop) }}
|
||||
questDialogDrops(:item="item")
|
||||
|
||||
div.clearfix(slot="modal-footer")
|
||||
span.balance.float-left {{ $t('yourBalance') }}
|
||||
@@ -73,6 +58,8 @@
|
||||
|
||||
.content {
|
||||
text-align: center;
|
||||
max-height: 80vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.item-wrapper {
|
||||
@@ -83,12 +70,7 @@
|
||||
margin: 33px auto auto;
|
||||
width: 400px;
|
||||
}
|
||||
.text {
|
||||
max-height: 220px;
|
||||
margin-bottom: 8px;
|
||||
overflow-y: scroll;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
.questInfo {
|
||||
width: 70%;
|
||||
@@ -117,34 +99,6 @@
|
||||
width: 364px;
|
||||
z-index: -1;
|
||||
height: 100%;
|
||||
|
||||
|
||||
h3 {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.reward-item {
|
||||
width: 306px;
|
||||
height: 84px;
|
||||
border-radius: 2px;
|
||||
background-color: $white;
|
||||
margin-bottom: 8px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
margin: 18px;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
}
|
||||
|
||||
.reward-text {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span.svg-icon.inline.icon-32 {
|
||||
@@ -237,12 +191,17 @@
|
||||
import QuestInfo from './questInfo.vue';
|
||||
import notifications from 'client/mixins/notifications';
|
||||
|
||||
import questDialogDrops from './questDialogDrops';
|
||||
import questDialogContent from './questDialogContent';
|
||||
|
||||
export default {
|
||||
mixins: [currencyMixin, notifications],
|
||||
components: {
|
||||
bModal,
|
||||
BalanceInfo,
|
||||
QuestInfo,
|
||||
questDialogDrops,
|
||||
questDialogContent,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<template lang="pug">
|
||||
div.quest-content
|
||||
.quest-image(:class="'quest_' + item.key")
|
||||
|
||||
h4.title {{ itemText }}
|
||||
div.text(v-html="itemNotes")
|
||||
|
||||
questInfo.questInfo(:quest="item")
|
||||
</template>
|
||||
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.quest-image {
|
||||
margin: 0 auto;
|
||||
margin-bottom: 1em;
|
||||
margin-top: 1.5em;
|
||||
}
|
||||
|
||||
.text {
|
||||
max-height: 220px;
|
||||
margin-bottom: 8px;
|
||||
overflow-y: scroll;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.questInfo {
|
||||
width: 70%;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
import QuestInfo from './questInfo.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
QuestInfo,
|
||||
},
|
||||
computed: {
|
||||
itemText () {
|
||||
if (this.item.text instanceof Function) {
|
||||
return this.item.text();
|
||||
} else {
|
||||
return this.item.text;
|
||||
}
|
||||
},
|
||||
itemNotes () {
|
||||
if (this.item.notes instanceof Function) {
|
||||
return this.item.notes();
|
||||
} else {
|
||||
return this.item.notes;
|
||||
}
|
||||
},
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
106
website/client/components/shops/quests/questDialogDrops.vue
Normal file
106
website/client/components/shops/quests/questDialogDrops.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<template lang="pug">
|
||||
div.questRewards
|
||||
h3.text-center(v-once) {{ $t('rewards') }}
|
||||
div.reward-item
|
||||
span.svg-icon.inline.icon(v-html="icons.experience")
|
||||
span.reward-text {{ $t('amountExperience', { amount: item.drop.exp }) }}
|
||||
div.reward-item(v-if="item.drop.gp != 0")
|
||||
span.svg-icon.inline.icon(v-html="icons.gold")
|
||||
span.reward-text {{ $t('amountGold', { amount: item.drop.gp }) }}
|
||||
h3.text-center(v-if='item.drop.items') {{$t('questOwnerRewards')}}
|
||||
div.reward-item(v-for="drop in item.drop.items")
|
||||
span.icon
|
||||
div(:class="getDropIcon(drop)")
|
||||
span.reward-text {{ getDropName(drop) }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.questRewards {
|
||||
overflow-y: auto;
|
||||
width: 364px;
|
||||
z-index: -1;
|
||||
height: 100%;
|
||||
|
||||
h3 {
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.reward-item {
|
||||
width: 306px;
|
||||
height: 84px;
|
||||
border-radius: 2px;
|
||||
background-color: #ffffff;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 1em;
|
||||
padding: 1em;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
.icon:not(.svg-icon) {
|
||||
height: 68px;
|
||||
width: 68px;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin: 15px;
|
||||
height: 38px;
|
||||
width: 38px;
|
||||
}
|
||||
|
||||
.reward-text {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
import svgGold from 'assets/svg/gold.svg';
|
||||
import svgExperience from 'assets/svg/experience.svg';
|
||||
|
||||
export default {
|
||||
mixins: [],
|
||||
components: {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
gold: svgGold,
|
||||
experience: svgExperience,
|
||||
}),
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getDropIcon (drop) {
|
||||
switch (drop.type) {
|
||||
case 'gear':
|
||||
return `shop_${drop.key}`;
|
||||
case 'hatchingPotions':
|
||||
return `Pet_HatchingPotion_${drop.key}`;
|
||||
case 'food':
|
||||
return `Pet_Food_${drop.key}`;
|
||||
case 'eggs':
|
||||
return `Pet_Egg_${drop.key}`;
|
||||
case 'quests':
|
||||
return `inventory_quest_scroll_${drop.key}`;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
},
|
||||
getDropName (drop) {
|
||||
return drop.text();
|
||||
},
|
||||
},
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -3,7 +3,7 @@
|
||||
span.col-4(v-if="quest.collect") {{ $t('collect') }}
|
||||
span.col-8(v-if="quest.collect")
|
||||
div(v-for="(collect, key) of quest.collect")
|
||||
span {{ collect.count }} {{ collect.text }}
|
||||
span {{ collect.count }} {{ getCollectText(collect) }}
|
||||
|
||||
span.col-4 {{ $t('difficulty') }}
|
||||
span.col-8
|
||||
@@ -78,6 +78,13 @@
|
||||
|
||||
return result;
|
||||
},
|
||||
getCollectText (collect) {
|
||||
if (collect.text instanceof Function) {
|
||||
return collect.text();
|
||||
} else {
|
||||
return collect.text;
|
||||
}
|
||||
},
|
||||
},
|
||||
props: {
|
||||
quest: {
|
||||
|
||||
@@ -117,5 +117,6 @@
|
||||
"loginReward": "<%= count %> Check-ins",
|
||||
"createAccountQuest": "You received this quest when you joined Habitica! If a friend joins, they'll get one too.",
|
||||
"questBundles": "Discounted Quest Bundles",
|
||||
"buyQuestBundle": "Buy Quest Bundle"
|
||||
"buyQuestBundle": "Buy Quest Bundle",
|
||||
"noQuestToStart": "Can’t find a quest to start? Try checking out the Quest Shop in the Market for new releases!"
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
import randomVal from '../libs/randomVal';
|
||||
import predictableRandom from '../fns/predictableRandom';
|
||||
|
||||
import { removePinnedGearByClass, addPinnedGearByClass } from './pinnedGearUtils';
|
||||
|
||||
module.exports = function revive (user, req = {}, analytics) {
|
||||
if (user.stats.hp > 0) {
|
||||
throw new NotAuthorized(i18n.t('cannotRevive', req.language));
|
||||
@@ -81,8 +83,12 @@ module.exports = function revive (user, req = {}, analytics) {
|
||||
let item = content.gear.flat[lostItem];
|
||||
|
||||
if (item) {
|
||||
removePinnedGearByClass(user);
|
||||
|
||||
user.items.gear.owned[lostItem] = false;
|
||||
|
||||
addPinnedGearByClass(user);
|
||||
|
||||
if (user.items.gear.equipped[item.type] === lostItem) {
|
||||
user.items.gear.equipped[item.type] = `${item.type}_base_0`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user