mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 06:07:21 +01:00
Sept 23 fixes (#9074)
* Discover challenges * Fixed hero loading * Moved add task button * Fixed bailey showing * Added logs for bad sub data * Fixed blurb editing * Added confirmation for deleteing message * Reset invite modals on invite * fixed group member sorting * Fixed chat time styles * Fixed hover on liked * Fixed like count * Added reverse * Fixed editing party * Added leader conditions * Added search * Added loading * Reset members when leaving party * Rounded pending * Fixed overflow on collecting quests * Added to invite friends * Hid summary from party * Fixed button styles * Fixed button class * Removed okay button * Fixed renav for profile modal * Added subscription back to menu * Fixed static link * Added daily due setting * Added local auth adding * Fixed centering of text * Removed message locally * Added count for new message * Added style fix for profile pet * Fixed achievement popovers * Fixed white boxes * Added plain color backgrounds * fixed challenge mutability * Fixed challenge editing * Added notation for large numbers * Add color text to guild sizes * Removed membership filters from discover challenges * Added invites to group * Cmd + enter send message * Made leader clickable * Updated group validation * Added cancelling autocomplete * Added mention icon * Added removing member * Removed extra string
This commit is contained in:
@@ -27,7 +27,7 @@ div
|
||||
span.small-text(v-html="$t('inviteFriendsParty')")
|
||||
br
|
||||
// TODO link to party creation or party page if partying solo
|
||||
button.btn.btn-primary(@click='openPartyModal()') {{ $t('startAParty') }}
|
||||
button.btn.btn-primary(@click='openPartyModal()') {{ partyMembers && partyMembers.length > 1 ? $t('startAParty') : $t('inviteFriends') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -63,6 +63,7 @@ div
|
||||
span {{Math.floor(user.stats.gp * 100) / 100}}
|
||||
notification-menu
|
||||
a.dropdown.item-with-icon.item-user
|
||||
span.message-count.top-count(v-if='user.inbox.newMessages > 0') {{user.inbox.newMessages}}
|
||||
.svg-icon.user(v-html="icons.user")
|
||||
.dropdown-menu.dropdown-menu-right.user-dropdown
|
||||
a.dropdown-item.edit-avatar.dropdown-separated(@click='showAvatar()')
|
||||
@@ -75,7 +76,8 @@ div
|
||||
a.dropdown-item(@click='showProfile("stats")') {{ $t('stats') }}
|
||||
a.dropdown-item(@click='showProfile("achievements")') {{ $t('achievements') }}
|
||||
a.dropdown-item.dropdown-separated(@click='showProfile("profile")') {{ $t('profile') }}
|
||||
router-link.dropdown-item.dropdown-separated(:to="{name: 'site'}") {{ $t('settings') }}
|
||||
router-link.dropdown-item(:to="{name: 'site'}") {{ $t('settings') }}
|
||||
router-link.dropdown-item.dropdown-separated(:to="{name: 'subscription'}") {{ $t('subscription') }}
|
||||
a.nav-link.dropdown-item.dropdown-separated(to="/", @click.prevent='logout()') {{ $t('logout') }}
|
||||
li(v-if='!this.user.purchased.plan.customerId', @click='showBuyGemsModal("subscribe")')
|
||||
.dropdown-item.text-center
|
||||
@@ -295,6 +297,13 @@ div
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.message-count.top-count {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: .5em;
|
||||
padding: .2em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template lang="pug">
|
||||
.row
|
||||
challenge-modal(:challenge='challenge', :cloning='cloning' v-on:updatedChallenge='updatedChallenge')
|
||||
challenge-modal(:cloning='cloning' v-on:updatedChallenge='updatedChallenge')
|
||||
close-challenge-modal(:members='members', :challengeId='challenge._id')
|
||||
challenge-member-progress-modal(:memberId='progressMemberId', :challengeId='challenge._id')
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.svg-icon.calendar-icon(v-html="icons.calendarIcon")
|
||||
| {{$t('endDate')}}
|
||||
// "endDate": "End Date: <% endDate %>",
|
||||
span {{challenge.endDate}}
|
||||
// span {{challenge.endDate}}
|
||||
.tags
|
||||
span.tag(v-for='tag in challenge.tags') {{tag}}
|
||||
.col-4
|
||||
@@ -28,13 +28,27 @@
|
||||
.svg-icon.gem-icon(v-html="icons.gemIcon")
|
||||
| {{challenge.prize}}
|
||||
.details(v-once) {{$t('prize')}}
|
||||
.row(v-if='isLeader')
|
||||
.col-6.offset-6
|
||||
span
|
||||
strong View Progress Of
|
||||
.row.leader-actions(v-if='isLeader')
|
||||
.col-7.offset-5
|
||||
span.view-progress
|
||||
strong {{ $t('viewProgressOf') }}
|
||||
b-dropdown.create-dropdown(text="Select a Participant")
|
||||
b-dropdown-item(v-for="member in members", :key="member._id", @click="openMemberProgressModal(member._id)")
|
||||
| {{ member.profile.name }}
|
||||
span(v-if='isLeader')
|
||||
b-dropdown.create-dropdown(:text="$t('create')", :variant="'success'")
|
||||
b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)")
|
||||
| {{$t(type)}}
|
||||
task-modal(
|
||||
:task="workingTask",
|
||||
:purpose="taskFormPurpose",
|
||||
@cancel="cancelTaskModal()",
|
||||
ref="taskModal",
|
||||
:challengeId="challengeId",
|
||||
v-on:taskCreated='taskCreated',
|
||||
v-on:taskEdited='taskEdited',
|
||||
@taskDestroyed='taskDestroyed'
|
||||
)
|
||||
|
||||
.row
|
||||
task-column.col-6(
|
||||
@@ -50,20 +64,6 @@
|
||||
button.btn.btn-success(v-once, @click='joinChallenge()') {{$t('joinChallenge')}}
|
||||
div(v-if='isMember')
|
||||
button.btn.btn-danger(v-once, @click='leaveChallenge()') {{$t('leaveChallenge')}}
|
||||
div(v-if='isLeader')
|
||||
b-dropdown.create-dropdown(:text="$t('create')")
|
||||
b-dropdown-item(v-for="type in columns", :key="type", @click="createTask(type)")
|
||||
| {{$t(type)}}
|
||||
task-modal(
|
||||
:task="workingTask",
|
||||
:purpose="taskFormPurpose",
|
||||
@cancel="cancelTaskModal()",
|
||||
ref="taskModal",
|
||||
:challengeId="challengeId",
|
||||
v-on:taskCreated='taskCreated',
|
||||
v-on:taskEdited='taskEdited',
|
||||
@taskDestroyed='taskDestroyed'
|
||||
)
|
||||
div(v-if='isLeader')
|
||||
button.btn.btn-secondary(v-once, @click='edit()') {{$t('editChallenge')}}
|
||||
div(v-if='isLeader')
|
||||
@@ -155,6 +155,14 @@
|
||||
.description-section {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.leader-actions {
|
||||
margin-top: 1em;
|
||||
|
||||
.view-progress {
|
||||
margin-right: .5em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
@@ -375,6 +383,7 @@ export default {
|
||||
edit () {
|
||||
// @TODO: set working challenge
|
||||
this.cloning = false;
|
||||
this.$store.state.challengeOptions.workingChallenge = Object.assign({}, this.$store.state.challengeOptions.workingChallenge, this.challenge);
|
||||
this.$root.$emit('show::modal', 'challenge-modal');
|
||||
},
|
||||
// @TODO: view members
|
||||
|
||||
@@ -130,6 +130,7 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import clone from 'lodash/clone';
|
||||
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';
|
||||
@@ -139,7 +140,7 @@ import { TAVERN_ID, MIN_SHORTNAME_SIZE_FOR_CHALLENGES, MAX_SUMMARY_SIZE_FOR_CHAL
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['challenge', 'groupId', 'cloning'],
|
||||
props: ['groupId', 'cloning'],
|
||||
components: {
|
||||
bModal,
|
||||
bDropdown,
|
||||
@@ -186,19 +187,19 @@ export default {
|
||||
},
|
||||
{
|
||||
label: 'mental_health',
|
||||
key: 'mental_health ',
|
||||
key: 'mental_health',
|
||||
},
|
||||
{
|
||||
label: 'getting_organized',
|
||||
key: 'getting_organized ',
|
||||
key: 'getting_organized',
|
||||
},
|
||||
{
|
||||
label: 'self_improvement',
|
||||
key: 'self_improvement ',
|
||||
key: 'self_improvement',
|
||||
},
|
||||
{
|
||||
label: 'spirituality',
|
||||
key: 'spirituality ',
|
||||
key: 'spirituality',
|
||||
},
|
||||
{
|
||||
label: 'time_management',
|
||||
@@ -250,7 +251,6 @@ export default {
|
||||
_id: TAVERN_ID,
|
||||
});
|
||||
|
||||
this.resetWorkingChallenge();
|
||||
this.setUpWorkingChallenge();
|
||||
},
|
||||
watch: {
|
||||
@@ -321,9 +321,14 @@ export default {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
challenge () {
|
||||
return this.$store.state.challengeOptions.workingChallenge;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setUpWorkingChallenge () {
|
||||
this.resetWorkingChallenge();
|
||||
|
||||
if (!this.challenge) return;
|
||||
|
||||
this.workingChallenge = Object.assign({}, this.workingChallenge, this.challenge);
|
||||
@@ -357,6 +362,8 @@ export default {
|
||||
shortName: '',
|
||||
todos: [],
|
||||
};
|
||||
|
||||
this.$store.state.workingChallenge = {};
|
||||
},
|
||||
async createChallenge () {
|
||||
// @TODO: improve error handling, add it to updateChallenge, make errors translatable. Suggestion: `<% fieldName %> is required` where possible, where `fieldName` is inserted as the translatable string that's used for the field header.
|
||||
@@ -385,9 +392,11 @@ export default {
|
||||
name: catName,
|
||||
});
|
||||
});
|
||||
this.workingChallenge.categories = serverCategories;
|
||||
|
||||
let challenge = await this.$store.dispatch('challenges:createChallenge', {challenge: this.workingChallenge});
|
||||
let challengeDetails = clone(this.workingChallenge);
|
||||
challengeDetails.categories = serverCategories;
|
||||
|
||||
let challenge = await this.$store.dispatch('challenges:createChallenge', {challenge: challengeDetails});
|
||||
// @TODO: When to remove from guild instead?
|
||||
this.user.balance -= this.workingChallenge.prize / 4;
|
||||
|
||||
@@ -403,18 +412,21 @@ export default {
|
||||
let categoryKeys = this.workingChallenge.categories;
|
||||
let serverCategories = [];
|
||||
categoryKeys.forEach(key => {
|
||||
let catName = this.categoriesHashByKey[key];
|
||||
let newKey = key.trim();
|
||||
let catName = this.categoriesHashByKey[newKey];
|
||||
serverCategories.push({
|
||||
slug: key,
|
||||
slug: newKey,
|
||||
name: catName,
|
||||
});
|
||||
});
|
||||
this.workingChallenge.categories = serverCategories;
|
||||
|
||||
let challengeDetails = clone(this.workingChallenge);
|
||||
challengeDetails.categories = serverCategories;
|
||||
|
||||
this.$emit('updatedChallenge', {
|
||||
challenge: this.workingChallenge,
|
||||
challenge: challengeDetails,
|
||||
});
|
||||
this.$store.dispatch('challenges:updateChallenge', {challenge: this.workingChallenge});
|
||||
this.$store.dispatch('challenges:updateChallenge', {challenge: challengeDetails});
|
||||
this.resetWorkingChallenge();
|
||||
this.$root.$emit('hide::modal', 'challenge-modal');
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
input.custom-control-input(type="checkbox", :value='group.key' v-model="categoryFilters")
|
||||
span.custom-control-indicator
|
||||
span.custom-control-description(v-once) {{ $t(group.label) }}
|
||||
.form-group
|
||||
.form-group(v-if='$route.name !== "findChallenges"')
|
||||
h3 Membership
|
||||
.form-check(
|
||||
v-for="group in roleOptions",
|
||||
|
||||
@@ -48,6 +48,10 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
text (newText) {
|
||||
if (!newText[newText.length - 1] || newText[newText.length - 1] === ' ') {
|
||||
this.searchActive = false;
|
||||
}
|
||||
|
||||
if (newText[newText.length - 1] !== '@') return;
|
||||
this.searchActive = true;
|
||||
this.currentSearchPosition = newText.length - 1;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
//.hr(v-if='displayDivider(msg)')
|
||||
.hr-middle(v-once) {{ msg.timestamp }}
|
||||
.row(v-if='user._id !== msg.uuid')
|
||||
.col-2
|
||||
div(:class='inbox ? "col-4" : "col-2"')
|
||||
avatar(
|
||||
v-if='cachedProfileData[msg.uuid]',
|
||||
:member="cachedProfileData[msg.uuid]",
|
||||
@@ -18,8 +18,9 @@
|
||||
:hideClassBadge='true',
|
||||
@click.native="showMemberModal(msg.uuid)",
|
||||
)
|
||||
.card.col-10
|
||||
.message-hidden(v-if='msg.flagCount > 0 && user.contributor.admin') Message Hidden
|
||||
.card(:class='inbox ? "col-8" : "col-10"')
|
||||
.mentioned-icon(v-if='isUserMentioned(msg)')
|
||||
.message-hidden(v-if='msg.flagCount > 0 && user.contributor.admin') Message Hidden - {{ msg.flagCount }} Flags
|
||||
.card-block
|
||||
h3.leader(
|
||||
:class='userLevelStyle(cachedProfileData[msg.uuid])'
|
||||
@@ -27,7 +28,7 @@
|
||||
)
|
||||
| {{msg.user}}
|
||||
.svg-icon(v-html="icons[`tier${cachedProfileData[msg.uuid].contributor.level}`]", v-if='cachedProfileData[msg.uuid] && cachedProfileData[msg.uuid].contributor && cachedProfileData[msg.uuid].contributor.level')
|
||||
p {{msg.timestamp | timeAgo}}
|
||||
p.time {{msg.timestamp | timeAgo}}
|
||||
.text(v-markdown='msg.text')
|
||||
hr
|
||||
.action(@click='like(msg, index)', v-if='msg.likes', :class='{active: msg.likes[user._id]}')
|
||||
@@ -43,13 +44,15 @@
|
||||
span.action(v-if='msg.uuid === user._id || inbox', @click='remove(msg, index)')
|
||||
.svg-icon(v-html="icons.delete")
|
||||
| {{$t('delete')}}
|
||||
span.action.float-right(v-if='likeCount(msg) > 0')
|
||||
span.action.float-right.liked(v-if='likeCount(msg) > 0')
|
||||
.svg-icon(v-html="icons.liked")
|
||||
| + {{ likeCount(msg) }}
|
||||
// @TODO can we avoid duplicating all this code? Cannot we just push everything
|
||||
// to the right if the user is the author?
|
||||
// Maybe we just create two sub components instead
|
||||
.row(v-if='user._id === msg.uuid')
|
||||
.card.col-10
|
||||
.card(:class='inbox ? "col-8" : "col-10"')
|
||||
.mentioned-icon(v-if='isUserMentioned(msg)')
|
||||
.message-hidden(v-if='msg.flagCount > 0 && user.contributor.admin') Message Hidden - {{ msg.flagCount }} Flags
|
||||
.card-block
|
||||
h3.leader(
|
||||
@@ -58,7 +61,7 @@
|
||||
)
|
||||
| {{msg.user}}
|
||||
.svg-icon(v-html="icons[`tier${cachedProfileData[msg.uuid].contributor.level}`]", v-if='cachedProfileData[msg.uuid] && cachedProfileData[msg.uuid].contributor && cachedProfileData[msg.uuid].contributor.level')
|
||||
p {{msg.timestamp | timeAgo}}
|
||||
p.time {{msg.timestamp | timeAgo}}
|
||||
.text(v-markdown='msg.text')
|
||||
hr
|
||||
.action(@click='like(msg, index)', v-if='msg.likes', :class='{active: msg.likes[user._id]}')
|
||||
@@ -74,10 +77,10 @@
|
||||
span.action(v-if='msg.uuid === user._id', @click='remove(msg, index)')
|
||||
.svg-icon(v-html="icons.delete")
|
||||
| {{$t('delete')}}
|
||||
span.action.float-right(v-if='likeCount(msg) > 0')
|
||||
span.action.float-right.liked(v-if='likeCount(msg) > 0')
|
||||
.svg-icon(v-html="icons.liked")
|
||||
| + {{ likeCount(msg) }}
|
||||
.col-2
|
||||
div(:class='inbox ? "col-4" : "col-2"')
|
||||
avatar(
|
||||
v-if='cachedProfileData[msg.uuid]',
|
||||
:member="cachedProfileData[msg.uuid]",
|
||||
@@ -134,6 +137,26 @@
|
||||
}
|
||||
// End of tier colors
|
||||
|
||||
.leader {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.time {
|
||||
font-size: 12px;
|
||||
color: #878190;
|
||||
}
|
||||
|
||||
.mentioned-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
background-color: #bda8ff;
|
||||
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
|
||||
position: absolute;
|
||||
right: -.5em;
|
||||
top: -.5em;
|
||||
}
|
||||
|
||||
h3 { // this is the user name
|
||||
cursor: pointer;
|
||||
|
||||
@@ -173,6 +196,7 @@
|
||||
.text {
|
||||
font-size: 14px;
|
||||
color: #4e4a57;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.action {
|
||||
@@ -185,6 +209,10 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.liked:hover {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.action .svg-icon {
|
||||
margin-right: .2em;
|
||||
width: 16px;
|
||||
@@ -302,6 +330,27 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isUserMentioned (message) {
|
||||
let user = this.user;
|
||||
|
||||
if (message.hasOwnProperty('highlight')) return message.highlight;
|
||||
|
||||
message.highlight = false;
|
||||
let messagetext = message.text.toLowerCase();
|
||||
let username = user.profile.name;
|
||||
let mentioned = messagetext.indexOf(username.toLowerCase());
|
||||
let pattern = `${username}([^\w]|$){1}`;
|
||||
|
||||
if (mentioned === -1) return message.highlight;
|
||||
|
||||
let preceedingchar = messagetext.substring(mentioned - 1, mentioned);
|
||||
if (mentioned === 0 || preceedingchar.trim() === '' || preceedingchar === '@') {
|
||||
let regex = new RegExp(pattern, 'i');
|
||||
message.highlight = regex.test(messagetext);
|
||||
}
|
||||
|
||||
return message.highlight;
|
||||
},
|
||||
canViewFlag (message) {
|
||||
if (message.uuid === this.user._id) return true;
|
||||
if (!message.flagCount || message.flagCount === 0) return true;
|
||||
@@ -345,7 +394,13 @@ export default {
|
||||
},
|
||||
likeCount (message) {
|
||||
if (!message.likes) return 0;
|
||||
return Object.keys(message.likes).length;
|
||||
|
||||
let likeCount = 0;
|
||||
for (let key in message.likes) {
|
||||
let like = message.likes[key];
|
||||
if (like) likeCount += 1;
|
||||
}
|
||||
return likeCount;
|
||||
},
|
||||
async like (messageToLike, index) {
|
||||
let message = cloneDeep(messageToLike);
|
||||
@@ -374,10 +429,13 @@ export default {
|
||||
this.$root.$emit('show::modal', 'report-flag');
|
||||
},
|
||||
async remove (message, index) {
|
||||
if (!confirm(this.$t('areYouSureDeleteMessage'))) return;
|
||||
|
||||
this.chat.splice(index, 1);
|
||||
|
||||
if (this.inbox) {
|
||||
axios.delete(`/api/v3/user/messages/${message.id}`);
|
||||
this.$delete(this.user.inbox.messages, message.id);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -228,8 +228,9 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
||||
.row.text-center.set-title
|
||||
strong {{backgroundShopSets[0].text}}
|
||||
.row.incentive-background-row
|
||||
.col-12(v-if='showPlainBackgroundBlurb(backgroundShopSets[0].identifier, backgroundShopSets[0].items)') {{ $t('incentiveBackgroundsUnlockedWithCheckins') }}
|
||||
.col-2(v-for='bg in backgroundShopSets[0].items',
|
||||
@click='buy("background." + bg.key)',
|
||||
@click='unlock("background." + bg.key)',
|
||||
:popover-title='bg.text',
|
||||
:popover='bg.notes',
|
||||
popover-trigger='mouseenter')
|
||||
@@ -248,7 +249,6 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
||||
.row(v-for='set in sets', v-if='activeSubPage === key')
|
||||
.col-8.offset-2.text-center.set-title
|
||||
strong {{set.text}}
|
||||
.col-12(v-if='showPlainBackgroundBlurb(set.identifier, set.items)') {{ $t('incentiveBackgroundsUnlockedWithCheckins') }}
|
||||
.col-4.text-center.customize-option.background-button(v-for='bg in set.items',
|
||||
@click='!user.purchased.background[bg.key] ? backgroundSelected(bg) : unlock("background." + bg.key)',
|
||||
:popover-title='bg.text',
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
.col-6.title-details
|
||||
h1 {{group.name}}
|
||||
strong.float-left(v-once) {{$t('groupLeader')}}
|
||||
span.float-left(v-if='group.leader.profile') : {{group.leader.profile.name}}
|
||||
span.leader.float-left(v-if='group.leader.profile', @click='showMemberProfile(group.leader)') : {{group.leader.profile.name}}
|
||||
.col-6
|
||||
.row.icon-row
|
||||
.col-4.offset-4(v-bind:class="{ 'offset-8': isParty }")
|
||||
@@ -16,7 +16,7 @@
|
||||
.svg-icon.shield(v-html="icons.goldGuildBadgeIcon", v-if='group.memberCount > 1000')
|
||||
.svg-icon.shield(v-html="icons.silverGuildBadgeIcon", v-if='group.memberCount > 100 && group.memberCount < 999')
|
||||
.svg-icon.shield(v-html="icons.bronzeGuildBadgeIcon", v-if='group.memberCount < 100')
|
||||
span.number {{group.memberCount}}
|
||||
span.number {{ group.memberCount | abbrNum }}
|
||||
div(v-once) {{ $t('members') }}
|
||||
.col-4(v-if='!isParty')
|
||||
.item-with-icon
|
||||
@@ -30,8 +30,11 @@
|
||||
.row.new-message-row
|
||||
textarea(:placeholder="!isParty ? $t('chatPlaceholder') : $t('partyChatPlaceholder')", v-model='newMessage', @keydown='updateCarretPosition')
|
||||
autocomplete(:text='newMessage', v-on:select="selectedAutocomplete", :coords='coords', :chat='group.chat')
|
||||
button.btn.btn-secondary.send-chat.float-right(v-once, @click='sendMessage()') {{ $t('send') }}
|
||||
button.btn.btn-secondary.float-left(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
|
||||
button.btn.btn-secondary.send-chat.float-left(v-once, @click='sendMessage()') {{ $t('send') }}
|
||||
.row
|
||||
.col-6
|
||||
button.btn.btn-secondary.float-left.fetch(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
|
||||
button.btn.btn-secondary.float-left(v-once, @click='reverseChat()') {{ $t('reverseChat') }}
|
||||
|
||||
.row.community-guidelines(v-if='!communityGuidelinesAccepted')
|
||||
div.col-8(v-once, v-html="$t('communityGuidelinesIntro')")
|
||||
@@ -75,7 +78,7 @@
|
||||
.svg-icon(v-html="icons.questIcon")
|
||||
h4(v-once) {{ $t('youAreNotOnQuest') }}
|
||||
p(v-once) {{ $t('questDescription') }}
|
||||
button.btn.btn-secondary(v-once, @click="openStartQuestModal()") {{ $t('startAQuest') }}
|
||||
button.btn.btn-secondary(v-once, @click="openStartQuestModal()", v-if='isLeader') {{ $t('startAQuest') }}
|
||||
.row.quest-active-section(v-if='isParty && onPendingQuest && !onActiveQuest')
|
||||
h2 Pending quest
|
||||
button.btn.btn-secondary(v-once, @click="questForceStart()") {{ $t('begin') }}
|
||||
@@ -110,7 +113,7 @@
|
||||
| {{parseFloat(group.quest.progress.hp).toFixed(2)}} / {{parseFloat(questData.boss.hp).toFixed(2)}}
|
||||
.col-6
|
||||
// @TODO: Why do we not sync quset progress on the group doc? Each user could have different progress
|
||||
span.float-right {{user.party.quest.progress.up || 0}} pending damage
|
||||
span.float-right {{parseFloat(user.party.quest.progress.up).toFixed(1) || 0}} pending damage
|
||||
.row.rage-bar-row(v-if='questData.boss.rage')
|
||||
.col-12
|
||||
.grey-progress-bar
|
||||
@@ -119,9 +122,9 @@
|
||||
.col-6
|
||||
span.float-left
|
||||
| Rage {{questData.boss.rage.value}}
|
||||
button.btn.btn-secondary(v-once, @click="questAbort()") {{ $t('abort') }}
|
||||
button.btn.btn-secondary(v-once, @click="questAbort()", v-if='isLeader') {{ $t('abort') }}
|
||||
|
||||
.section-header
|
||||
.section-header(v-if='!isParty')
|
||||
.row
|
||||
.col-10
|
||||
h3(v-once) {{ $t('guildSummary') }}
|
||||
@@ -164,7 +167,7 @@
|
||||
.section(v-if="sections.challenges")
|
||||
group-challenges(:groupId='searchId')
|
||||
div.text-center
|
||||
button.btn.btn-primary(class='btn-danger', v-if='isMember', @click='clickLeave()') {{ $t('leave') }}
|
||||
button.btn.btn-danger(v-if='isMember', @click='clickLeave()') {{ $t('leave') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -174,6 +177,10 @@
|
||||
color: $purple-200;
|
||||
}
|
||||
|
||||
.leader:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
margin-bottom: 1em;
|
||||
|
||||
@@ -294,7 +301,7 @@
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
bottom: 3em;
|
||||
bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,7 +418,7 @@
|
||||
.collect-progress-bar {
|
||||
background-color: #24cc8f;
|
||||
height: 15px;
|
||||
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.hr {
|
||||
@@ -649,6 +656,11 @@ export default {
|
||||
document.body.removeChild(div);
|
||||
},
|
||||
updateCarretPosition (eventUpdate) {
|
||||
if (eventUpdate.metaKey && eventUpdate.keyCode === 13) {
|
||||
this.sendMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
let text = eventUpdate.target;
|
||||
this.getCoord(eventUpdate, text);
|
||||
},
|
||||
@@ -661,6 +673,8 @@ export default {
|
||||
this.$root.$emit('show::modal', 'members-modal');
|
||||
},
|
||||
async sendMessage () {
|
||||
if (!this.newMessage) return;
|
||||
|
||||
let response = await this.$store.dispatch('chat:postChat', {
|
||||
group: this.group,
|
||||
message: this.newMessage,
|
||||
@@ -685,6 +699,7 @@ export default {
|
||||
}
|
||||
|
||||
let group = await this.$store.dispatch('guilds:getGroup', {groupId: this.searchId});
|
||||
|
||||
if (this.isParty) {
|
||||
this.$store.state.party.data = group;
|
||||
this.group = this.$store.state.party.data;
|
||||
@@ -749,14 +764,10 @@ export default {
|
||||
if (this.isParty) {
|
||||
data.type = 'party';
|
||||
Analytics.updateUser({partySize: null, partyID: null});
|
||||
this.$store.state.party.members = [];
|
||||
}
|
||||
|
||||
await this.$store.dispatch('guilds:leave', data);
|
||||
|
||||
// @TODO: Implement
|
||||
// User.sync().then(function () {
|
||||
// $rootScope.hardRedirect('/party');
|
||||
// });
|
||||
},
|
||||
upgradeGroup () {
|
||||
this.$store.state.upgradingGroup = this.group;
|
||||
@@ -794,6 +805,12 @@ export default {
|
||||
}
|
||||
// $rootScope.$state.go('options.inventory.quests');
|
||||
},
|
||||
async showMemberProfile (leader) {
|
||||
let heroDetails = await this.$store.dispatch('members:fetchMember', { memberId: leader._id });
|
||||
this.$store.state.profileUser = heroDetails.data.data;
|
||||
this.$store.state.profileOptions.startingPage = 'profile';
|
||||
this.$root.$emit('show::modal', 'profile');
|
||||
},
|
||||
async questCancel () {
|
||||
if (!confirm(this.$t('sureCancel'))) return;
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/cancel'});
|
||||
|
||||
@@ -373,7 +373,7 @@ export default {
|
||||
async submit () {
|
||||
if (this.$store.state.user.data.balance < 1 && !this.workingGroup.id) {
|
||||
// @TODO: Add proper notifications
|
||||
alert('Not enough gems');
|
||||
alert(this.$t('notEnoughGems'));
|
||||
return;
|
||||
// @TODO return $rootScope.openModal('buyGems', {track:"Gems > Gems > Create Group"});
|
||||
// @TODO when modal is implemented, enable analytics
|
||||
@@ -385,27 +385,16 @@ export default {
|
||||
}); */
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
let errors = [];
|
||||
|
||||
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.workingGroup.name) errors.push(this.$t('nameRequired'));
|
||||
if (!this.workingGroup.summary) errors.push(this.$t('summaryRequired'));
|
||||
if (this.workingGroup.summary.length > MAX_SUMMARY_SIZE_FOR_GUILDS) errors.push(this.$t('summaryTooLong'));
|
||||
if (!this.workingGroup.description) errors.push(this.$t('descriptionRequired'));
|
||||
if (!this.isParty && (!this.workingGroup.categories || this.workingGroup.categories.length === 0)) errors.push(this.$t('categoiresRequired'));
|
||||
|
||||
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.workingGroup.categories || this.workingGroup.categories.length === 0) {
|
||||
// @TODO: Add proper notifications
|
||||
alert('One or more categories must be selected');
|
||||
if (errors.length > 0) {
|
||||
alert(errors.join('\n'));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ b-modal#invite-modal(:title="$t('inviteFriends')", size='lg')
|
||||
input.form-control(type='text', v-model='user.uuid')
|
||||
tr
|
||||
td
|
||||
button.btn.btn-xs.pull-right(@click='addUuid()')
|
||||
button.btn.btn-primary.pull-right(@click='addUuid()')
|
||||
i.glyphicon.glyphicon-plus
|
||||
| +
|
||||
tr
|
||||
@@ -36,7 +36,7 @@ b-modal#invite-modal(:title="$t('inviteFriends')", size='lg')
|
||||
input.form-control(type='email', v-model='email.email')
|
||||
tr
|
||||
td(colspan=2)
|
||||
a.btn.btn-xs.pull-right(@click='addEmail()')
|
||||
button.btn.btn-primary.pull-right(@click='addEmail()')
|
||||
i.glyphicon.glyphicon-plus
|
||||
| +
|
||||
tr
|
||||
@@ -132,6 +132,9 @@ export default {
|
||||
|
||||
this.text(this.$t(invitationString));
|
||||
|
||||
this.invitees = [];
|
||||
this.emails = [];
|
||||
|
||||
// @TODO: This function didn't make it over this.resetInvitees();
|
||||
|
||||
// @TODO: Sync group invites?
|
||||
@@ -140,7 +143,7 @@ export default {
|
||||
// } else {
|
||||
// this.$router.push(`/groups/guilds/${this.group._id}`);
|
||||
// }
|
||||
this.$root.$emit('hide:modal', 'invite-modal');
|
||||
this.$root.$emit('hide::modal', 'invite-modal');
|
||||
// @TODO: error?
|
||||
// _resetInvitees();
|
||||
},
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<template lang="pug">
|
||||
// @TODO: Move this to a member directory
|
||||
div
|
||||
b-modal#members-modal(:title="$t('createGuild')", size='md')
|
||||
remove-member-modal(:member-to-remove='memberToRemove', :group-id='this.groupId' @member-removed='memberRemoved')
|
||||
b-modal#members-modal(:title="$t('createGuild')", size='md', :hide-footer='true')
|
||||
.header-wrap(slot="modal-header")
|
||||
.row
|
||||
.col-6
|
||||
@@ -16,36 +17,47 @@ div
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(v-for='sortOption in sortOptions', @click='sort(sortOption.value)', :key='sortOption.value') {{sortOption.text}}
|
||||
.row(v-for='member in sortedMembers')
|
||||
.col-11.no-padding-left
|
||||
member-details(:member='member')
|
||||
.col-1.actions
|
||||
b-dropdown(right=true)
|
||||
.svg-icon.inline.dots(slot='button-content', v-html="icons.dots")
|
||||
b-dropdown-item(@click='sort(option.value)', v-if='isLeader')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon", v-if='isLeader')
|
||||
span.text {{$t('removeMember')}}
|
||||
b-dropdown-item(@click='sendMessage(member._id)')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.messageIcon")
|
||||
span.text {{$t('sendMessage')}}
|
||||
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)', 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)', v-if='isLeader && groupIsSubscribed')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon")
|
||||
span.text {{$t('removeManager2')}}
|
||||
.row(v-if='groupId === "challenge"')
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary(@click='loadMoreMembers()') {{ $t('loadMore') }}
|
||||
.row.gradient(v-if='members.length > 3')
|
||||
.row(v-if='invites.length > 0')
|
||||
.col-6.offset-3.nav
|
||||
.nav-item(@click='viewMembers()', :class="{active: selectedPage === 'members'}") {{ $t('members') }}
|
||||
.nav-item(@click='viewInvites()', :class="{active: selectedPage === 'invites'}") {{ $t('invites') }}
|
||||
div(v-if='selectedPage === "members"')
|
||||
.row(v-for='(member, index) in sortedMembers')
|
||||
.col-11.no-padding-left
|
||||
member-details(:member='member')
|
||||
.col-1.actions
|
||||
b-dropdown(right=true)
|
||||
.svg-icon.inline.dots(slot='button-content', v-html="icons.dots")
|
||||
b-dropdown-item(@click='removeMember(member, index)', v-if='isLeader')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon", v-if='isLeader')
|
||||
span.text {{$t('removeMember')}}
|
||||
b-dropdown-item(@click='sendMessage(member._id)')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.messageIcon")
|
||||
span.text {{$t('sendMessage')}}
|
||||
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)', 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)', v-if='isLeader && groupIsSubscribed')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon")
|
||||
span.text {{$t('removeManager2')}}
|
||||
.row(v-if='groupId === "challenge"')
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary(@click='loadMoreMembers()') {{ $t('loadMore') }}
|
||||
.row.gradient(v-if='members.length > 3')
|
||||
div(v-if='selectedPage === "invites"')
|
||||
.row(v-for='member in invites')
|
||||
.col-11.no-padding-left
|
||||
member-details(:member='member')
|
||||
.modal-footer
|
||||
button.btn.btn-primary(@click='close()') {{ $t('close') }}
|
||||
</template>
|
||||
|
||||
<style lang='scss'>
|
||||
@@ -130,10 +142,29 @@ div
|
||||
.dropdown-icon-item .svg-icon {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
font-weight: bold;
|
||||
margin-bottom: .5em;
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 0 auto;
|
||||
padding: .5em;
|
||||
color: #878190;
|
||||
}
|
||||
|
||||
.nav-item:hover, .nav-item.active {
|
||||
color: #4f2a93;
|
||||
border-bottom: 2px solid #4f2a93;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// @TODO: Move this under members directory
|
||||
import sortBy from 'lodash/sortBy';
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
import bDropdown from 'bootstrap-vue/lib/components/dropdown';
|
||||
@@ -141,6 +172,7 @@ import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
|
||||
import { mapState } from 'client/libs/store';
|
||||
|
||||
import privateMessageModal from 'client/components/private-message-modal';
|
||||
import removeMemberModal from 'client/components/members/removeMemberModal';
|
||||
import MemberDetails from '../memberDetails';
|
||||
import removeIcon from 'assets/members/remove.svg';
|
||||
import messageIcon from 'assets/members/message.svg';
|
||||
@@ -155,12 +187,15 @@ export default {
|
||||
bDropdownItem,
|
||||
MemberDetails,
|
||||
privateMessageModal,
|
||||
removeMemberModal,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
sortOption: '',
|
||||
selectedPage: 'members',
|
||||
members: [],
|
||||
memberToRemove: '',
|
||||
invites: [],
|
||||
memberToRemove: {},
|
||||
sortOptions: [
|
||||
{
|
||||
value: 'level',
|
||||
@@ -212,6 +247,13 @@ export default {
|
||||
},
|
||||
sortedMembers () {
|
||||
let sortedMembers = this.members;
|
||||
|
||||
if (this.searchTerm) {
|
||||
sortedMembers = sortedMembers.filter(member => {
|
||||
return member.profile.name.toLowerCase().indexOf(this.searchTerm.toLowerCase) !== -1;
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.sortOption) return sortedMembers;
|
||||
|
||||
sortedMembers = sortBy(this.members, [(member) => {
|
||||
@@ -227,7 +269,7 @@ export default {
|
||||
}
|
||||
}]);
|
||||
|
||||
return this.members;
|
||||
return sortedMembers;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
@@ -252,6 +294,12 @@ export default {
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
this.members = members;
|
||||
|
||||
let invites = await this.$store.dispatch('members:getGroupInvites', {
|
||||
groupId,
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
this.invites = invites;
|
||||
}
|
||||
|
||||
if (this.$store.state.memberModalOptions.viewingMembers.length > 0) {
|
||||
@@ -277,24 +325,15 @@ export default {
|
||||
|
||||
this.$root.$emit('show::modal', 'members-modal');
|
||||
},
|
||||
async removeMember (member) {
|
||||
async removeMember (member, index) {
|
||||
this.memberToRemove = member;
|
||||
this.memberToRemove.index = index;
|
||||
this.$root.$emit('show::modal', 'remove-member');
|
||||
},
|
||||
async confirmRemoveMember (confirmation) {
|
||||
if (!confirmation) {
|
||||
this.memberToRemove = '';
|
||||
return;
|
||||
}
|
||||
|
||||
await this.$store.dispatch('members:removeMember', {
|
||||
memberId: this.memberToRemove._id,
|
||||
groupId: this.group._id,
|
||||
message: this.removeMessage,
|
||||
});
|
||||
|
||||
this.memberToRemove = '';
|
||||
this.removeMessage = '';
|
||||
memberRemoved () {
|
||||
this.members.splice(this.memberToRemove.index, 1);
|
||||
this.group.memberCount -= 1;
|
||||
this.memberToRemove = {};
|
||||
},
|
||||
async quickReply (uid) {
|
||||
this.memberToReply = uid;
|
||||
@@ -330,6 +369,12 @@ export default {
|
||||
|
||||
this.members = this.members.concat(newMembers);
|
||||
},
|
||||
viewMembers () {
|
||||
this.selectedPage = 'members';
|
||||
},
|
||||
viewInvites () {
|
||||
this.selectedPage = 'invites';
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -4,11 +4,11 @@ router-link.card-link(:to="{ name: 'guild', params: { groupId: guild._id } }")
|
||||
.card-block
|
||||
.row
|
||||
.col-md-2.badge-column
|
||||
.shield-wrap
|
||||
.shield-wrap(:class="{gold: guild.memberCount > 1000, silver: guild.memberCount > 100 && guild.memberCount < 999}")
|
||||
.svg-icon.shield(v-html="icons.goldGuildBadge", v-if='guild.memberCount > 1000')
|
||||
.svg-icon.shield(v-html="icons.silverGuildBadgeIcon", v-if='guild.memberCount > 100 && guild.memberCount < 999')
|
||||
.svg-icon.shield(v-html="icons.bronzeGuildBadgeIcon", v-if='guild.memberCount < 100')
|
||||
.member-count {{guild.memberCount}}
|
||||
.member-count {{ guild.memberCount | abbrNum }}
|
||||
.col-md-10
|
||||
.row
|
||||
.col-md-8
|
||||
@@ -76,6 +76,14 @@ router-link.card-link(:to="{ name: 'guild', params: { groupId: guild._id } }")
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.gold {
|
||||
color: #fdbb5a;
|
||||
}
|
||||
|
||||
.silver {
|
||||
color: #c2c2c2;
|
||||
}
|
||||
|
||||
.badge-column {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
div(v-if='questData')
|
||||
questDialogContent(:item="questData")
|
||||
div.text-center
|
||||
button.btn.btn-primary(@click='questInit()', :disabled="!Boolean(selectedQuest)") {{$t('inviteToPartyOrQuest')}}
|
||||
button.btn.btn-primary(@click='questInit()', :disabled="!Boolean(selectedQuest) || loading") {{$t('inviteToPartyOrQuest')}}
|
||||
div.text-center
|
||||
p {{$t('inviteInformation')}}
|
||||
.side-panel(v-if='questData')
|
||||
@@ -122,6 +122,7 @@ export default {
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
selectedQuest: {},
|
||||
icons: Object.freeze({
|
||||
copy: copyIcon,
|
||||
@@ -157,6 +158,8 @@ export default {
|
||||
},
|
||||
|
||||
async questInit () {
|
||||
this.loading = true;
|
||||
|
||||
Analytics.updateUser({
|
||||
partyID: this.group._id,
|
||||
partySize: this.group.memberCount,
|
||||
@@ -170,6 +173,8 @@ export default {
|
||||
|
||||
if (this.$store.state.party.data) this.$store.state.party.data.quest = quest;
|
||||
|
||||
this.loading = false;
|
||||
|
||||
this.$root.$emit('hide::modal', 'start-quest-modal');
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,8 +12,13 @@
|
||||
.row
|
||||
textarea(:placeholder="$t('tavernCommunityGuidelinesPlaceholder')", v-model='newMessage', :class='{"user-entry": newMessage}', @keydown='updateCarretPosition')
|
||||
autocomplete(:text='newMessage', v-on:select="selectedAutocomplete", :coords='coords', :chat='group.chat')
|
||||
button.btn.btn-secondary.send-chat.float-right(v-once, @click='sendMessage()') {{ $t('send') }}
|
||||
button.btn.btn-secondary.float-left(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
|
||||
|
||||
.row
|
||||
.col-6
|
||||
button.btn.btn-secondary.send-chat.float-left(v-once, @click='sendMessage()') {{ $t('send') }}
|
||||
.col-6
|
||||
button.btn.btn-secondary.float-right.fetch(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
|
||||
button.btn.btn-secondary.float-right(v-once, @click='reverseChat()') {{ $t('reverseChat') }}
|
||||
|
||||
.row.community-guidelines(v-if='!communityGuidelinesAccepted')
|
||||
div.col-8(v-once, v-html="$t('communityGuidelinesIntro')")
|
||||
@@ -523,6 +528,11 @@ export default {
|
||||
document.body.removeChild(div);
|
||||
},
|
||||
updateCarretPosition (eventUpdate) {
|
||||
if (eventUpdate.metaKey && eventUpdate.keyCode === 13) {
|
||||
this.sendMessage();
|
||||
return;
|
||||
}
|
||||
|
||||
let text = eventUpdate.target;
|
||||
this.getCoord(eventUpdate, text);
|
||||
},
|
||||
@@ -551,6 +561,9 @@ export default {
|
||||
async fetchRecentMessages () {
|
||||
this.group = await this.$store.dispatch('guilds:getGroup', {groupId: TAVERN_ID});
|
||||
},
|
||||
reverseChat () {
|
||||
this.group.chat.reverse();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -186,8 +186,9 @@ export default {
|
||||
window.scrollTo(0, 200);
|
||||
this.loadHero(id, index);
|
||||
},
|
||||
clickMember (hero) {
|
||||
this.$store.state.profileUser = hero;
|
||||
async clickMember (hero) {
|
||||
let heroDetails = await this.$store.dispatch('members:fetchMember', { memberId: hero._id });
|
||||
this.$store.state.profileUser = heroDetails.data.data;
|
||||
this.$store.state.profileOptions.startingPage = 'profile';
|
||||
this.$root.$emit('show::modal', 'profile');
|
||||
},
|
||||
|
||||
53
website/client/components/members/removeMemberModal.vue
Normal file
53
website/client/components/members/removeMemberModal.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<template lang="pug">
|
||||
b-modal#remove-member(:title="$t('removeMember')", size='md', :hide-footer="true")
|
||||
.text-center
|
||||
h2.col-12 {{ $t('sureKick') }}
|
||||
.col-12.removing-member(v-if='memberToRemove.profile') {{memberToRemove.profile.name}}
|
||||
.modal-body
|
||||
textarea.form-control(type='text',
|
||||
rows='5',
|
||||
:placeholder="$t('optionalMessage')",
|
||||
v-model='removeMessage')
|
||||
.modal-footer
|
||||
button.pull-left.btn.btn-danger(@click='confirmRemoveMember()') {{ $t('yesRemove') }}
|
||||
button.btn.btn-default(@click='close()') {{ $t('cancel') }}
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.removing-member {
|
||||
color: #878190;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import bModal from 'bootstrap-vue/lib/components/modal';
|
||||
|
||||
export default {
|
||||
props: ['memberToRemove', 'groupId'],
|
||||
components: {
|
||||
bModal,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
removeMessage: '',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async confirmRemoveMember () {
|
||||
await this.$store.dispatch('members:removeMember', {
|
||||
memberId: this.memberToRemove._id,
|
||||
groupId: this.groupId,
|
||||
message: this.removeMessage,
|
||||
});
|
||||
|
||||
this.removeMessage = '';
|
||||
this.$emit('member-removed', this.memberToRemove);
|
||||
this.close();
|
||||
},
|
||||
close () {
|
||||
this.$root.$emit('hide::modal', 'remove-member');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -34,7 +34,8 @@
|
||||
.form-horizontal(v-if='user.flags.classSelected && !user.preferences.disableClasses')
|
||||
h5 {{ $t('characterBuild') }}
|
||||
h6(v-once) {{ $t('class') + ': ' }}
|
||||
span {{ classText }}
|
||||
// @TODO: what is classText
|
||||
span(v-if='classText') {{ classText }}
|
||||
button.btn.btn-danger.btn-xs(@click='changeClass(null)', v-once) {{ $t('changeClass') }}
|
||||
small.cost 3
|
||||
span.Pet_Currency_Gem1x.inline-gems
|
||||
@@ -117,21 +118,20 @@
|
||||
button.btn.btn-primary(v-if='!user.auth[network.key].id', @click='socialLogin(network.key, user)') {{ $t('registerWithSocial', {network: network.name}) }}
|
||||
button.btn.btn-primary(disabled='disabled', v-if='!hasBackupAuthOption(network.key) && user.auth[network.key].id') {{ $t('registeredWithSocial', {network: network.name}) }}
|
||||
button.btn.btn-danger(@click='deleteSocialAuth(network.key)', v-if='hasBackupAuthOption(network.key) && user.auth[network.key].id') {{ $t('detachSocial', {network: network.name}) }}
|
||||
// hr
|
||||
// TODO
|
||||
// div(v-if='!user.auth.local.username')
|
||||
hr
|
||||
div(v-if='!user.auth.local.username')
|
||||
p {{ $t('addLocalAuth') }}
|
||||
form(ng-submit='http("post", "/api/v3/user/auth/local/register", localAuth, "addedLocalAuth")', name='localAuth', novalidate)
|
||||
.form(name='localAuth', novalidate)
|
||||
//-.alert.alert-danger(ng-messages='changeUsername.$error && changeUsername.submitted') {{ $t('fillAll') }}
|
||||
.form-group
|
||||
input.form-control(type='text', placeholder="$t('username')", v-model='localAuth.username', required)
|
||||
input.form-control(type='text', :placeholder="$t('username')", v-model='localAuth.username', required)
|
||||
.form-group
|
||||
input.form-control(type='text', placeholder="$t('email')", v-model='localAuth.email', required)
|
||||
input.form-control(type='text', :placeholder="$t('email')", v-model='localAuth.email', required)
|
||||
.form-group
|
||||
input.form-control(type='password', placeholder="$t('password')", v-model='localAuth.password', required)
|
||||
input.form-control(type='password', :placeholder="$t('password')", v-model='localAuth.password', required)
|
||||
.form-group
|
||||
input.form-control(type='password', placeholder="$t('confirmPass')", v-model='localAuth.confirmPassword', required)
|
||||
button.btn.btn-primary(type='submit', ng-disabled='localAuth.$invalid', value="$t('submit')")
|
||||
input.form-control(type='password', :placeholder="$t('confirmPass')", v-model='localAuth.confirmPassword', required)
|
||||
button.btn.btn-primary(type='submit', @click='addLocalAuth()') {{ $t('submit') }}
|
||||
|
||||
.usersettings(v-if='user.auth.local.username')
|
||||
p {{ $t('username') }}
|
||||
@@ -231,6 +231,12 @@ export default {
|
||||
usernameUpdates: {},
|
||||
emailUpdates: {},
|
||||
passwordUpdates: {},
|
||||
localAuth: {
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
confirmPassword: '',
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
@@ -290,6 +296,7 @@ export default {
|
||||
// Guide.goto('intro', 0, true);
|
||||
},
|
||||
showBailey () {
|
||||
this.user.flags.newStuff = true;
|
||||
this.$root.$emit('show::modal', 'new-stuff');
|
||||
},
|
||||
hasBackupAuthOption (networkKeyToCheck) {
|
||||
@@ -380,6 +387,9 @@ export default {
|
||||
alert(e.message);
|
||||
}
|
||||
},
|
||||
addLocalAuth () {
|
||||
axios.post('/api/v3/user/auth/local/register', this.localAuth, 'addedLocalAuth');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -163,6 +163,16 @@ export default {
|
||||
}]);
|
||||
},
|
||||
purchasedPlanIdInfo () {
|
||||
if (!this.subscriptionBlocks[this.user.purchased.plan.planId]) {
|
||||
// @TODO: find which subs are in the common
|
||||
console.log(this.subscriptionBlocks[this.user.purchased.plan.planId]); // eslint-disable-line
|
||||
return {
|
||||
price: 0,
|
||||
months: 0,
|
||||
plan: '',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
price: this.subscriptionBlocks[this.user.purchased.plan.planId].price,
|
||||
months: this.subscriptionBlocks[this.user.purchased.plan.planId].months,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template lang="pug">
|
||||
nav.navbar.navbar-inverse.fixed-top.navbar-toggleable-sm
|
||||
.navbar-header
|
||||
router-link.nav-item(
|
||||
to='/static/home',
|
||||
)
|
||||
router-link.nav-item(:to='!isUserLoggedIn ? "/static/home" : "/"')
|
||||
.logo.svg-icon(v-html='icons.logo')
|
||||
.collapse.navbar-collapse
|
||||
ul.navbar-nav.mr-auto(v-if='$route.name !== "home"')
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
.filters.d-flex.justify-content-end
|
||||
.filter.small-text(
|
||||
v-for="filter in types[type].filters",
|
||||
:class="{active: activeFilter.label === filter.label}",
|
||||
:class="{active: activeFilters[type].label === filter.label}",
|
||||
@click="activateFilter(type, filter)",
|
||||
) {{ $t(filter.label) }}
|
||||
.tasks-list(ref="taskList", v-sortable='', @onsort='sorted')
|
||||
@@ -226,9 +226,14 @@ export default {
|
||||
reward: rewardIcon,
|
||||
});
|
||||
|
||||
let activeFilters = {};
|
||||
for (let type in types) {
|
||||
activeFilters[type] = types[type].filters.find(f => f.default === true);
|
||||
}
|
||||
|
||||
return {
|
||||
types,
|
||||
activeFilter: types[this.type].filters.find(f => f.default === true),
|
||||
activeFilters,
|
||||
icons,
|
||||
openedCompletedTodos: false,
|
||||
|
||||
@@ -252,7 +257,7 @@ export default {
|
||||
return inAppRewards(this.user);
|
||||
},
|
||||
hasRewardsList () {
|
||||
return this.isUser === true && this.type === 'reward' && this.activeFilter.label !== 'custom';
|
||||
return this.isUser === true && this.type === 'reward' && this.activeFilters[this.type].label !== 'custom';
|
||||
},
|
||||
initialColumnDescription () {
|
||||
// Show the column description in the middle only if there are no elements (tasks or in app items)
|
||||
@@ -262,6 +267,12 @@ export default {
|
||||
|
||||
return this.tasks[`${this.type}s`].length === 0;
|
||||
},
|
||||
dailyDueDefaultView () {
|
||||
if (this.user.preferences.dailyDueDefaultView) {
|
||||
this.activateFilter('daily', this.types.daily.filters[1]);
|
||||
}
|
||||
return this.user.preferences.dailyDueDefaultView;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
taskList: {
|
||||
@@ -270,6 +281,11 @@ export default {
|
||||
}, 250),
|
||||
deep: true,
|
||||
},
|
||||
dailyDueDefaultView () {
|
||||
if (this.user.preferences.dailyDueDefaultView) {
|
||||
this.activateFilter('daily', this.types.daily.filters[1]);
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.setColumnBackgroundVisibility();
|
||||
@@ -301,7 +317,7 @@ export default {
|
||||
if (type === 'todo' && filter.label === 'complete2') {
|
||||
this.loadCompletedTodos();
|
||||
}
|
||||
this.activeFilter = filter;
|
||||
this.activeFilters[type] = filter;
|
||||
},
|
||||
setColumnBackgroundVisibility () {
|
||||
this.$nextTick(() => {
|
||||
@@ -330,7 +346,7 @@ export default {
|
||||
},
|
||||
filterTask (task) {
|
||||
// View
|
||||
if (!this.activeFilter.filter(task)) return false;
|
||||
if (!this.activeFilters[task.type].filter(task)) return false;
|
||||
|
||||
// Tags
|
||||
const selectedTags = this.selectedTags;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
.svg-icon.envelope(v-html="icons.messageIcon")
|
||||
h4(v-once) Nothing Here Yet
|
||||
p(v-once) Select a conversation on the left
|
||||
chat-message.container-fluid.message-scroll(:chat.sync='activeChat', :inbox='true', ref="chatscroll")
|
||||
chat-message.message-scroll(:chat.sync='activeChat', :inbox='true', ref="chatscroll")
|
||||
|
||||
// @TODO: Implement new message header here when we fix the above
|
||||
|
||||
|
||||
@@ -20,9 +20,9 @@ div
|
||||
member-details(:member="user")
|
||||
.row
|
||||
.col-6.offset-3.text-center.nav
|
||||
.nav-item(@click='selectedPage = "profile"', :class="{active: selectedPage === 'profile'}") {{ $t('profile') }}
|
||||
.nav-item(@click='selectedPage = "stats"', :class="{active: selectedPage === 'stats'}") {{ $t('stats') }}
|
||||
.nav-item(@click='selectedPage = "achievements"', :class="{active: selectedPage === 'achievements'}") {{ $t('achievements') }}
|
||||
.nav-item(@click='selectPage("profile")', :class="{active: selectedPage === 'profile'}") {{ $t('profile') }}
|
||||
.nav-item(@click='selectPage("stats")', :class="{active: selectedPage === 'stats'}") {{ $t('stats') }}
|
||||
.nav-item(@click='selectPage("achievements")', :class="{active: selectedPage === 'achievements'}") {{ $t('achievements') }}
|
||||
#userProfile.standard-page(v-show='selectedPage === "profile"', v-if='user.profile')
|
||||
.row
|
||||
.col-8
|
||||
@@ -94,9 +94,9 @@ div
|
||||
.row(v-for='(category, key) in achievements')
|
||||
h2.col-12.text-center {{ $t(key+'Achievs') }}
|
||||
.col-3.text-center(v-for='(achievement, key) in category.achievements')
|
||||
.box.achievement-container(:id='key', :class='{"achievement-unearned": !achievement.earned}')
|
||||
.box.achievement-container(:id='key + "-achievement"', :class='{"achievement-unearned": !achievement.earned}')
|
||||
b-popover(
|
||||
:target="'#' + key",
|
||||
:target="'#' + key + '-achievement'",
|
||||
triggers="hover",
|
||||
placement="top",
|
||||
)
|
||||
@@ -121,11 +121,11 @@ div
|
||||
span {{ value }}
|
||||
#stats.standard-page(v-show='selectedPage === "stats"', v-if='user.preferences')
|
||||
.row
|
||||
.col-6 {{$t('equipment')}}
|
||||
h2.text-center
|
||||
.col-6
|
||||
h2.text-center {{$t('equipment')}}
|
||||
.well
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.eyewear}')
|
||||
.box(:class='{white: equippedItems.eyewear && equippedItems.eyewear.indexOf("base_0") === -1}')
|
||||
div(:class="`shop_${equippedItems.eyewear}`")
|
||||
h3 {{$t('eyewear')}}
|
||||
.col-4.item-wrapper
|
||||
@@ -133,11 +133,11 @@ div
|
||||
div(:class="`shop_${equippedItems.head}`")
|
||||
h3 {{$t('headGear')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.headAccessory}')
|
||||
.box(:class='{white: equippedItems.headAccessory && equippedItems.headAccessory.indexOf("base_0") === -1}')
|
||||
div(:class="`shop_${equippedItems.headAccessory}`")
|
||||
h3 {{$t('headAccess')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.backAccessory}')
|
||||
.box(:class='{white: equippedItems.backAccessory && equippedItems.backAccessory.indexOf("base_0") === -1}')
|
||||
div(:class="`shop_${equippedItems.backAccessory}`")
|
||||
h3 {{$t('backAccess')}}
|
||||
.col-4.item-wrapper
|
||||
@@ -145,7 +145,7 @@ div
|
||||
div(:class="`shop_${equippedItems.armor}`")
|
||||
h3 {{$t('armor')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: equippedItems.bodyAccessory}')
|
||||
.box(:class='{white: equippedItems.bodyAccessory && equippedItems.bodyAccessory.indexOf("base_0") === -1}')
|
||||
div(:class="`shop_${equippedItems.bodyAccessory}`")
|
||||
h3 {{$t('bodyAccess')}}
|
||||
.col-4.item-wrapper
|
||||
@@ -161,7 +161,7 @@ div
|
||||
h2.text-center {{$t('costume')}}
|
||||
.well
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.eyewear}')
|
||||
.box(:class='{white: costumeItems.eyewear && costumeItems.eyewear.indexOf("base_0") === -1}')
|
||||
div(:class="`shop_${costumeItems.eyewear}`")
|
||||
h3 {{$t('eyewear')}}
|
||||
.col-4.item-wrapper
|
||||
@@ -169,11 +169,11 @@ div
|
||||
div(:class="`shop_${costumeItems.head}`")
|
||||
h3 {{$t('headGear')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.headAccessory}')
|
||||
.box(:class='{white: costumeItems.headAccessory && costumeItems.headAccessory.indexOf("base_0") === -1}')
|
||||
div(:class="`shop_${costumeItems.headAccessory}`")
|
||||
h3 {{$t('headAccess')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.backAccessory}')
|
||||
.box(:class='{white: costumeItems.backAccessory && costumeItems.backAccessory.indexOf("base_0") === -1}')
|
||||
div(:class="`shop_${costumeItems.backAccessory}`")
|
||||
h3 {{$t('backAccess')}}
|
||||
.col-4.item-wrapper
|
||||
@@ -181,7 +181,7 @@ div
|
||||
div(:class="`shop_${costumeItems.armor}`")
|
||||
h3 {{$t('armor')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.bodyAccessory}')
|
||||
.box(:class='{white: costumeItems.bodyAccessory && costumeItems.bodyAccessory.indexOf("base_0") === -1}')
|
||||
div(:class="`shop_${costumeItems.bodyAccessory}`")
|
||||
h3 {{$t('bodyAccess')}}
|
||||
.col-4.item-wrapper
|
||||
@@ -189,8 +189,8 @@ div
|
||||
div(:class="`shop_${costumeItems.weapon}`")
|
||||
h3 {{$t('mainHand')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: user.preferences.background}')
|
||||
div(:class="user.preferences.background")
|
||||
.box(:class='{white: user.preferences.background}', style="overflow:hidden")
|
||||
div(:class="'background_' + user.preferences.background")
|
||||
h3 {{$t('background')}}
|
||||
.col-4.item-wrapper
|
||||
.box(:class='{white: costumeItems.shield && costumeItems.shield.indexOf("base_0") === -1}')
|
||||
@@ -326,7 +326,7 @@ div
|
||||
}
|
||||
|
||||
.pet, .mount {
|
||||
margin-top: -1.6em;
|
||||
margin-top: -1.8em !important;
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -660,6 +660,7 @@ export default {
|
||||
|
||||
this.editingProfile.name = user.profile.name;
|
||||
this.editingProfile.imageUrl = user.profile.imageUrl;
|
||||
this.editingProfile.blurb = user.profile.blurb;
|
||||
|
||||
if (!user.achievements.quests) user.achievements.quests = {};
|
||||
if (!user.achievements.challenges) user.achievements.challenges = {};
|
||||
@@ -700,6 +701,11 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
selectPage (page) {
|
||||
this.selectedPage = page;
|
||||
// @TODO: rename this property?
|
||||
this.$store.state.profileOptions.startingPage = page;
|
||||
},
|
||||
sendMessage () {
|
||||
this.$store.state.userIdToMessage = this.user._id;
|
||||
this.$root.$emit('show::modal', 'private-message');
|
||||
|
||||
@@ -1,6 +1,32 @@
|
||||
import intersection from 'lodash/intersection';
|
||||
|
||||
export default {
|
||||
filters: {
|
||||
// https://stackoverflow.com/questions/2685911/is-there-a-way-to-round-numbers-into-a-reader-friendly-format-e-g-1-1k
|
||||
abbrNum: (number) => {
|
||||
let decPlaces = 2;
|
||||
decPlaces = Math.pow(10, decPlaces);
|
||||
|
||||
let abbrev = ['k', 'm', 'b', 't'];
|
||||
for (let i = abbrev.length - 1; i >= 0; i--) {
|
||||
let size = Math.pow(10, (i + 1) * 3);
|
||||
|
||||
if (size <= number) {
|
||||
number = Math.round(number * decPlaces / size) / decPlaces;
|
||||
|
||||
if (number === 1000 && i < abbrev.length - 1) {
|
||||
number = 1;
|
||||
i++;
|
||||
}
|
||||
|
||||
number += abbrev[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return number;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
isMemberOfGroup (user, group) {
|
||||
if (group._id === this.$store.state.constants.TAVERN_ID) return true;
|
||||
|
||||
@@ -21,8 +21,11 @@ export async function fetchMember (store, payload) {
|
||||
|
||||
export async function getGroupInvites (store, payload) {
|
||||
let url = `${apiV3Prefix}/groups/${payload.groupId}/invites`;
|
||||
if (payload.includeAllPublicFields) {
|
||||
url += '?includeAllPublicFields=true';
|
||||
}
|
||||
let response = await axios.get(url);
|
||||
return response;
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
export async function getChallengeMembers (store, payload) {
|
||||
|
||||
@@ -95,6 +95,7 @@ export default function () {
|
||||
challengeOptions: {
|
||||
cloning: false,
|
||||
tasksToClone: {},
|
||||
workingChallenge: {},
|
||||
},
|
||||
editingGroup: {}, // @TODO move to local state
|
||||
// content data, frozen to prevent Vue from modifying it since it's static and never changes
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
"joinedChallenge": "Joined a Challenge",
|
||||
"joinedChallengeText": "This user put themselves to the test by joining a Challenge!",
|
||||
"myChallenges": "My Challenges",
|
||||
"findChallenges": "Find Challenges",
|
||||
"findChallenges": "Discover Challenges",
|
||||
"noChallengeTitle": "You don't have any Challenges.",
|
||||
"challengeDescription1": "Challenges are community events in which players compete and earn prizes by completing a group of related tasks.",
|
||||
"challengeDescription2": "Find recommended Challenges based on your interests, browse Habitica's public Challenges, or create your own Challenges.",
|
||||
@@ -123,5 +123,6 @@
|
||||
"summaryTooLong": "Summary is too long",
|
||||
"descriptionRequired": "Description is required",
|
||||
"locationRequired": "Location of challenge is required ('Add to')",
|
||||
"categoiresRequired": "One or more categories must be selected"
|
||||
"categoiresRequired": "One or more categories must be selected",
|
||||
"viewProgressOf": "View Progress Of"
|
||||
}
|
||||
|
||||
@@ -382,5 +382,8 @@
|
||||
"questOwnerRewards": "Quest Owner Rewards",
|
||||
"updateParty": "Update Party",
|
||||
"upgrade": "Upgrade",
|
||||
"selectPartyMember": "Select a Party Member"
|
||||
"selectPartyMember": "Select a Party Member",
|
||||
"areYouSureDeleteMessage": "Are you sure you want to delete this message?",
|
||||
"reverseChat": "Reverse Chat",
|
||||
"invites": "Invites"
|
||||
}
|
||||
|
||||
@@ -170,6 +170,8 @@ api.getMemberAchievements = {
|
||||
};
|
||||
|
||||
// Return a request handler for getMembersForGroup / getInvitesForGroup / getMembersForChallenge
|
||||
|
||||
// @TODO: This violates the Liskov substitution principle. We should create factory functions. See Webhooks for a good example
|
||||
function _getMembersForItem (type) {
|
||||
// check for allowed `type`
|
||||
if (['group-members', 'group-invites', 'challenge-members'].indexOf(type) === -1) {
|
||||
@@ -243,9 +245,18 @@ function _getMembersForItem (type) {
|
||||
} else if (type === 'group-invites') {
|
||||
if (group.type === 'guild') { // eslint-disable-line no-lonely-if
|
||||
query['invitations.guilds.id'] = group._id;
|
||||
|
||||
if (req.query.includeAllPublicFields === 'true') {
|
||||
fields = memberFields;
|
||||
addComputedStats = true;
|
||||
}
|
||||
} else {
|
||||
query['invitations.party.id'] = group._id; // group._id and not groupId because groupId could be === 'party'
|
||||
// @TODO invitations are now stored like this: `'invitations.parties': []` Probably need a database index for it.
|
||||
if (req.query.includeAllPublicFields === 'true') {
|
||||
fields = memberFields;
|
||||
addComputedStats = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user