mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
display customizations in new shop
This commit is contained in:
committed by
Sabe Jones
parent
982069df36
commit
f99ddbe60f
@@ -146,6 +146,12 @@
|
|||||||
>
|
>
|
||||||
{{ $t('titleTimeTravelers') }}
|
{{ $t('titleTimeTravelers') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<router-link
|
||||||
|
class="topbar-dropdown-item dropdown-item"
|
||||||
|
:to="{name: 'customizations'}"
|
||||||
|
>
|
||||||
|
{{ $t('titleCustomizations') }}
|
||||||
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<b-nav-item
|
<b-nav-item
|
||||||
|
|||||||
499
website/client/src/components/shops/customizations/index.vue
Normal file
499
website/client/src/components/shops/customizations/index.vue
Normal file
@@ -0,0 +1,499 @@
|
|||||||
|
<template>
|
||||||
|
<div class="row customizations">
|
||||||
|
<div
|
||||||
|
class="standard-sidebar d-none d-sm-block">
|
||||||
|
<filter-sidebar>
|
||||||
|
<div
|
||||||
|
slot="search"
|
||||||
|
class="form-group"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
v-model="searchText"
|
||||||
|
class="form-control input-search"
|
||||||
|
type="text"
|
||||||
|
:placeholder="$t('search')"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<filter-group>
|
||||||
|
<checkbox
|
||||||
|
v-for="category in categories"
|
||||||
|
:id="`category-${category.identifier}`"
|
||||||
|
:key="category.identifier"
|
||||||
|
:checked.sync="viewOptions[category.identifier].selected"
|
||||||
|
:text="category.text"
|
||||||
|
/>
|
||||||
|
</filter-group>
|
||||||
|
<div class="form-group clearfix">
|
||||||
|
<h3
|
||||||
|
v-once
|
||||||
|
class="float-left"
|
||||||
|
>
|
||||||
|
{{ $t('hidePinned') }}
|
||||||
|
</h3>
|
||||||
|
<toggle-switch
|
||||||
|
v-model="hidePinned"
|
||||||
|
class="float-right"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</filter-sidebar>
|
||||||
|
</div>
|
||||||
|
<div class="standard-page">
|
||||||
|
<div class="featuredItems">
|
||||||
|
<div
|
||||||
|
class="background"
|
||||||
|
:style="{'background-image': imageURLs.background}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="npc"
|
||||||
|
:style="{'background-image': imageURLs.npc}"
|
||||||
|
>
|
||||||
|
<div class="featured-label">
|
||||||
|
<span class="rectangle"></span><span
|
||||||
|
v-once
|
||||||
|
class="text"
|
||||||
|
>Beffy</span><span class="rectangle"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="clearfix">
|
||||||
|
<div class="float-right">
|
||||||
|
<span class="dropdown-label">{{ $t('sortBy') }}</span>
|
||||||
|
<select-translated-array
|
||||||
|
:right="true"
|
||||||
|
:value="selectedSortItemsBy"
|
||||||
|
:items="sortItemsBy"
|
||||||
|
:inline-dropdown="false"
|
||||||
|
class="inline"
|
||||||
|
@select="selectedSortItemsBy = $event"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- eslint-disable vue/no-use-v-if-with-v-for -->
|
||||||
|
<div
|
||||||
|
v-for="category in categories"
|
||||||
|
v-if="!anyFilterSelected || viewOptions[category.identifier].selected"
|
||||||
|
:key="category.identifier"
|
||||||
|
:class="category.identifier"
|
||||||
|
>
|
||||||
|
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
|
||||||
|
<h2 class="mb-3">
|
||||||
|
{{ category.text }}
|
||||||
|
</h2>
|
||||||
|
<itemRows
|
||||||
|
v-if="category.identifier === 'backgrounds'"
|
||||||
|
:items="customizationItems(category, selectedSortItemsBy,
|
||||||
|
searchTextThrottled, hidePinned)"
|
||||||
|
:item-width="94"
|
||||||
|
:item-margin="24"
|
||||||
|
:type="category.identifier"
|
||||||
|
>
|
||||||
|
<template
|
||||||
|
slot="item"
|
||||||
|
slot-scope="ctx"
|
||||||
|
>
|
||||||
|
<shopItem
|
||||||
|
:key="ctx.item.key"
|
||||||
|
:item="ctx.item"
|
||||||
|
:price="ctx.item.value"
|
||||||
|
:price-type="ctx.item.currency"
|
||||||
|
:empty-item="false"
|
||||||
|
@click="selectItemToBuy(ctx.item)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="ctx.item.text != ''"
|
||||||
|
slot="popoverContent"
|
||||||
|
slot-scope="ctx"
|
||||||
|
><div><h4 class="popover-content-title">{{ ctx.item.text }}</h4></div></span>>
|
||||||
|
<template
|
||||||
|
slot="itemBadge"
|
||||||
|
slot-scope="ctx"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="ctx.item.pinType !== 'IGNORE'"
|
||||||
|
class="badge-top"
|
||||||
|
@click.prevent.stop="togglePinned(ctx.item)"
|
||||||
|
>
|
||||||
|
<pin-badge
|
||||||
|
:pinned="ctx.item.pinned"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</shopItem>
|
||||||
|
</template>
|
||||||
|
</itemRows>
|
||||||
|
<div v-else
|
||||||
|
v-for="items in getGrouped(customizationItems(category, selectedSortItemsBy,
|
||||||
|
searchTextThrottled, hidePinned))"
|
||||||
|
v-bind:key="items[0].set.key"
|
||||||
|
class="mb-5">
|
||||||
|
<h3>{{ items[0].set.text() }}</h3>
|
||||||
|
<itemRows
|
||||||
|
:items="items"
|
||||||
|
:item-width="94"
|
||||||
|
:item-margin="24"
|
||||||
|
:type="category.identifier">
|
||||||
|
<template
|
||||||
|
slot="item"
|
||||||
|
slot-scope="ctx"
|
||||||
|
>
|
||||||
|
<shopItem
|
||||||
|
:key="ctx.item.path"
|
||||||
|
:item="ctx.item"
|
||||||
|
:price="ctx.item.value"
|
||||||
|
:price-type="ctx.item.currency"
|
||||||
|
:empty-item="false"
|
||||||
|
@click="selectItemToBuy(ctx.item)"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="ctx.item.text != ''"
|
||||||
|
slot="popoverContent"
|
||||||
|
slot-scope="ctx"
|
||||||
|
><div><h4 class="popover-content-title">{{ ctx.item.text }}</h4></div></span>>
|
||||||
|
<template
|
||||||
|
slot="itemBadge"
|
||||||
|
slot-scope="ctx"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
v-if="ctx.item.pinType !== 'IGNORE'"
|
||||||
|
class="badge-top"
|
||||||
|
@click.prevent.stop="togglePinned(ctx.item)"
|
||||||
|
>
|
||||||
|
<pin-badge
|
||||||
|
:pinned="ctx.item.pinned"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</shopItem>
|
||||||
|
</template>
|
||||||
|
</itemRows>
|
||||||
|
<div
|
||||||
|
v-if="items[0].set"
|
||||||
|
:style="'width: ' + (items.length * (94 + 24) - 24) + 'px'"
|
||||||
|
class="purchase-set"
|
||||||
|
@click="unlock()"
|
||||||
|
>
|
||||||
|
<div class="purchase-set-content mx-auto">
|
||||||
|
<span class="label">{{ $t('purchaseAll') }}</span>
|
||||||
|
<div
|
||||||
|
class="svg-icon gem"
|
||||||
|
v-html="icons.gem"
|
||||||
|
></div>
|
||||||
|
<span class="price">{{ items[0].set.setPrice }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- eslint-disable max-len -->
|
||||||
|
<style lang="scss">
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
// these styles may be applied to other pages too
|
||||||
|
|
||||||
|
.group {
|
||||||
|
display: inline-block;
|
||||||
|
width: 33%;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
.items {
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #edecee;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-wrapper {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.items > div:not(:last-of-type) {
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.customizations {
|
||||||
|
.standard-page {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.badge-pin:not(.pinned) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item:hover .badge-pin {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
cursor: default;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.featuredItems {
|
||||||
|
height: 216px;
|
||||||
|
|
||||||
|
.background {
|
||||||
|
height: 216px;
|
||||||
|
background-repeat: repeat-x;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.npc {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 216px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
|
.featured-label {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -14px;
|
||||||
|
margin: 0;
|
||||||
|
left: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.purchase-set {
|
||||||
|
background: #fff;
|
||||||
|
padding: 0.5em;
|
||||||
|
border-radius: 0 0 2px 2px;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||||
|
margin-top: -28px;
|
||||||
|
width: 180px;
|
||||||
|
display: block;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.price {
|
||||||
|
color: #24cc8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gem, .coin {
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.single {
|
||||||
|
width: 141px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gem, .coin {
|
||||||
|
width: 20px;
|
||||||
|
margin: 0 .5em;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.purchase-set-content {
|
||||||
|
display: block;
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!-- eslint-enable max-len -->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _filter from 'lodash/filter';
|
||||||
|
import _sortBy from 'lodash/sortBy';
|
||||||
|
import _throttle from 'lodash/throttle';
|
||||||
|
import _groupBy from 'lodash/groupBy';
|
||||||
|
import _map from 'lodash/map';
|
||||||
|
import _find from 'lodash/find';
|
||||||
|
import isPinned from '@/../../common/script/libs/isPinned';
|
||||||
|
import shops from '@/../../common/script/libs/shops';
|
||||||
|
import { mapState } from '@/libs/store';
|
||||||
|
|
||||||
|
import ShopItem from '../shopItem';
|
||||||
|
import ItemRows from '@/components/ui/itemRows';
|
||||||
|
import PinBadge from '@/components/ui/pinBadge';
|
||||||
|
import toggleSwitch from '@/components/ui/toggleSwitch';
|
||||||
|
|
||||||
|
import svgHourglass from '@/assets/svg/hourglass.svg';
|
||||||
|
import gem from '@/assets/svg/gem.svg';
|
||||||
|
|
||||||
|
import pinUtils from '@/mixins/pinUtils';
|
||||||
|
import FilterSidebar from '@/components/ui/filterSidebar';
|
||||||
|
import FilterGroup from '@/components/ui/filterGroup';
|
||||||
|
import Checkbox from '@/components/ui/checkbox';
|
||||||
|
import SelectTranslatedArray from '@/components/tasks/modal-controls/selectTranslatedArray';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
SelectTranslatedArray,
|
||||||
|
Checkbox,
|
||||||
|
FilterGroup,
|
||||||
|
FilterSidebar,
|
||||||
|
ShopItem,
|
||||||
|
ItemRows,
|
||||||
|
PinBadge,
|
||||||
|
toggleSwitch,
|
||||||
|
},
|
||||||
|
mixins: [pinUtils],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
viewOptions: {},
|
||||||
|
|
||||||
|
searchText: null,
|
||||||
|
searchTextThrottled: null,
|
||||||
|
|
||||||
|
icons: Object.freeze({
|
||||||
|
hourglass: svgHourglass,
|
||||||
|
gem,
|
||||||
|
}),
|
||||||
|
|
||||||
|
sortItemsBy: ['AZ', 'sortByNumber'],
|
||||||
|
selectedSortItemsBy: 'AZ',
|
||||||
|
|
||||||
|
selectedItemToBuy: null,
|
||||||
|
|
||||||
|
hidePinned: false,
|
||||||
|
|
||||||
|
backgroundUpdate: new Date(),
|
||||||
|
|
||||||
|
currentEvent: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
content: 'content',
|
||||||
|
user: 'user.data',
|
||||||
|
userStats: 'user.data.stats',
|
||||||
|
userItems: 'user.data.items',
|
||||||
|
currentEventList: 'worldState.data.currentEventList',
|
||||||
|
}),
|
||||||
|
|
||||||
|
shop () {
|
||||||
|
return shops.getCustomizationShop(this.user);
|
||||||
|
},
|
||||||
|
|
||||||
|
categories () {
|
||||||
|
const { categories } = this.shop;
|
||||||
|
|
||||||
|
categories.forEach(category => {
|
||||||
|
// do not reset the viewOptions if already set once
|
||||||
|
if (typeof this.viewOptions[category.identifier] === 'undefined') {
|
||||||
|
this.$set(this.viewOptions, category.identifier, {
|
||||||
|
selected: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return categories;
|
||||||
|
},
|
||||||
|
anyFilterSelected () {
|
||||||
|
return Object.values(this.viewOptions).some(g => g.selected);
|
||||||
|
},
|
||||||
|
imageURLs () {
|
||||||
|
if (!this.currentEvent || !this.currentEvent.season || this.currentEvent.season === 'thanksgiving') {
|
||||||
|
return {
|
||||||
|
background: 'url(/static/npc/normal/market_background.png)',
|
||||||
|
npc: 'url(/static/npc/normal/market_banner_npc.png)',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
background: `url(/static/npc/${this.currentEvent.season}/market_background.png)`,
|
||||||
|
npc: `url(/static/npc/${this.currentEvent.season}/market_banner_npc.png)`,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
searchText: _throttle(function throttleSearch () {
|
||||||
|
this.searchTextThrottled = this.searchText.toLowerCase();
|
||||||
|
}, 250),
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.$store.dispatch('common:setTitle', {
|
||||||
|
subSection: this.$t('titleCustomizations'),
|
||||||
|
section: this.$t('shops'),
|
||||||
|
});
|
||||||
|
this.$root.$on('buyModal::boughtItem', () => {
|
||||||
|
this.backgroundUpdate = new Date();
|
||||||
|
});
|
||||||
|
this.$root.$on('bv::modal::hidden', event => {
|
||||||
|
if (event.componentId === 'buy-quest-modal') {
|
||||||
|
this.$root.$emit('buyModal::hidden', this.selectedItemToBuy.key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.currentEvent = _find(this.currentEventList, event => Boolean(['winter', 'spring', 'summer', 'fall'].includes(event.season)));
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this.$root.$off('buyModal::boughtItem');
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
customizationItems (category, sortBy, searchBy, hidePinned) {
|
||||||
|
let result = _map(category.items, e => ({
|
||||||
|
...e,
|
||||||
|
pinned: isPinned(this.user, e),
|
||||||
|
}));
|
||||||
|
|
||||||
|
result = _filter(result, i => {
|
||||||
|
if (hidePinned && i.pinned) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !searchBy || i.text.toLowerCase().indexOf(searchBy) !== -1;
|
||||||
|
});
|
||||||
|
|
||||||
|
switch (sortBy) { // eslint-disable-line default-case
|
||||||
|
case 'AZ': {
|
||||||
|
result = _sortBy(result, ['set.key', 'text']);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'sortByNumber': {
|
||||||
|
result = _sortBy(result, ['set.key', 'value']);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
getGrouped (entries) {
|
||||||
|
return _groupBy(entries, 'set.key');
|
||||||
|
},
|
||||||
|
selectItemToBuy (item) {
|
||||||
|
if (item.purchaseType === 'quests') {
|
||||||
|
this.selectedItemToBuy = item;
|
||||||
|
|
||||||
|
this.$root.$emit('bv::show::modal', 'buy-quest-modal');
|
||||||
|
} else {
|
||||||
|
this.$root.$emit('buyModal::showItem', item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
resetItemToBuy ($event) {
|
||||||
|
if (!$event) {
|
||||||
|
this.selectedItemToBuy = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
@@ -26,6 +26,12 @@
|
|||||||
>
|
>
|
||||||
{{ $t('titleTimeTravelers') }}
|
{{ $t('titleTimeTravelers') }}
|
||||||
</router-link>
|
</router-link>
|
||||||
|
<router-link
|
||||||
|
class="nav-link"
|
||||||
|
:to="{name: 'customizations'}"
|
||||||
|
>
|
||||||
|
{{ $t('titleCustomizations') }}
|
||||||
|
</router-link>
|
||||||
</secondary-menu>
|
</secondary-menu>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<router-view />
|
<router-view />
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ const MarketPage = () => import(/* webpackChunkName: "shops-market" */'@/compone
|
|||||||
const QuestsPage = () => import(/* webpackChunkName: "shops-quest" */'@/components/shops/quests/index');
|
const QuestsPage = () => import(/* webpackChunkName: "shops-quest" */'@/components/shops/quests/index');
|
||||||
const SeasonalPage = () => import(/* webpackChunkName: "shops-seasonal" */'@/components/shops/seasonal/index');
|
const SeasonalPage = () => import(/* webpackChunkName: "shops-seasonal" */'@/components/shops/seasonal/index');
|
||||||
const TimeTravelersPage = () => import(/* webpackChunkName: "shops-timetravelers" */'@/components/shops/timeTravelers/index');
|
const TimeTravelersPage = () => import(/* webpackChunkName: "shops-timetravelers" */'@/components/shops/timeTravelers/index');
|
||||||
|
const CustomizationsShopPage = () => import(/* webpackChunkName: "shops-customizations" */'@/components/shops/customizations/index');
|
||||||
|
|
||||||
Vue.use(VueRouter);
|
Vue.use(VueRouter);
|
||||||
|
|
||||||
@@ -113,6 +114,7 @@ const router = new VueRouter({
|
|||||||
{ name: 'quests', path: 'quests', component: QuestsPage },
|
{ name: 'quests', path: 'quests', component: QuestsPage },
|
||||||
{ name: 'seasonal', path: 'seasonal', component: SeasonalPage },
|
{ name: 'seasonal', path: 'seasonal', component: SeasonalPage },
|
||||||
{ name: 'time', path: 'time', component: TimeTravelersPage },
|
{ name: 'time', path: 'time', component: TimeTravelersPage },
|
||||||
|
{ name: 'customizations', path: 'customizations', component: CustomizationsShopPage },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ name: 'party', path: '/party', component: GroupPage },
|
{ name: 'party', path: '/party', component: GroupPage },
|
||||||
|
|||||||
@@ -34,6 +34,9 @@
|
|||||||
"bodyFacialHair": "Facial Hair",
|
"bodyFacialHair": "Facial Hair",
|
||||||
"beard": "Beard",
|
"beard": "Beard",
|
||||||
"mustache": "Mustache",
|
"mustache": "Mustache",
|
||||||
|
"titleFacialHair": "Facial Hair",
|
||||||
|
"titleHaircolor": "Hair Colors",
|
||||||
|
"titleHairbase": "Hair styles",
|
||||||
"flower": "Flower",
|
"flower": "Flower",
|
||||||
"accent": "Accent",
|
"accent": "Accent",
|
||||||
"headband": "Headband",
|
"headband": "Headband",
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
"gotIt": "Got it!",
|
"gotIt": "Got it!",
|
||||||
"titleTimeTravelers": "Time Travelers",
|
"titleTimeTravelers": "Time Travelers",
|
||||||
"titleSeasonalShop": "Seasonal Shop",
|
"titleSeasonalShop": "Seasonal Shop",
|
||||||
|
"titleCustomizations": "Customizations",
|
||||||
"saveEdits": "Save Edits",
|
"saveEdits": "Save Edits",
|
||||||
"showMore": "Show More",
|
"showMore": "Show More",
|
||||||
"showLess": "Show Less",
|
"showLess": "Show Less",
|
||||||
|
|||||||
@@ -40,3 +40,4 @@ export { default as QUEST_PETS } from '../quests/pets';
|
|||||||
export { default as QUEST_POTIONS } from '../quests/potions';
|
export { default as QUEST_POTIONS } from '../quests/potions';
|
||||||
export { default as QUEST_TIME_TRAVEL } from '../quests/timeTravel';
|
export { default as QUEST_TIME_TRAVEL } from '../quests/timeTravel';
|
||||||
export { default as QUEST_WORLD } from '../quests/world';
|
export { default as QUEST_WORLD } from '../quests/world';
|
||||||
|
export { getScheduleMatchingGroup, getCurrentGalaKey } from './schedule';
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import SEASONAL_SETS from './seasonalSets';
|
|||||||
|
|
||||||
function backgroundMatcher (month1, month2, oddYear) {
|
function backgroundMatcher (month1, month2, oddYear) {
|
||||||
return function call (key) {
|
return function call (key) {
|
||||||
if (!key.startsWith('backgrounds')) return true;
|
|
||||||
const keyLength = key.length;
|
const keyLength = key.length;
|
||||||
const month = parseInt(key.substring(keyLength - 6, keyLength - 4), 10);
|
const month = parseInt(key.substring(keyLength - 6, keyLength - 4), 10);
|
||||||
return (month === month1 || month === month2)
|
return (month === month1 || month === month2)
|
||||||
@@ -24,6 +23,26 @@ function inListMatcher (list) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ALWAYS_AVAILABLE_CUSTOMIZATIONS = [
|
||||||
|
'animalSkins',
|
||||||
|
'rainbowSkins',
|
||||||
|
'rainbowHairColors',
|
||||||
|
'specialShirts',
|
||||||
|
'facialHair',
|
||||||
|
'baseHair1',
|
||||||
|
'baseHair2',
|
||||||
|
'baseHair3',
|
||||||
|
];
|
||||||
|
|
||||||
|
function customizationMatcher (list) {
|
||||||
|
return function call (item) {
|
||||||
|
if (ALWAYS_AVAILABLE_CUSTOMIZATIONS.indexOf(item) !== -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return list.indexOf(item) !== -1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const FIRST_RELEASE_DAY = 1;
|
export const FIRST_RELEASE_DAY = 1;
|
||||||
export const SECOND_RELEASE_DAY = 7;
|
export const SECOND_RELEASE_DAY = 7;
|
||||||
export const THIRD_RELEASE_DAY = 14;
|
export const THIRD_RELEASE_DAY = 14;
|
||||||
@@ -601,6 +620,12 @@ export const MONTHLY_SCHEDULE = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const GALA_SWITCHOVER_DAY = 21;
|
export const GALA_SWITCHOVER_DAY = 21;
|
||||||
|
export const GALA_KEYS = [
|
||||||
|
'winter',
|
||||||
|
'spring',
|
||||||
|
'summer',
|
||||||
|
'fall',
|
||||||
|
];
|
||||||
export const GALA_SCHEDULE = {
|
export const GALA_SCHEDULE = {
|
||||||
0: [
|
0: [
|
||||||
{
|
{
|
||||||
@@ -620,6 +645,13 @@ export const GALA_SCHEDULE = {
|
|||||||
'evilsanta2',
|
'evilsanta2',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'customizations',
|
||||||
|
matcher: customizationMatcher([
|
||||||
|
'winteryHairColors',
|
||||||
|
'winterySkins',
|
||||||
|
]),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
1: [
|
1: [
|
||||||
{
|
{
|
||||||
@@ -632,20 +664,15 @@ export const GALA_SCHEDULE = {
|
|||||||
'shinySeed',
|
'shinySeed',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'customizations',
|
||||||
|
matcher: customizationMatcher([
|
||||||
|
'shimmerHairColors',
|
||||||
|
'pastelSkins',
|
||||||
|
]),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
2: [
|
2: [
|
||||||
{
|
|
||||||
type: 'seasonalGear',
|
|
||||||
items: SEASONAL_SETS.fall,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'seasonalSpells',
|
|
||||||
items: [
|
|
||||||
'spookySparkles',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
3: [
|
|
||||||
{
|
{
|
||||||
type: 'seasonalGear',
|
type: 'seasonalGear',
|
||||||
items: SEASONAL_SETS.summer,
|
items: SEASONAL_SETS.summer,
|
||||||
@@ -656,9 +683,45 @@ export const GALA_SCHEDULE = {
|
|||||||
'seafoam',
|
'seafoam',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'customizations',
|
||||||
|
matcher: customizationMatcher([
|
||||||
|
'splashySkins',
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
3: [
|
||||||
|
{
|
||||||
|
type: 'seasonalGear',
|
||||||
|
items: SEASONAL_SETS.fall,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'seasonalSpells',
|
||||||
|
items: [
|
||||||
|
'spookySparkles',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'customizations',
|
||||||
|
matcher: customizationMatcher([
|
||||||
|
'hauntedHairColors',
|
||||||
|
'supernaturalSkins',
|
||||||
|
]),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getGalaIndex (date) {
|
||||||
|
const month = date instanceof moment ? date.month() : date.getMonth();
|
||||||
|
const todayDay = date instanceof moment ? date.date() : date.getDate();
|
||||||
|
let galaMonth = month;
|
||||||
|
const galaCount = Object.keys(GALA_SCHEDULE).length;
|
||||||
|
if (todayDay >= GALA_SWITCHOVER_DAY) {
|
||||||
|
galaMonth += 1;
|
||||||
|
}
|
||||||
|
return parseInt((galaCount / 12) * galaMonth, 10);
|
||||||
|
}
|
||||||
|
|
||||||
export function assembleScheduledMatchers (date) {
|
export function assembleScheduledMatchers (date) {
|
||||||
const items = [];
|
const items = [];
|
||||||
const month = date instanceof moment ? date.month() : date.getMonth();
|
const month = date instanceof moment ? date.month() : date.getMonth();
|
||||||
@@ -674,12 +737,8 @@ export function assembleScheduledMatchers (date) {
|
|||||||
items.push(...value);
|
items.push(...value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let galaMonth = month;
|
|
||||||
const galaCount = Object.keys(GALA_SCHEDULE).length;
|
items.push(...GALA_SCHEDULE[getGalaIndex(date)]);
|
||||||
if (todayDay >= GALA_SWITCHOVER_DAY) {
|
|
||||||
galaMonth += 1;
|
|
||||||
}
|
|
||||||
items.push(...GALA_SCHEDULE[parseInt((galaCount / 12) * galaMonth, 10)]);
|
|
||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,7 +747,7 @@ let cachedScheduleMatchers = null;
|
|||||||
export function getScheduleMatchingGroup (type, date) {
|
export function getScheduleMatchingGroup (type, date) {
|
||||||
if (!cachedScheduleMatchers) {
|
if (!cachedScheduleMatchers) {
|
||||||
cachedScheduleMatchers = {};
|
cachedScheduleMatchers = {};
|
||||||
assembleScheduledMatchers(date !== undefined ? date : new Date()).forEach(matcher => {
|
assembleScheduledMatchers(date || new Date()).forEach(matcher => {
|
||||||
if (!cachedScheduleMatchers[matcher.type]) {
|
if (!cachedScheduleMatchers[matcher.type]) {
|
||||||
cachedScheduleMatchers[matcher.type] = {
|
cachedScheduleMatchers[matcher.type] = {
|
||||||
matchers: [],
|
matchers: [],
|
||||||
@@ -718,3 +777,7 @@ export function getScheduleMatchingGroup (type, date) {
|
|||||||
}
|
}
|
||||||
return cachedScheduleMatchers[type];
|
return cachedScheduleMatchers[type];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getCurrentGalaKey (date) {
|
||||||
|
return GALA_KEYS[getGalaIndex(date || new Date())];
|
||||||
|
}
|
||||||
|
|||||||
@@ -379,6 +379,96 @@ export default function getItemInfo (user, type, item, officialPinnedItems, lang
|
|||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'haircolor': {
|
||||||
|
itemInfo = {
|
||||||
|
key: item.key,
|
||||||
|
class: `hair_bangs_${user.preferences.hair.bangs}_${item.key}`,
|
||||||
|
text: item.key,
|
||||||
|
notes: '',
|
||||||
|
value: item.price,
|
||||||
|
set: item.set,
|
||||||
|
locked: false,
|
||||||
|
currency: 'gems',
|
||||||
|
path: `customizations.hair.color.${item.key}`,
|
||||||
|
pinType: 'timeTravelersStable',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'hairbase': {
|
||||||
|
itemInfo = {
|
||||||
|
key: item.key,
|
||||||
|
class: `hair_base_${item.key}_${user.preferences.hair.color}`,
|
||||||
|
text: item.key,
|
||||||
|
notes: '',
|
||||||
|
value: item.price,
|
||||||
|
set: item.set,
|
||||||
|
locked: false,
|
||||||
|
currency: 'gems',
|
||||||
|
path: `customizations.hair.base.${item.key}`,
|
||||||
|
pinType: 'timeTravelersStable',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'hairmustache': {
|
||||||
|
itemInfo = {
|
||||||
|
key: item.key,
|
||||||
|
class: `hair_mustache_${item.key}_${user.preferences.hair.color}`,
|
||||||
|
text: item.key,
|
||||||
|
notes: '',
|
||||||
|
value: item.price,
|
||||||
|
set: item.set,
|
||||||
|
locked: false,
|
||||||
|
currency: 'gems',
|
||||||
|
path: `customizations.hair.mustache.${item.key}`,
|
||||||
|
pinType: 'timeTravelersStable',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'hairbeard': {
|
||||||
|
itemInfo = {
|
||||||
|
key: item.key,
|
||||||
|
class: `hair_beard_${item.key}_${user.preferences.hair.color}`,
|
||||||
|
text: item.key,
|
||||||
|
notes: '',
|
||||||
|
value: item.price,
|
||||||
|
set: item.set,
|
||||||
|
locked: false,
|
||||||
|
currency: 'gems',
|
||||||
|
path: `customizations.hair.beard.${item.key}`,
|
||||||
|
pinType: 'timeTravelersStable',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'shirt': {
|
||||||
|
itemInfo = {
|
||||||
|
key: item.key,
|
||||||
|
class: `${user.preferences.size}_shirt_${item.key}`,
|
||||||
|
text: item.key,
|
||||||
|
notes: '',
|
||||||
|
value: item.price,
|
||||||
|
set: item.set,
|
||||||
|
locked: false,
|
||||||
|
currency: 'gems',
|
||||||
|
path: `customizations.shirt.${item.key}`,
|
||||||
|
pinType: 'timeTravelersStable',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'skin': {
|
||||||
|
itemInfo = {
|
||||||
|
key: item.key,
|
||||||
|
class: `skin_${item.key}`,
|
||||||
|
text: item.key,
|
||||||
|
notes: '',
|
||||||
|
value: item.price,
|
||||||
|
set: item.set,
|
||||||
|
locked: false,
|
||||||
|
currency: 'gems',
|
||||||
|
path: `customizations.skin.${item.key}`,
|
||||||
|
pinType: 'timeTravelersStable',
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (itemInfo) {
|
if (itemInfo) {
|
||||||
|
|||||||
@@ -1,50 +1,25 @@
|
|||||||
import find from 'lodash/find';
|
|
||||||
import upperFirst from 'lodash/upperFirst';
|
import upperFirst from 'lodash/upperFirst';
|
||||||
import moment from 'moment';
|
|
||||||
import {
|
import {
|
||||||
EVENTS,
|
getCurrentGalaKey,
|
||||||
SEASONAL_SETS,
|
|
||||||
} from '../content/constants';
|
} from '../content/constants';
|
||||||
|
import {
|
||||||
|
armor,
|
||||||
|
} from '../content/gear/sets/special';
|
||||||
|
|
||||||
const CURRENT_EVENT = find(EVENTS, event => moment().isBetween(event.start, event.end)
|
const CURRENT_EVENT_KEY = getCurrentGalaKey();
|
||||||
&& ['winter', 'spring', 'summer', 'fall'].includes(event.season));
|
|
||||||
|
function getCurrentSeasonalSets () {
|
||||||
|
const year = new Date().getFullYear();
|
||||||
|
return {
|
||||||
|
rogue: armor[`${CURRENT_EVENT_KEY}${year}Rogue`].set,
|
||||||
|
warrior: armor[`${CURRENT_EVENT_KEY}${year}Warrior`].set,
|
||||||
|
wizard: armor[`${CURRENT_EVENT_KEY}${year}Mage`].set,
|
||||||
|
healer: armor[`${CURRENT_EVENT_KEY}${year}Healer`].set,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
opened: CURRENT_EVENT,
|
currentSeason: CURRENT_EVENT_KEY ? upperFirst(CURRENT_EVENT_KEY) : 'Closed',
|
||||||
|
pinnedSets: getCurrentSeasonalSets(),
|
||||||
currentSeason: CURRENT_EVENT ? upperFirst(CURRENT_EVENT.season) : 'Closed',
|
featuredSet: 'winter2019PoinsettiaSet',
|
||||||
|
|
||||||
dateRange: {
|
|
||||||
start: CURRENT_EVENT ? moment(CURRENT_EVENT.start) : moment().subtract(1, 'days').toDate(),
|
|
||||||
end: CURRENT_EVENT ? moment(CURRENT_EVENT.end) : moment().subtract(1, 'seconds').toDate(),
|
|
||||||
},
|
|
||||||
|
|
||||||
availableSets: CURRENT_EVENT
|
|
||||||
? [
|
|
||||||
...SEASONAL_SETS[CURRENT_EVENT.season],
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
|
|
||||||
pinnedSets: CURRENT_EVENT
|
|
||||||
? {
|
|
||||||
rogue: 'spring2024MeltingSnowRogueSet',
|
|
||||||
warrior: 'spring2024FluoriteWarriorSet',
|
|
||||||
wizard: 'spring2024HibiscusMageSet',
|
|
||||||
healer: 'spring2024BluebirdHealerSet',
|
|
||||||
}
|
|
||||||
: {},
|
|
||||||
|
|
||||||
availableSpells: CURRENT_EVENT && moment().isBetween('2024-04-18T08:00-04:00', CURRENT_EVENT.end)
|
|
||||||
? [
|
|
||||||
'shinySeed',
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
|
|
||||||
availableQuests: CURRENT_EVENT && moment().isBetween('2024-03-26T08:00-04:00', CURRENT_EVENT.end)
|
|
||||||
? [
|
|
||||||
'egg',
|
|
||||||
]
|
|
||||||
: [],
|
|
||||||
|
|
||||||
featuredSet: 'spring2020LapisLazuliRogueSet',
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -449,8 +449,8 @@ shops.getSeasonalShop = function getSeasonalShop (user, language) {
|
|||||||
identifier: 'seasonalShop',
|
identifier: 'seasonalShop',
|
||||||
text: i18n.t('seasonalShop'),
|
text: i18n.t('seasonalShop'),
|
||||||
notes: i18n.t(`seasonalShop${seasonalShopConfig.currentSeason}Text`),
|
notes: i18n.t(`seasonalShop${seasonalShopConfig.currentSeason}Text`),
|
||||||
imageName: seasonalShopConfig.opened ? 'seasonalshop_open' : 'seasonalshop_closed',
|
imageName: 'seasonalshop_open',
|
||||||
opened: seasonalShopConfig.opened,
|
opened: true,
|
||||||
categories: this.getSeasonalShopCategories(user, language),
|
categories: this.getSeasonalShopCategories(user, language),
|
||||||
featured: {
|
featured: {
|
||||||
text: i18n.t(seasonalShopConfig.featuredSet),
|
text: i18n.t(seasonalShopConfig.featuredSet),
|
||||||
@@ -467,10 +467,6 @@ shops.getSeasonalShop = function getSeasonalShop (user, language) {
|
|||||||
return resObject;
|
return resObject;
|
||||||
};
|
};
|
||||||
|
|
||||||
// To switch seasons/available inventory, edit the AVAILABLE_SETS object to whatever should be sold.
|
|
||||||
// let AVAILABLE_SETS = {
|
|
||||||
// setKey: i18n.t('setTranslationString', language),
|
|
||||||
// };
|
|
||||||
shops.getSeasonalShopCategories = function getSeasonalShopCategories (user, language) {
|
shops.getSeasonalShopCategories = function getSeasonalShopCategories (user, language) {
|
||||||
const officialPinnedItems = getOfficialPinnedItems(user);
|
const officialPinnedItems = getOfficialPinnedItems(user);
|
||||||
|
|
||||||
@@ -553,4 +549,107 @@ shops.getBackgroundShopSets = function getBackgroundShopSets (language) {
|
|||||||
return sets;
|
return sets;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Customization Shop */
|
||||||
|
|
||||||
|
shops.getCustomizationShop = function getCustomizationShop (user, language) {
|
||||||
|
return {
|
||||||
|
identifier: 'customizationShop',
|
||||||
|
text: i18n.t('titleCustomizations'),
|
||||||
|
notes: i18n.t('timeTravelersPopover'),
|
||||||
|
imageName: 'npc_timetravelers_active',
|
||||||
|
categories: shops.getCustomizationShopCategories(user, language),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
shops.getCustomizationShopCategories = function getCustomizationShopCategories (user, language) {
|
||||||
|
const categories = [];
|
||||||
|
const officialPinnedItems = getOfficialPinnedItems(user);
|
||||||
|
|
||||||
|
const backgroundCategory = {
|
||||||
|
identifier: 'backgrounds',
|
||||||
|
text: i18n.t('backgrounds', language),
|
||||||
|
items: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const matchers = getScheduleMatchingGroup('backgrounds');
|
||||||
|
eachRight(content.backgrounds, (group, key) => {
|
||||||
|
if (matchers.match(key)) {
|
||||||
|
each(group, bg => {
|
||||||
|
if (!user.purchased.background[bg.key]) {
|
||||||
|
const item = getItemInfo(
|
||||||
|
user,
|
||||||
|
'background',
|
||||||
|
bg,
|
||||||
|
officialPinnedItems,
|
||||||
|
language,
|
||||||
|
);
|
||||||
|
backgroundCategory.items.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
categories.push(backgroundCategory);
|
||||||
|
|
||||||
|
const facialHairCategory = {
|
||||||
|
identifier: 'facialHair',
|
||||||
|
text: i18n.t('titleFacialHair', language),
|
||||||
|
items: [],
|
||||||
|
};
|
||||||
|
const customizationMatcher = getScheduleMatchingGroup('customizations');
|
||||||
|
each(['color', 'base', 'mustache', 'beard'], hairType => {
|
||||||
|
let category;
|
||||||
|
if (hairType === 'beard' || hairType === 'mustache') {
|
||||||
|
category = facialHairCategory;
|
||||||
|
} else {
|
||||||
|
category = {
|
||||||
|
identifier: hairType,
|
||||||
|
text: i18n.t(`titleHair${hairType}`, language),
|
||||||
|
items: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
eachRight(content.appearances.hair[hairType], (hairStyle, key) => {
|
||||||
|
if (hairStyle.price > 0 && (!user.purchased.hair || !user.purchased.hair[hairType]
|
||||||
|
|| !user.purchased.hair[hairType][key])
|
||||||
|
&& customizationMatcher.match(hairStyle.set.key)) {
|
||||||
|
const item = getItemInfo(
|
||||||
|
user,
|
||||||
|
`hair${hairType}`,
|
||||||
|
hairStyle,
|
||||||
|
officialPinnedItems,
|
||||||
|
language,
|
||||||
|
);
|
||||||
|
category.items.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// only add the facial hair category once
|
||||||
|
if (hairType !== 'beard') {
|
||||||
|
categories.push(category);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
each(['shirt', 'skin'], type => {
|
||||||
|
const category = {
|
||||||
|
identifier: type,
|
||||||
|
text: i18n.t(type, language),
|
||||||
|
items: [],
|
||||||
|
};
|
||||||
|
eachRight(content.appearances[type], (appearance, key) => {
|
||||||
|
if (appearance.price > 0 && (!user.purchased[type] || !user.purchased[type][key])
|
||||||
|
&& customizationMatcher.match(appearance.set.key)) {
|
||||||
|
const item = getItemInfo(
|
||||||
|
user,
|
||||||
|
type,
|
||||||
|
appearance,
|
||||||
|
officialPinnedItems,
|
||||||
|
language,
|
||||||
|
);
|
||||||
|
category.items.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
categories.push(category);
|
||||||
|
});
|
||||||
|
|
||||||
|
return categories;
|
||||||
|
};
|
||||||
|
|
||||||
export default shops;
|
export default shops;
|
||||||
|
|||||||
@@ -144,4 +144,26 @@ api.getBackgroundShopItems = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @apiIgnore
|
||||||
|
* @api {get} /api/v3/shops/customizations get the available items for the backgrounds shop
|
||||||
|
* @apiName GetCustomizationShopItems
|
||||||
|
* @apiGroup Shops
|
||||||
|
*
|
||||||
|
* @apiSuccess {Object} data List of available backgrounds
|
||||||
|
* @apiSuccess {string} message Success message
|
||||||
|
*/
|
||||||
|
api.getBackgroundShopItems = {
|
||||||
|
method: 'GET',
|
||||||
|
url: '/shops/customizations',
|
||||||
|
middlewares: [authWithHeaders()],
|
||||||
|
async handler (req, res) {
|
||||||
|
const { user } = res.locals;
|
||||||
|
|
||||||
|
const resObject = shops.getCustomizationShop(user, req.language);
|
||||||
|
|
||||||
|
res.respond(200, resObject);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
|||||||
Reference in New Issue
Block a user