From c35e4f57502a3a695abf8b9d52a96908a2f173da Mon Sep 17 00:00:00 2001 From: negue Date: Sat, 26 Aug 2017 12:18:55 +0200 Subject: [PATCH] Items/Market/Quests/misc fixes (#8987) * use countBadge instead of class * generic purchase action from buyModal to handle all kind of purchases - able to purchase backgrounds - return backgrounds as flat array * List MysteryItem & Hourglass in Inventory/Items * add Subscribers Gem Item (purchase by gold) * fix mysterybox * sort unlocked gear first * add orb of rebirth to market * remove old quest scroll + class of the quest items * more padding on countBadge * use the generic purchase on quests --- .../misc/inventory_quest_scroll.png | Bin 3175 -> 0 bytes .../misc/inventory_quest_scroll_locked.png | Bin 1139 -> 0 bytes website/client/assets/scss/badge.scss | 7 -- .../components/inventory/items/index.vue | 70 +++++++++++-- website/client/components/shops/buyModal.vue | 17 +++- .../client/components/shops/market/index.vue | 81 ++++++++++++--- .../components/shops/quests/buyQuestModal.vue | 10 +- .../client/components/shops/quests/index.vue | 4 - .../components/shops/seasonal/index.vue | 4 - website/client/components/shops/shopItem.vue | 1 + website/client/components/ui/countBadge.vue | 2 +- website/client/mixins/notifications.js | 5 + website/client/store/actions/shops.js | 92 +++++++++++++----- website/client/store/actions/user.js | 8 ++ website/common/locales/en/newClient.json | 3 +- .../script/content/appearance/backgrounds.js | 10 +- website/common/script/content/index.js | 5 +- website/common/script/libs/getItemInfo.js | 2 +- website/common/script/ops/unlock.js | 15 ++- 19 files changed, 263 insertions(+), 73 deletions(-) delete mode 100644 website/assets/sprites/spritesmith/misc/inventory_quest_scroll.png delete mode 100644 website/assets/sprites/spritesmith/misc/inventory_quest_scroll_locked.png diff --git a/website/assets/sprites/spritesmith/misc/inventory_quest_scroll.png b/website/assets/sprites/spritesmith/misc/inventory_quest_scroll.png deleted file mode 100644 index 553ab4e8e386878d4eb4742e1e9647ee99a3175f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3175 zcmV-t44CtYP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0004!Nkl@i+7R?5wfYB4q3!a0LGcDga=N+4=(xTgRnv@OAcR zltSK6C<|R)M(4Tz$kFv}Vr>Z6I6AtNrEMQ!ZlJ5HQwSF$ah` zL>t~}YIB}z&Hhy!IgrXm@1|1#!28G7YOS{T1OT)Sb`wIJ{qFJC{JmY_JEY1}wN=F4 zi&*k}S8%#;I=P@T7(3BL&qBP)f2%E3ou_GSuew!tG>L#v!jHUOF1BUzVw_V{48Qt3VELclIKeUH>b@eN=Ug9 zHHA{m#AW1xPGrG~nA%2p!099j@jnrh@Le-PJFp47Vy@Mb>{vArErs&DUZ6 zl)fBA-%hKDgFMVN+b4C6~+V&jG7JOM!HtY_fNA0XlvE-Q170^j7^yAO`FX@Jj12K1;eKDz?|7))MOzi$=4 z2D0|)%UbIpWRb7yldkLh`E{4XE%5;f9SNJE>`QB;e?JERRLeOK1fu{%E-hJ}+ssW_ zU?L$>Z|%y%nSgzO$Pxi+g)0V;fx>dW7I7jRZ_fh&R*QR1{A({Yi~|r6Zrm>b02XE@ z000|CMLmD}TFUW`n@>M_M%zCJnAIlPW8-A|?bI0AaXAMTktYC|TY1;#7T=Bl0M>u* zgSpKIaMS#uY~F!6ZjL4ZfXr~*^63Seli<=+2BhlnpBDf#R+eS~0HY%EQeEU&{$4US z^Wcrj1QB8O)i8)^@3a41@DTFAf!y#(k+o-`BOH*}Z*~-a?5oWO$%Up==wJ5{WERLy zVyXK;RU!7!f3A}%x5%6OKN$(qPg<6N@W8lP=l_~l(Pb_2 ztHnJqfOIkj2CybFV~@Oj-rpMmGh?SxZG#UmgQ$jiYM=|I^MkaB{LTTnnUe!TeM0?N zb>q@Gkk&GxpUl`YBb^ZHV;Bdj@*^VbRF1$5^!0`Eq9}v~2R3E#X+BvYQsSz~HCkCSc14ijU5n1Pemk%^sVu!q{PxkNv z$357d8giNg2UyKTysFP|e^xoNt~Szv3z`FybYL(N@u&H(^OU5>drvgANK5d{e~A|k}&7i#K6X5;~=Otk$zK<@Ci zLZ4yPe1>vkFWC5zP}dB|PFu*93Af1Wkh42*sdT7LrmIijwGf?DdJ-B|C@=S=7GKXC z83+mWscz3(2%B=Lh4iX4k%)pd^-*(?nZBMdKqd$5XVBa0vM1{AKEUi+|B#2&L#vq_ zQ730f+e%x|GeGIg7}LeaZMh0==B8Y`(}8v+PUCQJAe|Yr_But2QO9bdJ^p%YEi2|^ zPxQ&X(Y8i!`u#V@+WBm&bo$=~+SXb;jpNK8pgTG}{sQUn5lrAX;Bf!|002ovPDHLk FV1kVE|A7Di diff --git a/website/client/assets/scss/badge.scss b/website/client/assets/scss/badge.scss index 629cb72011..4994ce8083 100644 --- a/website/client/assets/scss/badge.scss +++ b/website/client/assets/scss/badge.scss @@ -20,10 +20,3 @@ position: absolute; top: -9px; } - -.badge-quantity { - color: $white; - right: -9px; - padding: 4.5px 8.5px; - background-color: $orange-100; -} \ No newline at end of file diff --git a/website/client/components/inventory/items/index.vue b/website/client/components/inventory/items/index.vue index 6e8724f540..bc9c75e61b 100644 --- a/website/client/components/inventory/items/index.vue +++ b/website/client/components/inventory/items/index.vue @@ -32,7 +32,7 @@ h2 | {{ $t(group.key) }} | - span.badge.badge-pill.badge-default {{group.quantity}} + span.badge.badge-pill.badge-default(v-if="group.key != 'special'") {{group.quantity}} itemRows( @@ -47,7 +47,7 @@ item( :item="context.item", :key="context.item.key", - :itemContentClass="`${group.classPrefix}${context.item.key}`", + :itemContentClass="context.item.class", :highlightBorder="isHatchable(currentDraggingPotion, context.item.key)", v-drag.drop.hatch="context.item.key", @@ -61,7 +61,10 @@ h4.popover-content-title {{ context.item.text }} .popover-content-text(v-if="currentDraggingPotion == null") {{ context.item.notes }} template(slot="itemBadge", scope="context") - span.badge.badge-pill.badge-item.badge-quantity {{ context.item.quantity }} + countBadge( + :show="true", + :count="context.item.quantity" + ) itemRows( v-else-if="group.key === 'hatchingPotions'", @@ -75,7 +78,7 @@ item( :item="context.item", :key="context.item.key", - :itemContentClass="`${group.classPrefix}${context.item.key}`", + :itemContentClass="context.item.class", :showPopover="currentDraggingPotion == null", :active="currentDraggingPotion == context.item", v-drag.hatch="context.item.key", @@ -89,7 +92,10 @@ h4.popover-content-title {{ context.item.text }} .popover-content-text {{ context.item.notes }} template(slot="itemBadge", scope="context") - span.badge.badge-pill.badge-item.badge-quantity {{ context.item.quantity }} + countBadge( + :show="true", + :count="context.item.quantity" + ) itemRows( v-else, @@ -103,14 +109,18 @@ item( :item="context.item", :key="context.item.key", - :itemContentClass="`${group.classPrefix}${context.item.key}`", - :showPopover="currentDraggingPotion == null" + :itemContentClass="context.item.class", + :showPopover="currentDraggingPotion == null", + @click="itemClicked(group.key, context.item)", ) template(slot="popoverContent", scope="context") h4.popover-content-title {{ context.item.text }} .popover-content-text {{ context.item.notes }} template(slot="itemBadge", scope="context") - span.badge.badge-pill.badge-item.badge-quantity {{ context.item.quantity }} + countBadge( + :show="true", + :count="context.item.quantity" + ) hatchedPetDialog( :pet="hatchedPet", @@ -162,14 +172,16 @@ import bDropdown from 'bootstrap-vue/lib/components/dropdown'; import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item'; import Item from 'client/components/inventory/item'; import ItemRows from 'client/components/ui/itemRows'; +import CountBadge from 'client/components/ui/countBadge'; import HatchedPetDialog from '../stable/hatchedPetDialog'; import createAnimal from 'client/libs/createAnimal'; +import moment from 'moment'; const allowedSpecialItems = ['snowball', 'spookySparkles', 'shinySeed', 'seafoam']; - +import notifications from 'client/mixins/notifications'; import DragDropDirective from 'client/directives/dragdrop.directive'; import MouseMoveDirective from 'client/directives/mouseposition.directive'; @@ -191,6 +203,7 @@ const groups = [ let lastMouseMoveEvent = {}; export default { + mixins: [notifications], name: 'Items', components: { Item, @@ -198,6 +211,7 @@ export default { bDropdown, bDropdownItem, HatchedPetDialog, + CountBadge, }, directives: { drag: DragDropDirective, @@ -243,6 +257,7 @@ export default { if (isSearched) { itemsArray.push({ ...item, + class: `${group.classPrefix}${item.key}`, text: item.text(), notes: item.notes(), quantity: itemQuantity, @@ -262,6 +277,30 @@ export default { }); }); + let specialArray = []; + + if (this.user.purchased.plan.mysteryItems.length) { + specialArray.push({ + key: 'mysteryItem', + class: `inventory_present inventory_present_${moment().format('MM')}`, + text: this.$t('subscriberItemText'), + quantity: this.user.purchased.plan.mysteryItems.length, + }); + } + + if (this.user.purchased.plan.consecutive.trinkets) { + specialArray.push({ + key: 'timeTravelers', + class: 'inventory_special_trinket', + text: this.$t('mysticHourglassPopover'), + quantity: this.user.purchased.plan.consecutive.trinkets, + }); + } + + if (specialArray.length > 0) { + itemsByType.special = specialArray; + } + return itemsByType; }, }, @@ -347,6 +386,19 @@ export default { this.hatchedPet = null; }, + async itemClicked (groupKey, item) { + if (groupKey === 'special') { + if (item.key === 'timeTravelers') { + this.$router.push({name: 'time'}); + } else if (item.key === 'mysteryItem') { + let result = await this.$store.dispatch('user:openMysteryItem'); + + let openedItem = result.data.data; + let text = this.content.gear.flat[openedItem.key].text(); + this.drop(this.$t('messageDropMysteryItem', {dropText: text}), openedItem); + } + } + }, mouseMoved ($event) { if (this.potionClickMode) { diff --git a/website/client/components/shops/buyModal.vue b/website/client/components/shops/buyModal.vue index c61382914f..228e0644f2 100644 --- a/website/client/components/shops/buyModal.vue +++ b/website/client/components/shops/buyModal.vue @@ -167,9 +167,10 @@ import BalanceInfo from './balanceInfo.vue'; import currencyMixin from './_currencyMixin'; + import notifications from 'client/mixins/notifications'; export default { - mixins: [currencyMixin], + mixins: [currencyMixin, notifications], components: { bModal, BalanceInfo, @@ -206,6 +207,16 @@ this.$emit('change', $event); }, buyItem () { + if (this.genericPurchase) { + this.$store.dispatch('shops:genericPurchase', { + pinType: this.item.pinType, + type: this.item.purchaseType, + key: this.item.key, + currency: this.item.currency, + }); + this.purchased(this.item.text); + } + this.$emit('buyPressed', this.item); this.hideDialog(); }, @@ -236,6 +247,10 @@ withPin: { type: Boolean, }, + genericPurchase: { + type: Boolean, + default: true, + }, }, }; diff --git a/website/client/components/shops/market/index.vue b/website/client/components/shops/market/index.vue index 62105f5d58..480bdae4d6 100644 --- a/website/client/components/shops/market/index.vue +++ b/website/client/components/shops/market/index.vue @@ -150,9 +150,12 @@ span(slot="popoverContent") h4.popover-content-title {{ item.text }} + template(slot="itemImage", scope="scope") + span.svg-icon.inline.icon-48(v-if="scope.item.key == 'gem'", v-html="icons.gem") + template(slot="itemBadge", scope="ctx") countBadge( - v-if="item.purchaseType !== 'card'", + v-if="item.showCount != false", :show="userItems[item.purchaseType][item.key] != 0", :count="userItems[item.purchaseType][item.key] || 0" ) @@ -230,8 +233,7 @@ priceType="gold", :withPin="true", @change="resetGearToBuy($event)", - @buyPressed="buyGear($event)", - @togglePinned="togglePinned($event)" + @togglePinned="togglePinned($event)", ) template(slot="item", scope="ctx") div @@ -250,14 +252,16 @@ :item="selectedItemToBuy", :priceType="selectedItemToBuy ? selectedItemToBuy.currency : ''", @change="resetItemToBuy($event)", - @buyPressed="buyItem($event)", - @togglePinned="togglePinned($event)" + @togglePinned="togglePinned($event)", + @buyPressed="purchaseCallback($event)", + :genericPurchase="selectedItemToBuy != null && selectedItemToBuy.key != 'rebirth_orb'" ) template(slot="item", scope="ctx") item.flat.bordered-item( :item="ctx.item", :itemContentClass="ctx.item.class", - :showPopover="false" + :showPopover="false", + v-if="ctx.item.key != 'gem'" ) selectMembersModal( @@ -306,6 +310,10 @@ width: 12px; height: 12px; } + .icon-48 { + width: 48px; + height: 48px; + } .hand-cursor { cursor: pointer; @@ -409,6 +417,7 @@ import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item'; 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'; @@ -475,6 +484,7 @@ export default { icons: Object.freeze({ pin: svgPin, + gem: svgGem, information: svgInformation, warrior: svgWarrior, wizard: svgWizard, @@ -528,9 +538,50 @@ export default { items: _map(_filter(this.content.cardTypes, (value) => { return value.yearRound; }), (value) => { - return getItemInfo(this.user, 'card', value); + return { + ...getItemInfo(this.user, 'card', value), + showCount: false, + }; }), }); + + let specialItems = []; + + if (this.user.purchased.plan.customerId) { + specialItems.push({ + showCount: false, + key: 'gem', + class: 'gem', + pinKey: 'gems', + purchaseType: 'gems', + text: this.$t('subGemName'), + notes: this.$t('subGemPop'), + currency: 'gold', + value: 20, + }); + } + + if (this.user.flags.rebirthEnabled) { + specialItems.push({ + showCount: false, + key: 'rebirth_orb', + class: 'rebirth_orb', + purchaseType: 'rebirth_orb', + text: this.$t('rebirthName'), + notes: this.$t('rebirthPop'), + currency: 'gems', + value: this.user.stats.lvl < 100 ? 6 : '', + }); + } + + if (specialItems.length > 0) { + categories.push({ + identifier: 'special', + text: this.$t('special'), + items: specialItems, + }); + } + categories.map((category) => { this.$set(this.viewOptions, category.identifier, { selected: true, @@ -655,7 +706,9 @@ export default { return !this.userItems.gear.owned[gear.key]; }); - result = _sortBy(result, [sortGearTypeMap[sortBy]]); + // first all unlocked + // then the selected sort + result = _sortBy(result, [(item) => item.locked, sortGearTypeMap[sortBy]]); return result; }, @@ -735,12 +788,6 @@ export default { this.$parent.showUnpinNotification(item); } }, - buyGear (item) { - this.$store.dispatch('shops:buyItem', {key: item.key}); - }, - buyItem (item) { - this.$store.dispatch('shops:purchase', {type: item.purchaseType, key: item.key}); - }, itemSelected (item) { if (item.purchaseType === 'card') { if (this.user.party._id) { @@ -761,6 +808,12 @@ export default { this.$store.dispatch('user:castSpell', {key: this.selectedCardToBuy.key, targetId: member.id}); this.selectedCardToBuy = null; }, + async purchaseCallback (item) { + if (item.key === 'rebirth_orb') { + await this.$store.dispatch('user:rebirth'); + window.location.reload(true); + } + }, }, created () { this.selectedGroupGearByClass = this.userStats.class; diff --git a/website/client/components/shops/quests/buyQuestModal.vue b/website/client/components/shops/quests/buyQuestModal.vue index 4f0720b306..9da142755c 100644 --- a/website/client/components/shops/quests/buyQuestModal.vue +++ b/website/client/components/shops/quests/buyQuestModal.vue @@ -235,9 +235,10 @@ import BalanceInfo from '../balanceInfo.vue'; import currencyMixin from '../_currencyMixin'; import QuestInfo from './questInfo.vue'; + import notifications from 'client/mixins/notifications'; export default { - mixins: [currencyMixin], + mixins: [currencyMixin, notifications], components: { bModal, BalanceInfo, @@ -278,6 +279,13 @@ this.$emit('change', $event); }, buyItem () { + this.$store.dispatch('shops:genericPurchase', { + pinType: this.item.pinType, + type: this.item.purchaseType, + key: this.item.key, + currency: this.item.currency, + }); + this.purchased(this.item.text); this.$emit('buyPressed', this.item); this.hideDialog(); }, diff --git a/website/client/components/shops/quests/index.vue b/website/client/components/shops/quests/index.vue index 5546d83c74..91378d6458 100644 --- a/website/client/components/shops/quests/index.vue +++ b/website/client/components/shops/quests/index.vue @@ -183,7 +183,6 @@ :priceType="selectedItemToBuy ? selectedItemToBuy.currency : ''", :withPin="true", @change="resetItemToBuy($event)", - @buyPressed="buyItem($event)", @togglePinned="togglePinned($event)" ) template(slot="item", scope="ctx") @@ -477,9 +476,6 @@ export default { this.$parent.showUnpinNotification(item); } }, - buyItem (item) { - this.$store.dispatch('shops:purchase', {type: item.purchaseType, key: item.key}); - }, }, created () { this.$store.dispatch('shops:fetchQuests'); diff --git a/website/client/components/shops/seasonal/index.vue b/website/client/components/shops/seasonal/index.vue index 16d5c9c014..654974f909 100644 --- a/website/client/components/shops/seasonal/index.vue +++ b/website/client/components/shops/seasonal/index.vue @@ -112,7 +112,6 @@ :priceType="selectedItemToBuy ? selectedItemToBuy.currency : ''", :withPin="true", @change="resetItemToBuy($event)", - @buyPressed="buyItem($event)", @togglePinned="togglePinned($event)" ) template(slot="item", scope="ctx") @@ -491,9 +490,6 @@ this.$parent.showUnpinNotification(item); } }, - buyItem (item) { - this.$store.dispatch('shops:purchase', {type: item.purchaseType, key: item.key}); - }, }, created () { this.$store.dispatch('shops:fetchSeasonal'); diff --git a/website/client/components/shops/shopItem.vue b/website/client/components/shops/shopItem.vue index ae4c8b6910..c2fd1ef53c 100644 --- a/website/client/components/shops/shopItem.vue +++ b/website/client/components/shops/shopItem.vue @@ -23,6 +23,7 @@ b-popover( div.image div(:class="item.class", v-once) + slot(name="itemImage", :item="item") div.price span.svg-icon.inline.icon-16(v-html="icons[currencyClass]") diff --git a/website/client/components/ui/countBadge.vue b/website/client/components/ui/countBadge.vue index 9d05cf0637..8a003fea41 100644 --- a/website/client/components/ui/countBadge.vue +++ b/website/client/components/ui/countBadge.vue @@ -11,7 +11,7 @@ span.badge.badge-pill.badge-item.badge-count( right: -9px; color: $white; background: $gray-200; - padding: 4.5px 6px; + padding: 4.5px 8.5px; min-width: 24px; height: 24px; box-shadow: 0 1px 1px 0 rgba($black, 0.12); diff --git a/website/client/mixins/notifications.js b/website/client/mixins/notifications.js index 2d438e30e1..3d0f0fef2d 100644 --- a/website/client/mixins/notifications.js +++ b/website/client/mixins/notifications.js @@ -86,6 +86,11 @@ export default { mp (val) { this.notify(`${this.sign(val)} ${this.round(val)}`, 'mp', 'glyphicon glyphicon-fire', this.sign(val)); }, + purchased (itemName) { + this.notify(this.$t('purchasedItem', { + itemName, + })); + }, streak (val) { this.notify(`${this.$t('streaks')}: ${val}`, 'streak', 'glyphicon glyphicon-repeat'); }, diff --git a/website/client/store/actions/shops.js b/website/client/store/actions/shops.js index 26615f0feb..5d7bb832d1 100644 --- a/website/client/store/actions/shops.js +++ b/website/client/store/actions/shops.js @@ -1,10 +1,12 @@ import axios from 'axios'; import { loadAsyncResource } from 'client/libs/asyncResource'; import buyOp from 'common/script/ops/buy'; +import buyQuestOp from 'common/script/ops/buyQuest'; import purchaseOp from 'common/script/ops/purchaseWithSpell'; import buyMysterySetOp from 'common/script/ops/buyMysterySet'; import hourglassPurchaseOp from 'common/script/ops/hourglassPurchase'; import sellOp from 'common/script/ops/sell'; +import unlockOp from 'common/script/ops/unlock'; export function fetchMarket (store, forceLoad = false) { // eslint-disable-line no-shadow return loadAsyncResource({ @@ -57,44 +59,86 @@ export function fetchTimeTravelers (store, forceLoad = false) { // eslint-disabl export function buyItem (store, params) { const user = store.state.user.data; - buyOp(user, {params}); - axios - .post(`/api/v3/user/buy/${params.key}`); - // TODO - // .then((res) => console.log('equip', res)) - // .catch((err) => console.error('equip', err)); + let opResult = buyOp(user, {params}); + + return { + result: opResult, + httpCall: axios.post(`/api/v3/user/buy/${params.key}`), + }; +} + +export function buyQuestItem (store, params) { + const user = store.state.user.data; + let opResult = buyQuestOp(user, {params}); + + return { + result: opResult, + httpCall: axios.post(`/api/v3/user/buy-quest/${params.key}`), + }; } export function purchase (store, params) { const user = store.state.user.data; - purchaseOp(user, {params}); - axios - .post(`/api/v3/user/purchase/${params.type}/${params.key}`); - // TODO - // .then((res) => console.log('equip', res)) - // .catch((err) => console.error('equip', err)); + let opResult = purchaseOp(user, {params}); + + return { + result: opResult, + httpCall: axios.post(`/api/v3/user/purchase/${params.type}/${params.key}`), + }; } export function purchaseMysterySet (store, params) { const user = store.state.user.data; - buyMysterySetOp(user, {params}); - axios - .post(`/api/v3/user/buy-mystery-set/${params.key}`); - // TODO - // .then((res) => console.log('equip', res)) - // .catch((err) => console.error('equip', err)); + let opResult = buyMysterySetOp(user, {params}); + + return { + result: opResult, + httpCall: axios.post(`/api/v3/user/buy-mystery-set/${params.key}`), + }; } export function purchaseHourglassItem (store, params) { const user = store.state.user.data; - hourglassPurchaseOp(user, {params}); - axios - .post(`/api/v3/user/purchase-hourglass/${params.type}/${params.key}`); - // TODO - // .then((res) => console.log('equip', res)) - // .catch((err) => console.error('equip', err)); + let opResult = hourglassPurchaseOp(user, {params}); + + return { + result: opResult, + httpCall: axios.post(`/api/v3/user/purchase-hourglass/${params.type}/${params.key}`), + }; } +export function unlock (store, params) { + const user = store.state.user.data; + let opResult = unlockOp(user, params); + + return { + result: opResult, + httpCall: axios.post(`/api/v3/user/unlock?path=${params.query.path}`), + }; +} + +export function genericPurchase (store, params) { + switch (params.pinType) { + case 'mystery_set': + return purchaseMysterySet(store, params); + case 'potion': + case 'armoire': + case 'marketGear': + return buyItem(store, params); + case 'background': + return unlock(store, { + query: { + path: `background.${params.key}`, + }, + }); + default: + if (params.pinType === 'quests' && params.currency === 'gold') { + return buyQuestItem(store, params); + } else { + return purchase(store, params); + } + } +} export function sellItems (store, params) { const user = store.state.user.data; diff --git a/website/client/store/actions/user.js b/website/client/store/actions/user.js index 4fcebfb71f..742187766e 100644 --- a/website/client/store/actions/user.js +++ b/website/client/store/actions/user.js @@ -96,3 +96,11 @@ export function castSpell (store, params) { return axios.post(spellUrl); } + +export function openMysteryItem () { + return axios.post('/api/v3/user/open-mystery-item'); +} + +export function rebirth () { + return axios.post('/api/v3/user/rebirth'); +} diff --git a/website/common/locales/en/newClient.json b/website/common/locales/en/newClient.json index dbb8ad68f3..430b198dda 100644 --- a/website/common/locales/en/newClient.json +++ b/website/common/locales/en/newClient.json @@ -303,5 +303,6 @@ "health_wellness": "Health & Wellness", "self_care": "Self-Care", "sendLink": "Send Link", - "forgotPassword": "Forgot Password" + "forgotPassword": "Forgot Password", + "purchasedItem": "You bought <%= itemName %>" } diff --git a/website/common/script/content/appearance/backgrounds.js b/website/common/script/content/appearance/backgrounds.js index cfa226410f..07c72047ff 100644 --- a/website/common/script/content/appearance/backgrounds.js +++ b/website/common/script/content/appearance/backgrounds.js @@ -584,12 +584,20 @@ let backgrounds = { }; /* eslint-enable quote-props */ +let flat = {}; + forOwn(backgrounds, function prefillBackgroundSet (backgroundsInSet, set) { forOwn(backgroundsInSet, function prefillBackground (background, bgKey) { background.key = bgKey; background.set = set; background.price = 7; + + flat[bgKey] = background; }); }); -module.exports = backgrounds; +module.exports = { + tree: backgrounds, + flat, +}; + diff --git a/website/common/script/content/index.js b/website/common/script/content/index.js index 0d00d2d01f..f3073ebcb4 100644 --- a/website/common/script/content/index.js +++ b/website/common/script/content/index.js @@ -24,7 +24,7 @@ import { } from './quests'; import appearances from './appearance'; -import backgrounds from './appearance/backgrounds.js'; +import backgrounds from './appearance/backgrounds'; import spells from './spells'; import subscriptionBlocks from './subscriptionBlocks'; import faq from './faq'; @@ -523,7 +523,8 @@ each(api.food, (food, key) => { api.appearances = appearances; -api.backgrounds = backgrounds; +api.backgrounds = backgrounds.tree; +api.backgroundsFlat = backgrounds.flat; api.userDefaults = { habits: [ diff --git a/website/common/script/libs/getItemInfo.js b/website/common/script/libs/getItemInfo.js index 31935111ca..02b1649fd1 100644 --- a/website/common/script/libs/getItemInfo.js +++ b/website/common/script/libs/getItemInfo.js @@ -137,7 +137,7 @@ module.exports = function getItemInfo (user, type, item, language = 'en') { }; }) : undefined, lvl: item.lvl, - class: locked ? `inventory_quest_scroll_locked inventory_quest_scroll_${item.key}_locked` : `inventory_quest_scroll inventory_quest_scroll_${item.key}`, + class: locked ? `inventory_quest_scroll_${item.key}_locked` : `inventory_quest_scroll_${item.key}`, purchaseType: 'quests', path: `quests.${item.key}`, pinType: 'quests', diff --git a/website/common/script/ops/unlock.js b/website/common/script/ops/unlock.js index 24eeb1f31d..dbbb01352e 100644 --- a/website/common/script/ops/unlock.js +++ b/website/common/script/ops/unlock.js @@ -9,6 +9,10 @@ import { BadRequest, } from '../libs/errors'; +import { removeItemByPath } from './pinnedGearUtils'; +import getItemInfo from '../libs/getItemInfo'; +import content from '../content/index'; + // If item is already purchased -> equip it // Otherwise unlock it module.exports = function unlock (user, req = {}, analytics) { @@ -75,10 +79,11 @@ module.exports = function unlock (user, req = {}, analytics) { setWith(user, `purchased.${pathPart}`, true, Object); }); } else { + let split = path.split('.'); + let value = split.pop(); + let key = split.join('.'); + if (alreadyOwns) { // eslint-disable-line no-lonely-if - let split = path.split('.'); - let value = split.pop(); - let key = split.join('.'); if (key === 'background' && value === user.preferences.background) { value = ''; } @@ -88,6 +93,10 @@ module.exports = function unlock (user, req = {}, analytics) { } else { // Using Object so path[1] won't create an array but an object {path: {1: value}} setWith(user, `purchased.${path}`, true, Object); + + let backgroundContent = content.backgroundsFlat[value]; + let itemInfo = getItemInfo(user, 'background', backgroundContent); + removeItemByPath(user, itemInfo.path); } }