diff --git a/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue b/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue index 5d6158598..7fb349c18 100644 --- a/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue +++ b/app/javascript/dashboard/components/widgets/conversation/MessagesView.vue @@ -93,7 +93,9 @@ import { mapGetters } from 'vuex'; import ReplyBox from './ReplyBox'; import Message from './Message'; -import conversationMixin from '../../../mixins/conversations'; +import conversationMixin, { + filterDuplicateSourceMessages, +} from '../../../mixins/conversations'; import Banner from 'dashboard/components/ui/Banner.vue'; import { getTypingUsersText } from '../../../helper/commons'; import { BUS_EVENTS } from 'shared/constants/busEvents'; @@ -171,24 +173,28 @@ export default { return ''; }, - getMessages() { - const [chat] = this.allConversations.filter( - c => c.id === this.currentChat.id - ); - return chat; + const messages = this.currentChat.messages || []; + if (this.isAWhatsAppChannel) { + return filterDuplicateSourceMessages(messages); + } + return messages; }, getReadMessages() { - const chat = this.getMessages; - return chat === undefined ? null : this.readMessages(chat); + return this.readMessages( + this.getMessages, + this.currentChat.agent_last_seen_at + ); }, getUnReadMessages() { - const chat = this.getMessages; - return chat === undefined ? null : this.unReadMessages(chat); + return this.unReadMessages( + this.getMessages, + this.currentChat.agent_last_seen_at + ); }, shouldShowSpinner() { return ( - (this.getMessages && this.getMessages.dataFetched === undefined) || + (this.currentChat && this.currentChat.dataFetched === undefined) || (!this.listLoadingStatus && this.isLoadingPrevious) ); }, @@ -208,7 +214,7 @@ export default { selectedTweet() { if (this.selectedTweetId) { - const { messages = [] } = this.getMessages; + const { messages = [] } = this.currentChat; const [selectedMessage] = messages.filter( message => message.id === this.selectedTweetId ); @@ -360,7 +366,7 @@ export default { async fetchPreviousMessages(scrollTop = 0) { this.setScrollParams(); const shouldLoadMoreMessages = - this.getMessages.dataFetched === true && + this.currentChat.dataFetched === true && !this.listLoadingStatus && !this.isLoadingPrevious; @@ -373,7 +379,7 @@ export default { try { await this.$store.dispatch('fetchPreviousMessages', { conversationId: this.currentChat.id, - before: this.getMessages.messages[0].id, + before: this.currentChat.messages[0].id, }); const heightDifference = this.conversationPanel.scrollHeight - this.heightBeforeLoad; diff --git a/app/javascript/dashboard/mixins/conversations.js b/app/javascript/dashboard/mixins/conversations.js index f7420c144..d864bc020 100644 --- a/app/javascript/dashboard/mixins/conversations.js +++ b/app/javascript/dashboard/mixins/conversations.js @@ -12,6 +12,26 @@ const getLastNonActivityMessage = (messageInStore, messageFromAPI) => { return messageInStore || messageFromAPI; }; +export const filterDuplicateSourceMessages = (messages = []) => { + const messagesWithoutDuplicates = []; + // We cannot use Map or any short hand method as it returns the last message with the duplicate ID + // We should return the message with smaller id when there is a duplicate + messages.forEach(m1 => { + if (m1.source_id) { + if ( + messagesWithoutDuplicates.findIndex( + m2 => m1.source_id === m2.source_id + ) < 0 + ) { + messagesWithoutDuplicates.push(m1); + } + } else { + messagesWithoutDuplicates.push(m1); + } + }); + return messagesWithoutDuplicates; +}; + export default { methods: { lastMessage(m) { @@ -34,14 +54,14 @@ export default { lastNonActivityMessageFromAPI ); }, - readMessages(m) { - return m.messages.filter( - chat => chat.created_at * 1000 <= m.agent_last_seen_at * 1000 + readMessages(messages, agentLastSeenAt) { + return messages.filter( + message => message.created_at * 1000 <= agentLastSeenAt * 1000 ); }, - unReadMessages(m) { - return m.messages.filter( - chat => chat.created_at * 1000 > m.agent_last_seen_at * 1000 + unReadMessages(messages, agentLastSeenAt) { + return messages.filter( + message => message.created_at * 1000 > agentLastSeenAt * 1000 ); }, }, diff --git a/app/javascript/dashboard/mixins/specs/conversation.spec.js b/app/javascript/dashboard/mixins/specs/conversation.spec.js index a8413e8fe..9db7f8c28 100644 --- a/app/javascript/dashboard/mixins/specs/conversation.spec.js +++ b/app/javascript/dashboard/mixins/specs/conversation.spec.js @@ -1,17 +1,50 @@ -import conversationMixin from '../conversations'; +import conversationMixin, { + filterDuplicateSourceMessages, +} from '../conversations'; import conversationFixture from './conversationFixtures'; import commonHelpers from '../../helper/commons'; commonHelpers(); +describe('#filterDuplicateSourceMessages', () => { + it('returns messages without duplicate source_id and all messages without source_id', () => { + expect( + filterDuplicateSourceMessages([ + { source_id: null, id: 1 }, + { source_id: '', id: 2 }, + { id: 3 }, + { source_id: 'wa_1', id: 4 }, + { source_id: 'wa_1', id: 5 }, + { source_id: 'wa_1', id: 6 }, + { source_id: 'wa_2', id: 7 }, + { source_id: 'wa_2', id: 8 }, + { source_id: 'wa_3', id: 9 }, + ]) + ).toEqual([ + { source_id: null, id: 1 }, + { source_id: '', id: 2 }, + { id: 3 }, + { source_id: 'wa_1', id: 4 }, + { source_id: 'wa_2', id: 7 }, + { source_id: 'wa_3', id: 9 }, + ]); + }); +}); + describe('#conversationMixin', () => { it('should return read messages if conversation is passed', () => { expect( - conversationMixin.methods.readMessages(conversationFixture.conversation) + conversationMixin.methods.readMessages( + conversationFixture.conversation.messages, + conversationFixture.conversation.agent_last_seen_at + ) ).toEqual(conversationFixture.readMessages); }); it('should return read messages if conversation is passed', () => { expect( - conversationMixin.methods.unReadMessages(conversationFixture.conversation) + conversationMixin.methods.unReadMessages( + conversationFixture.conversation.messages, + conversationFixture.conversation.agent_last_seen_at + ) ).toEqual(conversationFixture.unReadMessages); });