Sept 7 fixes (#9022)

* Fixed login incentives header

* Added achievement hover

* Removed grassy background from editing modal

* Fixed loading of other user equipment

* Prevented non admins from using habitica official

* Fixed challenge loading and leader changing on group reload

* Added community guidlines link

* Added challenge cloning

* Fixed heroes editing
This commit is contained in:
Keith Holliday
2017-09-07 13:26:53 -06:00
committed by GitHub
parent d9817be8f3
commit 3e1c128600
15 changed files with 183 additions and 76 deletions

View File

@@ -8,7 +8,7 @@ b-modal#login-incentives(:title="data.message", size='md', :hide-footer="true")
.reward-wrap .reward-wrap
div(v-if="nextReward.rewardKey.length === 1", :class="nextReward.rewardKey[0]") div(v-if="nextReward.rewardKey.length === 1", :class="nextReward.rewardKey[0]")
.reward(v-for="reward in nextReward.rewardKey", v-if="nextReward.rewardKey.length > 1", :class='reward') .reward(v-for="reward in nextReward.rewardKey", v-if="nextReward.rewardKey.length > 1", :class='reward')
div(v-if="data.nextRewardAt") .col-12.text-center(v-if="data.nextRewardAt")
h4 {{ $t('countLeft', {count: data.nextRewardAt - user.loginIncentives}) }} h4 {{ $t('countLeft', {count: data.nextRewardAt - user.loginIncentives}) }}
.row .row
.col-8.offset-2.text-center .col-8.offset-2.text-center

View File

@@ -1,6 +1,6 @@
<template lang="pug"> <template lang="pug">
.row .row
challenge-modal(:challenge='challenge', v-on:updatedChallenge='updatedChallenge') challenge-modal(:challenge='challenge', :cloning='cloning' v-on:updatedChallenge='updatedChallenge')
close-challenge-modal(:members='members', :challengeId='challenge._id') close-challenge-modal(:members='members', :challengeId='challenge._id')
challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id') challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id')
@@ -68,6 +68,8 @@
button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}} button.btn.btn-danger(v-once, @click='closeChallenge()') {{$t('endChallenge')}}
div(v-if='isLeader') div(v-if='isLeader')
button.btn.btn-secondary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}} button.btn.btn-secondary(v-once, @click='exportChallengeCsv()') {{$t('exportChallengeCsv')}}
div(v-if='isLeader')
button.btn.btn-secondary(v-once, @click='cloneChallenge()') {{$t('clone')}}
.description-section .description-section
h2 {{$t('challengeSummary')}} h2 {{$t('challengeSummary')}}
p {{challenge.summary}} p {{challenge.summary}}
@@ -162,11 +164,15 @@
</style> </style>
<script> <script>
const TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt', 'challenge'];
import Vue from 'vue'; import Vue from 'vue';
import bDropdown from 'bootstrap-vue/lib/components/dropdown'; import bDropdown from 'bootstrap-vue/lib/components/dropdown';
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item'; import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
import findIndex from 'lodash/findIndex'; import findIndex from 'lodash/findIndex';
import cloneDeep from 'lodash/cloneDeep'; import cloneDeep from 'lodash/cloneDeep';
import omit from 'lodash/omit';
import uuid from 'uuid';
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
import closeChallengeModal from './closeChallengeModal'; import closeChallengeModal from './closeChallengeModal';
@@ -194,12 +200,14 @@ export default {
}, },
data () { data () {
return { return {
searchId: '',
columns: ['habit', 'daily', 'todo', 'reward'], columns: ['habit', 'daily', 'todo', 'reward'],
icons: Object.freeze({ icons: Object.freeze({
gemIcon, gemIcon,
memberIcon, memberIcon,
calendarIcon, calendarIcon,
}), }),
cloning: false,
challenge: {}, challenge: {},
members: [], members: [],
tasksByType: { tasksByType: {
@@ -225,15 +233,69 @@ export default {
return this.user._id === this.challenge.leader._id; return this.user._id === this.challenge.leader._id;
}, },
}, },
async mounted () { mounted () {
this.challenge = await this.$store.dispatch('challenges:getChallenge', {challengeId: this.challengeId}); if (!this.searchId) this.searchId = this.challengeId;
this.members = await this.$store.dispatch('members:getChallengeMembers', {challengeId: this.challengeId}); if (!this.challenge._id) this.loadChallenge();
let tasks = await this.$store.dispatch('tasks:getChallengeTasks', {challengeId: this.challengeId}); },
async beforeRouteUpdate (to, from, next) {
this.searchId = to.params.challengeId;
await this.loadChallenge();
if (this.$store.state.challengeOptions.cloning) {
this.cloneTasks(this.$store.state.challengeOptions.tasksToClone);
}
next();
},
methods: {
cleanUpTask (task) {
let cleansedTask = omit(task, TASK_KEYS_TO_REMOVE);
// Copy checklists but reset to uncomplete and assign new id
if (!cleansedTask.checklist) cleansedTask.checklist = [];
cleansedTask.checklist.forEach((item) => {
item.completed = false;
item.id = uuid();
});
if (cleansedTask.type !== 'reward') {
delete cleansedTask.value;
}
return cleansedTask;
},
cloneTasks (tasksToClone) {
let clonedTasks = [];
for (let key in tasksToClone) {
let tasksSection = tasksToClone[key];
tasksSection.forEach(task => {
let clonedTask = cloneDeep(task);
clonedTask = this.cleanUpTask(clonedTask);
clonedTask = taskDefaults(clonedTask);
this.tasksByType[task.type].push(clonedTask);
clonedTasks.push(clonedTask);
});
}
this.$store.dispatch('tasks:createChallengeTasks', {
challengeId: this.searchId,
tasks: clonedTasks,
});
},
async loadChallenge () {
this.challenge = await this.$store.dispatch('challenges:getChallenge', {challengeId: this.searchId});
this.members = await this.$store.dispatch('members:getChallengeMembers', {challengeId: this.searchId});
let tasks = await this.$store.dispatch('tasks:getChallengeTasks', {challengeId: this.searchId});
this.tasksByType = {
habit: [],
daily: [],
todo: [],
reward: [],
};
tasks.forEach((task) => { tasks.forEach((task) => {
this.tasksByType[task.type].push(task); this.tasksByType[task.type].push(task);
}); });
}, },
methods: {
editTask (task) { editTask (task) {
this.taskFormPurpose = 'edit'; this.taskFormPurpose = 'edit';
this.editingTask = cloneDeep(task); this.editingTask = cloneDeep(task);
@@ -272,8 +334,8 @@ export default {
this.$root.$emit('show::modal', 'members-modal'); this.$root.$emit('show::modal', 'members-modal');
}, },
async joinChallenge () { async joinChallenge () {
this.user.challenges.push(this.challengeId); this.user.challenges.push(this.searchId);
await this.$store.dispatch('challenges:joinChallenge', {challengeId: this.challengeId}); await this.$store.dispatch('challenges:joinChallenge', {challengeId: this.searchId});
// @TODO: this doesn't work because of asyncresource // @TODO: this doesn't work because of asyncresource
let tasks = await this.$store.dispatch('tasks:fetchUserTasks'); let tasks = await this.$store.dispatch('tasks:fetchUserTasks');
this.$store.state.tasks.data = tasks.data; this.$store.state.tasks.data = tasks.data;
@@ -284,11 +346,11 @@ export default {
if (!keepChallenge) keep = 'remove-all'; if (!keepChallenge) keep = 'remove-all';
let index = findIndex(this.user.challenges, (challengeId) => { let index = findIndex(this.user.challenges, (challengeId) => {
return challengeId === this.challengeId; return challengeId === this.searchId;
}); });
this.user.challenges.splice(index, 1); this.user.challenges.splice(index, 1);
await this.$store.dispatch('challenges:leaveChallenge', { await this.$store.dispatch('challenges:leaveChallenge', {
challengeId: this.challengeId, challengeId: this.searchId,
keep, keep,
}); });
}, },
@@ -297,6 +359,7 @@ export default {
}, },
edit () { edit () {
// @TODO: set working challenge // @TODO: set working challenge
this.cloning = false;
this.$root.$emit('show::modal', 'challenge-modal'); this.$root.$emit('show::modal', 'challenge-modal');
}, },
// @TODO: view members // @TODO: view members
@@ -309,9 +372,14 @@ export default {
}, },
async exportChallengeCsv () { async exportChallengeCsv () {
// let response = await this.$store.dispatch('challenges:exportChallengeCsv', { // let response = await this.$store.dispatch('challenges:exportChallengeCsv', {
// challengeId: this.challengeId, // challengeId: this.searchId,
// }); // });
window.location = `/api/v3/challenges/${this.challengeId}/export/csv`; window.location = `/api/v3/challenges/${this.searchId}/export/csv`;
},
cloneChallenge () {
this.cloning = true;
this.$store.state.challengeOptions.tasksToClone = this.tasksByType;
this.$root.$emit('show::modal', 'challenge-modal');
}, },
}, },
}; };

View File

@@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
b-modal#challenge-modal(:title="$t('createChallenge')", size='lg') b-modal#challenge-modal(:title="title", size='lg')
.form .form
.form-group .form-group
label label
@@ -137,7 +137,7 @@ import { TAVERN_ID, MIN_SHORTNAME_SIZE_FOR_CHALLENGES, MAX_SUMMARY_SIZE_FOR_CHAL
import { mapState } from 'client/libs/store'; import { mapState } from 'client/libs/store';
export default { export default {
props: ['challenge', 'groupId'], props: ['challenge', 'groupId', 'cloning'],
components: { components: {
bModal, bModal,
bDropdown, bDropdown,
@@ -210,7 +210,6 @@ export default {
let categoriesHashByKey = hashedCategories; let categoriesHashByKey = hashedCategories;
return { return {
creating: true,
workingChallenge: { workingChallenge: {
name: '', name: '',
summary: '', summary: '',
@@ -234,21 +233,6 @@ export default {
}; };
}, },
async mounted () { async mounted () {
this.$root.$on('shown::modal', () => {
if (this.challenge) {
this.workingChallenge = Object.assign(this.workingChallenge, this.challenge);
this.workingChallenge.categories = [];
if (this.challenge.categories) {
this.challenge.categories.forEach(category => {
this.workingChallenge.categories.push(category.slug);
});
}
this.creating = false;
}
});
this.groups = await this.$store.dispatch('guilds:getMyGuilds'); this.groups = await this.$store.dispatch('guilds:getMyGuilds');
if (this.user.party._id) { if (this.user.party._id) {
let party = await this.$store.dispatch('guilds:getGroup', {groupId: 'party'}); let party = await this.$store.dispatch('guilds:getGroup', {groupId: 'party'});
@@ -265,14 +249,31 @@ export default {
}); });
this.resetWorkingChallenge(); this.resetWorkingChallenge();
this.setUpWorkingChallenge();
}, },
watch: { watch: {
user () { user () {
if (!this.challenge) this.workingChallenge.leader = this.user._id; if (!this.challenge) this.workingChallenge.leader = this.user._id;
}, },
challenge () {
this.setUpWorkingChallenge();
},
cloning () {
this.setUpWorkingChallenge();
},
}, },
computed: { computed: {
...mapState({user: 'user.data'}), ...mapState({user: 'user.data'}),
creating () {
return !this.workingChallenge.id;
},
title () {
if (this.creating) {
return this.$t('createChallenge');
}
return this.$t('editingChallenge');
},
charactersRemaining () { charactersRemaining () {
let currentLength = this.workingChallenge.summary ? this.workingChallenge.summary.length : 0; let currentLength = this.workingChallenge.summary ? this.workingChallenge.summary.length : 0;
return MAX_SUMMARY_SIZE_FOR_CHALLENGES - currentLength; return MAX_SUMMARY_SIZE_FOR_CHALLENGES - currentLength;
@@ -320,6 +321,23 @@ export default {
}, },
}, },
methods: { methods: {
setUpWorkingChallenge () {
if (!this.challenge) return;
this.workingChallenge = Object.assign({}, this.workingChallenge, this.challenge);
this.workingChallenge.categories = [];
if (this.challenge.categories) {
this.challenge.categories.forEach(category => {
this.workingChallenge.categories.push(category.slug);
});
}
if (this.cloning) {
this.$delete(this.workingChallenge, '_id');
this.$delete(this.workingChallenge, 'id');
}
},
resetWorkingChallenge () { resetWorkingChallenge () {
this.workingChallenge = { this.workingChallenge = {
name: '', name: '',
@@ -369,6 +387,9 @@ export default {
this.$emit('createChallenge', challenge); this.$emit('createChallenge', challenge);
this.resetWorkingChallenge(); this.resetWorkingChallenge();
if (this.cloning) this.$store.state.challengeOptions.cloning = true;
this.$root.$emit('hide::modal', 'challenge-modal'); this.$root.$emit('hide::modal', 'challenge-modal');
this.$router.push(`/challenges/${challenge._id}`); this.$router.push(`/challenges/${challenge._id}`);
} }

View File

@@ -95,11 +95,6 @@ export default {
computed: { computed: {
...mapState({user: 'user.data'}), ...mapState({user: 'user.data'}),
}, },
async mounted () {
this.groupIdForChallenges = this.groupId;
if (this.groupId === 'party' && this.user.party._id) this.groupIdForChallenges = this.user.party._id;
this.challenges = await this.$store.dispatch('challenges:getGroupChallenges', {groupId: this.groupIdForChallenges});
},
data () { data () {
return { return {
challenges: [], challenges: [],
@@ -111,6 +106,13 @@ export default {
groupIdForChallenges: '', groupIdForChallenges: '',
}; };
}, },
watch: {
async groupId () {
this.groupIdForChallenges = this.groupId;
if (this.groupId === 'party' && this.user.party._id) this.groupIdForChallenges = this.user.party._id;
this.challenges = await this.$store.dispatch('challenges:getGroupChallenges', {groupId: this.groupIdForChallenges});
},
},
methods: { methods: {
createChallenge () { createChallenge () {
this.$root.$emit('show::modal', 'challenge-modal'); this.$root.$emit('show::modal', 'challenge-modal');

View File

@@ -7,7 +7,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
.section.avatar-section.row(:class='{"page-2": modalPage === 2}') .section.avatar-section.row(:class='{"page-2": modalPage === 2}')
.col-6.offset-3 .col-6.offset-3
.user-creation-bg .user-creation-bg(v-if='!editing')
avatar(:member='user', :avatarOnly='!editing') avatar(:member='user', :avatarOnly='!editing')
.section(v-if='modalPage === 2') .section(v-if='modalPage === 2')

View File

@@ -1,5 +1,5 @@
<template lang="pug"> <template lang="pug">
.row(v-if="group") .row(v-if="group._id")
group-form-modal(v-if='isParty') group-form-modal(v-if='isParty')
invite-modal(:group='this.group') invite-modal(:group='this.group')
start-quest-modal(:group='this.group') start-quest-modal(:group='this.group')
@@ -8,7 +8,7 @@
.col-6.title-details .col-6.title-details
h1 {{group.name}} h1 {{group.name}}
strong.float-left(v-once) {{$t('groupLeader')}} strong.float-left(v-once) {{$t('groupLeader')}}
span.float-left(v-once, v-if='group.leader.profile') : {{group.leader.profile.name}} span.float-left(v-if='group.leader.profile') : {{group.leader.profile.name}}
.col-6 .col-6
.row.icon-row .row.icon-row
.col-4.offset-4(v-bind:class="{ 'offset-8': isParty }") .col-4.offset-4(v-bind:class="{ 'offset-8': isParty }")
@@ -461,8 +461,8 @@ export default {
}, },
data () { data () {
return { return {
searchId: null, searchId: '',
group: null, group: {},
icons: Object.freeze({ icons: Object.freeze({
like: likeIcon, like: likeIcon,
copy: copyIcon, copy: copyIcon,
@@ -568,7 +568,7 @@ export default {
} }
}, },
beforeRouteUpdate (to, from, next) { beforeRouteUpdate (to, from, next) {
this.searchId = to.params.groupId; this.$set(this, 'searchId', to.params.groupId);
next(); next();
}, },
watch: { watch: {
@@ -665,7 +665,8 @@ export default {
this.checkForAchievements(); this.checkForAchievements();
return; return;
} }
this.group = group;
this.$set(this, 'group', group);
}, },
deleteAllMessages () { deleteAllMessages () {
if (confirm(this.$t('confirmDeleteAllMessages'))) { if (confirm(this.$t('confirmDeleteAllMessages'))) {

View File

@@ -80,6 +80,7 @@
.form-check( .form-check(
v-for="group in categoryOptions", v-for="group in categoryOptions",
:key="group.key", :key="group.key",
v-if='group.key !== "habitica_official" || user.contributor.admin'
) )
label.custom-control.custom-checkbox label.custom-control.custom-checkbox
input.custom-control-input(type="checkbox", :value="group.key", v-model="workingGroup.categories") input.custom-control-input(type="checkbox", :value="group.key", v-model="workingGroup.categories")
@@ -174,6 +175,7 @@ import bFormCheckbox from 'bootstrap-vue/lib/components/form-checkbox';
import bFormSelect from 'bootstrap-vue/lib/components/form-select'; import bFormSelect from 'bootstrap-vue/lib/components/form-select';
import bTooltip from 'bootstrap-vue/lib/components/tooltip'; import bTooltip from 'bootstrap-vue/lib/components/tooltip';
import { mapState } from 'client/libs/store';
import toggleSwitch from 'client/components/ui/toggleSwitch'; import toggleSwitch from 'client/components/ui/toggleSwitch';
import gemIcon from 'assets/svg/gem.svg'; import gemIcon from 'assets/svg/gem.svg';
import informationIcon from 'assets/svg/information.svg'; import informationIcon from 'assets/svg/information.svg';
@@ -294,6 +296,7 @@ export default {
return data; return data;
}, },
computed: { computed: {
...mapState({user: 'user.data'}),
editingGroup () { editingGroup () {
return this.$store.state.editingGroup; return this.$store.state.editingGroup;
}, },

View File

@@ -119,9 +119,11 @@ export default {
let user = this.$store.state.user.data; let user = this.$store.state.user.data;
let filterGuild = this.filterGuild; let filterGuild = this.filterGuild;
return this.guilds.filter((guild) => { return this.guilds.filter((guild) => {
if (guild.categories) {
guild.categorySlugs = guild.categories.map(cat => { guild.categorySlugs = guild.categories.map(cat => {
return cat.slug; return cat.slug;
}); });
}
return filterGuild(guild, filters, search, user); return filterGuild(guild, filters, search, user);
}); });
}, },

View File

@@ -15,8 +15,8 @@
button.btn.btn-secondary.send-chat.float-right(v-once, @click='sendMessage()') {{ $t('send') }} button.btn.btn-secondary.send-chat.float-right(v-once, @click='sendMessage()') {{ $t('send') }}
button.btn.btn-secondary.float-left(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }} button.btn.btn-secondary.float-left(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
.row.community-guidelines(v-if='!communityGuidelinesAccepted') .row.community-guidelines(v-if='true || !communityGuidelinesAccepted')
div.col-8(v-once) {{ $t('communityGuidelinesIntro') }} div.col-8(v-once, v-html="$t('communityGuidelinesIntro')")
div.col-4 div.col-4
button.btn.btn-info(@click='acceptCommunityGuidelines()', v-once) {{ $t('acceptCommunityGuidelines') }} button.btn.btn-info(@click='acceptCommunityGuidelines()', v-once) {{ $t('acceptCommunityGuidelines') }}

View File

@@ -66,7 +66,7 @@
// h4 Backer Status // h4 Backer Status
// Add backer stuff like tier, disable adds, etcs // Add backer stuff like tier, disable adds, etcs
.form-group .form-group
button.form-control.btn.btn-primary button.form-control.btn.btn-primary(@click='saveHero()')
| {{ $t('save') }} | {{ $t('save') }}
.table-responsive .table-responsive
@@ -104,8 +104,10 @@ import quests from 'common/script/content/quests';
import { mountInfo, petInfo } from 'common/script/content/stable'; import { mountInfo, petInfo } from 'common/script/content/stable';
import { food, hatchingPotions, special } from 'common/script/content'; import { food, hatchingPotions, special } from 'common/script/content';
import gear from 'common/script/content/gear'; import gear from 'common/script/content/gear';
import notifications from 'client/mixins/notifications';
export default { export default {
mixins: [notifications],
data () { data () {
return { return {
heroes: [], heroes: [],
@@ -162,13 +164,17 @@ export default {
async loadHero (uuid, heroIndex) { async loadHero (uuid, heroIndex) {
this.currentHeroIndex = heroIndex; this.currentHeroIndex = heroIndex;
let hero = await this.$store.dispatch('hall:getHero', { uuid }); let hero = await this.$store.dispatch('hall:getHero', { uuid });
this.hero = hero; this.hero = Object.assign({}, this.hero, hero);
if (!this.hero.flags) {
this.hero.flags = {
chatRevoked: false,
};
}
}, },
async saveHero (hero) { async saveHero () {
this.hero.contributor.admin = this.hero.contributor.level > 7 ? true : false; this.hero.contributor.admin = this.hero.contributor.level > 7 ? true : false;
let heroUpdated = await this.$store.dispatch('hall:updateHero', { heroDetails: hero }); let heroUpdated = await this.$store.dispatch('hall:updateHero', { heroDetails: this.hero });
// @TODO: Import this.text('User updated');
// Notification.text("User updated");
this.hero = {}; this.hero = {};
this.heroID = -1; this.heroID = -1;
this.heroes[this.currentHeroIndex] = heroUpdated; this.heroes[this.currentHeroIndex] = heroUpdated;

View File

@@ -23,7 +23,7 @@ div
.nav-item(@click='selectedPage = "profile"', :class="{active: selectedPage === 'profile'}") Profile .nav-item(@click='selectedPage = "profile"', :class="{active: selectedPage === 'profile'}") Profile
.nav-item(@click='selectedPage = "stats"', :class="{active: selectedPage === 'stats'}") Stats .nav-item(@click='selectedPage = "stats"', :class="{active: selectedPage === 'stats'}") Stats
.nav-item(@click='selectedPage = "achievements"', :class="{active: selectedPage === 'achievements'}") Achievements .nav-item(@click='selectedPage = "achievements"', :class="{active: selectedPage === 'achievements'}") Achievements
.standard-page(v-show='selectedPage === "profile"', v-if='user.profile') #userProfile.standard-page(v-show='selectedPage === "profile"', v-if='user.profile')
.row .row
.col-8 .col-8
.header .header
@@ -91,14 +91,9 @@ div
#achievements.standard-page.container(v-show='selectedPage === "achievements"', v-if='user.achievements') #achievements.standard-page.container(v-show='selectedPage === "achievements"', v-if='user.achievements')
.row(v-for='(category, key) in achievements') .row(v-for='(category, key) in achievements')
h2.col-12.text-center {{ $t(key+'Achievs') }} h2.col-12.text-center {{ $t(key+'Achievs') }}
.col-3.text-center(v-for='achievment in category.achievements') .col-3.text-center(v-for='(achievment, key) in category.achievements')
.box.achievement-container(:class='{"achievement-unearned": !achievment.earned}', :data-popover-html='achievment.title + achievment.text', .box.achievement-container(:id='key', :class='{"achievement-unearned": !achievment.earned}')
popover-placement='achievPopoverPlacement', b-popover(:target="'#' + key", triggers="hover", placement="top", :content="achievment.title + achievment.text")
popover-append-to-body='achievAppendToBody')
div(popover-trigger='mouseenter',
:data-popover-html='achievment.title + achievment.text',
popover-placement='achievPopoverPlacement',
popover-append-to-body='achievAppendToBody')
.achievement(:class='achievment.icon + "2x"', v-if='achievment.earned') .achievement(:class='achievment.icon + "2x"', v-if='achievment.earned')
.counter.badge.badge-info.stack-count(v-if='achievment.optionalCount') {{achievment.optionalCount}} .counter.badge.badge-info.stack-count(v-if='achievment.optionalCount') {{achievment.optionalCount}}
.achievement.achievement-unearned(class='achievement-unearned2x', v-if='!achievment.earned') .achievement.achievement-unearned(class='achievement-unearned2x', v-if='!achievment.earned')
@@ -548,6 +543,7 @@ import autoAllocate from '../../../common/script/fns/autoAllocate';
import allocate from '../../../common/script/ops/allocate'; import allocate from '../../../common/script/ops/allocate';
import MemberDetails from '../memberDetails'; import MemberDetails from '../memberDetails';
import bPopover from 'bootstrap-vue/lib/components/popover';
import privateMessageModal from 'client/components/private-message-modal'; import privateMessageModal from 'client/components/private-message-modal';
import sendGemsModal from 'client/components/payments/sendGemsModal'; import sendGemsModal from 'client/components/payments/sendGemsModal';
import markdown from 'client/directives/markdown'; import markdown from 'client/directives/markdown';
@@ -573,6 +569,7 @@ export default {
sendGemsModal, sendGemsModal,
MemberDetails, MemberDetails,
toggleSwitch, toggleSwitch,
bPopover,
}, },
data () { data () {
return { return {
@@ -625,9 +622,13 @@ export default {
...mapState({ ...mapState({
userLoggedIn: 'user.data', userLoggedIn: 'user.data',
flatGear: 'content.gear.flat', flatGear: 'content.gear.flat',
equippedItems: 'user.data.items.gear.equipped',
costumeItems: 'user.data.items.gear.costume',
}), }),
equippedItems () {
return this.user.items.gear.equipped;
},
costumeItems () {
return this.user.items.gear.costume;
},
user () { user () {
let user = this.userLoggedIn; let user = this.userLoggedIn;

View File

@@ -14,9 +14,7 @@ export async function getHero (store, payload) {
export async function updateHero (store, payload) { export async function updateHero (store, payload) {
let url = `/api/v3/hall/heroes/${payload.heroDetails._id}`; let url = `/api/v3/hall/heroes/${payload.heroDetails._id}`;
let response = await axios.put(url, { let response = await axios.put(url, payload.heroDetails);
heroDetails: payload.heroDetails,
});
return response.data.data; return response.data.data;
} }

View File

@@ -82,6 +82,10 @@ export default function () {
message: {}, message: {},
groupId: '', groupId: '',
}, },
challengeOptions: {
cloning: false,
tasksToClone: {},
},
editingGroup: {}, // TODO move to local state editingGroup: {}, // TODO move to local state
// content data, frozen to prevent Vue from modifying it since it's static and never changes // content data, frozen to prevent Vue from modifying it since it's static and never changes
// TODO apply freezing to the entire codebase (the server) and not only to the client side? // TODO apply freezing to the entire codebase (the server) and not only to the client side?

View File

@@ -115,5 +115,6 @@
"updateChallenge": "Update Challenge", "updateChallenge": "Update Challenge",
"haveNoChallenges": "You don't have any Challenges", "haveNoChallenges": "You don't have any Challenges",
"loadMore": "Load More", "loadMore": "Load More",
"exportChallengeCsv": "Export Challenge" "exportChallengeCsv": "Export Challenge",
"editingChallenge": "Editing Challenge"
} }

View File

@@ -27,7 +27,7 @@
"pauseDailies": "Pause Damage", "pauseDailies": "Pause Damage",
"unpauseDailies": "Unpause Damage", "unpauseDailies": "Unpause Damage",
"staffAndModerators": "Staff and Moderators", "staffAndModerators": "Staff and Moderators",
"communityGuidelinesIntro": "Habitica tries to create a welcoming environment for users of all ages and backgrounds, especially in public spaces like the Tavern. If you have any questions, please consult our Community Guidelines.", "communityGuidelinesIntro": "Habitica tries to create a welcoming environment for users of all ages and backgrounds, especially in public spaces like the Tavern. If you have any questions, please consult our <a href='/static/community-guidelines' target='_blank'>Community Guidelines</a>.",
"acceptCommunityGuidelines": "I agree to follow the Community Guidelines", "acceptCommunityGuidelines": "I agree to follow the Community Guidelines",
"daniel": "Daniel", "daniel": "Daniel",
"danielText": "Welcome to the Tavern! Stay a while and meet the locals. If you need to rest (vacation? illness?), I'll set you up at the Inn. While checked-in, your Dailies won't hurt you at the day's end, but you can still check them off.", "danielText": "Welcome to the Tavern! Stay a while and meet the locals. If you need to rest (vacation? illness?), I'll set you up at the Inn. While checked-in, your Dailies won't hurt you at the day's end, but you can still check them off.",