New client many fixes (#8981)
* Footer style fixes * Limited string display * Fixed background reload * Began adding more avatar items * Fixed challenge updated cats and official to be seen by admins * Fixed min prize * Fixed required fields * Added my challenges and find challenges to menu * Removed nav to party page when have no party * Updated user and notifications icon * Added accept, reject and messages * Added selfcare * Underline links * Added forgot password * Fixed task adding * Disabled habit options that should be * Added markdown to tags * Added confirm to delete * Fixed cancel/delete style * Fixed rounding * Added gold icon * Fixed task icon styles * Fixed margin botton * Fixed some repeat styles * Fixed custom reward style * Hide like count 0 * Added new tavern images * Redirect to party page after create * Hid leader options from non leaders * Removed manager options from non group plan * Fixed some nav styles * Fixed overlay color * Prevented edit data from being transfered to create * Added hover state for spells * Add performance fixes for chat avatars * Fixed merge conflicts * Updated fron navigation * Fixed reg gryphon logo * Began adding gem modal functionality * Added purchase gems with gold * Fixed restore * Replaced description with summary * Spells that target tasks fix * Added initial challenge task load * Fixed lint issue
@@ -21,6 +21,13 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.modal-backdrop.show {
|
||||
opacity: 1 !important;
|
||||
background-color: rgba(67, 40, 116, 0.9) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import AppMenu from './components/appMenu';
|
||||
|
||||
BIN
website/client/assets/images/melior.png
Executable file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
website/client/assets/images/melior@2x.png
Executable file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
website/client/assets/images/melior@3x.png
Executable file
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="20" viewBox="0 0 24 20">
|
||||
<path fill="#C3C0C7" fill-rule="evenodd" d="M13 16h2v-2h-2v2zm-4 0h2v-2H9v2zm-4 0h2v-2H5v2zm12-4h2v-2h-2v2zm-4 0h2v-2h-2v2zm-4 0h2v-2H9v2zm13-4H2v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8zm2-2v10a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V6a4 4 0 0 1 4-4h1V0h2v2h10V0h2v2h1a4 4 0 0 1 4 4zM5 12h2v-2H5v2z"/>
|
||||
<path fill-rule="evenodd" d="M13 16h2v-2h-2v2zm-4 0h2v-2H9v2zm-4 0h2v-2H5v2zm12-4h2v-2h-2v2zm-4 0h2v-2h-2v2zm-4 0h2v-2H9v2zm13-4H2v8a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V8zm2-2v10a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V6a4 4 0 0 1 4-4h1V0h2v2h10V0h2v2h1a4 4 0 0 1 4 4zM5 12h2v-2H5v2z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 382 B After Width: | Height: | Size: 367 B |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="20" viewBox="0 0 30 20">
|
||||
<path fill="#C3C0C7" fill-rule="evenodd" d="M11 11H9v2H7v-2H5V9h2V7h2v2h2v2zm8 0h6V9h-6v2zm9 5c0 1.103-.897 2-2 2H16V2h10c1.103 0 2 .897 2 2v12zM4 18c-1.103 0-2-.897-2-2V4c0-1.103.897-2 2-2h10v16H4zM26 0H4a4 4 0 0 0-4 4v12a4 4 0 0 0 4 4h22a4 4 0 0 0 4-4V4a4 4 0 0 0-4-4z"/>
|
||||
<path fill-rule="evenodd" d="M11 11H9v2H7v-2H5V9h2V7h2v2h2v2zm8 0h6V9h-6v2zm9 5c0 1.103-.897 2-2 2H16V2h10c1.103 0 2 .897 2 2v12zM4 18c-1.103 0-2-.897-2-2V4c0-1.103.897-2 2-2h10v16H4zM26 0H4a4 4 0 0 0-4 4v12a4 4 0 0 0 4 4h22a4 4 0 0 0 4-4V4a4 4 0 0 0-4-4z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 354 B |
7
website/client/assets/svg/notifications.svg
Executable file → Normal file
@@ -1,4 +1,3 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>notifications</title>
|
||||
<path d="M26 4h-20c-1.7 0-3 1.3-3 3v14c0 1.7 1.3 3 3 3h5l2.9 3.1c1.2 1.2 3.1 1.2 4.2 0l2.9-3.1h5c1.7 0 3-1.3 3-3v-14c0-1.7-1.3-3-3-3v0zM27 21c0 0.6-0.4 1-1 1h-5.9l-3.5 3.7c-0.2 0.2-0.4 0.3-0.6 0.3s-0.4-0.1-0.7-0.3l-3.4-3.7h-5.9c-0.6 0-1-0.4-1-1v-14c0-0.6 0.4-1 1-1h20c0.6 0 1 0.4 1 1v14zM24 11h-16v-2h16v2zM24 15h-16v-2h16v2zM24 19h-16v-2h16v2z"></path>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path fill="#D5C8FF" fill-rule="evenodd" d="M21 0H3C1.3 0 0 1.3 0 3v14c0 1.7 1.3 3 3 3h4l2.9 3.1c1.2 1.2 3.1 1.2 4.2 0L17 20h4c1.7 0 3-1.3 3-3V3c0-1.7-1.3-3-3-3zm1 17c0 .6-.4 1-1 1h-4.9l-3.5 3.7c-.2.2-.4.3-.6.3-.2 0-.4-.1-.7-.3L7.9 18H3c-.6 0-1-.4-1-1V3c0-.6.4-1 1-1h18c.6 0 1 .4 1 1v14zM19 7H5V5h14v2zm0 4H5V9h14v2zm0 4H5v-2h14v2z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 487 B After Width: | Height: | Size: 430 B |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="20" viewBox="0 0 26 20">
|
||||
<path fill="#C3C0C7" fill-rule="evenodd" d="M24 10h-8V8h4a2 2 0 0 0 2-2V2c1.103 0 2 .897 2 2v6zm0 6a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-4h8v1a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2v-1h8v4zM2 4c0-1.103.897-2 2-2v4a2 2 0 0 0 2 2h4v2H2V4zm10 9h2V8h-2v5zm8-11v4H6V2h14zm2-2H4a4 4 0 0 0-4 4v12a4 4 0 0 0 4 4h18a4 4 0 0 0 4-4V4a4 4 0 0 0-4-4z"/>
|
||||
<path fill-rule="evenodd" d="M24 10h-8V8h4a2 2 0 0 0 2-2V2c1.103 0 2 .897 2 2v6zm0 6a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-4h8v1a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2v-1h8v4zM2 4c0-1.103.897-2 2-2v4a2 2 0 0 0 2 2h4v2H2V4zm10 9h2V8h-2v5zm8-11v4H6V2h14zm2-2H4a4 4 0 0 0-4 4v12a4 4 0 0 0 4 4h18a4 4 0 0 0 4-4V4a4 4 0 0 0-4-4z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 421 B After Width: | Height: | Size: 406 B |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill="#C3C0C7" fill-rule="evenodd" d="M8.343 14.916c-.312 0-.61-.123-.831-.344l-3.831-3.831 1.662-1.662 2.934 2.934 5.938-6.929L16 6.613l-6.764 7.893a1.182 1.182 0 0 1-.848.409l-.045.001zM18 16c0 1.103-.897 2-2 2H4c-1.102 0-2-.897-2-2V4c0-1.103.898-2 2-2h12c1.103 0 2 .897 2 2v12zM16 0H4a4 4 0 0 0-4 4v12a4 4 0 0 0 4 4h12a4 4 0 0 0 4-4V4a4 4 0 0 0-4-4z"/>
|
||||
<path fill-rule="evenodd" d="M8.343 14.916c-.312 0-.61-.123-.831-.344l-3.831-3.831 1.662-1.662 2.934 2.934 5.938-6.929L16 6.613l-6.764 7.893a1.182 1.182 0 0 1-.848.409l-.045.001zM18 16c0 1.103-.897 2-2 2H4c-1.102 0-2-.897-2-2V4c0-1.103.898-2 2-2h12c1.103 0 2 .897 2 2v12zM16 0H4a4 4 0 0 0-4 4v12a4 4 0 0 0 4 4h12a4 4 0 0 0 4-4V4a4 4 0 0 0-4-4z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 457 B After Width: | Height: | Size: 442 B |
5
website/client/assets/svg/user.svg
Executable file → Normal file
@@ -1,4 +1,3 @@
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>user</title>
|
||||
<path d="M20 17h-0.4c1.9-1.2 3.3-3.3 3.4-5.8 0.1-3.8-3.1-7.2-6.9-7.2-4 0-7.1 3.1-7.1 7 0 2.6 1.3 4.8 3.4 6h-0.4c-3.9 0-7 3.1-7 7v1c0 1.7 1.3 3 3 3h16c1.7 0 3-1.3 3-3v-1c0-3.9-3.1-7-7-7v0zM11 11c0-2.8 2.2-5 5-5s5 2.2 5 5c0 2.8-2.2 5-5 5s-5-2.2-5-5v0zM24 26h-16c-0.6 0-1-0.4-1-1v-1c0-2.8 2.2-5 5-5h8c2.8 0 5 2.2 5 5v1c0 0.6-0.4 1-1 1v0z"></path>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="24" viewBox="0 0 22 24">
|
||||
<path fill-rule="evenodd" d="M15 13h-.4c1.9-1.2 3.3-3.3 3.4-5.8.1-3.8-3.1-7.2-6.9-7.2C7.1 0 4 3.1 4 7c0 2.6 1.3 4.8 3.4 6H7c-3.9 0-7 3.1-7 7v1c0 1.7 1.3 3 3 3h16c1.7 0 3-1.3 3-3v-1c0-3.9-3.1-7-7-7zM6 7c0-2.8 2.2-5 5-5s5 2.2 5 5-2.2 5-5 5-5-2.2-5-5zm13 15H3c-.6 0-1-.4-1-1v-1c0-2.8 2.2-5 5-5h8c2.8 0 5 2.2 5 5v1c0 .6-.4 1-1 1z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 469 B After Width: | Height: | Size: 424 B |
@@ -113,7 +113,8 @@
|
||||
<style lang="scss" scoped>
|
||||
footer {
|
||||
background-color: #e1e0e3;
|
||||
height: 376px;
|
||||
min-height: 408px;
|
||||
width: 100%;
|
||||
padding-left: 6em;
|
||||
padding-right: 6em;
|
||||
padding-top: 3em;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template lang="pug">
|
||||
#app-header.row
|
||||
create-party-modal
|
||||
members-modal(:group='user.party', :hide-badge="true")
|
||||
members-modal(:hide-badge="true")
|
||||
member-details(:member="user")
|
||||
.view-party(v-if="user.party && user.party._id && partyMembers && partyMembers.length > 1")
|
||||
// TODO button should open the party members modal
|
||||
@@ -124,6 +124,8 @@ export default {
|
||||
openPartyModal () {
|
||||
if (this.user.party._id) {
|
||||
this.$store.state.groupId = this.user.party._id;
|
||||
// @TODO: do we need to fetch party?
|
||||
this.$store.state.memberModalOptions.group = this.$store.state.party;
|
||||
this.$root.$emit('show::modal', 'members-modal');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,9 @@ div
|
||||
router-link.dropdown-item(:to="{name: 'quests'}") {{ $t('quests') }}
|
||||
router-link.dropdown-item(:to="{name: 'seasonal'}") {{ $t('titleSeasonalShop') }}
|
||||
router-link.dropdown-item(:to="{name: 'time'}") {{ $t('titleTimeTravelers') }}
|
||||
router-link.nav-item(tag="li", :to="{name: 'party'}")
|
||||
router-link.nav-item(tag="li", :to="{name: 'party'}", v-if='this.user.party._id')
|
||||
a.nav-link(v-once) {{ $t('party') }}
|
||||
.nav-item(@click='openPartyModal()', v-if='!this.user.party._id')
|
||||
a.nav-link(v-once) {{ $t('party') }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'tavern'}", :class="{'active': $route.path.startsWith('/guilds')}")
|
||||
a.nav-link(v-once) {{ $t('guilds') }}
|
||||
@@ -30,15 +32,15 @@ div
|
||||
router-link.dropdown-item(:to="{name: 'tavern'}") {{ $t('tavern') }}
|
||||
router-link.dropdown-item(:to="{name: 'myGuilds'}") {{ $t('myGuilds') }}
|
||||
router-link.dropdown-item(:to="{name: 'guildsDiscovery'}") {{ $t('guildsDiscovery') }}
|
||||
router-link.nav-item.dropdown(
|
||||
tag="li",
|
||||
:to="{name: 'groupPlan'}",
|
||||
:class="{'active': $route.path.startsWith('/group-plan')}")
|
||||
a.nav-link(v-once) {{ $t('group') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(v-for='group in groupPlans', :key='group._id', :to="{name: 'groupPlanDetailTaskInformation', params: {groupId: group._id}}") {{ group.name }}
|
||||
router-link.nav-item(tag="li", :to="{name: 'myChallenges'}", exact)
|
||||
.nav-item.dropdown(tag="li", :class="{'active': $route.path.startsWith('/group-plans')}")
|
||||
a.nav-link(v-once) {{ $t('group') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(v-for='group in groupPlans', :key='group._id', :to="{name: 'groupPlanDetailTaskInformation', params: {groupId: group._id}}") {{ group.name }}
|
||||
router-link.nav-item.dropdown(tag="li", :to="{name: 'myChallenges'}", :class="{'active': $route.path.startsWith('/challenges')}")
|
||||
a.nav-link(v-once) {{ $t('challenges') }}
|
||||
.dropdown-menu
|
||||
router-link.dropdown-item(:to="{name: 'myChallenges'}") {{ $t('myChallenges') }}
|
||||
router-link.dropdown-item(:to="{name: 'findChallenges'}") {{ $t('findChallenges') }}
|
||||
router-link.nav-item.dropdown(tag="li", to="/help", :class="{'active': $route.path.startsWith('/help')}", :to="{name: 'faq'}")
|
||||
a.nav-link(v-once) {{ $t('help') }}
|
||||
.dropdown-menu
|
||||
@@ -57,10 +59,10 @@ div
|
||||
span {{userGems | roundBigNumber}}
|
||||
.item-with-icon
|
||||
.svg-icon(v-html="icons.gold")
|
||||
span {{user.stats.gp | roundBigNumber}}
|
||||
span {{Math.floor(user.stats.gp * 100) / 100}}
|
||||
notification-menu
|
||||
a.dropdown.item-with-icon.item-user
|
||||
.svg-icon(v-html="icons.user")
|
||||
.svg-icon.user(v-html="icons.user")
|
||||
.dropdown-menu.dropdown-menu-right.user-dropdown
|
||||
a.dropdown-item.edit-avatar.dropdown-separated(@click='showAvatar()')
|
||||
h3 {{ user.profile.name }}
|
||||
@@ -173,11 +175,12 @@ div
|
||||
padding-left: 16px;
|
||||
|
||||
.svg-icon {
|
||||
vertical-align: middle;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
vertical-align: bottom;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
float: left;
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,13 +190,13 @@ div
|
||||
color: $header-color;
|
||||
transition: none;
|
||||
|
||||
&:hover {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 0px;
|
||||
color: $white;
|
||||
color: $header-color;
|
||||
|
||||
&:hover {
|
||||
color: $white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +279,9 @@ export default {
|
||||
async getUserGroupPlans () {
|
||||
this.groupPlans = await this.$store.dispatch('guilds:getGroupPlans');
|
||||
},
|
||||
openPartyModal () {
|
||||
this.$root.$emit('show::modal', 'create-party-modal');
|
||||
},
|
||||
showBuyGemsModal () {
|
||||
this.$root.$emit('show::modal', 'buy-gems');
|
||||
},
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
#top-background
|
||||
.seamless_stars_varied_opacity_repeat
|
||||
|
||||
form#login-form(v-on:submit.prevent='handleSubmit', @keyup.enter="handleSubmit")
|
||||
form#login-form(v-on:submit.prevent='handleSubmit', @keyup.enter="handleSubmit", v-if='!forgotPassword')
|
||||
.text-center
|
||||
div
|
||||
.svg-icon.gryphon(v-html="icons.gryphon")
|
||||
.svg-icon.gryphon
|
||||
div
|
||||
.svg-icon.habitica-logo(v-html="icons.habiticaIcon")
|
||||
.form-group.row.text-center
|
||||
@@ -29,6 +29,7 @@
|
||||
input#emailInput.form-control(type='email', :placeholder='$t("emailPlaceholder")', v-model='email')
|
||||
.form-group
|
||||
label(for='passwordInput', v-once) {{$t('password')}}
|
||||
a.float-right.forgot-password(v-once, v-if='!registering', @click='forgotPassword = true') {{$t('forgotPassword')}}
|
||||
input#passwordInput.form-control(type='password', :placeholder='$t("passwordPlaceholder")', v-model='password')
|
||||
.form-group(v-if='registering')
|
||||
label(for='confirmPasswordInput', v-once) {{$t('confirmPassword')}}
|
||||
@@ -43,6 +44,21 @@
|
||||
router-link(:to="{name: 'register'}", v-if='!registering', exact)
|
||||
a.toggle-link(v-once) Don't have an account? Join Habitica!
|
||||
|
||||
form#forgot-form(v-on:submit.prevent='handleSubmit', @keyup.enter="handleSubmit", v-if='forgotPassword')
|
||||
.text-center
|
||||
div
|
||||
.svg-icon.gryphon
|
||||
div
|
||||
.svg-icon.habitica-logo(v-html="icons.habiticaIcon")
|
||||
.header
|
||||
h2 Email a Password Reset Link
|
||||
p Enter the email address you used to register your Habitica account.
|
||||
.form-group.row.text-center
|
||||
label(for='usernameInput', v-once) {{$t('email')}}
|
||||
input#usernameInput.form-control(type='text', :placeholder='$t("emailPlaceholder")', v-model='username')
|
||||
.text-center
|
||||
.btn.btn-info(@click='forgotPasswordLink()', v-once) {{$t('sendLink')}}
|
||||
|
||||
#bottom-wrap
|
||||
#bottom-background
|
||||
.seamless_mountains_demo_repeat
|
||||
@@ -56,6 +72,7 @@
|
||||
|
||||
small a {
|
||||
color: #fff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -85,7 +102,7 @@
|
||||
color: $purple-400;
|
||||
}
|
||||
|
||||
#login-form {
|
||||
#login-form, #forgot-form {
|
||||
margin: 0 auto;
|
||||
width: 40em;
|
||||
padding-top: 5em;
|
||||
@@ -93,9 +110,20 @@
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.header {
|
||||
|
||||
h2 {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.gryphon {
|
||||
background-image: url('~assets/images/melior@3x.png');
|
||||
width: 63.2px;
|
||||
height: 69.4px;
|
||||
background-size: cover;
|
||||
color: $white;
|
||||
margin: 0 auto;
|
||||
}
|
||||
@@ -188,9 +216,14 @@
|
||||
.toggle-link {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
color: #bda8ff !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import hello from 'hellojs';
|
||||
|
||||
import gryphon from 'assets/svg/gryphon.svg';
|
||||
@@ -205,6 +238,7 @@ export default {
|
||||
email: '',
|
||||
password: '',
|
||||
passwordConfirm: '',
|
||||
forgotPassword: false,
|
||||
};
|
||||
|
||||
data.icons = Object.freeze({
|
||||
@@ -282,8 +316,25 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.forgotPassword) {
|
||||
this.forgotPasswordLink();
|
||||
return;
|
||||
}
|
||||
|
||||
this.login();
|
||||
},
|
||||
async forgotPasswordLink () {
|
||||
if (!this.username) {
|
||||
alert('Email is required');
|
||||
return;
|
||||
}
|
||||
|
||||
await axios.post('/api/v3/user/reset-password', {
|
||||
email: this.username,
|
||||
});
|
||||
|
||||
alert(this.$t('newPassSent'));
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -250,13 +250,17 @@ export default {
|
||||
this.tasksByType[task.type].splice(index, 1, task);
|
||||
},
|
||||
showMemberModal () {
|
||||
this.$store.state.groupId = 'challenge'; // @TODO: change these terrible settings
|
||||
this.$store.state.viewingMembers = this.members;
|
||||
this.$store.state.memberModalOptions.groupId = 'challenge'; // @TODO: change these terrible settings
|
||||
this.$store.state.memberModalOptions.group = this.group;
|
||||
this.$store.state.memberModalOptions.viewingMembers = this.members;
|
||||
this.$root.$emit('show::modal', 'members-modal');
|
||||
},
|
||||
async joinChallenge () {
|
||||
this.user.challenges.push(this.challengeId);
|
||||
await this.$store.dispatch('challenges:joinChallenge', {challengeId: this.challengeId});
|
||||
// @TODO: this doesn't work because of asyncresource
|
||||
let tasks = await this.$store.dispatch('tasks:fetchUserTasks');
|
||||
this.$store.state.tasks.data = tasks.data;
|
||||
},
|
||||
async leaveChallenge () {
|
||||
let keepChallenge = confirm('Do you want to keep challenge tasks?');
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
div Challenge Prize
|
||||
.row.description
|
||||
.col-12
|
||||
| {{challenge.description}}
|
||||
| {{challenge.summary}}
|
||||
.well.row
|
||||
.col-3
|
||||
.count-details
|
||||
@@ -104,7 +104,8 @@
|
||||
|
||||
.description {
|
||||
color: $gray-200;
|
||||
margin-bottom: 2em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,9 +34,12 @@
|
||||
.form-check(
|
||||
v-for="group in categoryOptions",
|
||||
:key="group.key",
|
||||
v-if='group.key !== "habitica_official" || user.contributor.admin'
|
||||
)
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type="checkbox", :value="group.key" v-model="workingChallenge.categories")
|
||||
input.custom-control-input(type="checkbox",
|
||||
:value='group.key',
|
||||
v-model="workingChallenge.categories")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t(group.label) }}
|
||||
button.btn.btn-primary(@click.prevent="toggleCategorySelect") {{$t('close')}}
|
||||
@@ -47,7 +50,7 @@
|
||||
.form-group
|
||||
label
|
||||
strong(v-once) {{$t('prize')}}
|
||||
input(type='number', min='1', :max='maxPrize', v-model="workingChallenge.prize")
|
||||
input(type='number', :min='minPrize', :max='maxPrize', v-model="workingChallenge.prize")
|
||||
.row.footer-wrap
|
||||
.col-12.text-center.submit-button-wrapper
|
||||
.alert.alert-warning(v-if='insufficientGemsForTavernChallenge')
|
||||
@@ -220,6 +223,13 @@ export default {
|
||||
if (this.challenge) {
|
||||
Object.assign(this.workingChallenge, this.challenge);
|
||||
this.workingChallenge.categories = [];
|
||||
|
||||
if (this.challenge.categories) {
|
||||
this.challenge.categories.forEach(category => {
|
||||
this.workingChallenge.categories.push(category.slug);
|
||||
});
|
||||
}
|
||||
|
||||
this.creating = false;
|
||||
}
|
||||
});
|
||||
@@ -230,6 +240,7 @@ export default {
|
||||
this.groups.push({
|
||||
name: party.name,
|
||||
_id: party._id,
|
||||
privacy: 'private',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -256,7 +267,13 @@ export default {
|
||||
userBalance = userBalance * 4;
|
||||
|
||||
let groupBalance = 0;
|
||||
let group = find(this.groups, { _id: this.workingChallenge.group });
|
||||
let group;
|
||||
this.groups.forEach(item => {
|
||||
if (item._id === this.workingChallenge.group) {
|
||||
group = item;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (group && group.balance && group.leader === this.user._id) {
|
||||
groupBalance = group.balance * 4;
|
||||
@@ -264,6 +281,18 @@ export default {
|
||||
|
||||
return userBalance + groupBalance;
|
||||
},
|
||||
minPrize () {
|
||||
let groupFound;
|
||||
this.groups.forEach(group => {
|
||||
if (group._id === this.workingChallenge.group) {
|
||||
groupFound = group;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
if (groupFound && groupFound.privacy === 'private') return 0;
|
||||
return 1;
|
||||
},
|
||||
insufficientGemsForTavernChallenge () {
|
||||
let balance = this.user.balance || 0;
|
||||
let isForTavern = this.workingChallenge.group === TAVERN_ID;
|
||||
@@ -320,6 +349,17 @@ export default {
|
||||
}
|
||||
},
|
||||
updateChallenge () {
|
||||
let categoryKeys = this.workingChallenge.categories;
|
||||
let serverCategories = [];
|
||||
categoryKeys.forEach(key => {
|
||||
let catName = this.categoriesHashByKey[key];
|
||||
serverCategories.push({
|
||||
slug: key,
|
||||
name: catName,
|
||||
});
|
||||
});
|
||||
this.workingChallenge.categories = serverCategories;
|
||||
|
||||
this.$emit('updatedChallenge', {
|
||||
challenge: this.workingChallenge,
|
||||
});
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
span.action(v-if='msg.uuid === user._id', @click='remove(msg, index)')
|
||||
.svg-icon(v-html="icons.delete")
|
||||
| {{$t('delete')}}
|
||||
span.action.float-right
|
||||
span.action.float-right(v-if='likeCount(msg) > 0')
|
||||
.svg-icon(v-html="icons.liked")
|
||||
| + {{ likeCount(msg) }}
|
||||
.row(v-if='user._id === msg.uuid')
|
||||
@@ -58,7 +58,7 @@
|
||||
span.action(v-if='msg.uuid === user._id', @click='remove(msg, index)')
|
||||
.svg-icon(v-html="icons.delete")
|
||||
| {{$t('delete')}}
|
||||
span.action.float-right
|
||||
span.action.float-right(v-if='likeCount(msg) > 0')
|
||||
.svg-icon(v-html="icons.liked")
|
||||
| + {{ likeCount(msg) }}
|
||||
.col-2
|
||||
@@ -128,6 +128,7 @@ import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import throttle from 'lodash/throttle';
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
import Avatar from '../avatar';
|
||||
import styleHelper from 'client/mixins/styleHelper';
|
||||
@@ -155,6 +156,14 @@ export default {
|
||||
mounted () {
|
||||
this.loadProfileCache();
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('scroll', throttle(() => {
|
||||
this.loadProfileCache(window.scrollY / 1000);
|
||||
}, 1000));
|
||||
},
|
||||
destroyed () {
|
||||
// window.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -167,6 +176,8 @@ export default {
|
||||
copyingMessage: {},
|
||||
currentDayDividerDisplay: moment().day(),
|
||||
cachedProfileData: {},
|
||||
currentProfileLoadedCount: 0,
|
||||
currentProfileLoadedEnd: 10,
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
@@ -191,14 +202,22 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async loadProfileCache () {
|
||||
async loadProfileCache (screenPosition) {
|
||||
let promises = [];
|
||||
|
||||
// @TODO: write an explination
|
||||
if (screenPosition && Math.floor(screenPosition) + 1 > this.currentProfileLoadedEnd / 10) {
|
||||
this.currentProfileLoadedEnd = 10 * (Math.floor(screenPosition) + 1);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
this.messages.forEach(message => {
|
||||
let uuid = message.uuid;
|
||||
if (uuid && !this.cachedProfileData[uuid]) {
|
||||
if (uuid === 'system') return;
|
||||
if (uuid === 'system' || this.currentProfileLoadedCount === this.currentProfileLoadedEnd) return;
|
||||
promises.push(axios.get(`/api/v3/members/${uuid}`));
|
||||
this.currentProfileLoadedCount += 1;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -53,8 +53,10 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.slim_shirt_pink.option(@click='set({"preferences.shirt":"pink"})', :class='{active: user.preferences.shirt === "pink"}')
|
||||
.slim_shirt_white.option(@click='set({"preferences.shirt":"white"})', :class='{active: user.preferences.shirt === "white"}')
|
||||
.slim_shirt_yellow.option(@click='set({"preferences.shirt":"yellow"})', :class='{active: user.preferences.shirt === "yellow"}')
|
||||
.col-12.premium-shirts(v-if='editing')
|
||||
.broad_shirt_convict.option(@click='set({"preferences.shirt":"convict"})', :class='{active: user.preferences.shirt === "convict"}')
|
||||
.col-12.customize-options
|
||||
.option(v-for='option in ["convict", "cross", "fire", "horizon", "ocean", "purple", "rainbow", "redblue", "thunder", "tropical", "zombie"]',
|
||||
:class='[`broad_shirt_${option}`, {active: user.preferences.shirt === option}]',
|
||||
@click='set({"preferences.shirt": option})')
|
||||
|
||||
.section.customize-section(v-if='activeTopPage === "skin"')
|
||||
.row.sub-menu.col-6.offset-3.text-center
|
||||
@@ -141,6 +143,13 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
.hair_flower_4.option(@click='set({"preferences.hair.flower":4})', :class='{active: user.preferences.hair.flower === 4}')
|
||||
.hair_flower_5.option(@click='set({"preferences.hair.flower":5})', :class='{active: user.preferences.hair.flower === 5}')
|
||||
.hair_flower_6.option(@click='set({"preferences.hair.flower":6})', :class='{active: user.preferences.hair.flower === 6}')
|
||||
.row(v-if='activeSubPage === "flower"')
|
||||
.col-12.customize-options
|
||||
// button.customize-option(ng-repeat='item in ::getGearArray("animal")', class='{{::item.key}}',
|
||||
ng-class="{locked: user.items.gear.owned[item.key] == undefined, selectableInventory: user.preferences.costume ? user.items.gear.costume.headAccessory == item.key : user.items.gear.equipped.headAccessory == item.key}",
|
||||
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.sub-menu.col-6.offset-3
|
||||
@@ -172,6 +181,7 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
@click.prevent.stop="togglePinned(bg)"
|
||||
)
|
||||
span.svg-icon.inline.icon-12.color(v-html="icons.pin")
|
||||
|
||||
.col-12.text-center(v-if='!ownsSet("background", set.items) && set.identifier !== "incentiveBackgrounds"')
|
||||
.gem-amount
|
||||
.svg-icon.gem(v-html='icons.gem')
|
||||
@@ -215,6 +225,11 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
input.custom-control-input(type="checkbox")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('creativity') }}
|
||||
div
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type="checkbox")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('self_care') }}
|
||||
|
||||
.section.row.justin-message-section(:class='{top: modalPage > 1}')
|
||||
.col-9
|
||||
@@ -401,6 +416,10 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.background:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.purchase-single {
|
||||
width: 141px;
|
||||
margin: 0 auto;
|
||||
@@ -489,7 +508,6 @@ b-modal#avatar-modal(title="", size='lg', :hide-header='true', :hide-footer='tru
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.badge-svg {
|
||||
left: calc((100% - 18px) / 2);
|
||||
cursor: pointer;
|
||||
@@ -559,22 +577,9 @@ export default {
|
||||
data () {
|
||||
let backgroundShopSets = getBackgroundShopSets();
|
||||
|
||||
// @TODO: add dates to backgrounds
|
||||
let backgroundShopSetsByYear = {
|
||||
2014: [],
|
||||
2015: [],
|
||||
2016: [],
|
||||
2017: [],
|
||||
};
|
||||
backgroundShopSets.forEach((set) => {
|
||||
let year = set.identifier.substr(set.identifier.length - 4);
|
||||
if (!backgroundShopSetsByYear[year]) return;
|
||||
backgroundShopSetsByYear[year].push(set);
|
||||
});
|
||||
|
||||
return {
|
||||
backgroundShopSets,
|
||||
backgroundShopSetsByYear,
|
||||
backgroundUpdate: new Date(),
|
||||
icons: Object.freeze({
|
||||
logoPurple,
|
||||
bodyIcon,
|
||||
@@ -610,6 +615,32 @@ export default {
|
||||
startingPage () {
|
||||
return this.$store.state.avatarEditorOptions.startingPage;
|
||||
},
|
||||
backgroundShopSetsByYear () {
|
||||
// @TODO: add dates to backgrounds
|
||||
let backgroundShopSetsByYear = {
|
||||
2014: [],
|
||||
2015: [],
|
||||
2016: [],
|
||||
2017: [],
|
||||
};
|
||||
|
||||
// Hack to force update for now until we restructure the data
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
|
||||
this.backgroundShopSets.forEach((set) => {
|
||||
let year = set.identifier.substr(set.identifier.length - 4);
|
||||
if (!backgroundShopSetsByYear[year]) return;
|
||||
|
||||
let setOwnedByUser = false;
|
||||
for (let key in set.items) {
|
||||
if (this.user.purchased.background[key]) setOwnedByUser = true;
|
||||
}
|
||||
set.userOwns = setOwnedByUser;
|
||||
|
||||
backgroundShopSetsByYear[year].push(set);
|
||||
});
|
||||
return backgroundShopSetsByYear;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
prev () {
|
||||
@@ -654,7 +685,6 @@ export default {
|
||||
for (let key in set) {
|
||||
let value = set[key];
|
||||
if (type === 'background') key = value.key;
|
||||
|
||||
if (this.user.purchased[type][key]) setOwnedByUser = true;
|
||||
}
|
||||
|
||||
@@ -697,6 +727,7 @@ export default {
|
||||
path,
|
||||
},
|
||||
});
|
||||
this.backgroundUpdate = new Date();
|
||||
} catch (e) {
|
||||
alert(e.message);
|
||||
}
|
||||
|
||||
@@ -172,9 +172,10 @@ export default {
|
||||
};
|
||||
group.name = this.$t('possessiveParty', {name: this.user.profile.name});
|
||||
let party = await this.$store.dispatch('guilds:create', {group});
|
||||
this.$store.state.party = party;
|
||||
this.$store.state.party.data = party;
|
||||
this.user.party._id = party._id;
|
||||
this.$root.$emit('hide::modal', 'create-party-modal');
|
||||
this.$router.push('/party');
|
||||
// @TODO: Analytics.updateUser({'partyID': $scope.group ._id, 'partySize': 1});
|
||||
},
|
||||
},
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
|
||||
.sort-select {
|
||||
margin: 2em;
|
||||
}
|
||||
@@ -120,6 +120,7 @@ export default {
|
||||
this.loading = false;
|
||||
},
|
||||
createGroup () {
|
||||
this.$store.state.editingGroup = {};
|
||||
this.$root.$emit('show::modal', 'guild-form');
|
||||
},
|
||||
},
|
||||
|
||||
@@ -578,7 +578,8 @@ export default {
|
||||
this.newMessage = newText;
|
||||
},
|
||||
showMemberModal () {
|
||||
this.$store.state.groupId = this.group._id;
|
||||
this.$store.state.memberModalOptions.groupId = this.group._id;
|
||||
this.$store.state.memberModalOptions.group = this.group;
|
||||
this.$root.$emit('show::modal', 'members-modal');
|
||||
},
|
||||
async sendMessage () {
|
||||
@@ -638,8 +639,7 @@ export default {
|
||||
}
|
||||
},
|
||||
async join () {
|
||||
// @TODO: This needs to be in the notifications where users will now accept invites
|
||||
if (this.group.cancelledPlan && !confirm(window.env.t('aboutToJoinCancelledGroupPlan'))) {
|
||||
if (this.group.cancelledPlan && !confirm(this.$t('aboutToJoinCancelledGroupPlan'))) {
|
||||
return;
|
||||
}
|
||||
await this.$store.dispatch('guilds:join', {guildId: this.group._id, type: 'myGuilds'});
|
||||
@@ -685,11 +685,6 @@ export default {
|
||||
|
||||
await this.$store.dispatch('guilds:join', {groupId: this.group._id});
|
||||
},
|
||||
// @TODO: Move to notificatin component
|
||||
async reject () {
|
||||
await this.$store.dispatch('guilds:rejectInvite', {groupId: this.group._id});
|
||||
// User.sync();
|
||||
},
|
||||
clickStartQuest () {
|
||||
// Analytics.track({'hitType':'event','eventCategory':'button','eventAction':'click','eventLabel':'Start a Quest'});
|
||||
let hasQuests = find(this.user.items.quests, (quest) => {
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
.form-group
|
||||
label
|
||||
strong(v-once) {{$t('name')}} *
|
||||
b-form-input(type="text", :placeholder="$t('newGuildPlaceholder')", v-model="workingGuild.name")
|
||||
.form-group(v-if='workingGuild.id && members.length > 0')
|
||||
b-form-input(type="text", :placeholder="$t('newGuildPlaceholder')", v-model="workingGroup.name")
|
||||
.form-group(v-if='workingGroup.id && members.length > 0')
|
||||
label
|
||||
strong(v-once) {{$t('guildOrPartyLeader')}} *
|
||||
select.form-control(v-model="workingGuild.newLeader")
|
||||
select.form-control(v-model="workingGroup.newLeader")
|
||||
option(v-for='member in members', :value="member._id") {{ member.profile.name }}
|
||||
|
||||
.form-group
|
||||
@@ -16,7 +16,7 @@
|
||||
strong(v-once) {{$t('privacySettings')}} *
|
||||
br
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type="checkbox", v-model="workingGuild.onlyLeaderCreatesChallenges")
|
||||
input.custom-control-input(type="checkbox", v-model="workingGroup.onlyLeaderCreatesChallenges")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('onlyLeaderCreatesChallenges') }}
|
||||
b-tooltip.icon(:content="$t('privateDescription')")
|
||||
@@ -24,13 +24,13 @@
|
||||
|
||||
// br
|
||||
// @TODO Implement in V2 label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type="checkbox", v-model="workingGuild.guildLeaderCantBeMessaged")
|
||||
input.custom-control-input(type="checkbox", v-model="workingGroup.guildLeaderCantBeMessaged")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('guildLeaderCantBeMessaged') }}
|
||||
|
||||
br
|
||||
label.custom-control.custom-checkbox(v-if='!isParty')
|
||||
input.custom-control-input(type="checkbox", v-model="workingGuild.privateGuild")
|
||||
input.custom-control-input(type="checkbox", v-model="workingGroup.privateGuild")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('privateGuild') }}
|
||||
b-tooltip.icon(:content="$t('privateDescription')")
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
// br
|
||||
// @TODO: Implement in v2 label.custom-control.custom-checkbox(v-if='!creatingParty')
|
||||
input.custom-control-input(type="checkbox", v-model="workingGuild.allowGuildInvationsFromNonMembers")
|
||||
input.custom-control-input(type="checkbox", v-model="workingGroup.allowGuildInvationsFromNonMembers")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t('allowGuildInvationsFromNonMembers') }}
|
||||
|
||||
@@ -46,16 +46,16 @@
|
||||
label
|
||||
strong(v-once) {{$t('guildSummary')}} *
|
||||
div.summary-count {{charactersRemaining}} {{ $t('charactersRemaining') }}
|
||||
textarea.form-control.summary-textarea(:placeholder="$t('guildSummaryPlaceholder')", v-model="workingGuild.summary")
|
||||
textarea.form-control.summary-textarea(:placeholder="isParty ? $t('partyDescriptionPlaceHolder') : $t('guildSummaryPlaceholder')", v-model="workingGroup.summary")
|
||||
// @TODO: need summary only for PUBLIC GUILDS, not for tavern, private guilds, or party
|
||||
|
||||
.form-group
|
||||
label
|
||||
strong(v-once) {{$t('groupDescription')}} *
|
||||
a.float-right {{ $t('markdownFormattingHelp') }}
|
||||
b-form-input.description-textarea(type="text", textarea, :placeholder="creatingParty ? $t('partyDescriptionPlaceholder') : $t('guildDescriptionPlaceholder')", v-model="workingGuild.description")
|
||||
b-form-input.description-textarea(type="text", textarea, :placeholder="isParty ? $t('partyDescriptionPlaceholder') : $t('guildDescriptionPlaceholder')", v-model="workingGroup.description")
|
||||
|
||||
.form-group(v-if='creatingParty && !workingGuild.id')
|
||||
.form-group(v-if='creatingParty && !workingGroup.id')
|
||||
span
|
||||
toggleSwitch(:label="$t('inviteMembersNow')", v-model='inviteMembers')
|
||||
|
||||
@@ -63,21 +63,21 @@
|
||||
label
|
||||
strong(v-once) {{$t('categories')}} *
|
||||
div.category-wrap(@click.prevent="toggleCategorySelect")
|
||||
span.category-select(v-if='workingGuild.categories.length === 0') {{$t('none')}}
|
||||
.category-label(v-for='category in workingGuild.categories') {{$t(categoriesHashByKey[category])}}
|
||||
span.category-select(v-if='workingGroup.categories.length === 0') {{$t('none')}}
|
||||
.category-label(v-for='category in workingGroup.categories') {{$t(categoriesHashByKey[category])}}
|
||||
.category-box(v-if="showCategorySelect")
|
||||
.form-check(
|
||||
v-for="group in categoryOptions",
|
||||
:key="group.key",
|
||||
)
|
||||
label.custom-control.custom-checkbox
|
||||
input.custom-control-input(type="checkbox", :value="group.key", v-model="workingGuild.categories")
|
||||
input.custom-control-input(type="checkbox", :value="group.key", v-model="workingGroup.categories")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t(group.label) }}
|
||||
button.btn.btn-primary(@click.prevent="toggleCategorySelect") {{$t('close')}}
|
||||
// @TODO: need categories only for PUBLIC GUILDS, not for tavern, private guilds, or party
|
||||
|
||||
.form-group(v-if='inviteMembers && !workingGuild.id')
|
||||
.form-group(v-if='inviteMembers && !workingGroup.id')
|
||||
label
|
||||
strong(v-once) Invite via Email or User ID
|
||||
p(v-once) {{$t('inviteMembersHowTo')}} *
|
||||
@@ -91,12 +91,12 @@
|
||||
button(@click.prevent='addMemberToInvite()') Add
|
||||
|
||||
.form-group.text-center
|
||||
div.item-with-icon(v-if='!this.workingGuild.id')
|
||||
div.item-with-icon(v-if='!this.workingGroup.id')
|
||||
.svg-icon(v-html="icons.gem")
|
||||
span.count 4
|
||||
button.btn.btn-primary.btn-md(v-if='!workingGuild.id', :disabled='!workingGuild.name || !workingGuild.description') {{ creatingParty ? $t('createParty') : $t('createGuild') }}
|
||||
button.btn.btn-primary.btn-md(v-if='workingGuild.id', :disabled='!workingGuild.name || !workingGuild.description') {{ isParty ? $t('updateParty') : $t('updateGuild') }}
|
||||
.gem-description(v-once, v-if='!this.workingGuild.id') {{ $t('guildGemCostInfo') }}
|
||||
button.btn.btn-primary.btn-md(v-if='!workingGroup.id', :disabled='!workingGroup.name || !workingGroup.description') {{ creatingParty ? $t('createParty') : $t('createGuild') }}
|
||||
button.btn.btn-primary.btn-md(v-if='workingGroup.id', :disabled='!workingGroup.name || !workingGroup.description') {{ isParty ? $t('updateParty') : $t('updateGuild') }}
|
||||
.gem-description(v-once, v-if='!this.workingGroup.id') {{ $t('guildGemCostInfo') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -187,7 +187,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
let data = {
|
||||
workingGuild: {
|
||||
workingGroup: {
|
||||
id: '',
|
||||
name: '',
|
||||
type: 'guild',
|
||||
@@ -286,25 +286,34 @@ export default {
|
||||
// @TODO: do we need this? Maybe us computed. If we need, then make it on show a specific modal
|
||||
this.$root.$on('shown::modal', () => {
|
||||
let editingGroup = this.$store.state.editingGroup;
|
||||
if (!editingGroup._id) return;
|
||||
this.workingGuild.name = editingGroup.name;
|
||||
this.workingGuild.type = editingGroup.type;
|
||||
this.workingGuild.privacy = editingGroup.privacy;
|
||||
if (editingGroup.summary) this.workingGuild.summary = editingGroup.summary;
|
||||
if (editingGroup.description) this.workingGuild.description = editingGroup.description;
|
||||
if (editingGroup._id) this.workingGuild.id = editingGroup._id;
|
||||
if (editingGroup.leader._id) this.workingGuild.newLeader = editingGroup.leader._id;
|
||||
if (!editingGroup._id) {
|
||||
this.resetWorkingGroup();
|
||||
return;
|
||||
}
|
||||
|
||||
this.workingGroup.name = editingGroup.name;
|
||||
this.workingGroup.type = editingGroup.type;
|
||||
|
||||
this.workingGroup.privateGuild = true;
|
||||
if (editingGroup.privacy === 'public') {
|
||||
this.workingGroup.privateGuild = false;
|
||||
}
|
||||
|
||||
if (editingGroup.summary) this.workingGroup.summary = editingGroup.summary;
|
||||
if (editingGroup.description) this.workingGroup.description = editingGroup.description;
|
||||
if (editingGroup._id) this.workingGroup.id = editingGroup._id;
|
||||
if (editingGroup.leader._id) this.workingGroup.newLeader = editingGroup.leader._id;
|
||||
if (editingGroup._id) this.getMembers();
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
charactersRemaining () {
|
||||
let currentLength = this.workingGuild.summary ? this.workingGuild.summary.length : 0;
|
||||
let currentLength = this.workingGroup.summary ? this.workingGroup.summary.length : 0;
|
||||
return MAX_SUMMARY_SIZE_FOR_GUILDS - currentLength;
|
||||
},
|
||||
title () {
|
||||
if (this.creatingParty) return this.$t('createParty');
|
||||
if (!this.workingGuild.id) return this.$t('createGuild');
|
||||
if (!this.workingGroup.id) return this.$t('createGuild');
|
||||
if (this.isParty) return this.$t('updateParty');
|
||||
return this.$t('updateGuild');
|
||||
},
|
||||
@@ -312,14 +321,14 @@ export default {
|
||||
return this.$store.state.groupFormOptions.createParty;
|
||||
},
|
||||
isParty () {
|
||||
return this.workingGuild.type === 'party';
|
||||
return this.workingGroup.type === 'party';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async getMembers () {
|
||||
if (!this.workingGuild.id) return;
|
||||
if (!this.workingGroup.id) return;
|
||||
let members = await this.$store.dispatch('members:getGroupMembers', {
|
||||
groupId: this.workingGuild.id,
|
||||
groupId: this.workingGroup.id,
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
this.members = members;
|
||||
@@ -339,51 +348,51 @@ export default {
|
||||
this.showCategorySelect = !this.showCategorySelect;
|
||||
},
|
||||
async submit () {
|
||||
if (this.$store.state.user.data.balance < 1 && !this.workingGuild.id) {
|
||||
if (this.$store.state.user.data.balance < 1 && !this.workingGroup.id) {
|
||||
// @TODO: Add proper notifications
|
||||
alert('Not enough gems');
|
||||
return;
|
||||
// @TODO return $rootScope.openModal('buyGems', {track:"Gems > Create Group"});
|
||||
}
|
||||
|
||||
if (!this.workingGuild.name || !this.workingGuild.description) {
|
||||
if (!this.workingGroup.name || !this.workingGroup.description) {
|
||||
// @TODO: Add proper notifications - split this out into two, make errors translatable. Suggestion: `<% fieldName %> is required` for all errors where possible, where `fieldName` is inserted as the translatable string that's used for the field header.
|
||||
alert('Enter a name and description');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.workingGuild.summary) {
|
||||
if (!this.workingGroup.summary) {
|
||||
// @TODO: Add proper notifications. Summary is mandatory for only public guilds (not tavern, private guilds, parties)
|
||||
alert('Enter a summary');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.workingGuild.summary.length > MAX_SUMMARY_SIZE_FOR_GUILDS) {
|
||||
if (this.workingGroup.summary.length > MAX_SUMMARY_SIZE_FOR_GUILDS) {
|
||||
// @TODO: Add proper notifications. Summary is mandatory for only public guilds (not tavern, private guilds, parties)
|
||||
alert('Summary is too long');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.workingGuild.categories || this.workingGuild.categories.length === 0) {
|
||||
if (!this.workingGroup.categories || this.workingGroup.categories.length === 0) {
|
||||
// @TODO: Add proper notifications
|
||||
alert('One or more categories must be selected');
|
||||
return;
|
||||
}
|
||||
|
||||
// @TODO: Add proper notifications
|
||||
if (!this.workingGuild.id && !confirm(this.$t('confirmGuild'))) return;
|
||||
if (!this.workingGroup.id && !confirm(this.$t('confirmGuild'))) return;
|
||||
|
||||
if (!this.workingGuild.privateGuild) {
|
||||
this.workingGuild.privacy = 'public';
|
||||
if (!this.workingGroup.privateGuild) {
|
||||
this.workingGroup.privacy = 'public';
|
||||
}
|
||||
|
||||
if (!this.workingGuild.onlyLeaderCreatesChallenges) {
|
||||
this.workingGuild.leaderOnly = {
|
||||
if (!this.workingGroup.onlyLeaderCreatesChallenges) {
|
||||
this.workingGroup.leaderOnly = {
|
||||
challenges: true,
|
||||
};
|
||||
}
|
||||
|
||||
let categoryKeys = this.workingGuild.categories;
|
||||
let categoryKeys = this.workingGroup.categories;
|
||||
let serverCategories = [];
|
||||
categoryKeys.forEach(key => {
|
||||
let catName = this.categoriesHashByKey[key];
|
||||
@@ -392,22 +401,22 @@ export default {
|
||||
name: catName,
|
||||
});
|
||||
});
|
||||
this.workingGuild.categories = serverCategories;
|
||||
this.workingGroup.categories = serverCategories;
|
||||
|
||||
let newgroup;
|
||||
if (this.workingGuild.id) {
|
||||
await this.$store.dispatch('guilds:update', {group: this.workingGuild});
|
||||
this.$root.$emit('updatedGroup', this.workingGuild);
|
||||
if (this.workingGroup.id) {
|
||||
await this.$store.dispatch('guilds:update', {group: this.workingGroup});
|
||||
this.$root.$emit('updatedGroup', this.workingGroup);
|
||||
// @TODO: this doesn't work because of the async resource
|
||||
// if (updatedGroup.type === 'party') this.$store.state.party = {data: updatedGroup};
|
||||
} else {
|
||||
newgroup = await this.$store.dispatch('guilds:create', {group: this.workingGuild});
|
||||
newgroup = await this.$store.dispatch('guilds:create', {group: this.workingGroup});
|
||||
this.$store.state.user.data.balance -= 1;
|
||||
}
|
||||
|
||||
this.$store.state.editingGroup = {};
|
||||
|
||||
this.workingGuild = {
|
||||
this.workingGroup = {
|
||||
name: '',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
@@ -424,6 +433,19 @@ export default {
|
||||
}
|
||||
this.$root.$emit('hide::modal', 'guild-form');
|
||||
},
|
||||
resetWorkingGroup () {
|
||||
this.workingGroup = {
|
||||
name: '',
|
||||
type: 'guild',
|
||||
privacy: 'private',
|
||||
description: '',
|
||||
categories: [],
|
||||
onlyLeaderCreatesChallenges: true,
|
||||
guildLeaderCantBeMessaged: true,
|
||||
privateGuild: true,
|
||||
allowGuildInvationsFromNonMembers: true,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -19,24 +19,24 @@ div
|
||||
.col-8.offset-1
|
||||
member-details(:member='member')
|
||||
.col-3.actions
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
b-dropdown(text="...", right=true)
|
||||
b-dropdown-item(@click='sort(option.value)', v-if='isLeader')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon")
|
||||
.svg-icon.inline(v-html="icons.removeIcon", v-if='isLeader')
|
||||
span.text {{$t('removeMember')}}
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.messageIcon")
|
||||
span.text {{$t('sendMessage')}}
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
b-dropdown-item(@click='sort(option.value)', v-if='isLeader')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.starIcon")
|
||||
span.text {{$t('promoteToLeader')}}
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
b-dropdown-item(@click='sort(option.value)', v-if='isLeader && groupIsSubscribed')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.starIcon")
|
||||
span.text {{$t('addManager')}}
|
||||
b-dropdown-item(@click='sort(option.value)')
|
||||
b-dropdown-item(@click='sort(option.value)', v-if='isLeader && groupIsSubscribed')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon")
|
||||
span.text {{$t('removeManager2')}}
|
||||
@@ -109,6 +109,7 @@ import sortBy from 'lodash/sortBy';
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
|
||||
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
import MemberDetails from '../memberDetails';
|
||||
import removeIcon from 'assets/members/remove.svg';
|
||||
@@ -116,7 +117,7 @@ import messageIcon from 'assets/members/message.svg';
|
||||
import starIcon from 'assets/members/star.svg';
|
||||
|
||||
export default {
|
||||
props: ['group', 'hideBadge'],
|
||||
props: ['hideBadge'],
|
||||
components: {
|
||||
bModal,
|
||||
bDropdown,
|
||||
@@ -160,6 +161,16 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
isLeader () {
|
||||
return this.user._id === this.group.leader || this.user._id === this.group.leader._id;
|
||||
},
|
||||
groupIsSubscribed () {
|
||||
return this.group.purchased.active;
|
||||
},
|
||||
group () {
|
||||
return this.$store.state.memberModalOptions.group;
|
||||
},
|
||||
sortedMembers () {
|
||||
let sortedMembers = this.members;
|
||||
if (!this.sortOption) return sortedMembers;
|
||||
@@ -182,7 +193,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async getMembers () {
|
||||
let groupId = this.$store.state.groupId || this.group._id;
|
||||
let groupId = this.$store.state.memberModalOptions.groupId || this.group._id;
|
||||
if (groupId && groupId !== 'challenge') {
|
||||
let members = await this.$store.dispatch('members:getGroupMembers', {
|
||||
groupId,
|
||||
@@ -191,7 +202,7 @@ export default {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
if (this.$store.state.viewingMembers.length > 0) {
|
||||
if (this.$store.state.memberModalOptions.viewingMembers.length > 0) {
|
||||
this.members = this.$store.state.viewingMembers;
|
||||
}
|
||||
},
|
||||
|
||||
@@ -136,6 +136,7 @@ export default {
|
||||
this.loading = false;
|
||||
},
|
||||
createGroup () {
|
||||
this.$store.state.editingGroup = {};
|
||||
this.$root.$emit('show::modal', 'guild-form');
|
||||
},
|
||||
},
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
.col-md-4.sidebar
|
||||
.section
|
||||
.grassy-meadow-backdrop
|
||||
.daniel_front
|
||||
|
||||
.sleep.below-header-sections
|
||||
strong(v-once) {{ $t('sleepDescription') }}
|
||||
@@ -196,12 +197,21 @@
|
||||
}
|
||||
|
||||
.grassy-meadow-backdrop {
|
||||
background-image: url('~assets/images/tavern_backdrop_web.png');
|
||||
background-size: cover;
|
||||
background-image: url('~assets/images/tavern_backdrop_web_backgroundtile.png');
|
||||
background-repeat: repeat-x;
|
||||
width: 100%;
|
||||
height: 246px;
|
||||
}
|
||||
|
||||
.daniel_front {
|
||||
background-image: url('~assets/images/tavern_backdrop_web_daniel_and_props.png');
|
||||
width: 100%;
|
||||
height: 246px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.sleep {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template lang="pug">
|
||||
.item-with-icon.item-notifications.dropdown
|
||||
.svg-icon(v-html="icons.notifications")
|
||||
div.item-with-icon.item-notifications.dropdown
|
||||
.svg-icon.notifications(v-html="icons.notifications")
|
||||
// span.glyphicon(:class='iconClasses()')
|
||||
// span.notification-counter(v-if='getNotificationsCount()') {{getNotificationsCount()}}
|
||||
.dropdown-menu.dropdown-menu-right.user-dropdown
|
||||
@@ -9,24 +9,32 @@
|
||||
a.dropdown-item(v-if='user.purchased.plan.mysteryItems.length', @click='go("/inventory/items")')
|
||||
span.glyphicon.glyphicon-gift
|
||||
span {{ $t('newSubscriberItem') }}
|
||||
a.dropdown-item(v-for='party in user.invitations.parties', @click='go("/party")')
|
||||
span.glyphicon.glyphicon-user
|
||||
span {{ $t('invitedTo', {name: party.name}) }}
|
||||
a.dropdown-item(v-for='party in user.invitations.parties')
|
||||
div
|
||||
span.glyphicon.glyphicon-user
|
||||
span {{ $t('invitedTo', {name: party.name}) }}
|
||||
div
|
||||
span(@click='accept(party)') Accept
|
||||
span(@click='reject(party)') Reject
|
||||
a.dropdown-item(v-if='user.flags.cardReceived', @click='go("/inventory/items")')
|
||||
span.glyphicon.glyphicon-envelope
|
||||
span {{ $t('cardReceived') }}
|
||||
a.dropdown-item(@click='clearCards()', :popover="$t('clear')",
|
||||
popover-placement='right', popover-trigger='mouseenter', popover-append-to-body='true')
|
||||
a.dropdown-item(v-for='guild in user.invitations.guilds', @click='go("/groups/discovery")')
|
||||
span.glyphicon.glyphicon-user
|
||||
span {{ $t('invitedTo', {name: guild.name}) }}
|
||||
a.dropdown-item(v-for='guild in user.invitations.guilds')
|
||||
div
|
||||
span.glyphicon.glyphicon-user
|
||||
span {{ $t('invitedTo', {name: guild.name}) }}
|
||||
div
|
||||
span(@click='accept(guild)') Accept
|
||||
span(@click='reject(guild)') Reject
|
||||
a.dropdown-item(v-if='user.flags.classSelected && !user.preferences.disableClasses && user.stats.points',
|
||||
@click='go("/user/profile")')
|
||||
span.glyphicon.glyphicon-plus-sign
|
||||
span {{ $t('haveUnallocated', {points: user.stats.points}) }}
|
||||
a.dropdown-item(v-for='(k,v) in user.newMessages', v-if='v.value', @click='navigateToGroup(k)')
|
||||
a.dropdown-item(v-for='(message, key) in user.newMessages', v-if='message.value', @click='navigateToGroup(key)')
|
||||
span.glyphicon.glyphicon-comment
|
||||
span {{v.name}}
|
||||
span {{message.name}}
|
||||
a.dropdown-item(@click='clearMessages(k)', :popover="$t('clear')", popover-placement='right', popover-trigger='mouseenter',popover-append-to-body='true')
|
||||
a.dropdown-item(v-for='(notification, index) in user.groupNotifications', @click='viewGroupApprovalNotification(notification, index, true)')
|
||||
span(:class="groupApprovalNotificationIcon(notification)")
|
||||
@@ -42,14 +50,25 @@
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
.svg-icon {
|
||||
width: 25px;
|
||||
|
||||
.item-notifications {
|
||||
width: 44px;
|
||||
}
|
||||
|
||||
.item-notifications:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.notifications {
|
||||
vertical-align: bottom;
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
margin-left: 8px;
|
||||
margin-top: .2em;
|
||||
}
|
||||
|
||||
/* @TODO: Move to shared css */
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
@@ -231,7 +250,7 @@ export default {
|
||||
// @TODO: USe notifications: User.readNotification(notification.id);
|
||||
this.user.groupNotifications.splice(index, 1);
|
||||
return navigate; // @TODO: remove
|
||||
// @TODO: this.$route.go if (navigate) go('options.social.guilds.detail', {gid: notification.data.groupId});
|
||||
// @TODO: this.$router.go if (navigate) go('options.social.guilds.detail', {gid: notification.data.groupId});
|
||||
},
|
||||
groupApprovalNotificationIcon (notification) {
|
||||
if (notification.type === 'GROUP_TASK_APPROVAL') {
|
||||
@@ -241,7 +260,7 @@ export default {
|
||||
}
|
||||
},
|
||||
go (path) {
|
||||
this.$route.push(path);
|
||||
this.$router.push(path);
|
||||
},
|
||||
navigateToGroup (key) {
|
||||
if (key === this.party._id || key === this.user.party._id) {
|
||||
@@ -250,6 +269,18 @@ export default {
|
||||
}
|
||||
this.go(`/groups/guild/${key}`);
|
||||
},
|
||||
async reject (group) {
|
||||
await this.$store.dispatch('guilds:rejectInvite', {groupId: group.id});
|
||||
// @TODO: User.sync();
|
||||
},
|
||||
async accept (group) {
|
||||
if (group.cancelledPlan && !confirm(this.$t('aboutToJoinCancelledGroupPlan'))) {
|
||||
return;
|
||||
}
|
||||
// @TODO: check for party , type: 'myGuilds'
|
||||
await this.$store.dispatch('guilds:join', {guildId: group.id});
|
||||
// this.user.guilds.push(this.group._id);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,112 +1,111 @@
|
||||
<template lang="pug">
|
||||
b-modal#buy-gems(title="Amazon", :hide-footer="true", size='lg')
|
||||
b-modal#buy-gems(title="Buy Gems", :hide-footer="true", size='lg')
|
||||
.modal-body
|
||||
.buy-gems
|
||||
// @TODO: +gemButton(true)
|
||||
div(v-if='userReachedGemCap')
|
||||
h2 {{ $t('buyGemsGold') }}
|
||||
p {{ $t('maxBuyGems') }}
|
||||
|
||||
div(ng-if='user.purchased.plan.customerId && (user.purchased.plan.gemsBought >= User.user.purchased.plan.consecutive.gemCapExtra + Shared.planGemLimits.convCap)')
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
h3 {{ $t('buyGemsGold') }}
|
||||
p {{ $t('maxBuyGems') }}
|
||||
.row(v-if='!userReachedGemCap')
|
||||
.col-12
|
||||
h2 {{ $t('buyGemsGold') }}
|
||||
p {{ $t('subGemPop') }}
|
||||
|
||||
div(ng-if='user.purchased.plan.customerId && (user.purchased.plan.gemsBought < User.user.purchased.plan.consecutive.gemCapExtra + Shared.planGemLimits.convCap)')
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
h3 {{ $t('buyGemsGold') }}
|
||||
p {{ $t('subGemPop') }}
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-3
|
||||
button.customize-option(ng-click='User.purchase({params:{type:"gems",key:"gem"}})')
|
||||
span.Pet_Currency_Gem.inline-gems
|
||||
// @TODO: .badge.badge-success.stack-count {{Shared.planGemLimits.convCap + User.user.purchased.plan.consecutive.gemCapExtra - User.user.purchased.plan.gemsBought}}
|
||||
.col-4
|
||||
button.btn.btn-primary(@click='purchase({ params: {type: "gems", key: "gem"} })')
|
||||
| Buy Gems for 20 Gold each
|
||||
span.Pet_Currency_Gem.inline-gems
|
||||
.badge.badge-success.stack-count {{planGemLimits.convCap + user.purchased.plan.consecutive.gemCapExtra - user.purchased.plan.gemsBought}}
|
||||
.col-8
|
||||
p {{ $t('buyGemsAllow1') }}
|
||||
| {{planGemLimits.convCap + user.purchased.plan.consecutive.gemCapExtra - user.purchased.plan.gemsBought}}
|
||||
| {{ $t('buyGemsAllow2') }}
|
||||
.col-12
|
||||
p(v-html="$t('seeSubscriptionDetails')")
|
||||
|
||||
.row(v-if='user.purchased.plan.customerId')
|
||||
.col-12
|
||||
h2 {{ $t('purchaseGemsSeparately') }}
|
||||
.col-12.alert.alert-info
|
||||
| $5 {{ $t('USD') }} = +20
|
||||
.col-12
|
||||
h3 {{ $t('paymentMethods') }}
|
||||
button.purchase.btn.btn-primary(ng-click='Payments.showStripe({})') {{ $t('card') }}
|
||||
a.purchase(href='/paypal/checkout?_id=${user._id}&apiToken=${User.settings.auth.apiToken}')
|
||||
img(src='https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png',alt='Pay now with Paypal')
|
||||
a.purchase(ng-click="Payments.amazonPayments.init({type: 'single'})")
|
||||
img(src='https://payments.amazon.com/gp/cba/button', alt='Pay now with Amazon Payments')
|
||||
|
||||
.row(v-if='!user.purchased.plan.customerId')
|
||||
.col-12
|
||||
h2 {{ $t('purchaseGems') }}
|
||||
.small
|
||||
span.dashed-underline(popover="$t('donateText3')", popover-trigger='mouseenter', popover-placement='bottom')
|
||||
| $5 {{ $t('USD') }}
|
||||
span#TotalGemPrice.dashed-underline(popover="$t('donateText1')",
|
||||
popover-trigger='mouseenter', ement='bottom')
|
||||
| +20
|
||||
span(class="Pet_Currency_Gem1x inline-gems")
|
||||
.container-fluid
|
||||
p
|
||||
| 20
|
||||
span.shop_gold
|
||||
.col-md-8
|
||||
.popover.right.gem-count-popover
|
||||
.arrow
|
||||
.popover-content
|
||||
p {{ $t('buyGemsAllow1') }}
|
||||
// @TOOD: | {{Shared.planGemLimits.convCap + User.user.purchased.plan.consecutive.gemCapExtra - User.user.purchased.plan.gemsBought}}
|
||||
| {{ $t('buyGemsAllow2') }}
|
||||
p {{ $t('seeSubscriptionDetails') }}
|
||||
div(ng-if='user.purchased.plan.customerId')
|
||||
small.muted {{ $t('paymentMethods') }}
|
||||
a.purchase.btn.btn-primary(ng-click='Payments.showStripe({})') {{ $t('card') }}
|
||||
a.purchase(href='/paypal/checkout?_id=${user._id}&apiToken=${User.settings.auth.apiToken}')
|
||||
img(src='https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png',
|
||||
alt='Pay now with Paypal')
|
||||
a.purchase(ng-click="Payments.amazonPayments.init({type: 'single'})")
|
||||
img(src='https://payments.amazon.com/gp/cba/button', alt='Pay now with Amazon Payments')
|
||||
|
||||
.container-fluid
|
||||
h2 {{ $t('freeGemsTitle') }}
|
||||
p {{ $t('subFreeGemsHow') }}
|
||||
|
||||
.well
|
||||
h3 {{ $t('purchaseGemsSeparately') }}
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-4.col-md-offset-4.alert.alert-info $5
|
||||
| {{ $t('USD') }}
|
||||
span#TotalGemPrice.dashed-underline(:popover="$t('donateText1')",
|
||||
popover-trigger='mouseenter',popover-placement='bottom')
|
||||
| +20
|
||||
span(class="Pet_Currency_Gem1x inline-gems")
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-10.col-md-offset-2
|
||||
p
|
||||
small.muted {{ $t('paymentMethods') }}
|
||||
a.purchase.btn.btn-primary(ng-click='Payments.showStripe({})') {{ $t('card') }}
|
||||
a.purchase(href='/paypal/checkout?_id=${user._id}&apiToken=${User.settings.auth.apiToken}')
|
||||
img(src='https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png',alt='Pay now with Paypal')
|
||||
a.purchase(ng-click="Payments.amazonPayments.init({type: 'single'})")
|
||||
img(src='https://payments.amazon.com/gp/cba/button', alt='Pay now with Amazon Payments')
|
||||
div(ng-if='!user.purchased.plan.customerId')
|
||||
.panel.panel-default
|
||||
.panel-body
|
||||
h3 {{ $t('purchaseGems') }}
|
||||
.small
|
||||
span.dashed-underline(popover="$t('donateText3')", popover-trigger='mouseenter', popover-placement='bottom')
|
||||
| {{ $t('donateText2') }}
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-4.col-md-offset-4.alert.alert-info $5
|
||||
| {{ $t('USD') }}
|
||||
span#TotalGemPrice.dashed-underline(popover="$t('donateText1')",
|
||||
popover-trigger='mouseenter', ement='bottom')
|
||||
| +20
|
||||
span(class="Pet_Currency_Gem1x inline-gems")
|
||||
.container-fluid
|
||||
.row
|
||||
.col-md-10.col-md-offset-2
|
||||
p
|
||||
small.muted {{ $t('paymentMethods') }}
|
||||
a.purchase.btn.btn-primary(ng-click='Payments.showStripe({})') {{ $t('card') }}
|
||||
a.purchase(href='/paypal/checkout?_id=${user._id}&apiToken=${User.settings.auth.apiToken}')
|
||||
img(src='https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png',
|
||||
alt='Pay now with Paypal')
|
||||
a.purchase(ng-click="Payments.amazonPayments.init({type: 'single'})")
|
||||
img(src='https://payments.amazon.com/gp/cba/button', alt='Pay now with Amazon Payments')
|
||||
h3
|
||||
.small {{ $t('buyGemsGoldTitle') }}
|
||||
h3 {{ $t('becomeSubscriber') }}
|
||||
|
||||
.container-fluid
|
||||
h3 {{ $t('freeGemsTitle') }}
|
||||
p {{ $t('subFreeGemsHow') }}
|
||||
div(ng-include="'partials/options.settings.subscription.html'", ng-controller='SettingsCtrl')
|
||||
|
||||
.well
|
||||
h3
|
||||
.small {{ $t('buyGemsGoldTitle') }}
|
||||
h3 {{ $t('becomeSubscriber') }}
|
||||
|
||||
div(ng-include="'partials/options.settings.subscription.html'", ng-controller='SettingsCtrl')
|
||||
div(ng-if='user.purchased.plan.customerId').pull-left
|
||||
p {{ $t('seeSubscriptionDetails') }}
|
||||
.text-right
|
||||
button.btn.btn-default(ng-click='$close()') {{ $t('close') }}
|
||||
.row(v-if='user.purchased.plan.customerId')
|
||||
.col-12
|
||||
p(v-html="$t('seeSubscriptionDetails')")
|
||||
.modal-footer
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary(@click='close()') {{ $t('close') }}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import planGemLimits from '../../../common/script/libs/planGemLimits';
|
||||
import purchase from '../../../common/script/ops/purchase';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
bModal,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
planGemLimits,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
userReachedGemCap () {
|
||||
return this.user.purchased.plan.customerId && this.user.purchased.plan.gemsBought >= this.user.purchased.plan.consecutive.gemCapExtra + this.planGemLimits.convCap;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('hide::modal', 'buy-gems');
|
||||
},
|
||||
purchase (params) {
|
||||
try {
|
||||
purchase(this.user, params);
|
||||
} catch (e) {
|
||||
alert(e.message);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -72,8 +72,8 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.restoreValues.stats = this.user.stats;
|
||||
this.restoreValues.achievements.streak = this.user.achievements.streak;
|
||||
Object.assign(this.restoreValues.stats, this.user.stats);
|
||||
Object.assign(this.restoreValues.achievements.streak, this.user.achievements.streak);
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
|
||||
@@ -7,46 +7,25 @@
|
||||
nav.navbar.navbar-toggleable-md.navbar-light.bg-faded
|
||||
button.navbar-toggler.navbar-toggler-right(type='button', data-toggle='collapse', data-target='#navbarNav', aria-controls='navbarNav', aria-expanded='false', aria-label='Toggle navigation')
|
||||
span.navbar-toggler-icon
|
||||
a.navbar-brand(href='#') Navbar
|
||||
a.navbar-brand(href='#')
|
||||
.logo.svg-icon(v-html="icons.logo")
|
||||
#navbarNav.collapse.navbar-collapse
|
||||
ul.navbar-nav
|
||||
li.nav-item.active
|
||||
a.nav-link(href='#')
|
||||
| Home
|
||||
span.sr-only (current)
|
||||
ul.navbar-nav.float-right
|
||||
li.nav-item
|
||||
a.nav-link(href='#') Features
|
||||
router-link.nav-link(to="/static/features") How it Works
|
||||
li.nav-item
|
||||
a.nav-link(href='#') Pricing
|
||||
router-link.nav-link(to="/static/plans") Group Plans
|
||||
li.nav-item
|
||||
a.nav-link.disabled(href='#') Disabled
|
||||
a.nav-link(href="https://habitica.wordpress.com/") Blog
|
||||
li.nav-item
|
||||
a.nav-link(href="http://blog.habitrpg.com/") Tumblr
|
||||
li.nav-item
|
||||
router-link.nav-link(to="/static/press-kit") Press Kit
|
||||
li.nav-item
|
||||
router-link.nav-link(to="/static/contact") Contact
|
||||
li.nav-item
|
||||
button#play-btn(class="btn btn-primary btn-lg gamifybutton") Enter Habitica
|
||||
|
||||
//-
|
||||
//- nav.navbar.navbar-light.bg-faded
|
||||
//- .navbar-header
|
||||
//- button.navbar-toggle.collapsed(type='button', data-toggle='collapse', data-target='#bs-example-navbar-collapse-1')
|
||||
//- span.sr-only Toggle navigation
|
||||
//- span.icon-bar
|
||||
//- span.icon-bar
|
||||
//- span.icon-bar
|
||||
//- a.navbar-brand(href='#')
|
||||
//- img.img-rendering-auto(src='https://d2afqr2xdmyzvu.cloudfront.net/assets/habitica_lockup2_desat.png', alt="$t('altAttrNavLogo')", width='156px')
|
||||
//- #bs-example-navbar-collapse-1.collapse.navbar-collapse
|
||||
//- ul.nav.navbar-nav.navbar-right
|
||||
//- li
|
||||
//- a(href='/static/features') {{ $t('companyAbout') }}
|
||||
//- li
|
||||
//- a(href='/static/plans') {{ $t('groupPlans') }}
|
||||
//- li
|
||||
//- a(href='https://habitica.wordpress.com/') {{ $t('companyBlog') }}
|
||||
//- li
|
||||
//- a(href='http://blog.habitrpg.com/') {{ $t('tumblr') }}
|
||||
//- li
|
||||
//- a(href='/static/press-kit') {{ $t('presskit') }}
|
||||
//- li
|
||||
//- a(href='/static/contact') {{ $t('contactUs') }}
|
||||
//- li
|
||||
//- button#header-play-button.btn.btn-primary.navbar-btn.navbar-right(@click='playButtonClick()') {{ $t('playButtonFull') }}
|
||||
#intro.container-fluid
|
||||
.row
|
||||
h1.col-12.text-center {{ $t('motivate1') }}
|
||||
@@ -556,6 +535,12 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.logo {
|
||||
width: 128px;
|
||||
height: 28px;
|
||||
color: purple;
|
||||
}
|
||||
|
||||
#intro {
|
||||
background: #fff;
|
||||
padding-top: 1em;
|
||||
@@ -634,9 +619,14 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import logo from 'assets/svg/logo.svg';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
logo,
|
||||
}),
|
||||
userCount: 1000000,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -49,6 +49,10 @@ div(v-if='user.stats.lvl > 10')
|
||||
white-space: initial;
|
||||
}
|
||||
|
||||
.spell:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.spell {
|
||||
background: #ffffff;
|
||||
margin-bottom: 1em;
|
||||
@@ -244,16 +248,16 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
// @TODO: do we need to fetcht the party everytime? We should probably just check store
|
||||
let party = await this.$store.dispatch('guilds:getGroup', {groupId: 'party'});
|
||||
let party = this.$store.state.party.members;
|
||||
party = isArray(party) ? party : [];
|
||||
party = party.concat(this.user);
|
||||
this.$store.state.party.data = party;
|
||||
this.castEnd(party, 'party');
|
||||
} else if (spell.target === 'tasks') {
|
||||
let tasks = this.$store.state.tasks.habits.concat(this.user.dailys)
|
||||
.concat(this.$store.state.tasks.rewards)
|
||||
.concat(this.$store.state.tasks.todos);
|
||||
let userTasks = this.$store.state.tasks.data;
|
||||
let tasks = userTasks.habits
|
||||
.concat(userTasks.dailys)
|
||||
.concat(userTasks.rewards)
|
||||
.concat(userTasks.todos);
|
||||
// exclude challenge tasks
|
||||
tasks = tasks.filter((task) => {
|
||||
if (!task.challenge) return true;
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
|
||||
// Habits right side control
|
||||
.right-control.d-flex.align-items-center.justify-content-center(v-if="task.type === 'habit'", :class="controlClass.down")
|
||||
.task-control.habit-control(:class="controlClass.down + '-control-habit'", @click="isUser ? score('down') : null")
|
||||
.task-control.habit-control(:class="controlClass.down + '-control-habit'", @click="(isUser && controlClass.down !== 'task-habit-disabled') ? score('down') : null")
|
||||
.svg-icon.negative(v-html="icons.negative")
|
||||
// Rewards right side control
|
||||
.right-control.d-flex.align-items-center.justify-content-center.reward-control(v-if="task.type === 'reward'", :class="controlClass", @click="isUser ? score('down') : null")
|
||||
@@ -62,7 +62,7 @@
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.task {
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 2px;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
background: transparent;
|
||||
border-radius: 2px;
|
||||
@@ -78,6 +78,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.task-habit-disabled-control-habit:hover {
|
||||
cursor: initial;
|
||||
}
|
||||
|
||||
.task-title {
|
||||
padding-bottom: 8px;
|
||||
color: $gray-10;
|
||||
@@ -247,6 +251,7 @@
|
||||
.small-text {
|
||||
margin-top: 4px;
|
||||
color: $yellow-10;
|
||||
font-style: initial;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -276,6 +281,11 @@
|
||||
color: $gray-300;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.task-reward {
|
||||
// @TODO: I'm unsure of where this is defined. Can't find it in search. So, I am using important for now
|
||||
background-color: rgba(255, 217, 160, 0.28) !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -11,10 +11,14 @@
|
||||
slot="modal-header",
|
||||
:class="[cssClass]",
|
||||
)
|
||||
h1 {{ title }}
|
||||
.row
|
||||
h1.col-8 {{ title }}
|
||||
.col-4
|
||||
span.cancel-task-btn(v-once, @click="cancel()") {{ $t('cancel') }}
|
||||
button.btn.btn-secondary(type="submit", v-once) {{ $t('save') }}
|
||||
.form-group
|
||||
label(v-once) {{ `${$t('title')}*` }}
|
||||
input.form-control(type='text', :class="[`${cssClass}-modal-input`]", required, v-model="task.text")
|
||||
input.form-control.title-input(type='text', :class="[`${cssClass}-modal-input`]", required, v-model="task.text", autofocus)
|
||||
.form-group
|
||||
label(v-once) {{ $t('notes') }}
|
||||
textarea.form-control(:class="[`${cssClass}-modal-input`]", v-model="task.notes", rows="3")
|
||||
@@ -22,6 +26,7 @@
|
||||
.option(v-if="task.type === 'reward'")
|
||||
label(v-once) {{ $t('cost') }}
|
||||
input(type="number", v-model="task.value", required, min="0")
|
||||
.svg-icon.gold(v-html="icons.gold")
|
||||
.option(v-if="['daily', 'todo'].indexOf(task.type) > -1")
|
||||
label(v-once) {{ $t('checklist') }}
|
||||
br
|
||||
@@ -69,14 +74,16 @@
|
||||
label(v-once) {{ $t('startDate') }}
|
||||
datepicker(v-model="task.startDate")
|
||||
.option(v-if="task.type === 'daily'")
|
||||
label(v-once) {{ $t('repeats') }}
|
||||
b-dropdown(:text="$t(task.frequency)")
|
||||
b-dropdown-item(v-for="frequency in ['daily', 'weekly', 'monthly', 'yearly']", :key="frequency", @click="task.frequency = frequency", :class="{active: task.frequency === frequency}")
|
||||
| {{ $t(frequency) }}
|
||||
label(v-once) {{ $t('repeatEvery') }}
|
||||
input.form-control(type="number", v-model="task.everyX", min="0", required)
|
||||
| {{ repeatSuffix }}
|
||||
br
|
||||
.form-group
|
||||
label(v-once) {{ $t('repeats') }}
|
||||
b-dropdown(:text="$t(task.frequency)")
|
||||
b-dropdown-item(v-for="frequency in ['daily', 'weekly', 'monthly', 'yearly']", :key="frequency", @click="task.frequency = frequency", :class="{active: task.frequency === frequency}")
|
||||
| {{ $t(frequency) }}
|
||||
.form-group
|
||||
label(v-once) {{ $t('repeatEvery') }}
|
||||
input(type="number", v-model="task.everyX", min="0", required)
|
||||
| {{ repeatSuffix }}
|
||||
br
|
||||
template(v-if="task.frequency === 'weekly'")
|
||||
.form-check-inline.weekday-check(
|
||||
v-for="(day, dayNumber) in ['su','m','t','w','th','f','s']",
|
||||
@@ -141,7 +148,6 @@
|
||||
@change="updateRequiresApproval")
|
||||
|
||||
.task-modal-footer(slot="modal-footer")
|
||||
button.btn.btn-primary(type="submit", v-once) {{ $t('save') }}
|
||||
span.cancel-task-btn(v-once, v-if="purpose === 'create'", @click="cancel()") {{ $t('cancel') }}
|
||||
span.delete-task-btn(v-once, v-else, @click="destroy()") {{ $t('delete') }}
|
||||
</template>
|
||||
@@ -311,6 +317,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.cancel-task-btn {
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.task-modal-footer {
|
||||
margin: 0 auto;
|
||||
padding-bottom: 24px;
|
||||
@@ -319,7 +329,6 @@
|
||||
margin-top: 50px;
|
||||
|
||||
.delete-task-btn, .cancel-task-btn {
|
||||
margin-left: 16px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover, &:focus, &:active {
|
||||
@@ -343,6 +352,14 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gold {
|
||||
width: 24px;
|
||||
margin-left: 5em;
|
||||
margin-top: -2.4em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
import { mapGetters, mapActions, mapState } from 'client/libs/store';
|
||||
@@ -361,6 +378,7 @@ import difficultyNormalIcon from 'assets/svg/difficulty-normal.svg';
|
||||
import positiveIcon from 'assets/svg/positive.svg';
|
||||
import negativeIcon from 'assets/svg/negative.svg';
|
||||
import deleteIcon from 'assets/svg/delete.svg';
|
||||
import goldIcon from 'assets/svg/gold.svg';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -385,6 +403,7 @@ export default {
|
||||
negative: negativeIcon,
|
||||
positive: positiveIcon,
|
||||
destroy: deleteIcon,
|
||||
gold: goldIcon,
|
||||
}),
|
||||
requiresApproval: false, // We can't set task.group fields so we use this field to toggle
|
||||
members: [],
|
||||
@@ -527,6 +546,7 @@ export default {
|
||||
this.$root.$emit('hide::modal', 'task-modal');
|
||||
},
|
||||
destroy () {
|
||||
if (!confirm('Are you sure you want to delete this task?')) return;
|
||||
this.destroyTask(this.task);
|
||||
this.$root.$emit('hide::modal', 'task-modal');
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
@change="toggleTag(tag)",
|
||||
)
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description {{ tag.name }}
|
||||
span.custom-control-description(v-markdown='tag.name')
|
||||
|
||||
.filter-panel-footer.clearfix
|
||||
template(v-if="editingTags === true")
|
||||
@@ -117,9 +117,9 @@
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
#create-dropdown .dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
#create-dropdown .dropdown-toggle::after {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -142,7 +142,16 @@
|
||||
}
|
||||
|
||||
.dropdown-icon-item .svg-icon {
|
||||
width: 16px;
|
||||
width: 22px;
|
||||
color: #C3C0C7;
|
||||
}
|
||||
|
||||
.dropdown-icon-item:hover .svg-icon, .dropdown-item.active .svg-icon {
|
||||
color: $purple-500;
|
||||
}
|
||||
|
||||
.dropdown-icon-item .text {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
button.btn.btn-secondary.filter-button {
|
||||
@@ -278,6 +287,7 @@
|
||||
import TaskColumn from './column';
|
||||
import TaskModal from './taskModal';
|
||||
import spells from './spells';
|
||||
import markdown from 'client/directives/markdown';
|
||||
|
||||
import positiveIcon from 'assets/svg/positive.svg';
|
||||
import filterIcon from 'assets/svg/filter.svg';
|
||||
@@ -315,6 +325,9 @@ export default {
|
||||
spells,
|
||||
SelectMembersModal,
|
||||
},
|
||||
directives: {
|
||||
markdown,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
columns: ['habit', 'daily', 'todo', 'reward'],
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
div
|
||||
span(:class="userLevelStyle(conversation)") {{conversation.name}}
|
||||
span.timeago {{conversation.date}}
|
||||
div {{conversation.lastMessageText}}
|
||||
div {{conversation.lastMessageText.substring(0, 30)}}
|
||||
.col-8.messages
|
||||
chat-message.container-fluid(:chat.sync='activeChat')
|
||||
|
||||
|
||||
@@ -256,6 +256,7 @@ const router = new VueRouter({
|
||||
{ name: 'merch', path: 'merch', component: MerchPage, meta: {requiresLogin: false}},
|
||||
// { name: 'newStuff', path: 'newStuff', component: NewStuffPage, meta: {requiresLogin: false}},
|
||||
{ name: 'overview', path: 'overview', component: OverviewPage, meta: {requiresLogin: false}},
|
||||
{ name: 'oldNews', path: 'old-news', component: ParentPage, meta: {requiresLogin: false}},
|
||||
{ name: 'plans', path: 'plans', component: GroupPlansPage, meta: {requiresLogin: false}},
|
||||
{ name: 'pressKit', path: 'press-kit', component: PressKitPage, meta: {requiresLogin: false}},
|
||||
{ name: 'privacy', path: 'privacy', component: PrivacyPage, meta: {requiresLogin: false}},
|
||||
|
||||
@@ -98,11 +98,12 @@ export async function create (store, createdTask) {
|
||||
|
||||
sanitizeChecklist(createdTask);
|
||||
|
||||
list.unshift(createdTask);
|
||||
store.state.user.data.tasksOrder[type].unshift(createdTask._id);
|
||||
const response = await axios.post('/api/v3/tasks/user', createdTask);
|
||||
|
||||
Object.assign(list[0], response.data.data);
|
||||
let newTask = response.data.data;
|
||||
list.unshift(newTask);
|
||||
store.state.user.data.tasksOrder[type].unshift(newTask._id);
|
||||
Object.assign(list[0], newTask);
|
||||
}
|
||||
|
||||
export async function save (store, editedTask) {
|
||||
|
||||
@@ -88,7 +88,11 @@ export default function () {
|
||||
selectedLanguage,
|
||||
}),
|
||||
hideHeader: false,
|
||||
viewingMembers: [],
|
||||
memberModalOptions: {
|
||||
viewingMembers: [],
|
||||
groupId: '',
|
||||
group: {},
|
||||
},
|
||||
openedItemRows: [],
|
||||
spellOptions: {
|
||||
castingSpell: false,
|
||||
|
||||
@@ -300,5 +300,8 @@
|
||||
"partyInformationPlaceholder": "Write a message to your Party members here!",
|
||||
"selectPartyMember": "Select a Party Member",
|
||||
"errorNotInParty": "You are not in a Party",
|
||||
"health_wellness": "Health & Wellness"
|
||||
"health_wellness": "Health & Wellness",
|
||||
"self_care": "Self-Care",
|
||||
"sendLink": "Send Link",
|
||||
"forgotPassword": "Forgot Password"
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ let schema = new Schema({
|
||||
group: {type: String, ref: 'Group', validate: [validator.isUUID, 'Invalid uuid.'], required: true},
|
||||
memberCount: {type: Number, default: 1},
|
||||
prize: {type: Number, default: 0, min: 0},
|
||||
categories: [{
|
||||
slug: {type: String},
|
||||
name: {type: String},
|
||||
}],
|
||||
}, {
|
||||
strict: true,
|
||||
minimize: false, // So empty objects are returned
|
||||
|
||||