New inbox client (#10644)

* new inbox client

* add tests for sendPrivateMessage returning the message

* update DELETE user message tests

* port v3 GET-inbox_messages

* use v4 delete message route

* sendPrivateMessage: return sent message

* fix
This commit is contained in:
Matteo Pagliazzi
2018-08-30 21:50:03 +02:00
committed by Sabe Jones
parent 64507a161e
commit 84329e5fad
14 changed files with 287 additions and 99 deletions

View File

@@ -1,5 +1,5 @@
<template lang="pug">
b-modal#inbox-modal(title="", :hide-footer="true", size='lg')
b-modal#inbox-modal(title="", :hide-footer="true", size='lg', @shown="onModalShown", @hide="onModalHide")
.header-wrap.container.align-items-center(slot="modal-header")
.row.align-items-center
.col-4
@@ -34,13 +34,19 @@
span.timeago {{conversation.date | timeAgo}}
div {{conversation.lastMessageText ? conversation.lastMessageText.substring(0, 30) : ''}}
.col-8.messages.d-flex.flex-column.justify-content-between
.empty-messages.text-center(v-if='activeChat.length === 0 && !selectedConversation.key')
.empty-messages.text-center(v-if='!selectedConversation.key')
.svg-icon.envelope(v-html="icons.messageIcon")
h4 {{placeholderTexts.title}}
p(v-html="placeholderTexts.description")
.empty-messages.text-center(v-if='activeChat.length === 0 && selectedConversation.key')
.empty-messages.text-center(v-if='selectedConversation.key && selectedConversationMessages.length === 0')
p {{ $t('beginningOfConversation', {userName: selectedConversation.name})}}
chat-message.message-scroll(v-if="activeChat.length > 0", :chat.sync='activeChat', :inbox='true', ref="chatscroll")
chat-messages.message-scroll(
v-if="selectedConversation.messages && selectedConversationMessages.length > 0",
:chat='selectedConversationMessages',
:inbox='true',
@message-removed='messageRemoved',
ref="chatscroll"
)
.pm-disabled-caption.text-center(v-if="user.inbox.optOut && selectedConversation.key")
h4 {{$t('PMDisabledCaptionTitle')}}
p {{$t('PMDisabledCaptionText')}}
@@ -196,43 +202,46 @@ import moment from 'moment';
import filter from 'lodash/filter';
import sortBy from 'lodash/sortBy';
import groupBy from 'lodash/groupBy';
import findIndex from 'lodash/findIndex';
import { mapState } from 'client/libs/store';
import styleHelper from 'client/mixins/styleHelper';
import toggleSwitch from 'client/components/ui/toggleSwitch';
import axios from 'axios';
import messageIcon from 'assets/svg/message.svg';
import chatMessage from '../chat/chatMessages';
import chatMessages from '../chat/chatMessages';
import svgClose from 'assets/svg/close.svg';
export default {
mixins: [styleHelper],
components: {
chatMessage,
chatMessages,
toggleSwitch,
},
mounted () {
this.$root.$on('habitica::new-inbox-message', (data) => {
this.$root.$emit('bv::show::modal', 'inbox-modal');
const conversation = this.conversations.find(convo => {
return convo.key === data.userIdToMessage;
});
// Wait for messages to be loaded
const unwatchLoaded = this.$watch('loaded', (loaded) => {
if (!loaded) return;
const conversation = this.conversations.find(convo => {
return convo.key === data.userIdToMessage;
});
if (loaded) setImmediate(() => unwatchLoaded());
if (conversation) {
this.selectConversation(data.userIdToMessage);
return;
}
this.initiatedConversation = {
user: data.userName,
uuid: data.userIdToMessage,
};
if (conversation) {
this.selectConversation(data.userIdToMessage);
return;
}
const newMessage = {
text: '',
timestamp: new Date(),
user: data.userName,
uuid: data.userIdToMessage,
id: '',
};
this.$set(this.user.inbox.messages, data.userIdToMessage, newMessage);
this.selectConversation(data.userIdToMessage);
}, {immediate: true});
});
},
destroyed () {
@@ -248,8 +257,10 @@ export default {
selectedConversation: {},
search: '',
newMessage: '',
activeChat: [],
showPopover: false,
messages: [],
loaded: false,
initiatedConversation: null,
};
},
filters: {
@@ -260,8 +271,18 @@ export default {
computed: {
...mapState({user: 'user.data'}),
conversations () {
const inboxGroup = groupBy(this.user.inbox.messages, 'uuid');
const inboxGroup = groupBy(this.messages, 'uuid');
// Add placeholder for new conversations
if (this.initiatedConversation && this.initiatedConversation.uuid) {
inboxGroup[this.initiatedConversation.uuid] = [{
id: '',
text: '',
user: this.initiatedConversation.user,
uuid: this.initiatedConversation.uuid,
timestamp: new Date(),
}];
}
// Create conversation objects
const convos = [];
for (let key in inboxGroup) {
@@ -283,12 +304,9 @@ export default {
return newChat;
});
// In case the last message is a placeholder, remove it
const recentMessage = newChatModels[newChatModels.length - 1];
// Special case where we have placeholder message because conversations are just grouped messages for now
if (!recentMessage.text) {
newChatModels.splice(newChatModels.length - 1, 1);
}
if (!recentMessage.text) newChatModels.splice(newChatModels.length - 1, 1);
const convoModel = {
name: recentMessage.toUser ? recentMessage.toUser : recentMessage.user, // Handles case where from user sent the only message or the to user sent the only message
@@ -308,6 +326,12 @@ export default {
return conversations.reverse();
},
// Separate from selectedConversation which is not coputed so messages don't update automatically
selectedConversationMessages () {
const selectedConversationKey = this.selectedConversation.key;
const selectedConversation = this.conversations.find(c => c.key === selectedConversationKey);
return selectedConversation ? selectedConversation.messages : [];
},
filtersConversations () {
if (!this.search) return this.conversations;
return filter(this.conversations, (conversation) => {
@@ -343,6 +367,25 @@ export default {
},
},
methods: {
async onModalShown () {
this.loaded = false;
const res = await axios.get('/api/v4/inbox/messages');
this.messages = res.data.data;
this.loaded = true;
},
onModalHide () {
this.messages = [];
this.loaded = false;
this.initiatedConversation = null;
},
messageRemoved (message) {
const messageIndex = this.messages.findIndex(msg => msg.id === message.id);
if (messageIndex !== -1) this.messages.splice(messageIndex, 1);
if (this.selectedConversationMessages.length === 0) this.initiatedConversation = {
user: this.selectedConversation.name,
uuid: this.selectedConversation.key,
};
},
toggleClick () {
this.displayCreate = !this.displayCreate;
},
@@ -354,14 +397,7 @@ export default {
return conversation.key === key;
});
this.selectedConversation = convoFound;
let activeChat = convoFound.messages;
activeChat = sortBy(activeChat, [(o) => {
return moment(o.timestamp).toDate();
}]);
this.$set(this, 'activeChat', activeChat);
this.selectedConversation = convoFound || {};
Vue.nextTick(() => {
if (!this.$refs.chatscroll) return;
@@ -372,22 +408,22 @@ export default {
sendPrivateMessage () {
if (!this.newMessage) return;
const convoFound = this.conversations.find((conversation) => {
return conversation.key === this.selectedConversation.key;
});
convoFound.messages.push({
this.messages.push({
sent: true,
text: this.newMessage,
timestamp: new Date(),
user: this.user.profile.name,
uuid: this.user._id,
user: this.selectedConversation.name,
uuid: this.selectedConversation.key,
contributor: this.user.contributor,
});
this.activeChat = convoFound.messages;
// Remove the placeholder message
if (this.initiatedConversation && this.initiatedConversation.uuid === this.selectedConversation.key) {
this.initiatedConversation = null;
}
convoFound.lastMessageText = this.newMessage;
convoFound.date = new Date();
this.selectedConversation.lastMessageText = this.newMessage;
this.selectedConversation.date = new Date();
Vue.nextTick(() => {
if (!this.$refs.chatscroll) return;
@@ -400,8 +436,7 @@ export default {
message: this.newMessage,
}).then(response => {
const newMessage = response.data.data.message;
const messageIndex = findIndex(convoFound.messages, msg => !msg.id);
convoFound.messages.splice(convoFound.messages.length - 1, messageIndex, newMessage);
Object.assign(this.messages[this.messages.length - 1], newMessage);
});
this.newMessage = '';