diff --git a/website/client/components/appMenu.vue b/website/client/components/appMenu.vue
index a7fd89a087..dc04ad49dc 100644
--- a/website/client/components/appMenu.vue
+++ b/website/client/components/appMenu.vue
@@ -364,6 +364,7 @@ export default {
this.$root.$emit('show::modal', 'avatar-modal');
},
showProfile (startingPage) {
+ this.$store.state.profileUser = this.user;
this.$store.state.profileOptions.startingPage = startingPage;
this.$root.$emit('show::modal', 'profile');
},
diff --git a/website/client/components/chat/chatMessages.vue b/website/client/components/chat/chatMessages.vue
index 4287f76ce1..9202a308c5 100644
--- a/website/client/components/chat/chatMessages.vue
+++ b/website/client/components/chat/chatMessages.vue
@@ -40,7 +40,7 @@
span.action(v-if='user.contributor.admin || (msg.uuid !== user._id && user.flags.communityGuidelinesAccepted)', @click='report(msg)')
.svg-icon(v-html="icons.report")
| {{$t('report')}}
- span.action(v-if='msg.uuid === user._id', @click='remove(msg, index)')
+ span.action(v-if='msg.uuid === user._id || inbox', @click='remove(msg, index)')
.svg-icon(v-html="icons.delete")
| {{$t('delete')}}
span.action.float-right(v-if='likeCount(msg) > 0')
@@ -375,6 +375,12 @@ export default {
},
async remove (message, index) {
this.chat.splice(index, 1);
+
+ if (this.inbox) {
+ axios.delete(`/api/v3/user/messages/${message.id}`);
+ return;
+ }
+
await this.$store.dispatch('chat:deleteChat', {
groupId: this.groupId,
chatId: message.id,
diff --git a/website/client/components/creatorIntro.vue b/website/client/components/creatorIntro.vue
index c53bebf531..e69de56667 100644
--- a/website/client/components/creatorIntro.vue
+++ b/website/client/components/creatorIntro.vue
@@ -189,13 +189,8 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
strong(v-once) {{$t('flower')}}
.row(v-if='activeSubPage === "glasses"')
.col-12.customize-options
- .eyewear_special_blackTopFrame.option(@click='equip("eyewear_special_blackTopFrame")', :class='{active: user.preferences.costume ? user.items.gear.costume.eyewear === "eyewear_special_blackTopFrame" : user.items.gear.equipped.eyewear === "eyewear_special_blackTopFrame"}')
- .eyewear_special_blueTopFrame.option(@click='equip("eyewear_special_blueTopFrame")', :class='{active: user.preferences.costume ? user.items.gear.costume.eyewear === "eyewear_special_blueTopFrame" : user.items.gear.equipped.eyewear === "eyewear_special_blueTopFrame"}')
- .eyewear_special_greenTopFrame.option(@click='equip("eyewear_special_greenTopFrame")', :class='{active: user.preferences.costume ? user.items.gear.costume.eyewear === "eyewear_special_greenTopFrame" : user.items.gear.equipped.eyewear === "eyewear_special_greenTopFrame"}')
- .eyewear_special_pinkTopFrame.option(@click='equip("eyewear_special_pinkTopFrame")', :class='{active: user.preferences.costume ? user.items.gear.costume.eyewear === "eyewear_special_pinkTopFrame" : user.items.gear.equipped.eyewear === "eyewear_special_pinkTopFrame"}')
- .eyewear_special_redTopFrame.option(@click='equip("eyewear_special_redTopFrame")', :class='{active: user.preferences.costume ? user.items.gear.costume.eyewear === "eyewear_special_redTopFrame" : user.items.gear.equipped.eyewear === "eyewear_special_redTopFrame"}')
- .eyewear_special_whiteTopFrame.option(@click='equip("eyewear_special_whiteTopFrame")', :class='{active: user.preferences.costume ? user.items.gear.costume.eyewear === "eyewear_special_whiteTopFrame" : user.items.gear.equipped.eyewear === "eyewear_special_whiteTopFrame"}')
- .eyewear_special_yellowTopFrame.option(@click='equip("eyewear_special_yellowTopFrame")', :class='{active: user.preferences.costume ? user.items.gear.costume.eyewear === "eyewear_special_yellowTopFrame" : user.items.gear.equipped.eyewear === "eyewear_special_yellowTopFrame"}')
+ .option(v-for='option in eyewear', :class='{active: option.active}')
+ .sprite.customize-option(:class="`eyewear_special_${option.key}`", @click='option.click')
#animal-ears.col-12.customize-options(v-if='editing')
.option(v-for='option in animalEars',
:class='{active: option.active, locked: option.locked}')
@@ -262,7 +257,8 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
span 7
span.badge.badge-pill.badge-item.badge-svg(
:class="{'item-selected-badge': isBackgroundPinned(bg), 'hide': !isBackgroundPinned(bg)}",
- @click.prevent.stop="togglePinned(bg)"
+ @click.prevent.stop="togglePinned(bg)",
+ v-if='!user.purchased.background[bg.key]'
)
span.svg-icon.inline.icon-12.color(v-html="icons.pin")
@@ -979,6 +975,20 @@ export default {
},
computed: {
...mapState({user: 'user.data'}),
+ eyewear () {
+ let keys = ['blackTopFrame', 'blueTopFrame', 'greenTopFrame', 'pinkTopFrame', 'redTopFrame', 'whiteTopFrame', 'yellowTopFrame'];
+ let options = keys.map(key => {
+ let newKey = `eyewear_special_${key}`;
+ let option = {};
+ option.key = key;
+ option.active = this.user.preferences.costume ? this.user.items.gear.costume.eyewear === newKey : this.user.items.gear.equipped.eyewear === newKey;
+ option.click = () => {
+ return this.equip(newKey);
+ };
+ return option;
+ });
+ return options;
+ },
animalEarsUnlockString () {
let animalItemKeys = this.animalEarsKeys.map(key => {
return `items.gear.owned.headAccessory_special_${key}`;
diff --git a/website/client/components/groups/startQuestModal.vue b/website/client/components/groups/startQuestModal.vue
index 108a7d7833..e55844ae21 100644
--- a/website/client/components/groups/startQuestModal.vue
+++ b/website/client/components/groups/startQuestModal.vue
@@ -12,7 +12,7 @@
div(v-if='questData')
questDialogContent(:item="questData")
div.text-center
- button.btn.btn-primary(@click='questInit()', :disabled="Boolean(group.quest)") {{$t('inviteToPartyOrQuest')}}
+ button.btn.btn-primary(@click='questInit()', :disabled="!Boolean(selectedQuest)") {{$t('inviteToPartyOrQuest')}}
div.text-center
p {{$t('inviteInformation')}}
.side-panel(v-if='questData')
diff --git a/website/client/components/inventory/items/index.vue b/website/client/components/inventory/items/index.vue
index c70991337a..a569b9a769 100644
--- a/website/client/components/inventory/items/index.vue
+++ b/website/client/components/inventory/items/index.vue
@@ -321,8 +321,8 @@ export default {
}
for (let type in this.content.cardTypes) {
- if (this.user.items.special[type] > 0) {
- let card = this.user.items.special[`${this.cardType}Received`];
+ let card = this.user.items.special[`${type}Received`] || [];
+ if (this.user.items.special[type] > 0 || card.length > 0) {
specialArray.push({
type: 'card',
key: type,
diff --git a/website/client/components/settings/site.vue b/website/client/components/settings/site.vue
index 507ba866e2..54930b078e 100644
--- a/website/client/components/settings/site.vue
+++ b/website/client/components/settings/site.vue
@@ -41,18 +41,6 @@
hr
div
- .checkbox
- label
- input(type='checkbox', @click='hideHeader() ', v-model='user.preferences.hideHeader')
- span.hint(popover-trigger='mouseenter', popover-placement='right', :popover="$t('showHeaderPop')") {{ $t('showHeader') }}
- .checkbox
- label
- input(type='checkbox', @click='toggleStickyHeader()', v-model='user.preferences.stickyHeader', :disabled="user.preferences.hideHeader")
- span.hint(popover-trigger='mouseenter', popover-placement='right', :popover="$t('stickyHeaderPop')") {{ $t('stickyHeader') }}
- .checkbox
- label
- input(type='checkbox', v-model='user.preferences.newTaskEdit', @click='set("newTaskEdit")')
- span.hint(popover-trigger='mouseenter', popover-placement='right', :popover="$t('newTaskEditPop')") {{ $t('newTaskEdit') }}
.checkbox
label
input(type='checkbox', v-model='user.preferences.tagsCollapsed', @change='set("tagsCollapsed")')
@@ -186,9 +174,9 @@
h5 {{ $t('dangerZone') }}
div
button.btn.btn-danger(@click='openResetModal()',
- popover-trigger='mouseenter', popover-placement='right', :popover="$t('resetAccPop')") {{ $t('resetAccount') }}
+ popover-trigger='mouseenter', popover-placement='right', v-b-popover.hover.auto="$t('resetAccPop')") {{ $t('resetAccount') }}
button.btn.btn-danger(@click='openDeleteModal()',
- popover-trigger='mouseenter', :popover="$t('deleteAccPop')") {{ $t('deleteAccount') }}
+ popover-trigger='mouseenter', v-b-popover.hover.auto="$t('deleteAccPop')") {{ $t('deleteAccount') }}
diff --git a/website/client/components/tasks/taskModal.vue b/website/client/components/tasks/taskModal.vue
index ed00b9ae10..05a1439a6e 100644
--- a/website/client/components/tasks/taskModal.vue
+++ b/website/client/components/tasks/taskModal.vue
@@ -30,10 +30,12 @@
.option(v-if="['daily', 'todo'].indexOf(task.type) > -1")
label(v-once) {{ $t('checklist') }}
br
- .inline-edit-input-group.checklist-group.input-group(v-for="(item, $index) in task.checklist")
- input.inline-edit-input.checklist-item.form-control(type="text", v-model="item.text")
- span.input-group-btn(@click="removeChecklistItem($index)")
- .svg-icon.destroy-icon(v-html="icons.destroy")
+ | {{checklist}}
+ div(v-sortable='', @onsort='sortedChecklist')
+ .inline-edit-input-group.checklist-group.input-group(v-for="(item, $index) in checklist")
+ input.inline-edit-input.checklist-item.form-control(type="text", v-model="item.text")
+ span.input-group-btn(@click="removeChecklistItem($index)")
+ .svg-icon.destroy-icon(v-html="icons.destroy")
input.inline-edit-input.checklist-item.form-control(type="text", :placeholder="$t('newChecklistItem')", @keydown.enter="addChecklistItem($event)", v-model="newChecklistItem")
.d-flex.justify-content-center(v-if="task.type === 'habit'")
.option-item(:class="optionClass(task.up === true)", @click="task.up = !task.up")
@@ -401,6 +403,8 @@ import { mapGetters, mapActions, mapState } from 'client/libs/store';
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
import toggleSwitch from 'client/components/ui/toggleSwitch';
+import sortable from 'client/directives/sortable.directive';
+import clone from 'lodash/clone';
import Datepicker from 'vuejs-datepicker';
import moment from 'moment';
import uuid from 'uuid';
@@ -423,6 +427,9 @@ export default {
Datepicker,
toggleSwitch,
},
+ directives: {
+ sortable,
+ },
props: ['task', 'purpose', 'challengeId', 'groupId'], // purpose is either create or edit, task is the task created or edited
data () {
return {
@@ -444,6 +451,7 @@ export default {
members: [],
memberNamesById: {},
assignedMembers: [],
+ checklist: [],
};
},
watch: {
@@ -464,6 +472,9 @@ export default {
this.assignedMembers = [];
if (this.task.group && this.task.group.assignedUsers) this.assignedMembers = this.task.group.assignedUsers;
}
+
+ // @TODO: This whole component is mutating a prop and that causes issues. We need to not copy the prop similar to group modals
+ if (this.task) this.checklist = clone(this.task.checklist);
},
},
computed: {
@@ -534,6 +545,13 @@ export default {
},
methods: {
...mapActions({saveTask: 'tasks:save', destroyTask: 'tasks:destroy', createTask: 'tasks:create'}),
+ sortedChecklist (data) {
+ let sorting = clone(this.checklist);
+ let movingItem = sorting[data.oldIndex];
+ sorting.splice(data.oldIndex, 1);
+ sorting.splice(data.newIndex, 0, movingItem);
+ this.task.checklist = sorting;
+ },
optionClass (activeCondition) {
if (activeCondition) {
return [`${this.cssClass}-color`, 'option-item-selected'];
@@ -547,11 +565,13 @@ export default {
text: this.newChecklistItem,
completed: false,
});
+ this.checklist = clone(this.task.checklist);
this.newChecklistItem = null;
if (e) e.preventDefault();
},
removeChecklistItem (i) {
this.task.checklist.splice(i, 1);
+ this.checklist = clone(this.task.checklist);
},
weekdaysMin (dayNumber) {
return moment.weekdaysMin(dayNumber);
diff --git a/website/client/components/userMenu/inbox.vue b/website/client/components/userMenu/inbox.vue
index f643cf3050..23413994a8 100644
--- a/website/client/components/userMenu/inbox.vue
+++ b/website/client/components/userMenu/inbox.vue
@@ -11,6 +11,8 @@
// @TODO: Implement this after we fix username bug
// .col-2.offset-1
// button.btn.btn-secondary(@click='toggleClick()') +
+ .col-4.offset-4
+ .svg-icon.close(v-html="icons.svgClose", @click='close()')
// .col-8.to-form(v-if='displayCreate')
// strong To:
// b-form-input
@@ -39,7 +41,7 @@
// @TODO: Implement new message header here when we fix the above
.new-message-row(v-if='selectedConversation')
- input(v-model='newMessage')
+ textarea(v-model='newMessage')
button.btn.btn-secondary(@click='sendPrivateMessage()') Send
@@ -51,6 +53,11 @@
margin-top: 1em;
}
+ .close {
+ margin-top: .5em;
+ width: 15px;
+ }
+
h2 {
margin-top: .5em;
}
@@ -107,12 +114,16 @@
width: 100%;
padding: 1em;
- input {
+ textarea {
+ height: 80%;
display: inline-block;
+ vertical-align: bottom;
width: 80%;
}
button {
+ vertical-align: bottom;
+ display: inline-block;
box-shadow: none;
margin-left: 1em;
}
@@ -155,6 +166,7 @@ import bFormInput from 'bootstrap-vue/lib/components/form-input';
import messageIcon from 'assets/svg/message.svg';
import chatMessage from '../chat/chatMessages';
+import svgClose from 'assets/svg/close.svg';
export default {
mixins: [styleHelper],
@@ -167,6 +179,7 @@ export default {
return {
icons: Object.freeze({
messageIcon,
+ svgClose,
}),
displayCreate: true,
selectedConversation: '',
@@ -201,6 +214,7 @@ export default {
timestamp: message.timestamp,
user: message.user,
uuid: message.uuid,
+ id: message.id,
};
if (message.sent) {
@@ -256,6 +270,8 @@ export default {
});
},
sendPrivateMessage () {
+ if (!this.newMessage) return;
+
let convoFound = this.conversations.find((conversation) => {
return conversation.key === this.selectedConversation;
});
@@ -284,6 +300,9 @@ export default {
chatscroll.scrollTop = chatscroll.scrollHeight;
});
},
+ close () {
+ this.$root.$emit('hide::modal', 'inbox-modal');
+ },
},
};
diff --git a/website/client/components/userMenu/profile.vue b/website/client/components/userMenu/profile.vue
index af0a6567a8..696507aa9a 100644
--- a/website/client/components/userMenu/profile.vue
+++ b/website/client/components/userMenu/profile.vue
@@ -47,7 +47,10 @@ div
h2 {{ $t('info') }}
div
strong {{ $t('joined') }}:
- | {{user.auth.timestamps.created}}
+ | {{userJoinedDate}}
+ div
+ strong {{ $t('lastLoggedIn') }}:
+ | {{userLastLoggedIn}}
div
strong {{ $t('totalLogins') }}:
span {{ $t('totalCheckins', {count: user.loginIncentives}) }}
@@ -100,7 +103,7 @@ div
h4.popover-content-title {{ achievement.title }}
div.popover-content-text(v-html="achievement.text")
.achievement(:class='achievement.icon + "2x"', v-if='achievement.earned')
- .counter.badge.badge-info.stack-count(v-if='achievement.optionalCount') {{achievement.optionalCount}}
+ .counter.badge.badge-info.stack-count(v-if='achievement.optionalCount') {{achievement.optionalCount}}
.achievement.achievement-unearned(class='achievement-unearned2x', v-if='!achievement.earned')
hr.col-12
.row
@@ -126,7 +129,7 @@ div
div(:class="`shop_${equippedItems.eyewear}`")
h3 {{$t('eyewear')}}
.col-4.item-wrapper
- .box(:class='{white: equippedItems.head}')
+ .box(:class='{white: equippedItems.head && equippedItems.head.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.head}`")
h3 {{$t('headGear')}}
.col-4.item-wrapper
@@ -138,7 +141,7 @@ div
div(:class="`shop_${equippedItems.backAccessory}`")
h3 {{$t('backAccess')}}
.col-4.item-wrapper
- .box(:class='{white: equippedItems.armor}')
+ .box(:class='{white: equippedItems.armor && equippedItems.armor.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.armor}`")
h3 {{$t('armor')}}
.col-4.item-wrapper
@@ -146,12 +149,12 @@ div
div(:class="`shop_${equippedItems.bodyAccessory}`")
h3 {{$t('bodyAccess')}}
.col-4.item-wrapper
- .box(:class='{white: equippedItems.weapon}')
+ .box(:class='{white: equippedItems.weapon && equippedItems.weapon.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.weapon}`")
h3 {{$t('mainHand')}}
.col-4.item-wrapper
.col-4.item-wrapper
- .box(:class='{white: equippedItems.shield}')
+ .box(:class='{white: equippedItems.shield && equippedItems.shield.indexOf("base_0") === -1}')
div(:class="`shop_${equippedItems.shield}`")
h3 {{$t('offHand')}}
.col-6
@@ -162,7 +165,7 @@ div
div(:class="`shop_${costumeItems.eyewear}`")
h3 {{$t('eyewear')}}
.col-4.item-wrapper
- .box(:class='{white: costumeItems.head}')
+ .box(:class='{white: costumeItems.head && costumeItems.head.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.head}`")
h3 {{$t('headGear')}}
.col-4.item-wrapper
@@ -174,7 +177,7 @@ div
div(:class="`shop_${costumeItems.backAccessory}`")
h3 {{$t('backAccess')}}
.col-4.item-wrapper
- .box(:class='{white: costumeItems.armor}')
+ .box(:class='{white: costumeItems.armor && costumeItems.armor.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.armor}`")
h3 {{$t('armor')}}
.col-4.item-wrapper
@@ -182,7 +185,7 @@ div
div(:class="`shop_${costumeItems.bodyAccessory}`")
h3 {{$t('bodyAccess')}}
.col-4.item-wrapper
- .box(:class='{white: costumeItems.weapon}')
+ .box(:class='{white: costumeItems.weapon && costumeItems.weapon.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.weapon}`")
h3 {{$t('mainHand')}}
.col-4.item-wrapper
@@ -190,7 +193,7 @@ div
div(:class="user.preferences.background")
h3 {{$t('background')}}
.col-4.item-wrapper
- .box(:class='{white: costumeItems.shield}')
+ .box(:class='{white: costumeItems.shield && costumeItems.shield.indexOf("base_0") === -1}')
div(:class="`shop_${costumeItems.shield}`")
h3 {{$t('offHand')}}
.row.pet-mount-row
@@ -200,7 +203,7 @@ div
.row.col-12
.col-4
.box(:class='{white: user.items.currentPet}')
- div(:class="user.items.currentPet")
+ .pet(:class="`Pet-${user.items.currentPet}`")
.col-8
div
| {{ formatAnimal(user.items.currentPet, 'pet') }}
@@ -216,7 +219,7 @@ div
.row.col-12
.col-4
.box(:class='{white: user.items.currentMount}')
- div(:class="user.items.currentMount")
+ .mount(:class="`Mount-${user.items.currentMount}`")
.col-8
div
| {{ formatAnimal(user.items.currentMount, 'mount') }}
@@ -322,6 +325,10 @@ div
margin-bottom: 2em;
}
+ .pet, .mount {
+ margin-top: -1.6em;
+ }
+
.header {
h1 {
color: #4f2a93;
@@ -399,9 +406,10 @@ div
color: #fff;
background-color: #ff944c;
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
- width: 24px;
- height: 24px;
- border-radius: 50%;
+ min-width: 24px;
+ min-height: 24px;
+ border-radius: 2em;
+ padding: .5em;
}
.achievement-icon {
@@ -537,6 +545,7 @@ div