mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 06:37:23 +01:00
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:
committed by
Sabe Jones
parent
64507a161e
commit
84329e5fad
@@ -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 = '';
|
||||
|
||||
Reference in New Issue
Block a user