From 744090e65228656f513f618e09469c31e324b3fe Mon Sep 17 00:00:00 2001 From: Keith Holliday Date: Thu, 21 Sep 2017 18:53:45 -0500 Subject: [PATCH] Sept 21 fixes (#9061) * Fixed analytics when party is not defined: * Waited to set Stripe * Added popovers to danger zone * Added date format to next cron * Redirect user back to home for static * Removed old settings * Fixed show bailey * Fixed close button on inbox * Fixed sending blank message * Changed input to text area in inbox * Fixed deleting messages in inbox * Allowed user to delete other user message in inbox * Fixed joined date * Fixed count styling * Fixed display of pet and mount * Removed white box when using base_0 items * Fixed your profile to show when clicking from menu * Prevented user from pinning already purchased backgroud * Added user last log in * Added date refresh for yesterdailies modal * Updatd eyewear * Fixed start a quest button * Fixed styles on home page footer * Added checklist sorting * Added support for if card type is missing computed field * Fixed linting --- website/client/components/appMenu.vue | 1 + .../client/components/chat/chatMessages.vue | 8 +++- website/client/components/creatorIntro.vue | 26 +++++++---- .../components/groups/startQuestModal.vue | 2 +- .../components/inventory/items/index.vue | 4 +- website/client/components/settings/site.vue | 25 ++++------- website/client/components/static/header.vue | 10 +++++ website/client/components/static/home.vue | 5 ++- website/client/components/tasks/taskModal.vue | 28 ++++++++++-- website/client/components/userMenu/inbox.vue | 23 +++++++++- .../client/components/userMenu/profile.vue | 45 ++++++++++++------- .../client/components/yesterdailyModal.vue | 6 ++- website/client/mixins/payments.js | 5 ++- website/client/store/actions/quests.js | 18 ++++++-- 14 files changed, 147 insertions(+), 59 deletions(-) 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