New client popups profile andmore (#8907)

* Added more styles to user profile modal and replaced memberDetail

* Added notify library

* Added edit avator

* Added notification menu updates

* Fixed lint issues

* Added group invite functionality

* Added many achievement modals

* Added initial quest modals

* Added guild, drops, and rebirth modals

* Added the reset of the achievement modals and fixed lint
This commit is contained in:
Keith Holliday 2017-08-01 12:52:49 -06:00 committed by GitHub
parent bca52cb6fa
commit 0dba37008f
39 changed files with 1624 additions and 348 deletions

View file

@ -125,6 +125,7 @@
"vue": "^2.1.0",
"vue-loader": "^11.0.0",
"vue-mugen-scroll": "^0.2.1",
"vue-notification": "^1.3.2",
"vue-router": "^2.0.0-rc.5",
"vue-style-loader": "^3.0.0",
"vue-template-compiler": "^2.1.10",

View file

@ -1,11 +1,12 @@
<template lang="pug">
#app
notifications
router-view(v-if="!isUserLoggedIn || isStaticPage")
template(v-else)
#loading-screen.h-100.w-100.d-flex.justify-content-center.align-items-center(v-if="!isUserLoaded")
p Loading...
template(v-else)
notifications
notifications-display
app-menu
.container-fluid
app-header
@ -18,7 +19,7 @@
import AppMenu from './components/appMenu';
import AppHeader from './components/appHeader';
import AppFooter from './components/appFooter';
import notifications from './components/notifications';
import notificationsDisplay from './components/notifications';
import { mapState } from 'client/libs/store';
export default {
@ -27,7 +28,7 @@ export default {
AppMenu,
AppHeader,
AppFooter,
notifications,
notificationsDisplay,
},
data () {
return {

View file

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
<g fill="none" fill-rule="evenodd">
<rect width="29.6" height="29.6" x="1.2" y="1.2" stroke="#A5A1AC" stroke-width="2.4" rx="4"/>
<path fill="#A5A1AC" d="M11 11l2-1-2-1-1-2-1 2-2 1 2 1 1 2zM23 14l2-1-2-1-1-2-1 2-2 1 2 1 1 2zM15.333 22.333L18 21l-2.667-1.333L14 17l-1.333 2.667L10 21l2.667 1.333L14 25z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 425 B

View file

@ -0,0 +1,26 @@
<template lang="pug">
b-modal#armoire-empty(:title="$t('armoireText')", size='lg', :hide-footer="true")
.modal-header
.shop_armoire.pull-right
.modal-body
p {{$t('armoireLastItem')}}
br
p {{$t('armoireNotesEmpty')}}
.modal-footer
button.btn.btn-default(@click='close()') {{$t('close')}}
</template>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
methods: {
close () {
this.$root.$emit('hide::modal', 'armoire-empty');
},
},
};
</script>

View file

@ -0,0 +1,120 @@
<template lang="pug">
b-modal#choose-class(:title="$t('chooseClassHeading')", size='lg', :hide-footer="true")
.modal-body.select-class
.container-fluid
.row
.col-md-3(@click='selectedClass = "warrior"')
h5 {{ $t('warriorWiki') }}
figure.herobox(:class='{"selected-class": selectedClass === "warrior"}')
.character-sprites
span(:class='`skin_${user.preferences.skin}`')
span(class='head_0')
span(:class='`${user.preferences.size}_armor_warrior_5`')
span(:class='`hair_base_${user.preferences.hair.base}_${user.preferences.hair.color}`')
span(:class='`hair_bangs_${user.preferences.hair.bangs}_${user.preferences.hair.color}`')
span(:class='`hair_beard_${user.preferences.hair.beard}_${user.preferences.hair.color}`')
span(:class='`hair_mustache_${user.preferences.hair.mustache}_${user.preferences.hair.color}`')
span(class='head_warrior_5')
span(class='shield_warrior_5')
span(class='weapon_warrior_6')
.col-md-3(@click='selectedClass = "wizard"')
h5 {{ $t('mageWiki') }}
figure.herobox(:class='{"selected-class": selectedClass === "wizard"}')
.character-sprites
span(class='`skin_${user.preferences.skin}`')
span(class='head_0')
span(:class='`${user.preferences.size}_armor_wizard_5`')
span(:class='`hair_base_${user.preferences.hair.base}_${user.preferences.hair.color}`')
span(:class='`hair_bangs_${user.preferences.hair.bangs}_${user.preferences.hair.color}`')
span(:class='`hair_beard_${user.preferences.hair.beard}_${user.preferences.hair.color}`')
span(:class='`hair_mustache_${user.preferences.hair.mustache}_${user.preferences.hair.color}`')
span(class='head_wizard_5')
span(class='shield_wizard_5')
span(class='weapon_wizard_6')
.col-md-3(@click='selectedClass = "rogue"')
h5 {{ $t('rogueWiki') }}
figure.herobox(:class='{"selected-class": selectedClass === "rogue"}')
.character-sprites
span(:class='`skin_${user.preferences.skin}`')
span(class='head_0')
span(:class='`${user.preferences.size}_armor_rogue_5`')
span(:class='`hair_base_${user.preferences.hair.base}_${user.preferences.hair.color}`')
span(:class='`hair_bangs_${user.preferences.hair.bangs}_${user.preferences.hair.color}`')
span(:class='`hair_beard_${user.preferences.hair.beard}_${user.preferences.hair.color}`')
span(:class='`hair_mustache_${user.preferences.hair.mustache}_${user.preferences.hair.color}`')
span(class='head_rogue_5')
span(class='shield_rogue_6')
span(class='weapon_rogue_6')
.col-md-3(@click='selectedClass = "healer"')
h5 {{ $t('healerWiki') }}
figure.herobox(ng-class='{"selected-class": selectedClass === "healer"}')
.character-sprites
span(:class='`skin_${user.preferences.skin}`')
span(class='head_0')
span(:class='`${user.preferences.size}_armor_healer_5`')
span(:class='`hair_base_${user.preferences.hair.base}_${user.preferences.hair.color}`')
span(:class='`hair_bangs_${user.preferences.hair.bangs}_${user.preferences.hair.color}`')
span(:class='`hair_beard_${user.preferences.hair.beard}_${user.preferences.hair.color}`')
span(:class='`hair_mustache_${user.preferences.hair.mustache}_${user.preferences.hair.color}`')
span(class='head_healer_5')
span(class='shield_healer_5')
span(class='weapon_healer_6')
br
.well(v-if='selectedClass === "warrior"') {{ $t('warriorText') }}
.well(v-if='selectedClass === "wizard"') {{ $t('mageText') }}
.well(v-if='selectedClass === "rogue"') {{ $t('rogueText') }}
.well(v-if='selectedClass === "healer"') {{ $t('healerText') }}
.modal-footer
span(popover-placement='left', popover-trigger='mouseenter', :popover="$t('optOutOfClassesText')")
button.btn.btn-danger(@click='disableClasses({}); close()') {{ $t('optOutOfClasses') }}
button.btn.btn-primary(:disabled='!selectedClass' @click='changeClass(selectedClass); selectedClass = undefined; close()') {{ $t('select') }}
.pull-left {{ $t('chooseClassLearn') }}
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import Avatar from '../avatar';
import { mapState } from 'client/libs/store';
import percent from '../../../common/script/libs/percent';
import {maxHealth} from '../../../common/script/index';
export default {
components: {
bModal,
Avatar,
},
data () {
return {
maxHealth,
selectedClass: '',
};
},
computed: {
...mapState({user: 'user.data'}),
barStyle () {
return {
width: `${percent(this.user.stats.hp, maxHealth)}%`,
};
},
},
methods: {
close () {
this.$root.$emit('hide::modal', 'choose-class');
},
disableClasses () {
// @TODO:
},
changeClass () {
// @TODO:
},
},
};
</script>

View file

@ -0,0 +1,38 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0') {{ $t('modalContribAchievement') }}
// @TODO: +achievementAvatar('boot',0)
| {{ $t('contribModal', {name: user.profile.name, level: user.contributor.level}) }}
a(:href="$t('conRewardsURL')", target='_blank') {{ $t('contribLink') }}
br
button.btn.btn-primary(style='margin-top:1em' @click='close()') {{ $t('huzzah') }}
// @TODO: +achievementFooter
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import { mapState } from 'client/libs/store';
export default {
components: {
bModal,
},
computed: {
...mapState({user: 'user.data'}),
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -0,0 +1,70 @@
<template lang="pug">
b-modal#death(:title="$t('lostAllHealth')", size='lg', :hide-footer="true")
.modal-body
.container-fluid
.row
.col-6.col-xs-12
.hero-stats
.meter-label(:tooltip="$t('health')")
span.glyphicon.glyphicon-heart
.meter.health(:tooltip='Math.round(user.stats.hp * 100) / 100')
.bar(:style='barStyle')
span.meter-text.value
| {{Math.ceil(user.stats.hp)}} / {{maxHealth}}
figure.herobox.text-center
.character-sprites
avatar(:member='user')
// @TOOD: Sleep +generatedAvatar({sleep:true})
span(class='knockout')
.col-6.col-xs-12
h4.dont-despair {{ $t('dontDespair') }}
p.death-penalty {{ $t('deathPenaltyDetails') }}
.modal-footer
a.btn.btn-danger.btn-lg.flex-column.btn-wrap(@click='revive(); close()') {{ $t('refillHealthTryAgain') }}
h4.text-center {{ $t('dyingOftenTips') }}
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import Avatar from '../avatar';
import { mapState } from 'client/libs/store';
import revive from '../../../common/script/ops/revive';
import percent from '../../../common/script/libs/percent';
import {maxHealth} from '../../../common/script/index';
export default {
components: {
bModal,
Avatar,
},
data () {
return {
maxHealth,
};
},
computed: {
...mapState({user: 'user.data'}),
barStyle () {
return {
width: `${percent(this.user.stats.hp, maxHealth)}%`,
};
},
},
methods: {
close () {
this.$root.$emit('hide::modal', 'death');
},
revive () {
// @TODO: Post
revive(this.user);
},
},
};
</script>

View file

@ -0,0 +1,55 @@
<template lang="pug">
b-modal#drops-enabled(:title="$t('dropsEnabled')", size='lg', :hide-footer="true")
.modal-header
h4 {{ $t('dropsEnabled') }}
.modal-body
p
figure
.item-drop-icon(class='Pet_Egg_Wolf')
span {{ firstDropText }}
br
p
figure
.item-drop-icon(class='Pet_Currency_Gem')
span {{ $t('useGems') }}
.modal-footer
button.btn.btn-default(@click='close()') {{ $t('close') }}
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import { mapState } from 'client/libs/store';
import eggs from '../../../common/script/content/eggs';
export default {
components: {
bModal,
},
data () {
return {
eggs,
};
},
computed: {
...mapState({user: 'user.data'}),
firstDropText () {
return this.$t('firstDrop', {
eggText: this.eggs.all.Wolf.text(),
eggNotes: this.eggs.all.Wolf.notes(),
});
},
},
methods: {
close () {
this.$root.$emit('hide::modal', 'drops-enabled');
},
},
};
</script>

View file

@ -0,0 +1,32 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0') {{ $t('modalAchievement') }}
// @TODO: +achievementAvatar('friends',0)
p {{ $t('invitedFriendText') }}
br
button.btn.btn-primary(@click='close()') {{ $t('huzzah') }}
// @TODO: +achievementFooter
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -0,0 +1,32 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0') {{ $t('modalAchievement') }}
// @TODO: +achievementAvatar('challenge',0)
p {{ $t('joinedChallengeText') }}
br
button.btn.btn-primary(@click='close()') {{ $t('huzzah') }}
// @TODO: +achievementFooter
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -0,0 +1,32 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0') {{ $t('modalAchievement') }}
// @TODO: +achievementAvatar('guild',0)
p {{ $t('joinedGuildText') }}
br
button.btn.btn-primary(@click='close()') {{ $t('huzzah') }}
// @TODO: +achievementFooter
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -0,0 +1,120 @@
<template lang="pug">
b-modal#level-up(:title="$t('levelUpShare')", size='sm', :hide-footer="true")
.modal-content
.modal-body.text-center
h3 {{ $t('gainedLevel') }}
.container-fluid
.row
.herobox
.character-sprites
// @TODO: ({sleep: false})
avatar(:member='user')
.row
.herobox
.avatar-level(:class='userLevelStyle(user)') {{ $t('level') + user.stats.lvl }}
h4 {{ $t('leveledUp', {level: user.stats.lvl}) }}
p {{ $t('fullyHealed') }}
br
div(v-if='user.flags.classSelected && !user.preferences.disableClasses && !user.preferences.automaticAllocation')
a.btn.btn-default(@click='statsAllocationBoxIsOpen = !statsAllocationBoxIsOpen',
data-toggle='collapse', data-target='#stat-allocation', aria-expanded='false', aria-controls='stat-allocation')
| {{statsAllocationBoxIsOpen ? $t('hideQuickAllocation') : $t('showQuickAllocation')}}
p &nbsp;
.collapse#stat-allocation
table.table.text-left
tr
td
p(v-if='user.stats.lvl >= 100') {{ $t('noMoreAllocate') }}
p(v-if='user.stats.points || user.stats.lvl < 100')
strong.inline
| {{user.stats.points}}&nbsp;
strong.hint(popover-trigger='mouseenter',
popover-placement='right', :popover="$t('quickAllocationLevelPopover')") {{ $t('unallocated') }}
td
// @TODO: +statAllocation
button.btn.btn-primary(@click='close()') {{ $t('huzzah') }}
.checkbox
label(style='display:inline-block') {{ $t('dontShowAgain') }}
input(type='checkbox', v-model='user.preferences.suppressModals.levelUp', @change='changeLevelupSuppress()')
.modal-footer
.container-fluid
.row
.col-4
a.twitter-share-button(:href='twitterLink') {{ $t('tweet') }}
.col-4
.fb-share-button(:data-href='socialLevelLink', data-layout='button')
.col-4
a.tumblr-share-button(:data-href='socialLevelLink', data-notes='none')
</template>
<style scope>
.modal-content {
min-width: 28em;
}
.modal-body {
padding-bottom: 0;
}
.modal-footer {
margin-top: 0;
}
.herobox {
margin:auto 8.3em;
width: 6em;
height: 9em;
padding-top: 0;
cursor:default;
}
.character-sprites {
margin: 0;
width: 0;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import Avatar from '../avatar';
import { mapState } from 'client/libs/store';
import {maxHealth} from '../../../common/script/index';
import styleHelper from 'client/mixins/styleHelper';
let BASE_URL = '@TODO';
export default {
mixins: [styleHelper],
components: {
bModal,
Avatar,
},
data () {
let tweet = this.$t('levelUpShare');
return {
maxHealth,
tweet,
socialLevelLink: `${BASE_URL}/social/level-up`,
twitterLink: `https://twitter.com/intent/tweet?text=${tweet}&via=habitica&url=${BASE_URL}/social/level-up&count=none`,
};
},
mounted () {
this.loadWidgets();
},
computed: {
...mapState({user: 'user.data'}),
},
methods: {
close () {
this.$root.$emit('hide::modal', 'level-up');
},
loadWidgets () {
// @TODO:
},
changeLevelupSuppress () {
// @TODO: dispatch set({"preferences.suppressModals.levelUp": user.preferences.suppressModals.levelUp?true: false})
},
},
};
</script>

View file

@ -0,0 +1,88 @@
<template lang="pug">
b-modal#low-health(:title="$t('losingHealthWarning')", size='lg', :hide-footer="true")
.modal-body
.hero-stats
.meter-label(:tooltip="$t('health')")
span.glyphicon.glyphicon-heart
.meter.health(:tooltip='Math.round(user.stats.hp * 100) / 100')
.bar(:style='barStyle')
span.meter-text.value
| {{healthLeft}}
.herobox.inline-block
.character-sprites
avatar(:member='user')
p {{ $t('losingHealthWarning2') }}
h4 {{ $t('toRegainHealth') }}
ul
li.spaced {{ $t('lowHealthTips1') }}
li.spaced {{ $t('lowHealthTips2') }}
h4 {{ $t('losingHealthQuickly') }}
ul
li.spaced {{ $t('lowHealthTips3') }}
li.spaced {{ $t('lowHealthTips4') }}
h4 {{ $t('goodLuck') }}
.modal-footer
a.btn.btn-primary(@click='acknowledgeHealthWarning(); close()') {{ $t('ok') }}
</template>
<style scope>
.hero-stats {
position: absolute;
margin-left: 9em;
width: 50%;
}
.character-sprites {
display: inline-flex;
margin: 3em auto;
}
.herobox {
padding-top: 0em;
margin-left: 16em;
}
.modal-footer {
margin-top: 0em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import Avatar from '../avatar';
import { mapState } from 'client/libs/store';
import percent from '../../../common/script/libs/percent';
import {maxHealth} from '../../../common/script/index';
export default {
components: {
bModal,
Avatar,
},
data () {
return {
maxHealth,
};
},
computed: {
...mapState({user: 'user.data'}),
barStyle () {
return {
width: `${percent(this.user.stats.hp, maxHealth)}%`,
};
},
healthLeft () {
return `${Math.ceil(this.user.stats.hp)} / ${this.maxHealth}`;
},
},
methods: {
close () {
this.$root.$emit('hide::modal', 'low-health');
},
acknowledgeHealthWarning () {
// @TODO: {'flags.warnedLowHealth':true}
},
},
};
</script>

View file

@ -0,0 +1,45 @@
<template lang="pug">
b-modal#new-stuff(:title="$t('newStuff')", size='lg', :hide-footer="true")
.modal-header
| {{ this.$t('newStuff') }} by&nbsp;
a(target='_blank', href='https://twitter.com/Mihakuu') Bailey
.modal-body.new-stuff-modal.modal-fixed-height
div(:class="baileyClass")
br
br
div(ng-bind-html='latestBaileyMessage')
.modal-footer
a.btn.btn-info(href='http://habitica.wikia.com/wiki/Whats_New', target='_blank') {{ this.$t('newsArchive') }}
button.btn.btn-default(@click='close()') {{ this.$t('cool') }}
button.btn.btn-warning(@click='dismissAlert(); close()') {{ this.$t('dismissAlert') }}
</template>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
data () {
let worldDmg = {
bailey: true,
};
return {
baileyClass: {
'npc_bailey_broken': worldDmg.bailey, // eslint-disable-line
'npc_bailey': !worldDmg.bailey, // eslint-disable-line
},
};
},
mounted () {
// @TODO: $http.get('/new-stuff.html') ?
},
methods: {
close () {
this.$root.$emit('hide::modal', 'new-stuff');
},
},
};
</script>

View file

@ -0,0 +1,56 @@
<template lang="pug">
b-modal#quest-completed(:title="$t('lostAllHealth')", size='lg', :hide-footer="true")
.modal-header
h4 "{{quests[user.party.quest.completed].text()}}"&nbsp;
| {{ $t('completed') }}
.modal-body
.col-centered(:class='`quest_${user.party.quest.completed}`')
p(v-html='quests[user.party.quest.completed].completion()')
.quest-rewards(key='user.party.quest.completed', header-participant="$t('youReceived')", header-quest-owner="$t('questOwnerReceived')")
.modal-footer
button.btn.btn-primary(@click='setQuestCompleted()') {{ $t('ok') }}
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import Avatar from '../avatar';
import { mapState } from 'client/libs/store';
import percent from '../../../common/script/libs/percent';
import {maxHealth} from '../../../common/script/index';
export default {
components: {
bModal,
Avatar,
},
data () {
return {
maxHealth,
};
},
computed: {
...mapState({user: 'user.data'}),
barStyle () {
return {
width: `${percent(this.user.stats.hp, maxHealth)}%`,
};
},
},
methods: {
close () {
this.$root.$emit('hide::modal', 'quest-completed');
},
setQuestCompleted () {
// @TODO: set({"party.quest.completed":""})
this.close();
},
},
};
</script>

View file

@ -0,0 +1,92 @@
<template lang="pug">
b-modal#quest-invitation(:title="$t('questInvitation')", size='lg', :hide-footer="true")
.modal-header
h4 {{ $t('questInvitation') }}
|&nbsp;{{quests[user.party.quest.key].text()}}
.modal-body
.pull-right-sm.text-center
.col-centered(:class='`quest_${quests[user.party.quest.key].key}`')
div(ng-if='quests[user.party.quest.key].boss')
h4 {{quests[user.party.quest.key].boss.name()}}
p
strong {{ $t('bossHP') }} + ': '
| {{quests[user.party.quest.key].boss.hp}}
p
strong {{ $t('bossStrength') }} + ': '
| {{quests[user.party.quest.key].boss.str}}
div(ng-if='quests[user.party.quest.key].collect')
p(ng-repeat='(k,v) in quests[user.party.quest.key].collect')
strong {{ $t('collect') }} + ': '
| {{quests[user.party.quest.key].collect[k].count}} {{quests[user.party.quest.key].collect[k].text()}}
div(ng-bind-html='quests[user.party.quest.key].notes()')
.quest-rewards(:key='user.party.quest.key', header-participant="$t('rewardsAllParticipants')", header-quest-owner="$t('rewardsQuestOwner')")
hr
h5 {{headerParticipant}}
table.table.table-striped
tr(ng-repeat='drop in _.reject(quest.drop.items, \'onlyOwner\')')
td {{drop.text()}}
tr(ng-if='quest.drop.exp > 0')
td {{quest.drop.exp}}&nbsp;
| {{ $t('experience') }}
tr(ng-if='quest.drop.gp > 0')
td {{quest.drop.gp}}&nbsp;
| {{ $t('gold') }}
tr(ng-if='quest.drop.unlock()')
td {{quest.drop.unlock()}}
div(ng-if='getQuestOwnerRewards(quest).length > 0')
h5 {{headerQuestOwner}}
table.table.table-striped
tr(ng-repeat='drop in getQuestOwnerRewards(quest)')
td {{drop.text()}}
.modal-footer
button.btn.btn-default(ng-click='questHold = true; $close()') {{ $t('askLater') }}
button.btn.btn-default(ng-click='questReject(); $close()') {{ $t('reject') }}
button.btn.btn-primary(ng-click='questAccept(); $close()') {{ $t('accept') }}
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import quests from 'common/script/content/quests';
import Avatar from '../avatar';
import { mapState } from 'client/libs/store';
import revive from '../../../common/script/ops/revive';
import percent from '../../../common/script/libs/percent';
import {maxHealth} from '../../../common/script/index';
export default {
components: {
bModal,
Avatar,
},
data () {
return {
maxHealth,
quests,
};
},
computed: {
...mapState({user: 'user.data'}),
barStyle () {
return {
width: `${percent(this.user.stats.hp, maxHealth)}%`,
};
},
},
methods: {
close () {
this.$root.$emit('hide::modal', 'death');
},
revive () {
// @TODO: Post
revive(this.user);
},
},
};
</script>

View file

@ -0,0 +1,40 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0') {{ $t('modalAchievement') }}
// @TODO: +achievementAvatar('sun',0)
div(ng-if='user.achievements.rebirthLevel < 100')
| {{ $t('rebirthAchievement', {number: user.achievements.rebirths, level: user.achievements.rebirthLevel}) }}
div(ng-if='user.achievements.rebirthLevel >= 100')
| {{ $t('rebirthAchievement100', {number: user.achievements.rebirths}) }}
br
button.btn.btn-primary(@click='close()') {{ $t('huzzah') }}
// @TODO: +achievementFooter
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import { mapState } from 'client/libs/store';
export default {
components: {
bModal,
},
computed: {
...mapState({user: 'user.data'}),
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -0,0 +1,38 @@
<template lang="pug">
b-modal#rebirth-enabled(:title="$t('rebirthNew')", size='lg', :hide-footer="true")
.modal-header
h4 {{ $t('rebirthNew') }}
.modal-body
figure
.rebirth_orb
p
span {{ $t('rebirthUnlock') }}
.modal-footer
button.btn.btn-default(@click='close()') {{ $t('close') }}
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import { mapState } from 'client/libs/store';
export default {
components: {
bModal,
},
computed: {
...mapState({user: 'user.data'}),
},
methods: {
close () {
this.$root.$emit('hide::modal', 'rebirth-enabled');
},
},
};
</script>

View file

@ -0,0 +1,43 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom: 0') {{ $t('streakAchievement') }}
// @TODO: +achievementAvatar('thermometer',2.5)
h4(ng-if='user.achievements.streak === 1') {{ $t('firstStreakAchievement') }}
h4(ng-if='user.achievements.streak > 1') {{ $t('streakAchievementCount', {streaks: user.achievements.streak}) }}
p {{ $t('twentyOneDays') }}
p {{ $t('dontBreakStreak') }}
br
button.btn.btn-primary(@click='close()') {{ $t('dontStop') }}
.checkbox
label(style='display:inline-block') {{ $t('dontShowAgain') }}
input(type='checkbox', ng-model='user.preferences.suppressModals.streak', ng-change='set({"preferences.suppressModals.streak": user.preferences.suppressModals.streak?true: false})')
// @TOOD: +achievementFooter
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
import { mapState } from 'client/libs/store';
export default {
components: {
bModal,
},
computed: {
...mapState({user: 'user.data'}),
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -0,0 +1,38 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content
.modal-body.text-center
h3 {{ $t('guildReminderTitle') }}
br
.scene_guilds.center-block
br
h4 {{ $t('guildReminderText1') }}
.modal-footer
.container-fluid
.row
.col-xs-6.text-center
button.btn-lg.btn-default(@click='close()') {{ $t('guildReminderDismiss') }}
.col-xs-6.text-center
button.btn-lg.btn-primary(ui-sref='options.social.guilds.public', href='/#/options/groups/guilds/public', ng-click='$close()') {{ $t('guildReminderCTA') }}
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -0,0 +1,38 @@
<template lang="pug">
b-modal#testingletiant(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content
.modal-body.text-center
h3 {{ $t('guildReminderTitle') }}
br
.scene_guilds.center-block
br
h4 {{ $t('guildReminderText2') }}
.modal-footer
.container-fluid
.row
.col-xs-6.text-center
button.btn-lg.btn-default(@click='close()') {{ $t('guildReminderDismiss') }}
.col-xs-6.text-center
button.btn-lg.btn-primary(ui-sref='options.social.guilds.public', href='/#/options/groups/guilds/public', ng-click='$close()') {{ $t('guildReminderCTA') }}
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testingletiant');
},
},
};
</script>

View file

@ -0,0 +1,53 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom:0') {{ $t('modalAchievement') }}
// @TODO: +achievementAvatar('armor',2.5)
p {{ $t('gearAchievement') }}
br
table.multi-achievement
tr
td(ng-if='::user.achievements.ultimateGearSets.healer').multi-achievement
.achievement-ultimate-healer2x.multi-achievement
| {{ $t('healer') }}
td(ng-if='::user.achievements.ultimateGearSets.wizard').multi-achievement
.achievement-ultimate-mage2x.multi-achievement
| {{ $t('mage') }}
td(ng-if='::user.achievements.ultimateGearSets.rogue').multi-achievement
.achievement-ultimate-rogue2x.multi-achievement
| {{ $t('rogue') }}
td(ng-if='::user.achievements.ultimateGearSets.warrior').multi-achievement
.achievement-ultimate-warrior2x.multi-achievement
| {{ $t('warrior') }}
br
div(ng-if='!(user.achievements.ultimateGearSets.healer && user.achievements.ultimateGearSets.wizard && user.achievements.ultimateGearSets.rogue && user.achievements.ultimateGearSets.warrior)')
p {{ $t('moreGearAchievements') }}
br
.shop_armoire.pull-right
p {{ $t("armoireUnlocked") }}
br
button.btn.btn-primary(@click='close()') {{ $t('huzzah') }}
// @TODO: +achievementFooter
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -0,0 +1,64 @@
<template lang="pug">
b-modal#testing(:title="$t('guildReminderTitle')", size='lg', :hide-footer="true")
.modal-content(style='min-width:28em')
.modal-body.text-center
h3(style='margin-bottom: 0') {{ $t('wonChallenge') }}
// @TODO: h4: markdown(text='user.achievements.challenges[user.achievements.challenges.length - 1]')
.container-fluid
.row(style='margin-bottom:1em')
.col-xs-4(style='padding:0')
.container-fluid
.row
.col-xs-4(style='padding:0')
.col-xs-4(style='padding:0')
.achievement-karaoke-2x(style='margin-top: 2em')
.col-xs-4(style='padding:0')
.herobox(style='padding:0; width:0; height:7em')
.character-sprites(style='width:0')
// @TODO: +generatedAvatar({sleep: false})
.col-xs-4(style='padding:0')
.container-fluid
.row
.col-xs-4(style='padding:0')
.col-xs-4(style='padding:0')
.achievement-karaoke-2x(style='margin-top: 2em')
p {{ $t('congratulations') }}
br
button.btn.btn-primary(@click='close()') {{ $t('hurray') }}
.modal-footer(style='margin-top:0', ng-init='loadWidgets()')
.container-fluid
.row
.col-xs-3
a.twitter-share-button(href='https://twitter.com/intent/tweet?text=#{tweet}&via=habitica&url=#{env.BASE_URL}/social/won-challenge&count=none') {{ $t('tweet') }}
.col-xs-4(style='margin-left:.8em')
.fb-share-button(data-href='#{env.BASE_URL}/social/won-challenge', data-layout='button')
.col-xs-4(style='margin-left:.8em')
a.tumblr-share-button(data-href='#{env.BASE_URL}/social/won-challenge', data-notes='none')
</template>
<style scope>
.dont-despair, .death-penalty {
margin-top: 1.5em;
}
</style>
<script>
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
components: {
bModal,
},
data () {
let tweet = this.$t('wonChallengeShare');
return {
tweet,
};
},
methods: {
close () {
this.$root.$emit('hide::modal', 'testing');
},
},
};
</script>

View file

@ -1,4 +1,4 @@
<template lang='pug'>
<template lang="pug">
.row
modify-inventory
footer.container-fluid
@ -93,6 +93,7 @@
a.btn.btn-default(@click='addTenGems()') +10 Gems
a.btn.btn-default(@click='addHourglass()') +1 Mystic Hourglass
a.btn.btn-default(@click='addGold()') +500GP
a.btn.btn-default(@click='plusTenHealth()') + 10HP
a.btn.btn-default(@click='addMana()') +MP
a.btn.btn-default(@click='addLevelsAndGold()') +Exp +GP +MP
a.btn.btn-default(@click='addOneLevel()') +1 Level
@ -166,6 +167,11 @@ export default {
...mapState({user: 'user.data'}),
},
methods: {
plusTenHealth () {
this.$store.dispatch('user:set', {
'stats.hp': this.user.stats.hp += 10,
});
},
setHealthLow () {
this.$store.dispatch('user:set', {
'stats.hp': 1,

View file

@ -1,6 +1,7 @@
<template lang="pug">
div
inbox-modal
creator-intro
nav.navbar.navbar-inverse.fixed-top.navbar-toggleable-sm
.navbar-header
.logo.svg-icon(v-html="icons.logo")
@ -50,10 +51,10 @@ div
.svg-icon(v-html="icons.gold")
span {{user.stats.gp | roundBigNumber}}
notification-menu
router-link.dropdown.item-with-icon.item-user(:to="{name: 'avatar'}")
a.dropdown.item-with-icon.item-user(@click='showAvatar()')
.svg-icon(v-html="icons.user")
.dropdown-menu.dropdown-menu-right.user-dropdown
router-link.dropdown-item.edit-avatar(:to="{name: 'avatar'}")
a.dropdown-item.edit-avatar(@click='showAvatar()')
h3 {{ user.profile.name }}
span.small-text {{ $t('editAvatar') }}
a.nav-link.dropdown-item(@click.prevent='showInbox()') {{ $t('inbox') }}
@ -180,7 +181,7 @@ div
.svg-icon {
margin-right: 0px;
color: inherit;
color: $white;
}
}
@ -209,11 +210,13 @@ import userIcon from 'assets/svg/user.svg';
import logo from 'assets/svg/logo.svg';
import InboxModal from './userMenu/inbox.vue';
import notificationMenu from './notificationMenu';
import creatorIntro from './creatorIntro';
export default {
components: {
InboxModal,
notificationMenu,
creatorIntro,
},
data () {
return {
@ -239,6 +242,10 @@ export default {
showInbox () {
this.$root.$emit('show::modal', 'inbox-modal');
},
showAvatar () {
this.$store.state.avatarEditorOptions.editingUser = true;
this.$root.$emit('show::modal', 'avatar-modal');
},
},
};
</script>

View file

@ -1,6 +1,6 @@
<template lang="pug">
b-modal#avatar-modal(title="", size='md', :hide-header='true', :hide-footer='true')
.section.row.welcome-section(v-if='modalPage == 1')
.section.row.welcome-section(v-if='modalPage === 1 && !editing')
.col-6.offset-3.text-center
h3(v-once) {{$t('welcomeTo')}}
.svg-icon.logo(v-html='icons.logoPurple')
@ -11,7 +11,7 @@ b-modal#avatar-modal(title="", size='md', :hide-header='true', :hide-footer='tru
avatar(:member='user')
div(v-if='modalPage == 2')
.section.row
// @TODO Implement in V2 .section.row
.col-12.text-center
button.btn.btn-secondary(v-once) {{$t('randomize')}}
.section.row.text-center.customize-menu
@ -31,6 +31,10 @@ b-modal#avatar-modal(title="", size='md', :hide-header='true', :hide-footer='tru
.menu-item(@click='changeTopPage("extra", "glasses")')
.svg-icon(v-html='icons.accessoriesIcon')
strong(v-once) {{$t('extra')}}
.col-3
.menu-item(@click='changeTopPage("backgrounds", "2017")')
.svg-icon(v-html='icons.backgroundsIcon')
strong(v-once) {{$t('backgrounds')}}
.section.customize-section(v-if='activeTopPage === "body"')
.row.sub-menu
.col-2.offset-4.sub-menu-item(@click='changeSubPage("size")', :class='{active: activeSubPage === "size"}')
@ -49,6 +53,8 @@ b-modal#avatar-modal(title="", size='md', :hide-header='true', :hide-footer='tru
.slim_shirt_pink.option(@click='set({"preferences.shirt":"pink"})', :class='{active: user.preferences.shirt === "pink"}')
.slim_shirt_white.option(@click='set({"preferences.shirt":"white"})', :class='{active: user.preferences.shirt === "white"}')
.slim_shirt_yellow.option(@click='set({"preferences.shirt":"yellow"})', :class='{active: user.preferences.shirt === "yellow"}')
.col-12
.broad_shirt_convict.option(@click='set({"preferences.shirt":"convict"})', :class='{active: user.preferences.shirt === "convict"}')
.section.customize-section(v-if='activeTopPage === "skin"')
.row.sub-menu
@ -136,7 +142,34 @@ b-modal#avatar-modal(title="", size='md', :hide-header='true', :hide-footer='tru
.hair_flower_5.option(@click='set({"preferences.hair.flower":5})', :class='{active: user.preferences.hair.flower === 5}')
.hair_flower_6.option(@click='set({"preferences.hair.flower":6})', :class='{active: user.preferences.hair.flower === 6}')
.container.interests-section(v-if='modalPage == 3')
.section.container.customize-section(v-if='activeTopPage === "backgrounds"')
.row.sub-menu
.col-3.text-center.sub-menu-item(@click='changeSubPage("2017")', :class='{active: activeSubPage === "2017"}')
strong(v-once) 2017
.col-3.text-center.sub-menu-item(@click='changeSubPage("2016")', :class='{active: activeSubPage === "2016"}')
strong(v-once) 2016
.col-3.text-center.sub-menu-item(@click='changeSubPage("2015")', :class='{active: activeSubPage === "2015"}')
strong(v-once) 2015
.col-3.text-center.sub-menu-item(@click='changeSubPage("2014")', :class='{active: activeSubPage === "2014"}')
strong(v-once) 2014
.row.customize-menu(v-for='(sets, key) in backgroundShopSetsByYear')
div(v-for='set in sets', v-if='activeSubPage === key')
h2 {{set.text}}
div(v-if='showPlainBackgroundBlurb(set.identifier, set.items)') {{ $t('incentiveBackgroundsUnlockedWithCheckins') }}
div(v-if='!ownsSet("background", set.items) && set.identifier !== "incentiveBackgrounds"')
//+gemCost(7)
button.btn.btn-primary(@click='unlock(setKeys("background", set.items))') {{ $t('unlockSet', {cost: 15}) }}
span.Pet_Currency_Gem1x.inline-gems
button.customize-option(v-for='bg in set.items',
type='button',
:class='[`background_${bg.key}`, backgroundLockedStatus(bg.key)]',
@click='unlock("background." + bg.key)',
:popover-title='bg.text',
:popover='bg.notes',
popover-trigger='mouseenter')
i.glyphicon.glyphicon-lock(v-if='!user.purchased.background[bg.key]')
.container.interests-section(v-if='modalPage === 3 && !editing')
.section.row
.col-12.text-center
h2 I want to work on:
@ -187,7 +220,7 @@ b-modal#avatar-modal(title="", size='md', :hide-header='true', :hide-footer='tru
.justin-message(v-if='modalPage > 1')
p(v-once) {{$t('justinIntroMessage3')}}
.section.container.footer
.section.container.footer(v-if='!editing')
.row
.col-3.offset-1.text-center
div(v-if='modalPage > 1', @click='prev()')
@ -339,7 +372,7 @@ b-modal#avatar-modal(title="", size='md', :hide-header='true', :hide-footer='tru
.customize-section {
background-color: #f9f9f9;
padding-top: 1em;
height: 250px;
min-height: 250px;
}
.interests-section {
@ -395,10 +428,12 @@ b-modal#avatar-modal(title="", size='md', :hide-header='true', :hide-footer='tru
</style>
<script>
// @TODO: Wait for my other PR (login/register) to fix the background and hiding the header
import map from 'lodash/map';
import get from 'lodash/get';
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 bModal from 'bootstrap-vue/lib/components/modal';
@ -407,6 +442,7 @@ import bodyIcon from 'assets/svg/body.svg';
import accessoriesIcon from 'assets/svg/accessories.svg';
import skinIcon from 'assets/svg/skin.svg';
import hairIcon from 'assets/svg/hair.svg';
import backgroundsIcon from 'assets/svg/backgrounds.svg';
export default {
components: {
@ -414,24 +450,50 @@ export default {
bModal,
},
mounted () {
this.$root.$emit('show::modal', 'avatar-modal');
if (this.editing) this.modalPage = 2;
},
data () {
let backgroundShopSets = getBackgroundShopSets();
// @TODO: add dates to backgrounds
let backgroundShopSetsByYear = {
2014: [],
2015: [],
2016: [],
2017: [],
};
backgroundShopSets.forEach((set) => {
let year = set.identifier.substr(set.identifier.length - 4);
if (!backgroundShopSetsByYear[year]) return;
backgroundShopSetsByYear[year].push(set);
});
return {
backgroundShopSets,
backgroundShopSetsByYear,
icons: Object.freeze({
logoPurple,
bodyIcon,
accessoriesIcon,
skinIcon,
hairIcon,
backgroundsIcon,
}),
modalPage: 1,
activeTopPage: 'body',
activeSubPage: 'size',
};
},
watch: {
editing () {
if (this.editing) this.modalPage = 2;
},
},
computed: {
...mapState({user: 'user.data'}),
editing () {
return this.$store.state.avatarEditorOptions.editingUser;
},
},
methods: {
prev () {
@ -457,6 +519,73 @@ export default {
this.$root.$emit('hide::modal', 'avatar-modal');
this.$router.push('/');
},
showPlainBackgroundBlurb (identifier, set) {
return identifier === 'incentiveBackgrounds' && !this.ownsSet('background', set);
},
ownsSet (type, set) {
let setOwnedByUser = false;
for (let key in set) {
let value = set[key];
if (type === 'background') key = value.key;
if (this.user.purchased[type][key]) setOwnedByUser = true;
}
// let setOwnedByUser = find(set, (value, key) => {
// console.log(type)
// if (type === 'background') key = value.key;
// return this.user.purchased[type][key];
// });
return Boolean(setOwnedByUser);
},
/**
* For gem-unlockable preferences, (a) if owned, select preference (b) else, purchase
* @param path: User.preferences <-> User.purchased maps like User.preferences.skin=abc <-> User.purchased.skin.abc.
* Pass in this paramater as "skin.abc". Alternatively, pass as an array ["skin.abc", "skin.xyz"] to unlock sets
*/
async unlock (path) {
let fullSet = path.indexOf(',') !== -1;
let isBackground = Boolean(path.indexOf('background.'));
let cost;
if (isBackground) {
cost = fullSet ? 3.75 : 1.75; // (Backgrounds) 15G per set, 7G per individual
} else {
cost = fullSet ? 1.25 : 0.5; // (Hair, skin, etc) 5G per set, 2G per individual
}
let loginIncentives = ['background.blue', 'background.green', 'background.red', 'background.purple', 'background.yellow', 'background.violet'];
if (loginIncentives.indexOf(path) === -1) {
if (fullSet) {
if (confirm(this.$t('purchaseFor', {cost: cost * 4})) !== true) return;
// @TODO: implement gem modal
// if (this.user.balance < cost) return $rootScope.openModal('buyGems');
} else if (!get(this.user, `purchased.${path}`)) {
if (confirm(this.$t('purchaseFor', {cost: cost * 4})) !== true) return;
// @TODO: implement gem modal
// if (this.user.balance < cost) return $rootScope.openModal('buyGems');
}
}
// @TODO: Add when we implment the user calls
// let response = await axios.post('/api/v3/user/unlock');
unlock(this.user, {
query: {
path,
},
});
},
setKeys (type, _set) {
return map(_set, (v, k) => {
if (type === 'background') k = v.key;
return `${type}.${k}`;
}).join(',');
},
backgroundLockedStatus (bgKey) {
let backgroundClass = 'background-locked';
if (this.user.purchased.background[bgKey]) backgroundClass = 'background-unlocked';
return backgroundClass;
},
},
};
</script>

View file

@ -1,7 +1,7 @@
<template lang="pug">
.row(v-if="group")
group-form-modal
invite-modal
invite-modal(:group='this.group')
start-quest-modal(:group='this.group')
.col-8.standard-page
.row
@ -361,7 +361,6 @@ import quests from 'common/script/content/quests';
import percent from 'common/script/libs/percent';
import groupFormModal from './groupFormModal';
import inviteModal from './inviteModal';
import memberModal from '../members/memberModal';
import chatMessage from '../chat/chatMessages';
import groupChallenges from '../challenges/groupChallenges';
@ -388,7 +387,6 @@ export default {
props: ['groupId'],
components: {
membersModal,
memberModal,
startQuestModal,
bCollapse,
bCard,
@ -521,6 +519,7 @@ export default {
},
methods: {
showMemberModal () {
this.$store.state.groupId = this.group._id;
this.$root.$emit('show::modal', 'members-modal');
},
async sendMessage () {

View file

@ -54,8 +54,10 @@ import { mapState } from 'client/libs/store';
import filter from 'lodash/filter';
import map from 'lodash/map';
import bModal from 'bootstrap-vue/lib/components/modal';
import notifications from 'client/mixins/notifications';
export default {
mixins: [notifications],
props: ['group'],
data () {
return {
@ -72,8 +74,9 @@ export default {
return this.user.profile.name;
},
sendInviteText () {
if (!this.group) return 'Send Invites';
return this.group.sendInviteText;
return 'Send Invites';
// if (!this.group) return 'Send Invites';
// return this.group.sendInviteText;
},
},
methods: {
@ -97,38 +100,41 @@ export default {
this.inviteByMethod(inviteMethod);
},
// inviteByMethod (inviteMethod) {
// let invitationDetails;
//
// if (inviteMethod === 'email') {
// let emails = this.getEmails();
// invitationDetails = { inviter: this.inviter, emails };
// } else if (inviteMethod === 'uuid') {
// let uuids = this.getOnlyUuids();
// invitationDetails = { uuids };
// } else {
// return alert('Invalid invite method.');
// }
async inviteByMethod (inviteMethod) {
let invitationDetails;
// @TODO: Add dispatch
// Groups.Group.invite(this.group._id, invitationDetails)
// .then(function () {
// let invitesSent = invitationDetails.emails || invitationDetails.uuids;
// let invitationString = invitesSent.length > 1 ? 'invitationsSent' : 'invitationSent';
//
// Notification.text(window.env.t(invitationString));
//
// _resetInvitees();
//
// if (this.group.type === 'party') {
// $rootScope.hardRedirect('/#/options/groups/party');
// } else {
// $rootScope.hardRedirect('/#/options/groups/guilds/' + this.group._id);
// }
// }, function(){
// _resetInvitees();
// });
// },
if (inviteMethod === 'email') {
let emails = this.getEmails();
invitationDetails = { inviter: this.inviter, emails };
} else if (inviteMethod === 'uuid') {
let uuids = this.getOnlyUuids();
invitationDetails = { uuids };
} else {
return alert('Invalid invite method.');
}
await this.$store.dispatch('guilds:invite', {
invitationDetails,
groupId: this.group._id,
});
let invitesSent = invitationDetails.emails || invitationDetails.uuids;
let invitationString = invitesSent.length > 1 ? 'invitationsSent' : 'invitationSent';
this.text(this.$t(invitationString));
// @TODO: This function didn't make it over this.resetInvitees();
// @TODO: Sync group invites?
// if (this.group.type === 'party') {
// this.$router.push('//party');
// } else {
// this.$router.push(`/groups/guilds/${this.group._id}`);
// }
this.$root.$emit('hide:modal', 'invite-modal');
// @TODO: error?
// _resetInvitees();
},
getOnlyUuids () {
let uuids = map(this.invitees, 'uuid');
let filteredUuids = filter(uuids, (id) => {

View file

@ -102,6 +102,7 @@ div
</style>
<script>
// @TODO: Move this under members directory
import bModal from 'bootstrap-vue/lib/components/modal';
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
@ -158,15 +159,16 @@ export default {
},
methods: {
async getMembers () {
if (this.group._id) {
let groupId = this.group._id || this.$store.state.groupId;
if (groupId) {
let members = await this.$store.dispatch('members:getGroupMembers', {
groupId: this.group._id,
groupId,
includeAllPublicFields: true,
});
this.members = members;
}
if (this.$store.state.viewingMembers) this.members = this.$store.state.viewingMembers;
if (this.$store.state.viewingMembers.length > 1) this.members = this.$store.state.viewingMembers;
},
async clickMember (uid, forceShow) {
let user = this.$store.state.user.data;

View file

@ -1,32 +1,33 @@
<template lang="pug">
.d-flex.member-details(:class="{ condensed, expanded }", @click='showMemberModal()')
avatar(:member="member",
@click.native="$emit('click')",
@mouseover.native="$emit('onHover')",
@mouseout.native="$emit('onHover')",
)
member-modal(:profile='member')
.member-stats
h3.character-name
| {{member.profile.name}}
.is-buffed(v-if="isBuffed")
.svg-icon(v-html="icons.buff")
span.small-text.character-level {{ characterLevel }}
.progress-container.d-flex
.svg-icon(v-html="icons.health")
.progress
.progress-bar.bg-health(:style="{width: `${percent(member.stats.hp, MAX_HEALTH)}%`}")
span.small-text {{member.stats.hp | round}} / {{MAX_HEALTH}}
.progress-container.d-flex
.svg-icon(v-html="icons.experience")
.progress
.progress-bar.bg-experience(:style="{width: `${percent(member.stats.exp, toNextLevel)}%`}")
span.small-text {{member.stats.exp | round}} / {{toNextLevel}}
.progress-container.d-flex(v-if="hasClass")
.svg-icon(v-html="icons.mana")
.progress
.progress-bar.bg-mana(:style="{width: `${percent(member.stats.mp, maxMP)}%`}")
span.small-text {{member.stats.mp | round}} / {{maxMP}}
div
profile
.d-flex.member-details(:class="{ condensed, expanded }", @click='showMemberModal()')
avatar(:member="member",
@click.native="$emit('click')",
@mouseover.native="$emit('onHover')",
@mouseout.native="$emit('onHover')",
)
.member-stats
h3.character-name
| {{member.profile.name}}
.is-buffed(v-if="isBuffed")
.svg-icon(v-html="icons.buff")
span.small-text.character-level {{ characterLevel }}
.progress-container.d-flex
.svg-icon(v-html="icons.health")
.progress
.progress-bar.bg-health(:style="{width: `${percent(member.stats.hp, MAX_HEALTH)}%`}")
span.small-text {{member.stats.hp | round}} / {{MAX_HEALTH}}
.progress-container.d-flex
.svg-icon(v-html="icons.experience")
.progress
.progress-bar.bg-experience(:style="{width: `${percent(member.stats.exp, toNextLevel)}%`}")
span.small-text {{member.stats.exp | round}} / {{toNextLevel}}
.progress-container.d-flex(v-if="hasClass")
.svg-icon(v-html="icons.mana")
.progress
.progress-bar.bg-mana(:style="{width: `${percent(member.stats.mp, maxMP)}%`}")
span.small-text {{member.stats.mp | round}} / {{maxMP}}
</template>
<style lang="scss" scoped>
@ -170,7 +171,7 @@
<script>
import Avatar from './avatar';
import { mapState } from 'client/libs/store';
import memberModal from './members/memberModal';
import profile from './userMenu/profile';
import { toNextLevel } from '../../common/script/statHelpers';
import statsComputed from '../../common/script/libs/statsComputed';
@ -184,7 +185,7 @@ import manaIcon from 'assets/svg/mana.svg';
export default {
components: {
Avatar,
memberModal,
profile,
},
props: {
member: {
@ -212,6 +213,10 @@ export default {
},
methods: {
percent,
showMemberModal () {
// @TODO: set viewing users in $store?
this.$root.$emit('show::modal', 'profile');
},
},
computed: {
...mapState({
@ -234,10 +239,6 @@ export default {
hasClass () {
return this.$store.getters['members:hasClass'](this.member);
},
showMemberModal () {
// @TODO: set viewing users in $store?
this.$root.$emit('show::modal', 'member-detail-modal');
},
},
};
</script>

View file

@ -1,143 +0,0 @@
<template lang="pug">
b-modal#member-detail-modal(title="Empty", size='lg')
.modal-header
h4
span {{profile.profile.name}}
// @TODO span(v-if='contribText && profile.contributor.level') - {{contribText(profile.contributor, profile.backer)}}
.modal-body
.container-fluid
.row
.col-md-6
img.img-renderiv-auto(v-if='profile.profile.imageUrl', :src='profile.profile.imageUrl')
markdown(v-if='profile.profile.blurb', text='profile.profile.blurb')
ul.muted.list-unstyled(v-if='profile.auth.timestamps')
li {{profile._id}}
li(v-if='profile.auth.timestamps.created')
|&nbsp;
| {{ $t('memberSince') }}
|&nbsp;
// @TODO | {{profile.auth.timestamps.created | date:user.preferences.dateFormat}} -
li(v-if='profile.auth.timestamps.loggedin')
|&nbsp;
| {{ $t('lastLoggedIn') }}
|&nbsp;
// @TODO | {{profile.auth.timestamps.loggedin | date:user.preferences.dateFormat}} -
h3 {{ $t('stats') }}
// @TODO: Figure out why this isn't showing up in front page
// @TODO .label.label-info {{ {warrior:env.t("warrior"), wizard:env.t("mage"), rogue:env.t("rogue"), healer:env.t("healer")}[profile.stats.class] }}
// include ../profiles/stats_all
.col-md-6
.row
//@TODO: +herobox()
.row
h3 {{ $t('achievements') }}
//include ../profiles/achievements
.modal-footer
.btn-group.pull-left(v-if='user')
button.btn.btn-md.btn-default(v-if='user.inbox.blocks.indexOf(profile._id) !== -1', :tooltip="$t('unblock')", @click="User.blockUser({params:{uuid:profile._id}})", tooltip-placement='right')
span.glyphicon.glyphicon-plus
button.btn.btn-md.btn-default(v-if='profile._id != user._id && !profile.contributor.admin && !(user.inbox.blocks | contains:profile._id)', tooltip {{ $t('block') }}, @click="User.blockUser({params:{uuid:profile._id}})", tooltip-placement='right')
span.glyphicon.glyphicon-ban-circle
button.btn.btn-md.btn-default(:tooltip="$t('sendPM')", @click="openModal('private-message',{controller:'MemberModalCtrl'})", tooltip-placement='right')
span.glyphicon.glyphicon-envelope
button.btn.btn-md.btn-default(:tooltip="$t('sendGift')", @click="openModal('send-gift',{controller:'MemberModalCtrl'})", tooltip-placement='right')
span.glyphicon.glyphicon-gift
button.btn.btn-default(@click='close()') {{ $t('close') }}
</template>
<script>
import { mapState } from 'client/libs/store';
import moment from 'moment';
import bModal from 'bootstrap-vue/lib/components/modal';
export default {
// @TODO: We should probably use a store. Only view one member at a time?
props: ['profile'],
data () {
return {
// @TODO: We don't send subscriptions so the structure has changed in the back. Update this when we update the views.
gift: {
type: 'gems',
gems: {amount: 0, fromBalance: true},
subscription: {key: ''},
message: '',
},
};
},
components: {
bModal,
},
computed: {
...mapState({user: 'user.data'}),
},
mounted () {
// @TODO: This.$store.selectmember
// if (member) {
// this.profile = member;
//
// this.achievements = Shared.achievements.getAchievementsForProfile(this.profile);
// this.achievPopoverPlacement = 'left';
// this.achievAppendToBody = 'false'; // append-to-body breaks popovers in modal windows
// }
},
methods: {
timestamp (timestamp) {
return moment(timestamp).format(this.user.preferences.dateFormat.toUpperCase());
},
// @TODO: create mixin for stats: this.statCalc = Stats;
// @TODO: create mixin or library for constume functions this.costume = Costume;
keyDownListener (e) {
if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
this.sendPrivateMessage(this.profile._id, this._message);
}
},
// @TODO: Inbox?
sendPrivateMessage (uuid, message) {
if (!message) return;
// Members.sendPrivateMessage(message, uuid)
// .then(function (response) {
// Notification.text(window.env.t('messageSentAlert'));
// $rootScope.User.sync();
// this.$close();
// });
},
async sendGift (uuid) {
await this.$store.dispatch('members:transferGems', {
message: this.gift.message,
toUserId: uuid,
gemAmount: this.gift.gems.amount,
});
// @TODO: Notification.text(this.$t('sentGems'));
// @TODO: What needs to be synced? $rootScope.User.sync();
this.close();
},
async reportAbuse (reporter, message, groupId) {
let response = await this.$store.dispatch('chat:flag', {
groupId,
chatId: message.id,
});
message.flags = response.flags;
message.flagCount = response.flagCount;
// @TODO: Notification.text(this.$t('abuseReported'));
this.close();
},
async clearFlagCount (message, groupId) {
await this.$store.dispatch('chat:clearFlagCount', {
groupId,
chatId: message.id,
});
message.flagCount = 0;
// @TODO: Notification.text("Flags cleared");
this.close();
},
close () {
this.$root.$emit('hide::modal', 'member-detail-modal');
},
},
};
</script>

View file

@ -6,27 +6,29 @@
.dropdown-menu.dropdown-menu-right.user-dropdown
h4.dropdown-item(v-if='!hasNoNotifications()') {{ $t('notifications') }}
h4.dropdown-item.toolbar-notifs-no-messages(v-if='hasNoNotifications()') {{ $t('noNotifications') }}
a.dropdown-item(v-if='user.purchased.plan.mysteryItems.length', @click='$state.go("options.inventory.drops"); ')
a.dropdown-item(v-if='user.purchased.plan.mysteryItems.length', @click='go("/inventory/items")')
span.glyphicon.glyphicon-gift
span {{ $t('newSubscriberItem') }}
a.dropdown-item(v-for='party in user.invitations.parties', ui-sref='options.social.party')
a.dropdown-item(v-for='party in user.invitations.parties', @click='go("/party")')
span.glyphicon.glyphicon-user
span {{ $t('invitedTo', {name: party.name}) }}
a.dropdown-item(v-if='user.flags.cardReceived', @click='$state.go("options.inventory.drops"); ')
a.dropdown-item(v-if='user.flags.cardReceived', @click='go("/inventory/items")')
span.glyphicon.glyphicon-envelope
span {{ $t('cardReceived') }}
a.dropdown-item(@click='clearCards()', :popover="$t('clear')", popover-placement='right', popover-trigger='mouseenter',popover-append-to-body='true')
a.dropdown-item(v-for='guild in user.invitations.guilds', ui-sref='options.social.guilds.public')
a.dropdown-item(@click='clearCards()', :popover="$t('clear')",
popover-placement='right', popover-trigger='mouseenter', popover-append-to-body='true')
a.dropdown-item(v-for='guild in user.invitations.guilds', @click='go("/groups/discovery")')
span.glyphicon.glyphicon-user
span {{ $t('invitedTo', {name: guild.name}) }}
a.dropdown-item(v-if='user.flags.classSelected && !user.preferences.disableClasses && user.stats.points', ui-sref='options.profile.stats')
a.dropdown-item(v-if='user.flags.classSelected && !user.preferences.disableClasses && user.stats.points',
@click='go("/user/profile")')
span.glyphicon.glyphicon-plus-sign
span {{ $t('haveUnallocated', {points: user.stats.points}) }}
a.dropdown-item(v-for='(k,v) in user.newMessages', v-if='v.value', @click='(k === party._id || k === user.party._id) ? $state.go("options.social.party") : $state.go("options.social.guilds.detail",{gid:k}); ')
a.dropdown-item(v-for='(k,v) in user.newMessages', v-if='v.value', @click='navigateToGroup(k)')
span.glyphicon.glyphicon-comment
span {{v.name}}
a.dropdown-item(@click='clearMessages(k)', :popover="$t('clear')", popover-placement='right', popover-trigger='mouseenter',popover-append-to-body='true')
a.dropdown-item(v-for='notification in user.groupNotifications', @click='viewGroupApprovalNotification(notification, $index, true)')
a.dropdown-item(@click='clearMessages(k)', :popover="$t('clear')", popover-placement='right', popover-trigger='mouseenter',popover-append-to-body='true')
a.dropdown-item(v-for='(notification, index) in user.groupNotifications', @click='viewGroupApprovalNotification(notification, index, true)')
span(:class="groupApprovalNotificationIcon(notification)")
span
| {{notification.data.message}}
@ -225,7 +227,7 @@ export default {
// @TODO: USe notifications: User.readNotification(notification.id);
this.user.groupNotifications.splice(index, 1);
return navigate; // @TODO: remove
// @TODO: this.$route.go if (navigate) $state.go('options.social.guilds.detail', {gid: notification.data.groupId});
// @TODO: this.$route.go if (navigate) go('options.social.guilds.detail', {gid: notification.data.groupId});
},
groupApprovalNotificationIcon (notification) {
if (notification.type === 'GROUP_TASK_APPROVAL') {
@ -234,6 +236,16 @@ export default {
return 'glyphicon glyphicon-ok-sign';
}
},
go (path) {
this.$route.push(path);
},
navigateToGroup (key) {
if (key === this.party._id || key === this.user.party._id) {
this.go('/party');
return;
}
this.go(`/groups/guild/${key}`);
},
},
};
</script>

View file

@ -1,16 +1,77 @@
<template lang="pug">
div
welcome-modal
new-stuff
death
low-health
level-up
choose-class
testing
testingletiant
rebirth-enabled
drops-enabled
contributor
won-challenge
ultimate-gear
streak
rebirth
joined-guild
joined-challenge
invited-friend
</template>
<script>
// import moment from 'moment';
import { mapState } from 'client/libs/store';
import notifications from 'client/mixins/notifications';
import welcomeModal from './achievements/welcome';
import newStuff from './achievements/newStuff';
import death from './achievements/death';
import lowHealth from './achievements/lowHealth';
import levelUp from './achievements/levelUp';
import chooseClass from './achievements/chooseClass';
import armoireEmpty from './achievements/armoireEmpty';
import questCompleted from './achievements/questCompleted';
import questInvitation from './achievements/questInvitation';
import testing from './achievements/testing';
import testingletiant from './achievements/testingletiant';
import rebirthEnabled from './achievements/rebirthEnabled';
import dropsEnabled from './achievements/dropsEnabled';
import contributor from './achievements/contributor';
import invitedFriend from './achievements/invitedFriend';
import joinedChallenge from './achievements/joinedChallenge';
import joinedGuild from './achievements/joinedGuild';
import rebirth from './achievements/rebirth';
import streak from './achievements/streak';
import ultimateGear from './achievements/ultimateGear';
import wonChallenge from './achievements/wonChallenge';
export default {
mixins: [notifications],
components: {
wonChallenge,
ultimateGear,
streak,
rebirth,
joinedGuild,
joinedChallenge,
invitedFriend,
welcomeModal,
newStuff,
death,
lowHealth,
levelUp,
chooseClass,
armoireEmpty,
questCompleted,
questInvitation,
testing,
testingletiant,
rebirthEnabled,
dropsEnabled,
contributor,
},
data () {
// Levels that already display modals and should not trigger generic Level Up
@ -71,21 +132,26 @@ export default {
invitedToQuest () {
return this.user.party.quest.RSVPNeeded && !this.user.party.quest.completed;
},
userDailies () {
return this.$store.state.tasks.data.dailys;
},
},
watch: {
baileyShouldShow () {
// @TODO: this.openModal('newStuff', {size:'lg'});
this.$root.$emit('show:modal', 'new-stuff');
},
userHp (after, before) {
if (after <= 0) {
this.playSound('Death');
// @TODO: this.openModal('death', {keyboard:false, backdrop:'static'});
this.$root.$emit('show:modal', 'death');
// @TODO: {keyboard:false, backdrop:'static'}
} else if (after <= 30 && !this.user.flags.warnedLowHealth) {
// @TODO: this.openModal('lowHealth', {keyboard:false, backdrop:'static', controller:'UserCtrl', track:'Health Warning'});
this.$root.$emit('show:modal', 'low-health');
// @TODO: {keyboard:false, backdrop:'static', controller:'UserCtrl', track:'Health Warning'}
}
if (after === before) return;
if (this.user.stats.lvl === 0) return;
// @TODO: Notification.hp(after - before, 'hp');
this.hp(after - before, 'hp');
// @TODO: I am pretty sure we no long need this with $store
// this.$broadcast('syncPartyRequest', {
@ -98,7 +164,7 @@ export default {
userExp (after, before) {
if (after === before) return;
if (this.user.stats.lvl === 0) return;
// @TODO: Notification.exp(after - before);
this.exp(after - before);
},
userGp (after, before) {
if (after === before) return;
@ -109,32 +175,33 @@ export default {
if (this.user._tmp) {
bonus = this.user._tmp.streakBonus || 0;
}
// @TODO: Notification.gp(money, bonus || 0);
this.gp(money, bonus || 0);
// Append Bonus
if (money > 0 && Boolean(bonus)) {
if (bonus < 0.01) bonus = 0.01;
// @TODO: Notification.text("+ " + Notification.coins(bonus) + ' ' + window.env.t('streakCoins'));
this.text(`+ ${Notification.coins(bonus)} ${this.$t('streakCoins')}`);
delete this.user._tmp.streakBonus;
}
},
userMp (after, before) {
if (after === before) return;
if (!this.user.flags.classSelected || this.user.preferences.disableClasses) return;
// let mana = after - before;
// @TODO: Notification.mp(mana);
let mana = after - before;
this.mp(mana);
},
userLvl (after, before) {
if (after <= before) return;
// @TODO: Notification.lvl();
this.lvl();
this.playSound('Level_Up');
if (this.user._tmp && this.user._tmp.drop && this.user._tmp.drop.type === 'Quest') return;
if (this.unlockLevels[`${after}`]) return;
// @TODO: if (!this.user.preferences.suppressModals.levelUp) this.openModal('levelUp', {controller:'UserCtrl', size:'sm'});
if (!this.user.preferences.suppressModals.levelUp) this.$root.$emit('show:modal', 'level-up');
},
userClassSelect (after) {
if (!after) return;
// @TODO: this.openModal('chooseClass', {controller:'UserCtrl', keyboard:false, backdrop:'static'});
this.$root.$emit('show::modal', 'choose-class');
// @TODO: {controller:'UserCtrl', keyboard:false, backdrop:'static'}
},
userNotifications (after) {
if (!this.user._wrapped) return;
@ -146,15 +213,18 @@ export default {
},
armoireEmpty (after, before) {
if (after === before || after === false) return;
// @TODO: this.openModal('armoireEmpty');
this.$root.$emit('show::modal', 'armoire-empty');
},
questCompleted (after) {
if (!after) return;
// @TODO: this.openModal('questCompleted', {controller:'InventoryCtrl'});
this.$root.$emit('show::modal', 'quest-completed');
},
invitedToQuest (after) {
if (after !== true) return;
// @TODO: this.openModal('questInvitation', {controller:'PartyCtrl'});
this.$root.$emit('show::modal', 'quest-invitation');
},
userDailies () {
this.runYesterDailies();
},
},
async mounted () {
@ -174,9 +244,10 @@ export default {
// let userDayStart = moment().startOf('day').add({ hours: this.user.preferences.dayStart });
if (!this.user.needsCron) return;
let dailys = this.user.dailys;
if (!this.appLoaded) return;
let dailys = this.$store.state.tasks.data.dailys;
// @TODO: How do we check this now? if (!this.appLoaded) return;
this.isRunningYesterdailies = true;
@ -267,59 +338,57 @@ export default {
// @TODO: Use factory function instead
switch (notification.type) {
case 'GUILD_PROMPT':
// @TODO: I'm pretty sure we can find better names for these
if (notification.data.textletiant === -1) {
// @TODO: this.openModal('testing');
this.$root.$emit('show::modal', 'testing');
} else {
// @TODO: this.openModal('testingletiant');
this.$root.$emit('show::modal', 'testingletiant');
}
break;
case 'DROPS_ENABLED':
// @TODO: this.openModal('dropsEnabled');
this.$root.$emit('show::modal', 'drops-enabled');
break;
case 'REBIRTH_ENABLED':
// @TODO: this.openModal('rebirthEnabled');
this.$root.$emit('show::modal', 'rebirth-enabled');
break;
case 'WON_CHALLENGE':
// @TODO:
// User.sync().then( function() {
// Achievement.displayAchievement('wonChallenge');
// });
this.$root.$emit('show::modal', 'won-challenge');
break;
case 'STREAK_ACHIEVEMENT':
// @TODO: Notification.streak(this.user.achievements.streak);
this.streak(this.user.achievements.streak);
this.playSound('Achievement_Unlocked');
if (!this.user.preferences.suppressModals.streak) {
// @TODO: Achievement.displayAchievement('streak', {size: 'md'});
this.$root.$emit('show::modal', 'streak');
}
break;
case 'ULTIMATE_GEAR_ACHIEVEMENT':
this.playSound('Achievement_Unlocked');
// @TODO: Achievement.displayAchievement('ultimateGear', {size: 'md'});
this.$root.$emit('show::modal', 'ultimate-gear');
break;
case 'REBIRTH_ACHIEVEMENT':
this.playSound('Achievement_Unlocked');
// @TODO: Achievement.displayAchievement('rebirth');
this.$root.$emit('show::modal', 'rebirth');
break;
case 'GUILD_JOINED_ACHIEVEMENT':
this.playSound('Achievement_Unlocked');
// @TODO: Achievement.displayAchievement('joinedGuild', {size: 'md'});
this.$root.$emit('show::modal', 'joined-guild');
break;
case 'CHALLENGE_JOINED_ACHIEVEMENT':
this.playSound('Achievement_Unlocked');
// @TODO: Achievement.displayAchievement('joinedChallenge', {size: 'md'});
this.$root.$emit('show::modal', 'joined-challenge');
break;
case 'INVITED_FRIEND_ACHIEVEMENT':
this.playSound('Achievement_Unlocked');
// @TODO: Achievement.displayAchievement('invitedFriend', {size: 'md'});
this.$root.$emit('show::modal', 'invited-friend');
break;
case 'NEW_CONTRIBUTOR_LEVEL':
this.playSound('Achievement_Unlocked');
// @TODO: Achievement.displayAchievement('contributor', {size: 'md'});
this.$root.$emit('show::modal', 'contributor');
break;
case 'CRON':
if (notification.data) {
// @TODO: if (notification.data.hp) Notification.hp(notification.data.hp, 'hp');
// @TODO: if (notification.data.mp) Notification.mp(notification.data.mp);
if (notification.data.hp) this.hp(notification.data.hp, 'hp');
if (notification.data.mp) this.mp(notification.data.mp);
}
break;
case 'GROUP_TASK_APPROVAL':
@ -383,7 +452,7 @@ export default {
});
// Show notification of task approved
// @TODO: Notification.markdown(scoreTaskNotification[i].data.message);
this.markdown(scoreTaskNotification[i].data.message);
}
// Score approved tasks

View file

@ -3,8 +3,8 @@ b-modal#profile(title="Profile", size='lg', :hide-footer="true")
.row
.col-6.offset-3.text-center.nav
.nav-item(@click='selectedPage = "profile"', :class="{active: selectedPage === 'profile'}") Profile
.nav-item(@click='selectedPage = "achievements"', :class="{active: selectedPage === 'achievements'}") Achievements
.nav-item(@click='selectedPage = "stats"', :class="{active: selectedPage === 'stats'}") Stats
.nav-item(@click='selectedPage = "achievements"', :class="{active: selectedPage === 'achievements'}") Achievements
.standard-page(v-show='selectedPage === "profile"')
.row
.col-8
@ -94,19 +94,92 @@ b-modal#profile(title="Profile", size='lg', :hide-footer="true")
span {{ content.quests[k].text() }}
span {{ value }}
.standard-page(v-show='selectedPage === "stats"')
h1 Stats
.row
.col-6
h2.text-center Equipment
.well.row
.col-4
// user.items.gear.equipped
.well
.col-4.item-wrapper
.box
h3 Eyewear
.col-4.item-wrapper
.box
h3 Head Gear
.col-4.item-wrapper
.box
h3 Head Access.
.col-4.item-wrapper
.box
h3 Back Access.
.col-4.item-wrapper
.box
h3 Armor
.col-4.item-wrapper
.box
h3 Body Access.
.col-4.item-wrapper
.box
h3 Main-Hand
.col-4.item-wrapper
.col-4.item-wrapper
.box
h3 Off-Hand
.col-6
h2.text-center Costume
// user.items.gear.costume
.well
.col-4.item-wrapper
.box
h3 Eyewear
.col-4.item-wrapper
.box
h3 Head Gear
.col-4.item-wrapper
.box
h3 Head Access.
.col-4.item-wrapper
.box
h3 Back Access.
.col-4.item-wrapper
.box
h3 Armor
.col-4.item-wrapper
.box
h3 Body Access.
.col-4.item-wrapper
.box
h3 Main-Hand
.col-4.item-wrapper
.box
h3 Background {{ user.preferences.background }}
.col-4.item-wrapper
.box
h3 Off-Hand
.row
.col-6
h2.text-center Pet
h2.text-center(v-once) {{ $t('pets') }}
ul
li(ng-if='user.items.currentPet')
| {{ $t('activePet') }}:
| {{ formatAnimal(user.items.currentPet, 'pet') }}
li
| {{ $t('petsFound') }}:
| {{ totalCount(user.items.pets) }}
li
| {{ $t('beastMasterProgress') }}:
| {{ beastMasterProgress(user.items.pets) }}
.col-6
h2.text-center Mount
h2.text-center(v-once) {{ $t('mounts') }}
ul
li(v-if='user.items.currentMount')
| {{ $t('activeMount') }}:
| {{ formatAnimal(user.items.currentMount, 'mount') }}
li
| {{ $t('mountsTamed') }}:
| {{ totalCount(user.items.mounts) }}
li
| {{ $t('mountMasterProgress') }}:
| {{ mountMasterProgress(user.items.mounts) }}
.row#attributes
hr.col-12
h2.col-12 Attributes
@ -133,64 +206,7 @@ b-modal#profile(title="Profile", size='lg', :hide-footer="true")
li
strong Buffs:
| {{user.stats.buffs[stat]}}
.row
.col-4
div
h3 Basics
ul
li Health: {{user.stats.hp}}/{{user.stats.maxHealth}}
li Mana: {{user.stats.mp}}/{{user.stats.maxMP}}
li Gold: {{user.stats.gp}}
li Level: {{user.stats.lvl}}
li Experience: {{user.stats.exp}}
div(v-if='user.flags.itemsEnabled')
h3 Battle Gear
ul
li(v-for='(key, itemType) in user.items.gear.equipped', v-if='flatGear[key]')
strong {{ flatGear[key].text() }}
strong(v-if='flatGear[key].str || flatGear[key].con || flatGear[key].per || flatGear[key].int') :&nbsp;
span(v-for='stat in ["str","con","per","int"]', v-if='flatGear[key][stat]') {{flatGear[key][stat]}} {{ $t(stat) }}&nbsp;
div(v-if='user.preferences.costume')
h4(v-once) {{ $t('costume') }}
div
div(ng-repeat='(key, itemType) in user.items.gear.costume')
strong {{flatGear[key].text()}}
div
h3 Background
ul
li(v-if='!user.preferences.background') None
li(v-if='user.preferences.background') {{ user.preferences.background }}
div(ng-if='user.flags.dropsEnabled')
h3(v-once) {{ $t('pets') }}
ul
li(ng-if='user.items.currentPet')
| {{ $t('activePet') }}:
| {{ formatAnimal(user.items.currentPet, 'pet') }}
li
| {{ $t('petsFound') }}:
| {{ totalCount(user.items.pets) }}
li
| {{ $t('beastMasterProgress') }}:
| {{ beastMasterProgress(user.items.pets) }}
h3(v-once) {{ $t('mounts') }}
ul
li(v-if='user.items.currentMount')
| {{ $t('activeMount') }}:
| {{ formatAnimal(user.items.currentMount, 'mount') }}
li
| {{ $t('mountsTamed') }}:
| {{ totalCount(user.items.mounts) }}
li
| {{ $t('mountMasterProgress') }}:
| {{ mountMasterProgress(user.items.mounts) }}
.col-4(v-if='user.flags.classSelected && !user.preferences.disableClasses')
// @TODO: Implement .col-4(v-if='user.flags.classSelected && !user.preferences.disableClasses')
h3(v-once) {{ $t('characterBuild') }}
h4(v-once) {{ $t('class') + ': ' }}
span {{ classText }}&nbsp;
@ -284,6 +300,26 @@ b-modal#profile(title="Profile", size='lg', :hide-footer="true")
text-align: center;
}
}
.well {
background-color: #edecee;
border-radius: 2px;
padding: 0.4em;
padding-top: 1em;
}
.item-wrapper {
.box {
width: 94px;
height: 92px;
border-radius: 2px;
border: dotted 1px #c3c0c7;
}
h3 {
text-align: center;
}
}
</style>
<script>
@ -353,7 +389,6 @@ export default {
this.editingProfile.name = this.user.profile.name;
this.editingProfile.imageUrl = this.user.profile.imageUrl;
this.achievements = achievementsLib.getAchievementsForProfile(this.user);
this.$root.$emit('show::modal', 'profile');
},
computed: {
...mapState({

View file

@ -0,0 +1,17 @@
<template lang="pug">
div
// @TODO: profile modal is pulled in on the header. So.. seems a little odd to depend on it that way, but for now let's depend
</template>
<script>
import profile from './profile';
export default {
components: {
profile,
},
mounted () {
this.$root.$emit('show::modal', 'profile');
},
};
</script>

View file

@ -10,6 +10,7 @@ import StoreModule from './libs/store';
import './filters/registerGlobals';
import i18n from './libs/i18n';
import axios from 'axios';
import Notifications from 'vue-notification';
const IS_PRODUCTION = process.env.NODE_ENV === 'production'; // eslint-disable-line no-process-env
@ -33,6 +34,7 @@ axios.interceptors.response.use((response) => {
return Promise.reject(error);
});
Vue.use(Notifications);
Vue.use(i18n);
Vue.use(StoreModule);

View file

@ -98,8 +98,12 @@ export default {
round (number) {
return Math.abs(number.toFixed(1));
},
// @TODO: Implement when we have a notify library
//notify (html, type, icon, canHide, onClick) {
notify (html) {
// @TODO: try these params type, icon, canHide, onClick
this.$notify({
title: 'Habitica',
text: html,
});
// let stack_topright = {"dir1": "down", "dir2": "left", "spacing1": 15, "spacing2": 15, "firstpos1": 60};
// let notice = $.pnotify({
// type: type || 'warning', //('info', 'text', 'warning', 'success', 'gp', 'xp', 'hp', 'lvl', 'death', 'mp', 'crit')
@ -119,6 +123,6 @@ export default {
// onClick();
// }
// });
//},
},
},
};

View file

@ -29,11 +29,10 @@ const VideosPage = () => import(/* webpackChunkName: "static" */'./components/st
const RegisterLogin = () => import(/* webpackChunkName: "auth" */'./components/auth/registerLogin');
// User Pages
const CreatorIntro = () => import(/* webpackChunkName: "creator" */'./components/creatorIntro');
const BackgroundsPage = () => import(/* webpackChunkName: "user" */'./components/userMenu/backgrounds');
// const StatsPage = () => import(/* webpackChunkName: "user" */'./components/userMenu/stats');
// const AchievementsPage = () => import(/* webpackChunkName: "user" */'./components/userMenu/achievements');
const ProfilePage = () => import(/* webpackChunkName: "user" */'./components/userMenu/profile');
const ProfilePage = () => import(/* webpackChunkName: "user" */'./components/userMenu/profilePage');
// Settings
const Settings = () => import(/* webpackChunkName: "settings" */'./components/settings/index');
@ -98,7 +97,6 @@ const router = new VueRouter({
},
// requiresLogin is true by default, isStatic false
routes: [
{ name: 'avatar', path: '/avatar', component: CreatorIntro },
{ name: 'home', path: '/home', component: FrontPage, meta: {requiresLogin: false} },
{ name: 'register', path: '/register', component: RegisterLogin, meta: {requiresLogin: false} },
{ name: 'login', path: '/login', component: RegisterLogin, meta: {requiresLogin: false} },

View file

@ -55,6 +55,10 @@ export default function () {
publicGuilds: [],
groupFormOptions: {
creatingParty: false,
groupId: '',
},
avatarEditorOptions: {
editingUser: false,
},
editingGroup: {}, // TODO move to local state
// content data, frozen to prevent Vue from modifying it since it's static and never changes