Sept 15 fixes (#9044)
* Adjusted styles and added loading for private messages * Allowed for assigning during group task creation * Fixed white logos and start overflow * Added state styles to home * Fixed position * Updated avatar purchasing
This commit is contained in:
@@ -184,6 +184,9 @@
|
||||
|
||||
#bottom-wrap {
|
||||
margin-top: 6em;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#bottom-background {
|
||||
|
||||
@@ -14,7 +14,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
// @TODO Implement in V2 .section.row
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary(v-once) {{$t('randomize')}}
|
||||
.container.section.text-center.customize-menu
|
||||
#options-nav.container.section.text-center.customize-menu
|
||||
.row
|
||||
div(:class='{"col-3": !editing, "col-2 offset-1": editing}')
|
||||
.menu-item(@click='changeTopPage("body", "size")')
|
||||
@@ -36,8 +36,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.menu-item(@click='changeTopPage("backgrounds", "2017")')
|
||||
.svg-icon(v-html='icons.backgroundsIcon')
|
||||
strong(v-once) {{$t('backgrounds')}}
|
||||
|
||||
.section.customize-section(v-if='activeTopPage === "body"')
|
||||
#body.section.customize-section(v-if='activeTopPage === "body"')
|
||||
.row.sub-menu.col-6.offset-3.text-center
|
||||
.col-2.offset-4.sub-menu-item(@click='changeSubPage("size")', :class='{active: activeSubPage === "size"}')
|
||||
strong(v-once) {{$t('size')}}
|
||||
@@ -53,16 +52,15 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
:class='{active: user.preferences.shirt === option}')
|
||||
.sprite.customize-option(:class="`slim_shirt_${option}`", @click='set({"preferences.shirt": option})')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in specialShirts',
|
||||
:class='{active: user.preferences.shirt === option, locked: !user.purchased.shirt[option]}')
|
||||
.sprite.customize-option(:class="`broad_shirt_${option}`", @click='user.purchased.shirt[option] ? set({"preferences.shirt": option}) : unlock(`shirt.${option}`)')
|
||||
.gem-lock(v-if='!user.purchased.shirt[option]')
|
||||
.option(v-for='item in specialShirts',
|
||||
:class='{active: item.active, locked: item.locked}')
|
||||
.sprite.customize-option(:class="`broad_shirt_${item.key}`", @click='item.click')
|
||||
.gem-lock(v-if='item.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary(@click='unlock(`shirt.${specialShirts.join(",shirt.")}`)') Purchase All
|
||||
|
||||
.section.customize-section(v-if='activeTopPage === "skin"')
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("shirt", specialShirtKeys)', @click='unlock(`shirt.${specialShirtKeys.join(",shirt.")}`)') $t('purchaseAll')
|
||||
#skin.section.customize-section(v-if='activeTopPage === "skin"')
|
||||
.row.sub-menu.col-6.offset-3.text-center
|
||||
.col-6.offset-3.text-center.sub-menu-item(:class='{active: activeSubPage === "color"}')
|
||||
strong(v-once) {{$t('color')}}
|
||||
@@ -73,41 +71,69 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.skin.sprite.customize-option(:class="`skin_${option}`", @click='set({"preferences.skin": option})')
|
||||
.row(v-if='editing')
|
||||
.col-12.customize-options
|
||||
.option(v-for='option in ["eb052b", "f69922", "f5d70f", "0ff591", "2b43f6", "d7a9f7", "800ed0", "rainbow"]',
|
||||
:class='{active: user.preferences.skin === option, locked: !user.purchased.skin[option]}')
|
||||
.skin.sprite.customize-option(:class="`skin_${option}`", @click='user.purchased.skin[option] ? set({"preferences.skin": option}) : unlock(`skin.${option}`)')
|
||||
.gem-lock(v-if='!user.purchased.skin[option]')
|
||||
.option(v-for='option in rainbowSkins',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.skin.sprite.customize-option(:class="`skin_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("skin", rainbowSkinKeys)', @click='unlock(`skin.${rainbowSkinKeys.join(",skin.")}`)') $t('purchaseAll')
|
||||
.row(v-if='editing')
|
||||
.col-12.customize-options
|
||||
.option(v-for='option in ["bear", "cactus", "fox", "lion", "panda", "pig", "tiger", "wolf"]',
|
||||
:class='{active: user.preferences.skin === option, locked: !user.purchased.skin[option]}')
|
||||
.skin.sprite.customize-option(:class="`skin_${option}`", @click='user.purchased.skin[option] ? set({"preferences.skin": option}) : unlock(`skin.${option}`)')
|
||||
.gem-lock(v-if='!user.purchased.skin[option]')
|
||||
.option(v-for='option in animalSkins',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.skin.sprite.customize-option(:class="`skin_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("skin", animalSkinKeys)', @click='unlock(`skin.${animalSkinKeys.join(",skin.")}`)') $t('purchaseAll')
|
||||
#hair.section.customize-section(v-if='activeTopPage === "hair"')
|
||||
.row.sub-menu.col-6.offset-3.text-center
|
||||
.col-2.offset-3.text-center.sub-menu-item(@click='changeSubPage("color")', :class='{active: activeSubPage === "color"}')
|
||||
.col-2.offset-1.text-center.sub-menu-item(@click='changeSubPage("color")', :class='{active: activeSubPage === "color"}')
|
||||
strong(v-once) {{$t('color')}}
|
||||
.col-2.text-center.sub-menu-item(@click='changeSubPage("style")', :class='{active: activeSubPage === "style"}', v-if='editing')
|
||||
strong(v-once) {{$t('style')}}
|
||||
.col-2.text-center.sub-menu-item(@click='changeSubPage("bangs")', :class='{active: activeSubPage === "bangs"}')
|
||||
strong(v-once) {{$t('bangs')}}
|
||||
.col-3.text-center.sub-menu-item(@click='changeSubPage("ponytail")', :class='{active: activeSubPage === "ponytail"}')
|
||||
strong(v-once) {{$t('ponytail')}}
|
||||
.row(v-if='activeSubPage === "color"')
|
||||
.col-2.text-center.sub-menu-item(@click='changeSubPage("facialhair")', :class='{active: activeSubPage === "facialhair"}', v-if='editing')
|
||||
strong(v-once) {{$t('facialhair')}}
|
||||
#hair-color.row(v-if='activeSubPage === "color"')
|
||||
.col-12.customize-options
|
||||
.option(v-for='option in ["white", "brown", "blond", "red", "black"]',
|
||||
:class='{active: user.preferences.hair.color === option}')
|
||||
.color-bangs.sprite.customize-option(:class="`hair_bangs_1_${option}`", @click='set({"preferences.hair.color": option})')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in ["rainbow", "yellow", "green", "purple", "blue", "TRUred"]',
|
||||
:class='{active: user.preferences.hair.color === option, locked: !user.purchased.hair.color || !user.purchased.hair.color[option]}')
|
||||
.color-bangs.sprite.customize-option(:class="`hair_bangs_1_${option}`", @click='user.purchased.hair.color && user.purchased.hair.color[option] ? set({"preferences.hair.color": option}) : unlock(`skin.${option}`)')
|
||||
.gem-lock(v-if='!user.purchased.hair.color || !user.purchased.hair.color[option]')
|
||||
.option(v-for='option in premiumHairColors',
|
||||
:class='{active: option.active === option, locked: option.locked}')
|
||||
.color-bangs.sprite.customize-option(:class="`hair_bangs_1_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", premiumHairColorKeys, "color")', @click='unlock(`hair.color.${premiumHairColorKeys.join(",hair.color.")}`)') $t('purchaseAll')
|
||||
#style.row(v-if='activeSubPage === "style"')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in baseHair3',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option.key}_${user.preferences.hair.color}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair3Keys, "base")', @click='unlock(`hair.base.${baseHair3Keys.join(",hair.base.")}`)') $t('purchaseAll')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in baseHair4',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option.key}_${user.preferences.hair.color}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair4Keys, "base")', @click='unlock(`hair.base.${baseHair4Keys.join(",hair.base.")}`)') $t('purchaseAll')
|
||||
#bangs.row(v-if='activeSubPage === "bangs"')
|
||||
.col-12.customize-options
|
||||
.head_0.option(@click='set({"preferences.hair.bangs": 0})',
|
||||
@@ -118,46 +144,38 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
#base-hair.row(v-if='activeSubPage === "ponytail"')
|
||||
.col-12.customize-options
|
||||
.head_0.option(@click='set({"preferences.hair.base": 0})', :class="[{ active: user.preferences.hair.base === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
|
||||
.option(v-for='option in ["1", "3"]',
|
||||
.option(v-for='option in baseHair1',
|
||||
:class='{active: user.preferences.hair.base === option}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.base": option})')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in ["2", "4", "5", "6", "7", "8"]',
|
||||
:class='{active: user.preferences.hair.base === option, locked: !user.purchased.hair.base || !user.purchased.hair.base[option]}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.base": option})')
|
||||
.gem-lock(v-if='!user.purchased.hair.base || !user.purchased.hair.base[option]')
|
||||
.option(v-for='option in baseHair2',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option.key}_${user.preferences.hair.color}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair2Keys, "base")', @click='unlock(`hair.base.${baseHair2Keys.join(",hair.base.")}`)') $t('purchaseAll')
|
||||
#facialhair.row(v-if='activeSubPage === "facialhair"')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in ["9", "10", "11", "12", "13", "14"]',
|
||||
:class='{active: user.preferences.hair.base === option, locked: !user.purchased.hair.base || !user.purchased.hair.base[option]}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.base": option})')
|
||||
.gem-lock(v-if='!user.purchased.hair.base || !user.purchased.hair.base[option]')
|
||||
.option(v-for='option in baseHair5',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.base.sprite.customize-option(:class="`hair_beard_${option.key}_${user.preferences.hair.color}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair5Keys, "beard")', @click='unlock(`hair.beard.${baseHair5Keys.join(",hair.beard.")}`)') $t('purchaseAll')
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in ["15", "16", "17", "18", "19", "20"]',
|
||||
:class='{active: user.preferences.hair.base === option, locked: !user.purchased.hair.base || !user.purchased.hair.base[option]}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.base": option})')
|
||||
.gem-lock(v-if='!user.purchased.hair.base || !user.purchased.hair.base[option]')
|
||||
.option(v-for='option in baseHair6',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.base.sprite.customize-option(:class="`hair_mustache_${option.key}_${user.preferences.hair.color}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in ["1", "2", "3"]',
|
||||
:class='{active: user.preferences.hair.beard === option, locked: !user.purchased.hair.base || !user.purchased.hair.base[option]}')
|
||||
.base.sprite.customize-option(:class="`hair_beard_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.beard": option})')
|
||||
.gem-lock(v-if='!user.purchased.hair.base || !user.purchased.hair.base[option]')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in ["1", "2"]',
|
||||
:class='{active: user.preferences.hair.mustache === option, locked: !user.purchased.hair.base || !user.purchased.hair.base[option]}')
|
||||
.base.sprite.customize-option(:class="`hair_mustache_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.mustache": option})')
|
||||
.gem-lock(v-if='!user.purchased.hair.base || !user.purchased.hair.base[option]')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
|
||||
.section.container.customize-section(v-if='activeTopPage === "extra"')
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!userOwnsSet("hair", baseHair6Keys, "mustache")', @click='unlock(`hair.mustache.${baseHair6Keys.join(",hair.mustache.")}`)') $t('purchaseAll')
|
||||
#extra.section.container.customize-section(v-if='activeTopPage === "extra"')
|
||||
.row.sub-menu.col-6.offset-3.text-center
|
||||
.col-4.text-center.sub-menu-item(@click='changeSubPage("glasses")', :class='{active: activeSubPage === "glasses"}')
|
||||
strong(v-once) {{$t('glasses')}}
|
||||
@@ -175,13 +193,14 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.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"}')
|
||||
#animal-ears.col-12.customize-options(v-if='editing')
|
||||
.option(v-for='option in ["bearEars", "cactusEars", "foxEars", "lionEars", "pandaEars", "pigEars", "tigerEars", "wolfEars"]',
|
||||
:class='[{active: user.preferences.costume ? user.items.gear.costume.headAccessory === `headAccessory_special_${option}` : user.items.gear.equipped.headAccessory === `headAccessory_special_${option}`}, {locked: !user.purchased.headAccessory || !user.purchased.headAccessory[option]}]')
|
||||
.sprite.customize-option(:class="`headAccessory_special_${option}`", @click='equip(`headAccessory_special_${option}`)')
|
||||
.gem-lock(v-if='!user.purchased.headAccessory || !user.purchased.headAccessory[option]')
|
||||
.option(v-for='option in animalEars',
|
||||
:class='{active: option.active, locked: option.locked}')
|
||||
.sprite.customize-option(:class="`headAccessory_special_${option.key}`", @click='option.click')
|
||||
.gem-lock(v-if='option.locked')
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
span 2
|
||||
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary.purchase-all(v-if='!animalEarsOwned', @click='unlock(animalEarsUnlockString)') $t('purchaseAll')
|
||||
#wheelchairs.row(v-if='activeSubPage === "wheelchair"')
|
||||
.col-12.customize-options.weelchairs
|
||||
.option(@click='set({"preferences.chair": "none"})', :class='{active: user.preferences.chair === "none"}')
|
||||
@@ -202,7 +221,6 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
popover='{{::item.notes()}}', popover-title='{{::item.text()}}', popover-trigger='mouseenter',
|
||||
popover-placement='right', popover-append-to-body='true',
|
||||
ng-click='user.items.gear.owned[item.key] ? equip(item.key) : purchase(item.type,item)')
|
||||
|
||||
#backgrounds.section.container.customize-section(v-if='activeTopPage === "backgrounds"')
|
||||
.row.col-12.text-center.set-title
|
||||
strong {{backgroundShopSets[0].text}}
|
||||
@@ -359,6 +377,10 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.purchase-all {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-top: 2em;
|
||||
}
|
||||
@@ -892,18 +914,26 @@ export default {
|
||||
},
|
||||
mounted () {
|
||||
if (this.editing) this.modalPage = 2;
|
||||
|
||||
// Buy modal is global, so we listen at root. I'd like to not
|
||||
this.$root.$on('buyModal::boughtItem', this.backgroundPurchased);
|
||||
},
|
||||
data () {
|
||||
let backgroundShopSets = getBackgroundShopSets();
|
||||
|
||||
return {
|
||||
loading: false,
|
||||
backgroundShopSets,
|
||||
backgroundUpdate: new Date(),
|
||||
specialShirts: ['convict', 'cross', 'fire', 'horizon', 'ocean', 'purple', 'rainbow', 'redblue', 'thunder', 'tropical', 'zombie'],
|
||||
specialShirtKeys: ['convict', 'cross', 'fire', 'horizon', 'ocean', 'purple', 'rainbow', 'redblue', 'thunder', 'tropical', 'zombie'],
|
||||
rainbowSkinKeys: ['eb052b', 'f69922', 'f5d70f', '0ff591', '2b43f6', 'd7a9f7', '800ed0', 'rainbow'],
|
||||
animalSkinKeys: ['bear', 'cactus', 'fox', 'lion', 'panda', 'pig', 'tiger', 'wolf'],
|
||||
premiumHairColorKeys: ['rainbow', 'yellow', 'green', 'purple', 'blue', 'TRUred'],
|
||||
baseHair1: ['1', '3'],
|
||||
baseHair2Keys: ['2', '4', '5', '6', '7', '8'],
|
||||
baseHair3Keys: ['9', '10', '11', '12', '13', '14'],
|
||||
baseHair4Keys: ['15', '16', '17', '18', '19', '20'],
|
||||
baseHair5Keys: ['1', '2', '3'],
|
||||
baseHair6Keys: ['1', '2'],
|
||||
animalEarsKeys: ['bearEars', 'cactusEars', 'foxEars', 'lionEars', 'pandaEars', 'pigEars', 'tigerEars', 'wolfEars'],
|
||||
icons: Object.freeze({
|
||||
logoPurple,
|
||||
bodyIcon,
|
||||
@@ -934,6 +964,125 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
animalEarsUnlockString () {
|
||||
let animalItemKeys = this.animalEarsKeys.map(key => {
|
||||
return `items.gear.owned.headAccessory_special_${key}`;
|
||||
});
|
||||
|
||||
return animalItemKeys.join(',');
|
||||
},
|
||||
animalEarsOwned () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
|
||||
let own = true;
|
||||
this.animalEarsKeys.forEach(key => {
|
||||
if (!this.user.items.gear.owned[`headAccessory_special_${key}`]) own = false;
|
||||
});
|
||||
return own;
|
||||
},
|
||||
animalEars () {
|
||||
// @TODO: This is not like other purchase items
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.animalEarsKeys;
|
||||
let options = keys.map(key => {
|
||||
let newKey = `headAccessory_special_${key}`;
|
||||
let userPurchased = this.user.items.gear.owned[newKey];
|
||||
let locked = !userPurchased;
|
||||
|
||||
let option = {};
|
||||
option.key = key;
|
||||
option.active = this.user.preferences.costume ? this.user.items.gear.costume.headAccessory === newKey : this.user.items.gear.equipped.headAccessory === newKey;
|
||||
option.locked = locked;
|
||||
option.click = () => {
|
||||
return locked ? this.purchase('gear', newKey) : this.equip(newKey);
|
||||
};
|
||||
return option;
|
||||
});
|
||||
return options;
|
||||
},
|
||||
specialShirts () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.specialShirtKeys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'shirt');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
rainbowSkins () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.rainbowSkinKeys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'skin');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
animalSkins () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.animalSkinKeys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'skin');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
premiumHairColors () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.premiumHairColorKeys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'color');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
baseHair2 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair2Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'base');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
baseHair3 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair3Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'base');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
baseHair4 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair4Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'base');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
baseHair5 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair5Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'beard');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
baseHair6 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair6Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'mustache');
|
||||
});
|
||||
return options;
|
||||
},
|
||||
editing () {
|
||||
return this.$store.state.avatarEditorOptions.editingUser;
|
||||
},
|
||||
@@ -968,6 +1117,41 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
purchase (type, key) {
|
||||
this.$store.dispatch('shops:purchase', {
|
||||
type,
|
||||
key,
|
||||
});
|
||||
this.backgroundUpdate = new Date();
|
||||
},
|
||||
mapKeysToOption (key, type, subType) {
|
||||
let userPreference = subType ? this.user.preferences[type][subType] : this.user.preferences[type];
|
||||
let userPurchased = subType ? this.user.purchased[type][subType] : this.user.purchased[type];
|
||||
let locked = !userPurchased || !userPurchased[key];
|
||||
let pathKey = subType ? `${type}.${subType}` : `${type}`;
|
||||
|
||||
let option = {};
|
||||
option.key = key;
|
||||
option.active = userPreference === key;
|
||||
option.locked = locked;
|
||||
option.click = () => {
|
||||
return locked ? this.unlock(`${pathKey}.${key}`) : this.set({[`preferences.${pathKey}`]: key});
|
||||
};
|
||||
return option;
|
||||
},
|
||||
userOwnsSet (type, setKeys, subType) {
|
||||
let owns = true;
|
||||
|
||||
setKeys.forEach(key => {
|
||||
if (subType) {
|
||||
if (!this.user.purchased[type] || !this.user.purchased[type][subType] || !this.user.purchased[type][subType][key]) owns = false;
|
||||
return;
|
||||
}
|
||||
if (!this.user.purchased[type][key]) owns = false;
|
||||
});
|
||||
|
||||
return owns;
|
||||
},
|
||||
prev () {
|
||||
this.modalPage -= 1;
|
||||
},
|
||||
|
||||
@@ -118,6 +118,7 @@ export default {
|
||||
|
||||
let guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
|
||||
guilds.forEach((guild) => {
|
||||
if (!guild.categories) return;
|
||||
guild.categorySlugs = guild.categories.map(cat => {
|
||||
return cat.slug;
|
||||
});
|
||||
|
||||
@@ -1,9 +1,20 @@
|
||||
<template lang="pug">
|
||||
b-modal#private-message(title="Message", size='sm', :hide-footer="true")
|
||||
textarea.form-control(v-model='privateMessage')
|
||||
button.btn.btn-primary(@click='sendPrivateMessage()') Send
|
||||
b-modal#private-message(title="Message", size='md', :hide-footer="true")
|
||||
.content
|
||||
textarea.form-control(v-model='privateMessage')
|
||||
button.btn.btn-primary(@click='sendPrivateMessage()', :disabled='loading') Send
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
padding: 1em;
|
||||
|
||||
textarea {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
import notifications from 'client/mixins/notifications';
|
||||
@@ -17,17 +28,22 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
privateMessage: '',
|
||||
loading: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async sendPrivateMessage () {
|
||||
if (!this.privateMessage || !this.userIdToMessage) return;
|
||||
|
||||
this.loading = true;
|
||||
|
||||
await this.$store.dispatch('members:sendPrivateMessage', {
|
||||
message: this.privateMessage,
|
||||
toUserId: this.userIdToMessage,
|
||||
});
|
||||
|
||||
this.loading = false;
|
||||
|
||||
this.text(this.$t('messageSentAlert'));
|
||||
},
|
||||
},
|
||||
|
||||
@@ -23,11 +23,11 @@
|
||||
.strike
|
||||
span OR
|
||||
.form
|
||||
input.form-control(type='text', placeholder='Username', v-model='username')
|
||||
input.form-control(type='email', placeholder='Email', v-model='email')
|
||||
input.form-control(type='password', placeholder='Password', v-model='password')
|
||||
input.form-control(type='password', placeholder='Confirm Password', v-model='passwordConfirm')
|
||||
p By clicking the button below, you are indicating that you have read and agree to the Terms of Service and Privacy Policy.
|
||||
input.form-control(type='text', placeholder='Username', v-model='username', :class='{"input-valid": username.length > 0}')
|
||||
input.form-control(type='email', placeholder='Email', v-model='email', :class='{"input-invalid": emailInvalid, "input-valid": emailValid}')
|
||||
input.form-control(type='password', placeholder='Password', v-model='password', :class='{"input-valid": password.length > 0}')
|
||||
input.form-control(type='password', placeholder='Confirm Password', v-model='passwordConfirm', :class='{"input-invalid": passwordConfirmInvalid, "input-valid": passwordConfirmValid}')
|
||||
p.form-text(v-once, v-html="$t('termsAndAgreement')")
|
||||
button.sign-up(@click='register()') Sign Up
|
||||
.col-12
|
||||
.spacer.svg-icon(v-html='icons.spacer')
|
||||
@@ -98,12 +98,10 @@
|
||||
h3.col-12 Join over 2,000,000 people having fun while accomplishing their goals!
|
||||
.row
|
||||
.col-12.text-center
|
||||
button.btn.btn-primary(@click='playButtonClick()') Join Habitica Today
|
||||
button.btn.btn-primary.join-button(@click='playButtonClick()') Join Habitica Today
|
||||
.row.featured
|
||||
.col-12.text-center
|
||||
strong Featured in
|
||||
.container-fluid
|
||||
.seamless_stars_varied_opacity_repeat
|
||||
.container-fluid.featured
|
||||
.row
|
||||
.col-12
|
||||
@@ -111,10 +109,12 @@
|
||||
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/nyt-logo.png', alt="$t(altAttrNewYorkTimes)")
|
||||
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/makeuseof.png', alt="$t(altAttrMakeUseOf)")
|
||||
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Forbes_logo.png', alt="$t(altAttrForbes)")
|
||||
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Cnetlogo.png', alt="$t(altAttrCnet)")
|
||||
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/Fast-Company-logo.png', alt="$t(altAttrFastCompany)")
|
||||
.cnet.svg-icon(v-html='icons.cnet')
|
||||
.fast-company.svg-icon(v-html='icons.fastCompany')
|
||||
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/kickstarter-logo.png', alt="$t(altAttrKickstarter)")
|
||||
img(src='https://d2afqr2xdmyzvu.cloudfront.net/front/images/presslogos/discover-logo.png', alt="$t(altAttrDiscover)")
|
||||
.container-fluid
|
||||
.seamless_stars_varied_opacity_repeat
|
||||
|
||||
#bottom-wrap.purple-4
|
||||
#bottom-background
|
||||
@@ -122,6 +122,34 @@
|
||||
.midground_foreground_extended2
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.form-text a {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
#purple-footer {
|
||||
background-color: #271b3d;
|
||||
|
||||
footer, footer a {
|
||||
background: transparent;
|
||||
color: #d5c8ff;
|
||||
}
|
||||
|
||||
.logo {
|
||||
color: #bda8ff;
|
||||
}
|
||||
|
||||
.social-circle, .btn-donate {
|
||||
background: #36205d;
|
||||
color: #bda8ff;
|
||||
|
||||
.svg-icon {
|
||||
color: #bda8ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/static.scss';
|
||||
|
||||
@@ -270,6 +298,11 @@
|
||||
color: $purple-400;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border: solid 2px #9a62ff;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
button.sign-up {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
@@ -280,6 +313,12 @@
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.sign-up:hover {
|
||||
background-color: #50b5e9;
|
||||
box-shadow: 0 4px 4px 0 rgba(26, 24, 29, 0.16), 0 1px 8px 0 rgba(26, 24, 29, 0.12);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
::-webkit-input-placeholder { /* Chrome/Opera/Safari */
|
||||
color: $purple-400;
|
||||
}
|
||||
@@ -336,6 +375,10 @@
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.app {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.iphones {
|
||||
width: 436px
|
||||
}
|
||||
@@ -372,6 +415,12 @@
|
||||
padding-bottom: 5em;
|
||||
}
|
||||
|
||||
.join-button:hover {
|
||||
cursor: pointer;
|
||||
background-color: #b288ff;
|
||||
box-shadow: 0 4px 4px 0 rgba(26, 24, 29, 0.16), 0 1px 8px 0 rgba(26, 24, 29, 0.12);
|
||||
}
|
||||
|
||||
.featured .row {
|
||||
margin-top: 0;
|
||||
}
|
||||
@@ -379,6 +428,26 @@
|
||||
.featured {
|
||||
text-align: center;
|
||||
|
||||
.svg-icon {
|
||||
max-height: 30px;
|
||||
max-width: 120px;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.cnet {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding-top: .5em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.fast-company {
|
||||
width: 161.3px;
|
||||
height: 24px;
|
||||
padding-top: .8em;
|
||||
}
|
||||
|
||||
img {
|
||||
max-height: 30px;
|
||||
max-width: 120px;
|
||||
@@ -440,6 +509,8 @@
|
||||
import pixelHorizontal3 from 'assets/images/home/pixel-horizontal-3.svg';
|
||||
import facebookSquareIcon from 'assets/svg/facebook-square.svg';
|
||||
import googleIcon from 'assets/svg/google.svg';
|
||||
import cnet from 'assets/svg/cnet.svg';
|
||||
import fastCompany from 'assets/svg/fast-company.svg';
|
||||
import * as Analytics from 'client/libs/analytics';
|
||||
|
||||
export default {
|
||||
@@ -455,6 +526,8 @@
|
||||
pixelHorizontal3,
|
||||
facebookIcon: facebookSquareIcon,
|
||||
googleIcon,
|
||||
cnet,
|
||||
fastCompany,
|
||||
}),
|
||||
userCount: 1000000,
|
||||
username: '',
|
||||
@@ -477,7 +550,29 @@
|
||||
google: process.env.GOOGLE_CLIENT_ID, // eslint-disable-line
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
emailValid () {
|
||||
if (this.email.length === 0) return false;
|
||||
return this.validateEmail(this.email);
|
||||
},
|
||||
emailInvalid () {
|
||||
if (this.email.length === 0) return false;
|
||||
return !this.validateEmail(this.email);
|
||||
},
|
||||
passwordConfirmValid () {
|
||||
if (this.passwordConfirm.length === 0) return false;
|
||||
return this.passwordConfirm === this.password;
|
||||
},
|
||||
passwordConfirmInvalid () {
|
||||
if (this.passwordConfirm.length === 0) return false;
|
||||
return this.passwordConfirm !== this.password;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
validateEmail (email) {
|
||||
let re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
return re.test(email);
|
||||
},
|
||||
async register () {
|
||||
if (this.password !== this.passwordConfirm) {
|
||||
alert('Passwords must match');
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
input.custom-control-input(type="checkbox", :value="member._id", v-model="assignedMembers", @change='toggleAssignment(member._id)')
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ member.profile.name }}
|
||||
|
||||
|
||||
.row
|
||||
button.btn.btn-primary(@click="showAssignedSelect = !showAssignedSelect") {{$t('close')}}
|
||||
|
||||
@@ -547,7 +547,7 @@ export default {
|
||||
weekdaysMin (dayNumber) {
|
||||
return moment.weekdaysMin(dayNumber);
|
||||
},
|
||||
submit () {
|
||||
async submit () {
|
||||
if (this.newChecklistItem) this.addChecklistItem();
|
||||
|
||||
if (this.purpose === 'create') {
|
||||
@@ -558,10 +558,21 @@ export default {
|
||||
});
|
||||
this.$emit('taskCreated', this.task);
|
||||
} else if (this.groupId) {
|
||||
this.$store.dispatch('tasks:createGroupTasks', {
|
||||
await this.$store.dispatch('tasks:createGroupTasks', {
|
||||
groupId: this.groupId,
|
||||
tasks: [this.task],
|
||||
});
|
||||
|
||||
let promises = this.assignedMembers.map(memberId => {
|
||||
return this.$store.dispatch('tasks:assignTask', {
|
||||
taskId: this.task._id,
|
||||
userId: memberId,
|
||||
});
|
||||
});
|
||||
Promise.all(promises);
|
||||
|
||||
this.task.group.assignedUsers = this.assignedMembers;
|
||||
|
||||
this.$emit('taskCreated', this.task);
|
||||
} else {
|
||||
this.createTask(this.task);
|
||||
@@ -596,13 +607,24 @@ export default {
|
||||
this.requiresApproval = truthy;
|
||||
},
|
||||
async toggleAssignment (memberId) {
|
||||
if (this.assignedMembers.indexOf(memberId) === -1) {
|
||||
let assignedIndex = this.assignedMembers.indexOf(memberId);
|
||||
|
||||
if (assignedIndex === -1) {
|
||||
if (this.purpose === 'create') {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$store.dispatch('tasks:unassignTask', {
|
||||
taskId: this.task._id,
|
||||
userId: this.user._id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.purpose === 'create') {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$store.dispatch('tasks:assignTask', {
|
||||
taskId: this.task._id,
|
||||
userId: this.user._id,
|
||||
|
||||
Reference in New Issue
Block a user