Fixes sept 1 (#9016)

* Added avatars to inbox

* Added ordering of inbox messages

* Fixed blurb not converting to string

* Added message to member modal

* Added quest invites

* Moved filters to server
This commit is contained in:
Keith Holliday
2017-09-01 15:26:10 -06:00
committed by GitHub
parent e450e52836
commit c2aaa9b592
11 changed files with 180 additions and 40 deletions

View File

@@ -4,15 +4,13 @@
.col-12
copy-as-todo-modal(:copying-message='copyingMessage', :group-name='groupName', :group-id='groupId')
report-flag-modal
.row
.hr.col-12
div(v-for="(msg, index) in chat", v-if='chat && (inbox || Object.keys(cachedProfileData).length > 0)')
// @TODO: is there a different way to do these conditionals? This creates an infinite loop
//.hr(v-if='displayDivider(msg)')
.hr-middle(v-once) {{ msg.timestamp }}
.row(v-if='user._id !== msg.uuid')
.col-2
.col-4
avatar(v-if='cachedProfileData[msg.uuid]',
:member="cachedProfileData[msg.uuid]", :avatarOnly="true",
:hideClassBadge='true')
@@ -41,7 +39,7 @@
.svg-icon(v-html="icons.liked")
| + {{ likeCount(msg) }}
.row(v-if='user._id === msg.uuid')
.card.col-8.offset-2
.card.col-8
.card-block
h3.leader(:class='userLevelStyle(cachedProfileData[msg.uuid])')
| {{msg.user}}
@@ -65,7 +63,7 @@
span.action.float-right(v-if='likeCount(msg) > 0')
.svg-icon(v-html="icons.liked")
| + {{ likeCount(msg) }}
.col-2
.col-4
avatar(v-if='cachedProfileData[msg.uuid]',
:member="cachedProfileData[msg.uuid]", :avatarOnly="true",
:hideClassBadge='true')
@@ -288,10 +286,13 @@ export default {
return;
}
// @TODO: Not sure we need this hash
let aboutToCache = {};
this.messages.forEach(message => {
let uuid = message.uuid;
if (uuid && !this.cachedProfileData[uuid]) {
if (uuid && !this.cachedProfileData[uuid] && !aboutToCache[uuid]) {
if (uuid === 'system' || this.currentProfileLoadedCount === this.currentProfileLoadedEnd) return;
aboutToCache[uuid] = {};
promises.push(axios.get(`/api/v3/members/${uuid}`));
this.currentProfileLoadedCount += 1;
}

View File

@@ -82,6 +82,13 @@ export default {
},
],
guilds: [],
queryFilters: {
minMemberCount: 0,
maxMemberCount: 0,
leader: false,
member: false,
categories: '',
},
};
},
created () {
@@ -100,18 +107,74 @@ export default {
},
},
methods: {
updateSearch (eventData) {
this.search = eventData.searchTerm;
async updateSearch (eventData) {
// this.search = eventData.searchTerm; @TODO: Probably don't need this anymore
// Reset the page when filters are updated but not the other queries
this.lastPageLoaded = 0;
this.queryFilters.page = this.lastPageLoaded;
this.queryFilters.search = eventData.searchTerm;
let guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
this.guilds = guilds;
},
updateFilters (eventData) {
this.filters = eventData;
async updateFilters (eventData) {
// this.filters = eventData; @TODO: Probably don't need this anymore
// Reset all filters
this.queryFilters = {
minMemberCount: 0,
maxMemberCount: 0,
leader: false,
member: false,
categories: '',
};
// Reset the page when filters are updated
this.lastPageLoaded = 0;
this.queryFilters.page = this.lastPageLoaded;
this.queryFilters.categories = eventData.categories.join(',');
// Role filters
let filteringRole = eventData.roles && eventData.roles.length > 0;
if (filteringRole && eventData.roles.indexOf('member') !== -1) {
this.queryFilters.member = true;
}
if (filteringRole && eventData.roles.indexOf('guild_leader') !== -1) {
this.queryFilters.leader = true;
}
// Size filters
if (eventData.guildSize && eventData.guildSize.indexOf('gold_tier') !== -1) {
this.queryFilters.minMemberCount = 1000;
this.queryFilters.maxMemberCount = 0; // No max
}
if (eventData.guildSize && eventData.guildSize.indexOf('silver_tier') !== -1) {
this.queryFilters.minMemberCount = 100;
this.queryFilters.maxMemberCount = 999;
}
if (eventData.guildSize && eventData.guildSize.indexOf('bronze_tier') !== -1) {
this.queryFilters.minMemberCount = 0; // No Min
this.queryFilters.maxMemberCount = 99;
}
let guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
this.guilds = guilds;
},
async fetchGuilds () {
// We have the data cached
if (this.lastPageLoaded === 0 && this.guilds.length > 0) return;
this.loading = true;
let guilds = await this.$store.dispatch('guilds:getPublicGuilds', {page: this.lastPageLoaded});
this.queryFilters.page = this.lastPageLoaded;
let guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
if (guilds.length === 0) this.hasLoadedAllGuilds = true;
this.guilds.push(...guilds);

View File

@@ -27,12 +27,15 @@
.col-12
h3(v-once) {{ $t('chat') }}
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') }}
.col-12
chat-message(:chat.sync='group.chat', :group-id='group._id', group-name='group.name')
.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') }}
.row
.col-12.hr
chat-message(:chat.sync='group.chat', :group-id='group._id', group-name='group.name')
.col-4.sidebar
.row(:class='{"guild-background": !isParty}')
@@ -256,11 +259,15 @@
.chat-row {
margin-top: 2em;
.send-chat {
margin-top: -3.5em;
z-index: 10;
.new-message-row {
position: relative;
margin-right: 1em;
}
.send-chat {
z-index: 10;
position: absolute;
right: 1em;
bottom: 3em;
}
}
@@ -370,6 +377,14 @@
height: 15px;
}
.hr {
width: 100%;
height: 20px;
border-bottom: 1px solid $gray-500;
text-align: center;
margin: 2em 0;
}
</style>
<script>

View File

@@ -24,7 +24,7 @@ div
span.dropdown-icon-item
.svg-icon.inline(v-html="icons.removeIcon", v-if='isLeader')
span.text {{$t('removeMember')}}
b-dropdown-item(@click='sort(option.value)')
b-dropdown-item(@click='sendMessage(member._id)')
span.dropdown-icon-item
.svg-icon.inline(v-html="icons.messageIcon")
span.text {{$t('sendMessage')}}
@@ -105,6 +105,7 @@ import bDropdown from 'bootstrap-vue/lib/components/dropdown';
import bDropdownItem from 'bootstrap-vue/lib/components/dropdown-item';
import { mapState } from 'client/libs/store';
import privateMessageModal from 'client/components/private-message-modal';
import MemberDetails from '../memberDetails';
import removeIcon from 'assets/members/remove.svg';
import messageIcon from 'assets/members/message.svg';
@@ -117,6 +118,7 @@ export default {
bDropdown,
bDropdownItem,
MemberDetails,
privateMessageModal,
},
data () {
return {
@@ -147,6 +149,7 @@ export default {
messageIcon,
starIcon,
}),
userIdToMessage: '',
};
},
computed: {
@@ -194,6 +197,10 @@ export default {
},
},
methods: {
sendMessage () {
this.userIdToMessage = this.user._id;
this.$root.$emit('show::modal', 'private-message');
},
async getMembers () {
let groupId = this.groupId;
if (groupId && groupId !== 'challenge') {

View File

@@ -142,10 +142,12 @@ export default {
this.emitFilters();
},
searchTerm: throttle(function searchTerm (newSearch) {
if (newSearch.length <= 1) return; // @TODO: eh, should we limit based on length?
this.$emit('search', {
searchTerm: newSearch,
});
}, 250),
}, 1000),
},
methods: {
emitFilters () {

View File

@@ -21,6 +21,7 @@
button.btn.btn-info(@click='acceptCommunityGuidelines()', v-once) {{ $t('acceptCommunityGuidelines') }}
.row
.hr.col-12
chat-message(:chat.sync='group.chat', :group-id='group._id', group-name='group.name')
.col-md-4.sidebar

View File

@@ -6,6 +6,11 @@ div.item-with-icon.item-notifications.dropdown
.dropdown-menu.dropdown-menu-right.user-dropdown
h4.dropdown-item.dropdown-separated(v-if='!hasNoNotifications()') {{ $t('notifications') }}
h4.dropdown-item.toolbar-notifs-no-messages(v-if='hasNoNotifications()') {{ $t('noNotifications') }}
a.dropdown-item(v-if='user.party.quest && user.party.quest.RSVPNeeded')
div {{ $t('invitedTo', {name: quests.quests[user.party.quest.key].text()}) }}
div
button.btn.btn-primary(@click='questAccept(user.party._id)') Accept
button.btn.btn-primary(@click='questReject(user.party._id)') Reject
a.dropdown-item(v-if='user.purchased.plan.mysteryItems.length', @click='go("/inventory/items")')
span.glyphicon.glyphicon-gift
span {{ $t('newSubscriberItem') }}
@@ -135,6 +140,7 @@ export default {
icons: Object.freeze({
notifications: notificationsIcon,
}),
quests,
};
},
computed: {
@@ -301,6 +307,14 @@ export default {
// @TODO: check for party , type: 'myGuilds'
await this.$store.dispatch('guilds:join', {guildId: group.id});
},
async questAccept (partyId) {
let quest = await this.$store.dispatch('quests:sendAction', {groupId: partyId, action: 'quests/accept'});
this.user.party.quest = quest;
},
async questReject (partyId) {
let quest = await this.$store.dispatch('quests:sendAction', {groupId: partyId, action: 'quests/reject'});
this.user.party.quest = quest;
},
},
};
</script>

View File

@@ -30,6 +30,10 @@
span.timeago {{conversation.date | timeAgo}}
div {{conversation.lastMessageText.substring(0, 30)}}
.col-8.messages
.empty-messages.text-center(v-if='activeChat.length === 0')
.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")
// @TODO: Implement new message header here when we fix the above
@@ -142,7 +146,7 @@
import Vue from 'vue';
import moment from 'moment';
import filter from 'lodash/filter';
// import sortBy from 'lodash/sortBy';
import sortBy from 'lodash/sortBy';
import { mapState } from 'client/libs/store';
import styleHelper from 'client/mixins/styleHelper';
@@ -184,11 +188,6 @@ export default {
let message = this.user.inbox.messages[messageId];
let userId = message.uuid;
if (!this.selectedConversation) {
this.selectedConversation = userId;
this.selectConversation(userId);
}
if (!conversations[userId]) {
conversations[userId] = {
name: message.user,
@@ -197,10 +196,19 @@ export default {
};
}
conversations[userId].messages.push({
let newMessage = {
text: message.text,
timestamp: message.timestamp,
});
user: message.user,
uuid: message.uuid,
};
if (message.sent) {
newMessage.user = this.user.profile.name;
newMessage.uuid = this.user._id;
}
conversations[userId].messages.push(newMessage);
conversations[userId].lastMessageText = message.text;
conversations[userId].date = message.timestamp;
}
@@ -225,11 +233,13 @@ export default {
selectConversation (key) {
this.selectedConversation = key;
let activeChat = this.conversations[this.selectedConversation].messages;
// @TODO: I think I did this wrong
// activeChat = sortBy(this.activeChat, [(o) => {
// return o.timestamp;
// }]);
activeChat = sortBy(activeChat, [(o) => {
return moment(o.timestamp).toDate();
}]);
this.$set(this, 'activeChat', activeChat);
Vue.nextTick(() => {
let chatscroll = this.$refs.chatscroll.$el;
chatscroll.scrollTop = chatscroll.scrollHeight;
@@ -244,6 +254,8 @@ export default {
this.conversations[this.selectedConversation].messages.push({
text: this.newMessage,
timestamp: new Date(),
user: this.user.profile.name,
uuid: this.user._id,
});
this.activeChat = this.conversations[this.selectedConversation].messages;

View File

@@ -411,6 +411,9 @@ export default {
// @TODO: this common code should handle the above
this.achievements = achievementsLib.getAchievementsForProfile(user);
// @TODO For some reason markdown doesn't seem to be handling numbers or maybe undefined?
user.profile.blurb = `${user.profile.blurb}`;
return user;
},
incentivesProgress () {

View File

@@ -3,12 +3,21 @@ import omit from 'lodash/omit';
import findIndex from 'lodash/findIndex';
export async function getPublicGuilds (store, payload) {
let params = {
type: 'publicGuilds',
paginate: true,
page: payload.page,
};
if (payload.categories) params.categories = payload.categories;
if (payload.minMemberCount) params.minMemberCount = payload.minMemberCount;
if (payload.maxMemberCount) params.maxMemberCount = payload.maxMemberCount;
if (payload.leader) params.leader = payload.leader;
if (payload.member) params.member = payload.member;
if (payload.search) params.search = payload.search;
let response = await axios.get('/api/v3/groups', {
params: {
type: 'publicGuilds',
paginate: true,
page: payload.page,
},
params,
});
return response.data.data;

View File

@@ -326,6 +326,19 @@ api.getGroups = {
filters.memberCount.$lte = parseInt(req.query.maxMemberCount, 10);
}
// @TODO: Tests for below?
if (req.query.leader) {
filters.leader = user._id;
}
if (req.query.member) {
filters._id = { $in: user.guilds };
}
if (req.query.search) {
filters.$text = { $search: req.query.search };
}
let results = await Group.getGroups({
user, types, groupFields, sort,
paginate, page: req.query.page, filters,