From 92e4d5cd68eb3e67e65356bd7d02e2d65f4c7fdc Mon Sep 17 00:00:00 2001 From: negue Date: Sun, 9 Sep 2018 12:05:33 +0200 Subject: [PATCH] Refactor/market vue (#10601) * extract inventoryDrawer from market * show scrollbar only if needed * extract featuredItemsHeader / pinUtils * extract pageLayout * extract layoutSection / filterDropdown - fix sortByNumber * rollback sortByNumber order-fix * move equipment lists out of the layout-section (for now) * refactor sellModal * extract checkbox * extract equipment section * extract category row * revert scroll - remove sellModal item template * fix(lint): commas and semis * Created category item component (#10613) * extract filter sidebar * fix gemCount - fix raising the item count if the item wasn't previously owned * fixes #10659 * remove unneeded method --- website/client/app.vue | 8 - .../components/inventory/stable/foodItem.vue | 5 +- .../components/inventory/stable/index.vue | 57 +- .../components/shared/inventoryDrawer.vue | 169 +++++ .../components/shops/featuredItemsHeader.vue | 126 ++++ website/client/components/shops/index.vue | 8 +- .../components/shops/market/categoryItem.vue | 52 ++ .../components/shops/market/categoryRow.vue | 94 +++ .../shops/market/equipmentSection.vue | 167 +++++ .../client/components/shops/market/filter.vue | 46 ++ .../client/components/shops/market/index.vue | 684 ++++-------------- .../components/shops/market/sellModal.vue | 77 +- .../client/components/shops/quests/index.vue | 8 +- .../components/shops/seasonal/index.vue | 8 +- .../components/shops/timeTravelers/index.vue | 7 +- website/client/components/ui/checkbox.vue | 26 + website/client/components/ui/countBadge.vue | 2 +- .../client/components/ui/filterDropdown.vue | 45 ++ .../client/components/ui/layoutSection.vue | 33 + website/client/components/ui/pageLayout.vue | 25 + website/client/mixins/inventoryUtils.js | 27 + website/client/mixins/pinUtils.js | 19 + website/common/script/libs/shops.js | 17 +- 23 files changed, 1048 insertions(+), 662 deletions(-) create mode 100644 website/client/components/shared/inventoryDrawer.vue create mode 100644 website/client/components/shops/featuredItemsHeader.vue create mode 100644 website/client/components/shops/market/categoryItem.vue create mode 100644 website/client/components/shops/market/categoryRow.vue create mode 100644 website/client/components/shops/market/equipmentSection.vue create mode 100644 website/client/components/shops/market/filter.vue create mode 100644 website/client/components/ui/checkbox.vue create mode 100644 website/client/components/ui/filterDropdown.vue create mode 100644 website/client/components/ui/layoutSection.vue create mode 100644 website/client/components/ui/pageLayout.vue create mode 100644 website/client/mixins/inventoryUtils.js create mode 100644 website/client/mixins/pinUtils.js diff --git a/website/client/app.vue b/website/client/app.vue index 295ff26a71..7002bdb5c8 100644 --- a/website/client/app.vue +++ b/website/client/app.vue @@ -29,7 +29,6 @@ div buyModal( :item="selectedItemToBuy || {}", :withPin="true", - @change="resetItemToBuy($event)", @buyPressed="customPurchase($event)", :genericPurchase="genericPurchase(selectedItemToBuy)", @@ -567,13 +566,6 @@ export default { }); } }, - resetItemToBuy ($event) { - // @TODO: Do we need this? I think selecting a new item - // overwrites. @negue might know - if (!$event && this.selectedItemToBuy.purchaseType !== 'card') { - this.selectedItemToBuy = null; - } - }, itemSelected (item) { this.selectedItemToBuy = item; }, diff --git a/website/client/components/inventory/stable/foodItem.vue b/website/client/components/inventory/stable/foodItem.vue index dfb15032f5..e858763ab4 100644 --- a/website/client/components/inventory/stable/foodItem.vue +++ b/website/client/components/inventory/stable/foodItem.vue @@ -17,7 +17,7 @@ div triggers="hover", placement="top", ) - h4.popover-content-title {{ item.text() }} + h4.popover-content-title {{ itemName || item.text() }} div.popover-content-text(v-html="item.notes()") @@ -45,6 +45,9 @@ export default { itemContentClass: { type: String, }, + itemName: { + type: String, + }, active: { type: Boolean, }, diff --git a/website/client/components/inventory/stable/index.vue b/website/client/components/inventory/stable/index.vue index a308d5908b..8619555884 100644 --- a/website/client/components/inventory/stable/index.vue +++ b/website/client/components/inventory/stable/index.vue @@ -145,47 +145,17 @@ .btn.btn-flat.btn-show-more(@click="setShowMore(mountGroup.key)", v-if='mountGroup.key !== "specialMounts"') | {{ $_openedItemRows_isToggled(mountGroup.key) ? $t('showLess') : $t('showMore') }} - drawer(:title="$t('quickInventory')", - :errorMessage="(!hasDrawerTabItems(selectedDrawerTab)) ? ((selectedDrawerTab === 0) ? $t('noFoodAvailable') : $t('noSaddlesAvailable')) : null") - div(slot="drawer-header") - .drawer-tab-container - .drawer-tab.text-right - a.drawer-tab-text( - @click="selectedDrawerTab = 0", - :class="{'drawer-tab-text-active': selectedDrawerTab === 0}", - ) {{ drawerTabs[0].label }} - .clearfix - .drawer-tab.float-left - a.drawer-tab-text( - @click="selectedDrawerTab = 1", - :class="{ 'drawer-tab-text-active': selectedDrawerTab === 1 }", - ) {{ drawerTabs[1].label }} - - #petLikeToEatStable.drawer-help-text(v-once) - | {{ $t('petLikeToEat') + ' ' }} - span.svg-icon.inline.icon-16(v-html="icons.information") - b-popover( - target="petLikeToEatStable" - placement="top" - ) - .popover-content-text(v-html="$t('petLikeToEatText')", v-once) - drawer-slider( - :items="drawerTabs[selectedDrawerTab].items", - :scrollButtonsVisible="hasDrawerTabItems(selectedDrawerTab)", - slot="drawer-slider", - :itemWidth=94, - :itemMargin=24, - :itemType="selectedDrawerTab" - ) - template(slot="item", slot-scope="context") - foodItem( - :item="context.item", - :itemCount="userItems.food[context.item.key]", - :active="currentDraggingFood == context.item", - @itemDragEnd="onDragEnd()", - @itemDragStart="onDragStart($event, context.item)", - @itemClick="onFoodClicked($event, context.item)" - ) + inventoryDrawer + template(slot="item", slot-scope="ctx") + foodItem( + :item="ctx.item", + :itemCount="ctx.itemCount", + :itemContentClass="ctx.itemClass", + :active="currentDraggingFood === ctx.item", + @itemDragEnd="onDragEnd()", + @itemDragStart="onDragStart($event, ctx.item)", + @itemClick="onFoodClicked($event, ctx.item)" + ) hatchedPetDialog(:hideText="true") div.foodInfo(ref="dragginFoodInfo") div(v-if="currentDraggingFood != null") @@ -284,9 +254,6 @@ } } - .drawer-slider .items { - height: 114px; - } .modal-backdrop.fade.show { background-color: $purple-50; @@ -386,6 +353,7 @@ import StarBadge from 'client/components/ui/starBadge'; import CountBadge from 'client/components/ui/countBadge'; import DrawerSlider from 'client/components/ui/drawerSlider'; + import InventoryDrawer from 'client/components/shared/inventoryDrawer'; import ResizeDirective from 'client/directives/resize.directive'; import DragDropDirective from 'client/directives/dragdrop.directive'; @@ -425,6 +393,7 @@ MountRaisedModal, WelcomeModal, HatchingModal, + InventoryDrawer, }, directives: { resize: ResizeDirective, diff --git a/website/client/components/shared/inventoryDrawer.vue b/website/client/components/shared/inventoryDrawer.vue new file mode 100644 index 0000000000..a2fa8fd83d --- /dev/null +++ b/website/client/components/shared/inventoryDrawer.vue @@ -0,0 +1,169 @@ + + + + + diff --git a/website/client/components/shops/featuredItemsHeader.vue b/website/client/components/shops/featuredItemsHeader.vue new file mode 100644 index 0000000000..04ccc614ad --- /dev/null +++ b/website/client/components/shops/featuredItemsHeader.vue @@ -0,0 +1,126 @@ + + + + + diff --git a/website/client/components/shops/index.vue b/website/client/components/shops/index.vue index 71d7b2c608..5c275f7a82 100644 --- a/website/client/components/shops/index.vue +++ b/website/client/components/shops/index.vue @@ -11,17 +11,11 @@ diff --git a/website/client/components/shops/market/categoryItem.vue b/website/client/components/shops/market/categoryItem.vue new file mode 100644 index 0000000000..bdd4546ca9 --- /dev/null +++ b/website/client/components/shops/market/categoryItem.vue @@ -0,0 +1,52 @@ + + + diff --git a/website/client/components/shops/market/categoryRow.vue b/website/client/components/shops/market/categoryRow.vue new file mode 100644 index 0000000000..d35758fda2 --- /dev/null +++ b/website/client/components/shops/market/categoryRow.vue @@ -0,0 +1,94 @@ + + + diff --git a/website/client/components/shops/market/equipmentSection.vue b/website/client/components/shops/market/equipmentSection.vue new file mode 100644 index 0000000000..a0bbd70493 --- /dev/null +++ b/website/client/components/shops/market/equipmentSection.vue @@ -0,0 +1,167 @@ + + + + + diff --git a/website/client/components/shops/market/filter.vue b/website/client/components/shops/market/filter.vue new file mode 100644 index 0000000000..2f32c507ed --- /dev/null +++ b/website/client/components/shops/market/filter.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/website/client/components/shops/market/index.vue b/website/client/components/shops/market/index.vue index c075987fed..ccf3f432de 100644 --- a/website/client/components/shops/market/index.vue +++ b/website/client/components/shops/market/index.vue @@ -1,245 +1,79 @@ @@ -358,14 +129,18 @@ import ShopItem from '../shopItem'; import KeysToKennel from './keysToKennel'; + import EquipmentSection from './equipmentSection'; + import CategoryRow from './categoryRow'; import Item from 'client/components/inventory/item'; import CountBadge from 'client/components/ui/countBadge'; - import Drawer from 'client/components/ui/drawer'; - import DrawerSlider from 'client/components/ui/drawerSlider'; - import DrawerHeaderTabs from 'client/components/ui/drawerHeaderTabs'; import ItemRows from 'client/components/ui/itemRows'; - import toggleSwitch from 'client/components/ui/toggleSwitch'; import Avatar from 'client/components/avatar'; + import InventoryDrawer from 'client/components/shared/inventoryDrawer'; + import FeaturedItemsHeader from '../featuredItemsHeader'; + import PageLayout from 'client/components/ui/pageLayout'; + import LayoutSection from 'client/components/ui/layoutSection'; + import FilterDropdown from 'client/components/ui/filterDropdown'; + import MarketFilter from './filter'; import SellModal from './sellModal.vue'; import EquipmentAttributesGrid from '../../inventory/equipment/attributesGrid.vue'; @@ -374,52 +149,45 @@ import svgPin from 'assets/svg/pin.svg'; import svgGem from 'assets/svg/gem.svg'; import svgInformation from 'assets/svg/information.svg'; - import svgWarrior from 'assets/svg/warrior.svg'; - import svgWizard from 'assets/svg/wizard.svg'; - import svgRogue from 'assets/svg/rogue.svg'; - import svgHealer from 'assets/svg/healer.svg'; import getItemInfo from 'common/script/libs/getItemInfo'; - import isPinned from 'common/script/libs/isPinned'; import shops from 'common/script/libs/shops'; - import planGemLimits from 'common/script/libs/planGemLimits'; import _filter from 'lodash/filter'; - import _sortBy from 'lodash/sortBy'; import _map from 'lodash/map'; import _throttle from 'lodash/throttle'; - const sortGearTypes = ['sortByType', 'sortByPrice', 'sortByCon', 'sortByPer', 'sortByStr', 'sortByInt']; + const sortItems = ['AZ', 'sortByNumber'].map(g => ({id: g})); import notifications from 'client/mixins/notifications'; import buyMixin from 'client/mixins/buy'; import currencyMixin from '../_currencyMixin'; - - const sortGearTypeMap = { - sortByType: 'type', - sortByPrice: 'value', - sortByCon: 'con', - sortByStr: 'str', - sortByInt: 'int', - }; + import inventoryUtils from 'client/mixins/inventoryUtils'; + import pinUtils from 'client/mixins/pinUtils'; export default { - mixins: [notifications, buyMixin, currencyMixin], + mixins: [notifications, buyMixin, currencyMixin, inventoryUtils, pinUtils], components: { ShopItem, KeysToKennel, Item, CountBadge, - Drawer, - DrawerSlider, - DrawerHeaderTabs, + ItemRows, - toggleSwitch, SellModal, EquipmentAttributesGrid, Avatar, + InventoryDrawer, + FeaturedItemsHeader, + PageLayout, + LayoutSection, + FilterDropdown, + EquipmentSection, + CategoryRow, + MarketFilter, + SelectMembersModal, }, watch: { @@ -438,24 +206,10 @@ export default { pin: svgPin, gem: svgGem, information: svgInformation, - warrior: svgWarrior, - wizard: svgWizard, - rogue: svgRogue, - healer: svgHealer, }), - selectedDrawerTab: 0, - selectedDrawerItemType: 'eggs', - - selectedGroupGearByClass: '', - - sortGearBy: sortGearTypes, - selectedSortGearBy: 'sortByType', - - sortItemsBy: ['AZ', 'sortByNumber'], - selectedSortItemsBy: 'AZ', - - selectedItemToSell: null, + sortItemsBy: sortItems, + selectedSortItemsBy: sortItems[0], hideLocked: false, hidePinned: false, @@ -474,120 +228,79 @@ export default { userStats: 'user.data.stats', userItems: 'user.data.items', }), - marketGearCategories () { - return shops.getMarketGearCategories(this.user); - }, market () { return shops.getMarketShop(this.user); }, categories () { - if (this.market) { - let categories = [ - ...this.market.categories, - ]; + if (!this.market) return []; - categories.push({ - identifier: 'equipment', - text: this.$t('equipment'), - }); - - categories.push({ - identifier: 'cards', - text: this.$t('cards'), - items: _map(_filter(this.content.cardTypes, (value) => { - return value.yearRound; - }), (value) => { - return { - ...getItemInfo(this.user, 'card', value), - showCount: false, - }; - }), - }); - - let specialItems = [{ - ...getItemInfo(this.user, 'fortify'), - showCount: false, - }]; - - if (this.user.purchased.plan.customerId) { - let gemItem = getItemInfo(this.user, 'gem'); - - specialItems.push({ - ...gemItem, - showCount: false, - }); - } - - if (this.user.flags.rebirthEnabled) { - let rebirthItem = getItemInfo(this.user, 'rebirth_orb'); - - specialItems.push({ - showCount: false, - ...rebirthItem, - }); - } - - if (specialItems.length > 0) { - categories.push({ - identifier: 'special', - text: this.$t('special'), - items: specialItems, - }); - } - - categories.map((category) => { - if (!this.viewOptions[category.identifier]) { - this.$set(this.viewOptions, category.identifier, { - selected: true, - }); - } - }); - - return categories; - } else { - return []; - } - }, - drawerTabs () { - return [ - { - key: 'eggs', - contentType: 'eggs', - label: this.$t('eggs'), - }, - { - key: 'food', - contentType: 'food', - label: this.$t('foodTitle'), - }, - { - key: 'hatchingPotions', - contentType: 'hatchingPotions', - label: this.$t('hatchingPotions'), - }, - { - key: 'special', - contentType: 'food', - label: this.$t('special'), - }, + let categories = [ + ...this.market.categories, ]; - }, - gemsLeft () { - if (!this.user.purchased.plan) return 0; - return planGemLimits.convCap + this.user.purchased.plan.consecutive.gemCapExtra - this.user.purchased.plan.gemsBought; + + categories.push({ + identifier: 'equipment', + text: this.$t('equipment'), + }); + + categories.push({ + identifier: 'cards', + text: this.$t('cards'), + items: _map(_filter(this.content.cardTypes, (value) => { + return value.yearRound; + }), (value) => { + return { + ...getItemInfo(this.user, 'card', value), + showCount: false, + }; + }), + }); + + let specialItems = [{ + ...getItemInfo(this.user, 'fortify'), + showCount: false, + }]; + + if (this.user.purchased.plan.customerId) { + let gemItem = getItemInfo(this.user, 'gem'); + + specialItems.push({ + ...gemItem, + showCount: false, + }); + } + + if (this.user.flags.rebirthEnabled) { + let rebirthItem = getItemInfo(this.user, 'rebirth_orb'); + + specialItems.push({ + showCount: false, + ...rebirthItem, + }); + } + + if (specialItems.length > 0) { + categories.push({ + identifier: 'special', + text: this.$t('special'), + items: specialItems, + }); + } + + categories.map((category) => { + if (!this.viewOptions[category.identifier]) { + this.$set(this.viewOptions, category.identifier, { + selected: true, + }); + } + }); + + return categories; }, }, methods: { - getClassName (classType) { - if (classType === 'wizard') { - return this.$t('mage'); - } else { - return this.$t(classType); - } - }, - tabSelected ($event) { - this.selectedDrawerTab = $event; - this.selectedDrawerItemType = this.drawerTabs[$event].key; + sellItem (itemScope) { + this.$root.$emit('sellItem', itemScope); }, ownedItems (type) { let mappedItems = _filter(this.content[type], i => { @@ -620,133 +333,18 @@ export default { return this.$t('noItemsAvailableForType', { type: this.$t(`${type}ItemType`) }); } }, - getItemClass (type, itemKey) { - switch (type) { - case 'food': - case 'special': - return `Pet_Food_${itemKey}`; - case 'eggs': - return `Pet_Egg_${itemKey}`; - case 'hatchingPotions': - return `Pet_HatchingPotion_${itemKey}`; - default: - return ''; - } - }, - getItemName (type, item) { - switch (type) { - case 'eggs': - return this.$t('egg', {eggType: item.text()}); - case 'hatchingPotions': - return this.$t('potion', {potionType: item.text()}); - default: - return item.text(); - } - }, - filteredGear (groupByClass, searchBy, sortBy, hideLocked, hidePinned) { - let category = _filter(this.marketGearCategories, ['identifier', groupByClass]); - - let result = _filter(category[0].items, (gear) => { - if (hideLocked && gear.locked) { - return false; - } - if (hidePinned && gear.pinned) { - return false; - } - - if (searchBy) { - let foundPosition = gear.text.toLowerCase().indexOf(searchBy); - if (foundPosition === -1) { - return false; - } - } - - // hide already owned - return !this.userItems.gear.owned[gear.key]; - }); - - // first all unlocked - // then the selected sort - result = _sortBy(result, [(item) => item.locked, sortGearTypeMap[sortBy]]); - - return result; - }, - sortedMarketItems (category, sortBy, searchBy, hidePinned) { - let result = _map(category.items, (e) => { - return { - ...e, - pinned: isPinned(this.user, e), - }; - }); - - result = _filter(result, (item) => { - if (hidePinned && item.pinned) { - return false; - } - - if (searchBy) { - let foundPosition = item.text.toLowerCase().indexOf(searchBy); - if (foundPosition === -1) { - return false; - } - } - - return true; - }); - - switch (sortBy) { - case 'AZ': { - result = _sortBy(result, ['text']); - - break; - } - case 'sortByNumber': { - result = _sortBy(result, item => { - if (item.showCount === false) return 0; - - return this.userItems[item.purchaseType][item.key] || 0; - }); - break; - } - } - - return result; - }, - resetItemToSell ($event) { - if (!$event) { - this.selectedItemToSell = null; - } - }, - isGearLocked (gear) { - if (gear.klass !== this.userStats.class) { - return true; - } - - return false; - }, - togglePinned (item) { - if (!this.$store.dispatch('user:togglePinnedItem', {type: item.pinType, path: item.path})) { - this.$parent.showUnpinNotification(item); - } - }, itemSelected (item) { this.$root.$emit('buyModal::showItem', item); }, featuredItemSelected (item) { if (item.purchaseType === 'gear') { - this.gearSelected(item); + if (!item.locked) { + this.itemSelected(item); + } } else { this.itemSelected(item); } }, - gearSelected (item) { - if (!item.locked) { - this.$root.$emit('buyModal::showItem', item); - } - }, - }, - created () { - this.selectedGroupGearByClass = this.userStats.class; }, }; diff --git a/website/client/components/shops/market/sellModal.vue b/website/client/components/shops/market/sellModal.vue index a3c2f654da..128208e2b7 100644 --- a/website/client/components/shops/market/sellModal.vue +++ b/website/client/components/shops/market/sellModal.vue @@ -1,6 +1,5 @@