Compare commits

...
5 changed files with 482 additions and 128 deletions
@@ -12,6 +12,62 @@ import {
import messageReadActions from './actions/messageReadActions';
import messageTranslateActions from './actions/messageTranslateActions';
import * as Sentry from '@sentry/vue';
import { applyPageFilters } from './helpers';
import { matchesFilters } from './helpers/filterHelpers';
const DEFAULT_TAB = 'all';
const deriveTabKeys = (conversation, state, rootGetters) => {
const tabKeys = new Set([DEFAULT_TAB]);
const filtersByTab = state.filtersByTab || {};
const currentUserId = rootGetters.getCurrentUser?.id;
Object.entries(filtersByTab).forEach(([rawTabKey, filters = {}]) => {
const tabKey = rawTabKey || DEFAULT_TAB;
if (tabKey === 'appliedFilters') {
if (
state.appliedFilters?.length &&
matchesFilters(conversation, state.appliedFilters)
) {
tabKeys.add(tabKey);
}
return;
}
const { inboxId, status, labels = [], teamId, conversationType } = filters;
const matchesFilter = applyPageFilters(conversation, {
inboxId,
status,
labels,
teamId,
conversationType,
});
if (!matchesFilter) {
return;
}
if (tabKey === 'me') {
if (conversation.meta?.assignee?.id === currentUserId) {
tabKeys.add(tabKey);
}
return;
}
if (tabKey === 'unassigned') {
if (!conversation.meta?.assignee) {
tabKeys.add(tabKey);
}
return;
}
tabKeys.add(tabKey);
});
return Array.from(tabKeys);
};
export const hasMessageFailedWithExternalError = pendingMessage => {
// This helper is used to check if the message has failed with an external error.
@@ -27,10 +83,14 @@ export const hasMessageFailedWithExternalError = pendingMessage => {
// actions
const actions = {
getConversation: async ({ commit }, conversationId) => {
getConversation: async ({ commit, state, rootGetters }, conversationId) => {
try {
const response = await ConversationApi.show(conversationId);
commit(types.UPDATE_CONVERSATION, response.data);
const tabKeys = deriveTabKeys(response.data, state, rootGetters);
commit(types.UPDATE_CONVERSATION, {
conversation: response.data,
tabKeys,
});
commit(`contacts/${types.SET_CONTACT_ITEM}`, response.data.meta.sender);
} catch (error) {
// Ignore error
@@ -125,11 +185,9 @@ const actions = {
{ commit, state, dispatch },
{ conversationId }
) => {
const { allConversations, syncConversationsMessages } = state;
const { conversationsById, syncConversationsMessages } = state;
const lastMessageId = syncConversationsMessages[conversationId];
const selectedChat = allConversations.find(
conversation => conversation.id === conversationId
);
const selectedChat = conversationsById[conversationId];
if (!selectedChat) return;
try {
const { messages } = selectedChat;
@@ -171,10 +229,8 @@ const actions = {
{ commit, state },
{ conversationId }
) => {
const { allConversations } = state;
const selectedChat = allConversations.find(
conversation => conversation.id === conversationId
);
const { conversationsById } = state;
const selectedChat = conversationsById[conversationId];
if (!selectedChat) return;
const { messages } = selectedChat;
const lastMessage = messages.last();
@@ -337,7 +393,10 @@ const actions = {
}
},
addConversation({ commit, state, dispatch, rootState }, conversation) {
addConversation(
{ commit, state, dispatch, rootState, rootGetters },
conversation
) {
const { currentInbox, appliedFilters } = state;
const {
inbox_id: inboxId,
@@ -353,7 +412,8 @@ const actions = {
!isOnUnattendedView(rootState) &&
isMatchingInboxFilter
) {
commit(types.ADD_CONVERSATION, conversation);
const tabKeys = deriveTabKeys(conversation, state, rootGetters);
commit(types.ADD_CONVERSATION, { conversation, tabKeys });
dispatch('contacts/setContact', sender);
}
},
@@ -370,11 +430,12 @@ const actions = {
}
},
updateConversation({ commit, dispatch }, conversation) {
updateConversation({ commit, dispatch, state, rootGetters }, conversation) {
const {
meta: { sender },
} = conversation;
commit(types.UPDATE_CONVERSATION, conversation);
const tabKeys = deriveTabKeys(conversation, state, rootGetters);
commit(types.UPDATE_CONVERSATION, { conversation, tabKeys });
dispatch('conversationLabels/setConversationLabel', {
id: conversation.id,
@@ -8,22 +8,80 @@ import {
} from '../../../helper/permissionsHelper';
import camelcaseKeys from 'camelcase-keys';
const DEFAULT_TAB = 'all';
const normalizeTabKey = tabKey => tabKey || DEFAULT_TAB;
const buildOrderedIdListForTab = (state, tabKey) => {
const tabPages = state.conversationPagesByTab[normalizeTabKey(tabKey)];
if (!tabPages) {
return [];
}
const seen = new Set();
const orderedIds = [];
Object.keys(tabPages)
.map(page => Number(page))
.sort((a, b) => a - b)
.forEach(pageNumber => {
const ids = tabPages[String(pageNumber)] || [];
ids.forEach(id => {
if (!seen.has(id)) {
seen.add(id);
orderedIds.push(id);
}
});
});
return orderedIds;
};
const conversationsFromIds = (state, ids) =>
ids.map(id => state.conversationsById[id]).filter(Boolean);
const buildTabList = (state, tabKey) => {
const orderedIds = buildOrderedIdListForTab(state, tabKey);
return conversationsFromIds(state, orderedIds);
};
const buildAllConversationList = state => {
const flattenIds = Object.values(state.conversationPagesByTab).reduce(
(acc, tabPages) => {
Object.values(tabPages).forEach(pageIds => {
pageIds.forEach(id => {
if (!acc.set.has(id)) {
acc.set.add(id);
acc.ids.push(id);
}
});
});
return acc;
},
{ set: new Set(), ids: [] }
);
if (!flattenIds.ids.length) {
return Object.values(state.conversationsById);
}
return conversationsFromIds(state, flattenIds.ids);
};
export const getSelectedChatConversation = ({
allConversations,
conversationsById,
selectedChatId,
}) =>
allConversations.filter(conversation => conversation.id === selectedChatId);
}) => {
const chat = conversationsById[selectedChatId];
return chat ? [chat] : [];
};
const getters = {
getAllConversations: ({ allConversations, chatSortFilter: sortKey }) => {
return allConversations.sort((a, b) => sortComparator(a, b, sortKey));
getAllConversations: state => {
const list = buildTabList(state, DEFAULT_TAB);
if (!list.length) {
return buildAllConversationList(state);
}
return [...list].sort((a, b) => sortComparator(a, b, state.chatSortFilter));
},
getFilteredConversations: (
{ allConversations, chatSortFilter, appliedFilters },
_,
__,
rootGetters
) => {
getFilteredConversations: (state, _, __, rootGetters) => {
const currentUser = rootGetters.getCurrentUser;
const currentUserId = rootGetters.getCurrentUser.id;
const currentAccountId = rootGetters.getCurrentAccountId;
@@ -31,11 +89,15 @@ const getters = {
const permissions = getUserPermissions(currentUser, currentAccountId);
const userRole = getUserRole(currentUser, currentAccountId);
return allConversations
const baseList = buildTabList(state, 'appliedFilters').length
? buildTabList(state, 'appliedFilters')
: buildAllConversationList(state);
return baseList
.filter(conversation => {
const matchesFilterResult = matchesFilters(
conversation,
appliedFilters
state.appliedFilters
);
const allowedForRole = applyRoleFilter(
conversation,
@@ -46,13 +108,10 @@ const getters = {
return matchesFilterResult && allowedForRole;
})
.sort((a, b) => sortComparator(a, b, chatSortFilter));
.sort((a, b) => sortComparator(a, b, state.chatSortFilter));
},
getSelectedChat: ({ selectedChatId, allConversations }) => {
const selectedChat = allConversations.find(
conversation => conversation.id === selectedChatId
);
return selectedChat || {};
getSelectedChat: ({ selectedChatId, conversationsById }) => {
return conversationsById[selectedChatId] || {};
},
getSelectedChatAttachments: ({ selectedChatId, attachments }) => {
return attachments[selectedChatId] || [];
@@ -72,10 +131,13 @@ const getters = {
return lastEmail;
},
getMineChats: (_state, _, __, rootGetters) => activeFilters => {
getMineChats: (state, _, __, rootGetters) => activeFilters => {
const currentUserID = rootGetters.getCurrentUser?.id;
const sourceList = buildTabList(state, 'me').length
? buildTabList(state, 'me')
: buildAllConversationList(state);
return _state.allConversations.filter(conversation => {
return sourceList.filter(conversation => {
const { assignee } = conversation.meta;
const isAssignedToMe = assignee && assignee.id === currentUserID;
const shouldFilter = applyPageFilters(conversation, activeFilters);
@@ -95,22 +157,29 @@ const getters = {
const hasAppliedFilters = _state.appliedFilters.length !== 0;
return hasAppliedFilters ? filterQueryGenerator(_state.appliedFilters) : [];
},
getUnAssignedChats: _state => activeFilters => {
return _state.allConversations.filter(conversation => {
getUnAssignedChats: state => activeFilters => {
const sourceList = buildTabList(state, 'unassigned').length
? buildTabList(state, 'unassigned')
: buildAllConversationList(state);
return sourceList.filter(conversation => {
const isUnAssigned = !conversation.meta.assignee;
const shouldFilter = applyPageFilters(conversation, activeFilters);
return isUnAssigned && shouldFilter;
});
},
getAllStatusChats: (_state, _, __, rootGetters) => activeFilters => {
getAllStatusChats: (state, _, __, rootGetters) => activeFilters => {
const currentUser = rootGetters.getCurrentUser;
const currentUserId = rootGetters.getCurrentUser.id;
const currentAccountId = rootGetters.getCurrentAccountId;
const permissions = getUserPermissions(currentUser, currentAccountId);
const userRole = getUserRole(currentUser, currentAccountId);
const sourceList = buildTabList(state, DEFAULT_TAB).length
? buildTabList(state, DEFAULT_TAB)
: buildAllConversationList(state);
return _state.allConversations.filter(conversation => {
return sourceList.filter(conversation => {
const shouldFilter = applyPageFilters(conversation, activeFilters);
const allowedForRole = applyRoleFilter(
conversation,
@@ -142,10 +211,8 @@ const getters = {
getChatStatusFilter: ({ chatStatusFilter }) => chatStatusFilter,
getChatSortFilter: ({ chatSortFilter }) => chatSortFilter,
getSelectedInbox: ({ currentInbox }) => currentInbox,
getConversationById: _state => conversationId => {
return _state.allConversations.find(
value => value.id === Number(conversationId)
);
getConversationById: state => conversationId => {
return state.conversationsById[Number(conversationId)] || null;
},
getConversationParticipants: _state => {
return _state.conversationParticipants;
@@ -45,7 +45,11 @@ export const buildConversationList = (
filterType
) => {
const { payload: conversationList, meta: metaData } = responseData;
context.commit(types.SET_ALL_CONVERSATION, conversationList);
context.commit(types.SET_ALL_CONVERSATION, {
tab: filterType,
page: requestPayload.page || 1,
conversations: conversationList,
});
context.dispatch('conversationStats/set', metaData);
context.dispatch(
'conversationLabels/setBulkConversationLabels',
@@ -53,10 +57,14 @@ export const buildConversationList = (
);
context.commit(types.CLEAR_LIST_LOADING_STATUS);
setContacts(context.commit, conversationList);
context.commit(types.SET_CONVERSATION_TAB_FILTERS, {
tab: filterType,
filters: requestPayload || {},
});
setPageFilter({
dispatch: context.dispatch,
filter: filterType,
page: requestPayload.page,
page: requestPayload.page || 1,
markEndReached: !conversationList.length,
});
};
@@ -1,14 +1,169 @@
import types from '../../mutation-types';
import getters, { getSelectedChatConversation } from './getters';
import actions from './actions';
import { findPendingMessageIndex } from './helpers';
import { findPendingMessageIndex, sortComparator } from './helpers';
import { MESSAGE_STATUS } from 'shared/constants/messages';
import wootConstants from 'dashboard/constants/globals';
import { BUS_EVENTS } from '../../../../shared/constants/busEvents';
import { emitter } from 'shared/helpers/mitt';
const DEFAULT_TAB = 'all';
const DEFAULT_PAGE = 1;
const DEFAULT_PAGE_SIZE = 25;
const normalizeTabKey = tab => tab || DEFAULT_TAB;
const clonePagesWithUpdate = (pagesByTab, tabKey, updater) => {
const normalizedTab = normalizeTabKey(tabKey);
const existingTabPages = pagesByTab[normalizedTab] || {};
const nextTabPages = updater(existingTabPages);
if (nextTabPages === existingTabPages) {
return pagesByTab;
}
return {
...pagesByTab,
[normalizedTab]: nextTabPages,
};
};
const removeIdFromTabPages = (tabPages, conversationId) => {
let mutated = false;
const nextPages = Object.entries(tabPages).reduce((acc, [pageKey, ids]) => {
const filteredIds = ids.filter(id => id !== conversationId);
if (filteredIds.length !== ids.length) {
mutated = true;
acc[pageKey] = filteredIds;
} else {
acc[pageKey] = ids;
}
return acc;
}, {});
return mutated ? nextPages : tabPages;
};
const removeIdFromAllTabs = (pagesByTab, conversationId) => {
let mutated = false;
const nextPagesByTab = Object.entries(pagesByTab).reduce(
(acc, [tabKey, tabPages]) => {
const updatedTabPages = removeIdFromTabPages(tabPages, conversationId);
if (updatedTabPages !== tabPages) {
mutated = true;
}
acc[tabKey] = updatedTabPages;
return acc;
},
{}
);
return mutated ? nextPagesByTab : pagesByTab;
};
const rebuildTabPagesWithConversation = (_state, tabKey, conversationId) => {
_state.conversationPagesByTab = clonePagesWithUpdate(
_state.conversationPagesByTab,
tabKey,
tabPages => {
const existingTabPages = Object.keys(tabPages).length
? tabPages
: { [String(DEFAULT_PAGE)]: [] };
const pageNumbers = Object.keys(existingTabPages)
.map(key => Number(key))
.sort((a, b) => a - b);
const collectedIds = [];
const seen = new Set();
pageNumbers.forEach(pageNumber => {
const ids = existingTabPages[String(pageNumber)] || [];
ids.forEach(id => {
if (id === conversationId) {
return;
}
if (!seen.has(id)) {
seen.add(id);
collectedIds.push(id);
}
});
});
collectedIds.push(conversationId);
const conversations = collectedIds
.map(id => _state.conversationsById[id])
.filter(Boolean);
const totalPagesNeeded = Math.max(
Math.ceil(conversations.length / DEFAULT_PAGE_SIZE),
1
);
const basePageNumbers = pageNumbers.length
? [...pageNumbers]
: [DEFAULT_PAGE];
while (basePageNumbers.length < totalPagesNeeded) {
const lastPage = basePageNumbers[basePageNumbers.length - 1];
basePageNumbers.push(lastPage + 1);
}
if (basePageNumbers.length > totalPagesNeeded) {
basePageNumbers.length = totalPagesNeeded;
}
if (!conversations.length) {
return basePageNumbers.reduce((acc, pageNumber) => {
acc[String(pageNumber)] = [];
return acc;
}, {});
}
const sorted = conversations
.slice()
.sort((a, b) => sortComparator(a, b, _state.chatSortFilter));
const sortedIds = sorted.map(item => item.id);
const nextPages = {};
basePageNumbers.forEach((pageNumber, index) => {
const startIndex = index * DEFAULT_PAGE_SIZE;
nextPages[String(pageNumber)] = sortedIds.slice(
startIndex,
startIndex + DEFAULT_PAGE_SIZE
);
});
return nextPages;
}
);
};
const upsertConversationEntity = (_state, conversation) => {
const existing = _state.conversationsById[conversation.id];
let updatedConversation = conversation;
if (existing) {
if (conversation.id === _state.selectedChatId) {
updatedConversation = {
...conversation,
allMessagesLoaded: existing.allMessagesLoaded,
messages: existing.messages,
dataFetched: existing.dataFetched,
};
} else {
updatedConversation = { ...existing, ...conversation };
}
}
_state.conversationsById = {
..._state.conversationsById,
[conversation.id]: updatedConversation,
};
};
const state = {
allConversations: [],
conversationsById: {},
conversationPagesByTab: {},
filtersByTab: {},
attachments: {},
listLoadingStatus: true,
chatStatusFilter: wootConstants.STATUS_TYPE.OPEN,
@@ -26,36 +181,27 @@ const state = {
// mutations
export const mutations = {
[types.SET_ALL_CONVERSATION](_state, conversationList) {
const newAllConversations = [..._state.allConversations];
conversationList.forEach(conversation => {
const indexInCurrentList = newAllConversations.findIndex(
c => c.id === conversation.id
);
if (indexInCurrentList < 0) {
newAllConversations.push(conversation);
} else if (conversation.id !== _state.selectedChatId) {
// If the conversation is already in the list, replace it
// Added this to fix the issue of the conversation not being updated
// When reconnecting to the websocket. If the selectedChatId is not the same as
// the conversation.id in the store, replace the existing conversation with the new one
newAllConversations[indexInCurrentList] = conversation;
} else {
// If the conversation is already in the list and selectedChatId is the same,
// replace all data except the messages array, attachments, dataFetched, allMessagesLoaded
const existingConversation = newAllConversations[indexInCurrentList];
newAllConversations[indexInCurrentList] = {
...conversation,
allMessagesLoaded: existingConversation.allMessagesLoaded,
messages: existingConversation.messages,
dataFetched: existingConversation.dataFetched,
};
}
[types.SET_ALL_CONVERSATION](_state, { tab, page, conversations }) {
const pageNumber = page || DEFAULT_PAGE;
const tabKey = normalizeTabKey(tab);
const conversationIds = conversations.map(conversation => {
upsertConversationEntity(_state, conversation);
return conversation.id;
});
_state.allConversations = newAllConversations;
_state.conversationPagesByTab = clonePagesWithUpdate(
_state.conversationPagesByTab,
tabKey,
tabPages => ({
...tabPages,
[String(pageNumber)]: conversationIds,
})
);
},
[types.EMPTY_ALL_CONVERSATION](_state) {
_state.allConversations = [];
_state.conversationsById = {};
_state.conversationPagesByTab = {};
_state.filtersByTab = {};
_state.selectedChatId = null;
},
[types.SET_ALL_MESSAGES_LOADED](_state) {
@@ -72,17 +218,25 @@ export const mutations = {
},
[types.SET_PREVIOUS_CONVERSATIONS](_state, { id, data }) {
if (data.length) {
const [chat] = _state.allConversations.filter(c => c.id === id);
chat.messages.unshift(...data);
if (!data.length) {
return;
}
const chat = _state.conversationsById[id];
if (!chat) {
return;
}
chat.messages = [...data, ...(chat.messages || [])];
},
[types.SET_ALL_ATTACHMENTS](_state, { id, data }) {
_state.attachments[id] = [...data];
},
[types.SET_MISSING_MESSAGES](_state, { id, data }) {
const [chat] = _state.allConversations.filter(c => c.id === id);
if (!chat) return;
const chat = _state.conversationsById[id];
if (!chat) {
return;
}
chat.messages = data;
},
@@ -98,22 +252,27 @@ export const mutations = {
},
[types.ASSIGN_TEAM](_state, { team, conversationId }) {
const [chat] = _state.allConversations.filter(c => c.id === conversationId);
chat.meta.team = team;
const chat = _state.conversationsById[conversationId];
if (chat) {
chat.meta.team = team;
}
},
[types.UPDATE_CONVERSATION_LAST_ACTIVITY](
_state,
{ lastActivityAt, conversationId }
) {
const [chat] = _state.allConversations.filter(c => c.id === conversationId);
if (chat) {
chat.last_activity_at = lastActivityAt;
const chat = _state.conversationsById[conversationId];
if (!chat) {
return;
}
chat.last_activity_at = lastActivityAt;
},
[types.ASSIGN_PRIORITY](_state, { priority, conversationId }) {
const [chat] = _state.allConversations.filter(c => c.id === conversationId);
chat.priority = priority;
const chat = _state.conversationsById[conversationId];
if (chat) {
chat.priority = priority;
}
},
[types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES](_state, custom_attributes) {
@@ -177,59 +336,89 @@ export const mutations = {
});
},
[types.ADD_MESSAGE]({ allConversations, selectedChatId }, message) {
[types.ADD_MESSAGE](_state, message) {
const { conversation_id: conversationId } = message;
const [chat] = getSelectedChatConversation({
allConversations,
selectedChatId: conversationId,
});
if (!chat) return;
const chat = _state.conversationsById[conversationId];
if (!chat) {
return;
}
const pendingMessageIndex = findPendingMessageIndex(chat, message);
if (pendingMessageIndex !== -1) {
chat.messages[pendingMessageIndex] = message;
} else {
chat.messages.push(message);
chat.timestamp = message.created_at;
const { conversation: { unread_count: unreadCount = 0 } = {} } = message;
chat.unread_count = unreadCount;
if (selectedChatId === conversationId) {
emitter.emit(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS);
emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
}
return;
}
chat.messages.push(message);
chat.timestamp = message.created_at;
const { conversation: { unread_count: unreadCount = 0 } = {} } = message;
chat.unread_count = unreadCount;
if (_state.selectedChatId === conversationId) {
emitter.emit(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS);
emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
}
},
[types.ADD_CONVERSATION](_state, conversation) {
_state.allConversations.push(conversation);
[types.ADD_CONVERSATION](_state, { conversation, tabKeys = [DEFAULT_TAB] }) {
upsertConversationEntity(_state, conversation);
tabKeys.forEach(tabKey => {
rebuildTabPagesWithConversation(_state, tabKey, conversation.id);
});
},
[types.DELETE_CONVERSATION](_state, conversationId) {
_state.allConversations = _state.allConversations.filter(
c => c.id !== conversationId
const { [conversationId]: removed, ...rest } = _state.conversationsById;
if (!removed) {
return;
}
_state.conversationsById = rest;
_state.conversationPagesByTab = removeIdFromAllTabs(
_state.conversationPagesByTab,
conversationId
);
},
[types.UPDATE_CONVERSATION](_state, conversation) {
const { allConversations } = _state;
const index = allConversations.findIndex(c => c.id === conversation.id);
[types.UPDATE_CONVERSATION](
_state,
{ conversation, tabKeys = [DEFAULT_TAB] }
) {
const existingConversation = _state.conversationsById[conversation.id];
if (index > -1) {
const selectedConversation = allConversations[index];
// ignore out of order events
if (conversation.updated_at < selectedConversation.updated_at) {
if (existingConversation) {
if (
conversation.updated_at &&
existingConversation.updated_at &&
conversation.updated_at < existingConversation.updated_at
) {
return;
}
const { messages, ...updates } = conversation;
allConversations[index] = { ...selectedConversation, ...updates };
if (_state.selectedChatId === conversation.id) {
emitter.emit(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS);
emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
}
const mergedConversation = {
...existingConversation,
...updates,
};
_state.conversationsById = {
..._state.conversationsById,
[conversation.id]: mergedConversation,
};
} else {
_state.allConversations.push(conversation);
upsertConversationEntity(_state, conversation);
}
_state.conversationPagesByTab = removeIdFromAllTabs(
_state.conversationPagesByTab,
conversation.id
);
tabKeys.forEach(tabKey => {
rebuildTabPagesWithConversation(_state, tabKey, conversation.id);
});
if (_state.selectedChatId === conversation.id) {
emitter.emit(BUS_EVENTS.FETCH_LABEL_SUGGESTIONS);
emitter.emit(BUS_EVENTS.SCROLL_TO_MESSAGE);
}
},
@@ -245,7 +434,7 @@ export const mutations = {
_state,
{ id, lastSeen, unreadCount = 0 }
) {
const [chat] = _state.allConversations.filter(c => c.id === id);
const chat = _state.conversationsById[id];
if (chat) {
chat.agent_last_seen_at = lastSeen;
chat.unread_count = unreadCount;
@@ -261,12 +450,14 @@ export const mutations = {
// Update assignee on action cable message
[types.UPDATE_ASSIGNEE](_state, payload) {
const [chat] = _state.allConversations.filter(c => c.id === payload.id);
chat.meta.assignee = payload.assignee;
const chat = _state.conversationsById[payload.id];
if (chat) {
chat.meta.assignee = payload.assignee;
}
},
[types.UPDATE_CONVERSATION_CONTACT](_state, { conversationId, ...payload }) {
const [chat] = _state.allConversations.filter(c => c.id === conversationId);
const chat = _state.conversationsById[conversationId];
if (chat) {
chat.meta.sender = payload;
}
@@ -277,23 +468,49 @@ export const mutations = {
},
[types.SET_CONVERSATION_CAN_REPLY](_state, { conversationId, canReply }) {
const [chat] = _state.allConversations.filter(c => c.id === conversationId);
const chat = _state.conversationsById[conversationId];
if (chat) {
chat.can_reply = canReply;
}
},
[types.CLEAR_CONTACT_CONVERSATIONS](_state, contactId) {
const chats = _state.allConversations.filter(
c => c.meta.sender.id !== contactId
);
_state.allConversations = chats;
const remaining = {};
const removedIds = [];
Object.values(_state.conversationsById).forEach(conversation => {
if (conversation.meta?.sender?.id === contactId) {
removedIds.push(conversation.id);
} else {
remaining[conversation.id] = conversation;
}
});
if (!removedIds.length) {
return;
}
_state.conversationsById = remaining;
removedIds.forEach(conversationId => {
_state.conversationPagesByTab = removeIdFromAllTabs(
_state.conversationPagesByTab,
conversationId
);
});
},
[types.SET_CONVERSATION_FILTERS](_state, data) {
_state.appliedFilters = data;
},
[types.SET_CONVERSATION_TAB_FILTERS](_state, { tab, filters }) {
const normalizedTab = normalizeTabKey(tab);
const { page, ...rest } = filters || {};
_state.filtersByTab = {
..._state.filtersByTab,
[normalizedTab]: rest,
};
},
[types.CLEAR_CONVERSATION_FILTERS](_state) {
_state.appliedFilters = [];
},
@@ -22,6 +22,7 @@ export default {
UPDATE_CONVERSATION_CONTACT: 'UPDATE_CONVERSATION_CONTACT',
CLEAR_CONTACT_CONVERSATIONS: 'CLEAR_CONTACT_CONVERSATIONS',
SET_CONVERSATION_FILTERS: 'SET_CONVERSATION_FILTERS',
SET_CONVERSATION_TAB_FILTERS: 'SET_CONVERSATION_TAB_FILTERS',
CLEAR_CONVERSATION_FILTERS: 'CLEAR_CONVERSATION_FILTERS',
SET_CONVERSATION_LAST_SEEN: 'SET_CONVERSATION_LAST_SEEN',
SET_LAST_MESSAGE_ID_IN_SYNC_CONVERSATION: