feat: Add Advanced Conversation Filters (#3239)
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: Pranav Raj S <pranav@chatwoot.com> Co-authored-by: Tejaswini <tejaswini@chatwoot.com>
This commit is contained in:
@@ -19,6 +19,9 @@ export const getters = {
|
||||
record => record.campaign_type === campaignType
|
||||
);
|
||||
},
|
||||
getAllCampaigns: _state => {
|
||||
return _state.records;
|
||||
},
|
||||
};
|
||||
|
||||
export const actions = {
|
||||
|
||||
@@ -6,6 +6,7 @@ const state = {
|
||||
me: 0,
|
||||
unassigned: 0,
|
||||
all: 0,
|
||||
appliedFilters: 0,
|
||||
},
|
||||
hasEndReached: {
|
||||
me: false,
|
||||
@@ -54,12 +55,14 @@ export const mutations = {
|
||||
me: 0,
|
||||
unassigned: 0,
|
||||
all: 0,
|
||||
appliedFilters: 0,
|
||||
};
|
||||
|
||||
$state.hasEndReached = {
|
||||
me: false,
|
||||
unassigned: false,
|
||||
all: false,
|
||||
appliedFilters: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -5,6 +5,42 @@ import MessageApi from '../../../api/inbox/message';
|
||||
import { MESSAGE_STATUS, MESSAGE_TYPE } from 'shared/constants/messages';
|
||||
import { createPendingMessage } from 'dashboard/helper/commons';
|
||||
|
||||
const setPageFilter = ({ dispatch, filter, page, markEndReached }) => {
|
||||
dispatch('conversationPage/setCurrentPage', { filter, page }, { root: true });
|
||||
if (markEndReached) {
|
||||
dispatch('conversationPage/setEndReached', { filter }, { root: true });
|
||||
}
|
||||
};
|
||||
|
||||
const setContacts = (commit, chatList) => {
|
||||
commit(
|
||||
`contacts/${types.SET_CONTACTS}`,
|
||||
chatList.map(chat => chat.meta.sender)
|
||||
);
|
||||
};
|
||||
|
||||
const buildConversationList = (
|
||||
context,
|
||||
requestPayload,
|
||||
responseData,
|
||||
filterType
|
||||
) => {
|
||||
const { payload: conversationList, meta: metaData } = responseData;
|
||||
context.commit(types.SET_ALL_CONVERSATION, conversationList);
|
||||
context.dispatch('conversationStats/set', metaData);
|
||||
context.dispatch(
|
||||
'conversationLabels/setBulkConversationLabels',
|
||||
conversationList
|
||||
);
|
||||
context.commit(types.CLEAR_LIST_LOADING_STATUS);
|
||||
setContacts(context.commit, conversationList);
|
||||
setPageFilter({
|
||||
dispatch: context.dispatch,
|
||||
filter: filterType,
|
||||
page: requestPayload.page,
|
||||
markEndReached: !conversationList.length,
|
||||
});
|
||||
};
|
||||
// actions
|
||||
const actions = {
|
||||
getConversation: async ({ commit }, conversationId) => {
|
||||
@@ -20,30 +56,30 @@ const actions = {
|
||||
fetchAllConversations: async ({ commit, dispatch }, params) => {
|
||||
commit(types.SET_LIST_LOADING_STATUS);
|
||||
try {
|
||||
const response = await ConversationApi.get(params);
|
||||
const {
|
||||
data: { payload: chatList, meta: metaData },
|
||||
} = response.data;
|
||||
commit(types.SET_ALL_CONVERSATION, chatList);
|
||||
dispatch('conversationStats/set', metaData);
|
||||
dispatch('conversationLabels/setBulkConversationLabels', chatList);
|
||||
commit(types.CLEAR_LIST_LOADING_STATUS);
|
||||
commit(
|
||||
`contacts/${types.SET_CONTACTS}`,
|
||||
chatList.map(chat => chat.meta.sender)
|
||||
data: { data },
|
||||
} = await ConversationApi.get(params);
|
||||
buildConversationList(
|
||||
{ commit, dispatch },
|
||||
params,
|
||||
data,
|
||||
params.assigneeType
|
||||
);
|
||||
dispatch(
|
||||
'conversationPage/setCurrentPage',
|
||||
{ filter: params.assigneeType, page: params.page },
|
||||
{ root: true }
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
}
|
||||
},
|
||||
|
||||
fetchFilteredConversations: async ({ commit, dispatch }, params) => {
|
||||
commit(types.SET_LIST_LOADING_STATUS);
|
||||
try {
|
||||
const { data } = await ConversationApi.filter(params);
|
||||
buildConversationList(
|
||||
{ commit, dispatch },
|
||||
params,
|
||||
data,
|
||||
'appliedFilters'
|
||||
);
|
||||
if (!chatList.length) {
|
||||
dispatch(
|
||||
'conversationPage/setEndReached',
|
||||
{ filter: params.assigneeType },
|
||||
{ root: true }
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// Handle error
|
||||
}
|
||||
@@ -198,12 +234,15 @@ const actions = {
|
||||
},
|
||||
|
||||
addConversation({ commit, state, dispatch }, conversation) {
|
||||
const { currentInbox } = state;
|
||||
const { currentInbox, appliedFilters } = state;
|
||||
const {
|
||||
inbox_id: inboxId,
|
||||
meta: { sender },
|
||||
} = conversation;
|
||||
if (!currentInbox || Number(currentInbox) === inboxId) {
|
||||
const hasAppliedFilters = !!appliedFilters.length;
|
||||
const isMatchingInboxFilter =
|
||||
!currentInbox || Number(currentInbox) === inboxId;
|
||||
if (!hasAppliedFilters && isMatchingInboxFilter) {
|
||||
commit(types.ADD_CONVERSATION, conversation);
|
||||
dispatch('contacts/setContact', sender);
|
||||
}
|
||||
@@ -288,6 +327,14 @@ const actions = {
|
||||
// Handle error
|
||||
}
|
||||
},
|
||||
|
||||
setConversationFilters({ commit }, data) {
|
||||
commit(types.SET_CONVERSATION_FILTERS, data);
|
||||
},
|
||||
|
||||
clearConversationFilters({ commit }) {
|
||||
commit(types.CLEAR_CONVERSATION_FILTERS);
|
||||
},
|
||||
};
|
||||
|
||||
export default actions;
|
||||
|
||||
@@ -31,6 +31,9 @@ const getters = {
|
||||
return isChatMine;
|
||||
});
|
||||
},
|
||||
getAppliedFilters: _state => {
|
||||
return _state.appliedFilters;
|
||||
},
|
||||
getUnAssignedChats: _state => activeFilters => {
|
||||
return _state.allConversations.filter(conversation => {
|
||||
const isUnAssigned = !conversation.meta.assignee;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import Vue from 'vue';
|
||||
import * as types from '../../mutation-types';
|
||||
import types from '../../mutation-types';
|
||||
import getters, { getSelectedChatConversation } from './getters';
|
||||
import actions from './actions';
|
||||
import { findPendingMessageIndex } from './helpers';
|
||||
@@ -11,11 +11,12 @@ const state = {
|
||||
chatStatusFilter: wootConstants.STATUS_TYPE.OPEN,
|
||||
currentInbox: null,
|
||||
selectedChatId: null,
|
||||
appliedFilters: [],
|
||||
};
|
||||
|
||||
// mutations
|
||||
export const mutations = {
|
||||
[types.default.SET_ALL_CONVERSATION](_state, conversationList) {
|
||||
[types.SET_ALL_CONVERSATION](_state, conversationList) {
|
||||
const newAllConversations = [..._state.allConversations];
|
||||
conversationList.forEach(conversation => {
|
||||
const indexInCurrentList = newAllConversations.findIndex(
|
||||
@@ -27,47 +28,47 @@ export const mutations = {
|
||||
});
|
||||
_state.allConversations = newAllConversations;
|
||||
},
|
||||
[types.default.EMPTY_ALL_CONVERSATION](_state) {
|
||||
[types.EMPTY_ALL_CONVERSATION](_state) {
|
||||
_state.allConversations = [];
|
||||
_state.selectedChatId = null;
|
||||
},
|
||||
[types.default.SET_ALL_MESSAGES_LOADED](_state) {
|
||||
[types.SET_ALL_MESSAGES_LOADED](_state) {
|
||||
const [chat] = getSelectedChatConversation(_state);
|
||||
Vue.set(chat, 'allMessagesLoaded', true);
|
||||
},
|
||||
|
||||
[types.default.CLEAR_ALL_MESSAGES_LOADED](_state) {
|
||||
[types.CLEAR_ALL_MESSAGES_LOADED](_state) {
|
||||
const [chat] = getSelectedChatConversation(_state);
|
||||
Vue.set(chat, 'allMessagesLoaded', false);
|
||||
},
|
||||
[types.default.CLEAR_CURRENT_CHAT_WINDOW](_state) {
|
||||
[types.CLEAR_CURRENT_CHAT_WINDOW](_state) {
|
||||
_state.selectedChatId = null;
|
||||
},
|
||||
|
||||
[types.default.SET_PREVIOUS_CONVERSATIONS](_state, { id, data }) {
|
||||
[types.SET_PREVIOUS_CONVERSATIONS](_state, { id, data }) {
|
||||
if (data.length) {
|
||||
const [chat] = _state.allConversations.filter(c => c.id === id);
|
||||
chat.messages.unshift(...data);
|
||||
}
|
||||
},
|
||||
|
||||
[types.default.SET_CURRENT_CHAT_WINDOW](_state, activeChat) {
|
||||
[types.SET_CURRENT_CHAT_WINDOW](_state, activeChat) {
|
||||
if (activeChat) {
|
||||
_state.selectedChatId = activeChat.id;
|
||||
}
|
||||
},
|
||||
|
||||
[types.default.ASSIGN_AGENT](_state, assignee) {
|
||||
[types.ASSIGN_AGENT](_state, assignee) {
|
||||
const [chat] = getSelectedChatConversation(_state);
|
||||
Vue.set(chat.meta, 'assignee', assignee);
|
||||
},
|
||||
|
||||
[types.default.ASSIGN_TEAM](_state, team) {
|
||||
[types.ASSIGN_TEAM](_state, team) {
|
||||
const [chat] = getSelectedChatConversation(_state);
|
||||
Vue.set(chat.meta, 'team', team);
|
||||
},
|
||||
|
||||
[types.default.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES](
|
||||
[types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES](
|
||||
_state,
|
||||
custom_attributes
|
||||
) {
|
||||
@@ -75,7 +76,7 @@ export const mutations = {
|
||||
Vue.set(chat, 'custom_attributes', custom_attributes);
|
||||
},
|
||||
|
||||
[types.default.CHANGE_CONVERSATION_STATUS](
|
||||
[types.CHANGE_CONVERSATION_STATUS](
|
||||
_state,
|
||||
{ conversationId, status, snoozedUntil }
|
||||
) {
|
||||
@@ -85,17 +86,17 @@ export const mutations = {
|
||||
Vue.set(conversation, 'status', status);
|
||||
},
|
||||
|
||||
[types.default.MUTE_CONVERSATION](_state) {
|
||||
[types.MUTE_CONVERSATION](_state) {
|
||||
const [chat] = getSelectedChatConversation(_state);
|
||||
Vue.set(chat, 'muted', true);
|
||||
},
|
||||
|
||||
[types.default.UNMUTE_CONVERSATION](_state) {
|
||||
[types.UNMUTE_CONVERSATION](_state) {
|
||||
const [chat] = getSelectedChatConversation(_state);
|
||||
Vue.set(chat, 'muted', false);
|
||||
},
|
||||
|
||||
[types.default.ADD_MESSAGE]({ allConversations, selectedChatId }, message) {
|
||||
[types.ADD_MESSAGE]({ allConversations, selectedChatId }, message) {
|
||||
const { conversation_id: conversationId } = message;
|
||||
const [chat] = getSelectedChatConversation({
|
||||
allConversations,
|
||||
@@ -115,11 +116,11 @@ export const mutations = {
|
||||
}
|
||||
},
|
||||
|
||||
[types.default.ADD_CONVERSATION](_state, conversation) {
|
||||
[types.ADD_CONVERSATION](_state, conversation) {
|
||||
_state.allConversations.push(conversation);
|
||||
},
|
||||
|
||||
[types.default.UPDATE_CONVERSATION](_state, conversation) {
|
||||
[types.UPDATE_CONVERSATION](_state, conversation) {
|
||||
const { allConversations } = _state;
|
||||
const currentConversationIndex = allConversations.findIndex(
|
||||
c => c.id === conversation.id
|
||||
@@ -139,32 +140,32 @@ export const mutations = {
|
||||
}
|
||||
},
|
||||
|
||||
[types.default.SET_LIST_LOADING_STATUS](_state) {
|
||||
[types.SET_LIST_LOADING_STATUS](_state) {
|
||||
_state.listLoadingStatus = true;
|
||||
},
|
||||
|
||||
[types.default.CLEAR_LIST_LOADING_STATUS](_state) {
|
||||
[types.CLEAR_LIST_LOADING_STATUS](_state) {
|
||||
_state.listLoadingStatus = false;
|
||||
},
|
||||
|
||||
[types.default.MARK_MESSAGE_READ](_state, { id, lastSeen }) {
|
||||
[types.MARK_MESSAGE_READ](_state, { id, lastSeen }) {
|
||||
const [chat] = _state.allConversations.filter(c => c.id === id);
|
||||
if (chat) {
|
||||
chat.agent_last_seen_at = lastSeen;
|
||||
}
|
||||
},
|
||||
|
||||
[types.default.CHANGE_CHAT_STATUS_FILTER](_state, data) {
|
||||
[types.CHANGE_CHAT_STATUS_FILTER](_state, data) {
|
||||
_state.chatStatusFilter = data;
|
||||
},
|
||||
|
||||
// Update assignee on action cable message
|
||||
[types.default.UPDATE_ASSIGNEE](_state, payload) {
|
||||
[types.UPDATE_ASSIGNEE](_state, payload) {
|
||||
const [chat] = _state.allConversations.filter(c => c.id === payload.id);
|
||||
Vue.set(chat.meta, 'assignee', payload.assignee);
|
||||
},
|
||||
|
||||
[types.default.UPDATE_CONVERSATION_CONTACT](
|
||||
[types.UPDATE_CONVERSATION_CONTACT](
|
||||
_state,
|
||||
{ conversationId, ...payload }
|
||||
) {
|
||||
@@ -174,11 +175,11 @@ export const mutations = {
|
||||
}
|
||||
},
|
||||
|
||||
[types.default.SET_ACTIVE_INBOX](_state, inboxId) {
|
||||
[types.SET_ACTIVE_INBOX](_state, inboxId) {
|
||||
_state.currentInbox = inboxId ? parseInt(inboxId, 10) : null;
|
||||
},
|
||||
|
||||
[types.default.SET_CONVERSATION_CAN_REPLY](
|
||||
[types.SET_CONVERSATION_CAN_REPLY](
|
||||
_state,
|
||||
{ conversationId, canReply }
|
||||
) {
|
||||
@@ -188,12 +189,20 @@ export const mutations = {
|
||||
}
|
||||
},
|
||||
|
||||
[types.default.CLEAR_CONTACT_CONVERSATIONS](_state, contactId) {
|
||||
[types.CLEAR_CONTACT_CONVERSATIONS](_state, contactId) {
|
||||
const chats = _state.allConversations.filter(
|
||||
c => c.meta.sender.id !== contactId
|
||||
);
|
||||
Vue.set(_state, 'allConversations', chats);
|
||||
},
|
||||
|
||||
[types.SET_CONVERSATION_FILTERS](_state, data) {
|
||||
_state.appliedFilters = data;
|
||||
},
|
||||
|
||||
[types.CLEAR_CONVERSATION_FILTERS](_state) {
|
||||
_state.appliedFilters = [];
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
|
||||
@@ -58,6 +58,11 @@ describe('#getters', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it('get all campaigns', () => {
|
||||
const state = { records: campaigns };
|
||||
expect(getters.getAllCampaigns(state)).toEqual(campaigns);
|
||||
});
|
||||
|
||||
it('getUIFlags', () => {
|
||||
const state = {
|
||||
uiFlags: {
|
||||
|
||||
@@ -23,8 +23,13 @@ describe('#mutations', () => {
|
||||
};
|
||||
mutations[types.default.CLEAR_CONVERSATION_PAGE](state);
|
||||
expect(state).toEqual({
|
||||
currentPage: { me: 0, unassigned: 0, all: 0 },
|
||||
hasEndReached: { me: false, unassigned: false, all: false },
|
||||
currentPage: { me: 0, unassigned: 0, all: 0, appliedFilters: 0 },
|
||||
hasEndReached: {
|
||||
me: false,
|
||||
unassigned: false,
|
||||
all: false,
|
||||
appliedFilters: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
import axios from 'axios';
|
||||
import actions from '../../conversations/actions';
|
||||
import types from '../../../mutation-types';
|
||||
const dataToSend = {
|
||||
payload: [
|
||||
{
|
||||
attribute_key: 'status',
|
||||
filter_operator: 'equal_to',
|
||||
values: ['open'],
|
||||
query_operator: null,
|
||||
},
|
||||
],
|
||||
};
|
||||
import { dataReceived } from './testConversationResponse';
|
||||
|
||||
const commit = jest.fn();
|
||||
const dispatch = jest.fn();
|
||||
@@ -73,7 +84,30 @@ describe('#actions', () => {
|
||||
inbox_id: 2,
|
||||
};
|
||||
actions.addConversation(
|
||||
{ commit, dispatch, state: { currentInbox: 1 } },
|
||||
{
|
||||
commit,
|
||||
dispatch,
|
||||
state: { currentInbox: 1, appliedFilters: [] },
|
||||
},
|
||||
conversation
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([]);
|
||||
expect(dispatch.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
it('doesnot send mutation if conversation filters are applied', () => {
|
||||
const conversation = {
|
||||
id: 1,
|
||||
messages: [],
|
||||
meta: { sender: { id: 1, name: 'john-doe' } },
|
||||
inbox_id: 1,
|
||||
};
|
||||
actions.addConversation(
|
||||
{
|
||||
commit,
|
||||
dispatch,
|
||||
state: { currentInbox: 1, appliedFilters: [{ id: 'random-filter' }] },
|
||||
},
|
||||
conversation
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([]);
|
||||
@@ -88,7 +122,11 @@ describe('#actions', () => {
|
||||
inbox_id: 1,
|
||||
};
|
||||
actions.addConversation(
|
||||
{ commit, dispatch, state: { currentInbox: 1 } },
|
||||
{
|
||||
commit,
|
||||
dispatch,
|
||||
state: { currentInbox: 1, appliedFilters: [] },
|
||||
},
|
||||
conversation
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
@@ -112,7 +150,10 @@ describe('#actions', () => {
|
||||
meta: { sender: { id: 1, name: 'john-doe' } },
|
||||
inbox_id: 1,
|
||||
};
|
||||
actions.addConversation({ commit, dispatch, state: {} }, conversation);
|
||||
actions.addConversation(
|
||||
{ commit, dispatch, state: { appliedFilters: [] } },
|
||||
conversation
|
||||
);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.ADD_CONVERSATION, conversation],
|
||||
]);
|
||||
@@ -262,6 +303,44 @@ describe('#actions', () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#fetchFilteredConversations', () => {
|
||||
it('fetches filtered conversations with a mock commit', async () => {
|
||||
axios.post.mockResolvedValue({
|
||||
data: dataReceived,
|
||||
});
|
||||
await actions.fetchFilteredConversations({ commit }, dataToSend);
|
||||
expect(commit).toHaveBeenCalledTimes(2);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
['SET_LIST_LOADING_STATUS'],
|
||||
['SET_ALL_CONVERSATION', dataReceived.payload],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#setConversationFilter', () => {
|
||||
it('commits the correct mutation and sets filter state', () => {
|
||||
const filters = [
|
||||
{
|
||||
attribute_key: 'status',
|
||||
filter_operator: 'equal_to',
|
||||
values: [{ id: 'snoozed', name: 'Snoozed' }],
|
||||
query_operator: 'and',
|
||||
},
|
||||
];
|
||||
actions.setConversationFilters({ commit }, filters);
|
||||
expect(commit.mock.calls).toEqual([
|
||||
[types.SET_CONVERSATION_FILTERS, filters],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#clearConversationFilter', () => {
|
||||
it('commits the correct mutation and clears filter state', () => {
|
||||
actions.clearConversationFilters({ commit });
|
||||
expect(commit.mock.calls).toEqual([[types.CLEAR_CONVERSATION_FILTERS]]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#deleteMessage', () => {
|
||||
|
||||
@@ -114,4 +114,21 @@ describe('#getters', () => {
|
||||
expect(getters.getConversationById(state)(1)).toEqual({ id: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('#getAppliedFilters', () => {
|
||||
it('getAppliedFilters', () => {
|
||||
const filtersList = [
|
||||
{
|
||||
attribute_key: 'status',
|
||||
filter_operator: 'equal_to',
|
||||
values: [{ id: 'snoozed', name: 'Snoozed' }],
|
||||
query_operator: 'and',
|
||||
},
|
||||
];
|
||||
const state = {
|
||||
appliedFilters: filtersList,
|
||||
};
|
||||
expect(getters.getAppliedFilters(state)).toEqual(filtersList);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -201,4 +201,43 @@ describe('#mutations', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#SET_CONVERSATION_FILTERS', () => {
|
||||
it('set conversation filter', () => {
|
||||
const appliedFilters = [
|
||||
{
|
||||
attribute_key: 'status',
|
||||
filter_operator: 'equal_to',
|
||||
values: [{ id: 'snoozed', name: 'Snoozed' }],
|
||||
query_operator: 'and',
|
||||
},
|
||||
];
|
||||
mutations[types.SET_CONVERSATION_FILTERS](appliedFilters);
|
||||
expect(appliedFilters).toEqual([
|
||||
{
|
||||
attribute_key: 'status',
|
||||
filter_operator: 'equal_to',
|
||||
values: [{ id: 'snoozed', name: 'Snoozed' }],
|
||||
query_operator: 'and',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#CLEAR_CONVERSATION_FILTERS', () => {
|
||||
it('clears applied conversation filters', () => {
|
||||
const state = {
|
||||
appliedFilters: [
|
||||
{
|
||||
attribute_key: 'status',
|
||||
filter_operator: 'equal_to',
|
||||
values: [{ id: 'snoozed', name: 'Snoozed' }],
|
||||
query_operator: 'and',
|
||||
},
|
||||
],
|
||||
};
|
||||
mutations[types.CLEAR_CONVERSATION_FILTERS](state);
|
||||
expect(state.appliedFilters).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
export const dataReceived = {
|
||||
meta: {
|
||||
mine_count: 3,
|
||||
unassigned_count: 0,
|
||||
all_count: 4,
|
||||
},
|
||||
payload: [
|
||||
{
|
||||
meta: {
|
||||
sender: {
|
||||
additional_attributes: {},
|
||||
availability_status: 'offline',
|
||||
email: null,
|
||||
id: 40,
|
||||
name: 'damp-field-834',
|
||||
phone_number: null,
|
||||
identifier: null,
|
||||
thumbnail: '',
|
||||
custom_attributes: {},
|
||||
last_activity_at: 1635764106,
|
||||
},
|
||||
channel: 'Channel::WebWidget',
|
||||
assignee: {
|
||||
id: 1,
|
||||
account_id: 1,
|
||||
availability_status: 'online',
|
||||
auto_offline: true,
|
||||
confirmed: true,
|
||||
email: 'john@acme.inc',
|
||||
available_name: 'John',
|
||||
name: 'John',
|
||||
role: 'administrator',
|
||||
thumbnail:
|
||||
'http://0.0.0.0:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCdz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--318d40b3d34e02760df9f4ea0c5c89d1f590dda4/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2QzNKbGMybDZaVWtpRERJMU1IZ3lOVEFHT3daVSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--e0e35266e8ed66e90c51be02408be8a022aca545/profile-pic.png',
|
||||
},
|
||||
},
|
||||
id: 10,
|
||||
messages: [
|
||||
{
|
||||
id: 85,
|
||||
content: 'Ok',
|
||||
account_id: 1,
|
||||
inbox_id: 6,
|
||||
conversation_id: 10,
|
||||
message_type: 1,
|
||||
created_at: 1635764265,
|
||||
updated_at: '2021-11-01T10:57:45.790Z',
|
||||
private: false,
|
||||
status: 'sent',
|
||||
source_id: null,
|
||||
content_type: 'text',
|
||||
content_attributes: {},
|
||||
sender_type: 'User',
|
||||
sender_id: 1,
|
||||
external_source_ids: {},
|
||||
sender: {
|
||||
id: 1,
|
||||
name: 'John',
|
||||
available_name: 'John',
|
||||
avatar_url:
|
||||
'http://0.0.0.0:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCdz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--318d40b3d34e02760df9f4ea0c5c89d1f590dda4/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2QzNKbGMybDZaVWtpRERJMU1IZ3lOVEFHT3daVSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--e0e35266e8ed66e90c51be02408be8a022aca545/profile-pic.png',
|
||||
type: 'user',
|
||||
availability_status: 'online',
|
||||
thumbnail:
|
||||
'http://0.0.0.0:3000/rails/active_storage/representations/redirect/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCdz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--318d40b3d34e02760df9f4ea0c5c89d1f590dda4/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdCem9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2QzNKbGMybDZaVWtpRERJMU1IZ3lOVEFHT3daVSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--e0e35266e8ed66e90c51be02408be8a022aca545/profile-pic.png',
|
||||
},
|
||||
},
|
||||
],
|
||||
account_id: 1,
|
||||
additional_attributes: {
|
||||
browser: {
|
||||
device_name: 'Unknown',
|
||||
browser_name: 'Chrome',
|
||||
platform_name: 'macOS',
|
||||
browser_version: '95.0.4638.54',
|
||||
platform_version: '10.15.7',
|
||||
},
|
||||
referer: 'http://localhost:3000/widget_tests',
|
||||
initiated_at: {
|
||||
timestamp: 'Mon Nov 01 2021 16:25:06 GMT+0530 (India Standard Time)',
|
||||
},
|
||||
},
|
||||
agent_last_seen_at: 1635846359,
|
||||
assignee_last_seen_at: 1635846359,
|
||||
can_reply: true,
|
||||
contact_last_seen_at: 1635764265,
|
||||
custom_attributes: {},
|
||||
inbox_id: 6,
|
||||
labels: [],
|
||||
muted: false,
|
||||
snoozed_until: null,
|
||||
status: 'open',
|
||||
timestamp: 1635764265,
|
||||
unread_count: 0,
|
||||
},
|
||||
],
|
||||
};
|
||||
Reference in New Issue
Block a user