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:
Keith Holliday
2017-09-18 11:54:25 -05:00
committed by GitHub
parent ff92f14a5b
commit ccc862f82a
10 changed files with 413 additions and 83 deletions
@@ -184,6 +184,9 @@
#bottom-wrap {
margin-top: 6em;
position: fixed;
width: 100%;
bottom: 0;
}
#bottom-background {
+248 -64
View File
@@ -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'));
},
},
+105 -10
View File
@@ -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');
+26 -4
View File
@@ -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,