feat: Add store for conversation watchers (#5808)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
parent
6ff0c93659
commit
0d9ed0674b
8 changed files with 240 additions and 0 deletions
|
@ -105,6 +105,16 @@ class ConversationApi extends ApiClient {
|
||||||
custom_attributes: customAttributes,
|
custom_attributes: customAttributes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fetchParticipants(conversationId) {
|
||||||
|
return axios.get(`${this.url}/${conversationId}/participants`);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateParticipants({ conversationId, userIds }) {
|
||||||
|
return axios.patch(`${this.url}/${conversationId}/participants`, {
|
||||||
|
user_ids: userIds,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new ConversationApi();
|
export default new ConversationApi();
|
||||||
|
|
|
@ -23,6 +23,7 @@ import conversations from './modules/conversations';
|
||||||
import conversationSearch from './modules/conversationSearch';
|
import conversationSearch from './modules/conversationSearch';
|
||||||
import conversationStats from './modules/conversationStats';
|
import conversationStats from './modules/conversationStats';
|
||||||
import conversationTypingStatus from './modules/conversationTypingStatus';
|
import conversationTypingStatus from './modules/conversationTypingStatus';
|
||||||
|
import conversationWatchers from './modules/conversationWatchers';
|
||||||
import csat from './modules/csat';
|
import csat from './modules/csat';
|
||||||
import customViews from './modules/customViews';
|
import customViews from './modules/customViews';
|
||||||
import dashboardApps from './modules/dashboardApps';
|
import dashboardApps from './modules/dashboardApps';
|
||||||
|
@ -66,6 +67,7 @@ export default new Vuex.Store({
|
||||||
conversationSearch,
|
conversationSearch,
|
||||||
conversationStats,
|
conversationStats,
|
||||||
conversationTypingStatus,
|
conversationTypingStatus,
|
||||||
|
conversationWatchers,
|
||||||
csat,
|
csat,
|
||||||
customViews,
|
customViews,
|
||||||
dashboardApps,
|
dashboardApps,
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
import types from '../mutation-types';
|
||||||
|
import { throwErrorMessage } from 'dashboard/store/utils/api';
|
||||||
|
|
||||||
|
import ConversationInboxApi from '../../api/inbox/conversation';
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
records: {},
|
||||||
|
uiFlags: {
|
||||||
|
isFetching: false,
|
||||||
|
isUpdating: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getters = {
|
||||||
|
getUIFlags($state) {
|
||||||
|
return $state.uiFlags;
|
||||||
|
},
|
||||||
|
getByConversationId: _state => conversationId => {
|
||||||
|
return _state.records[conversationId];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
show: async ({ commit }, { conversationId }) => {
|
||||||
|
commit(types.SET_CONVERSATION_WATCHERS_UI_FLAG, {
|
||||||
|
isFetching: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await ConversationInboxApi.fetchParticipants(
|
||||||
|
conversationId
|
||||||
|
);
|
||||||
|
commit(types.SET_CONVERSATION_WATCHERS, {
|
||||||
|
conversationId,
|
||||||
|
data: response.data,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throwErrorMessage(error);
|
||||||
|
} finally {
|
||||||
|
commit(types.SET_CONVERSATION_WATCHERS_UI_FLAG, {
|
||||||
|
isFetching: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
update: async ({ commit }, { conversationId, userIds }) => {
|
||||||
|
commit(types.SET_CONVERSATION_WATCHERS_UI_FLAG, {
|
||||||
|
isUpdating: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await ConversationInboxApi.updateParticipants({
|
||||||
|
conversationId,
|
||||||
|
userIds,
|
||||||
|
});
|
||||||
|
commit(types.SET_CONVERSATION_WATCHERS, {
|
||||||
|
conversationId,
|
||||||
|
data: response.data,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throwErrorMessage(error);
|
||||||
|
} finally {
|
||||||
|
commit(types.SET_CONVERSATION_WATCHERS_UI_FLAG, {
|
||||||
|
isUpdating: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mutations = {
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG]($state, data) {
|
||||||
|
$state.uiFlags = {
|
||||||
|
...$state.uiFlags,
|
||||||
|
...data,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
[types.SET_CONVERSATION_WATCHERS]($state, { data, conversationId }) {
|
||||||
|
Vue.set($state.records, conversationId, data);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
actions,
|
||||||
|
mutations,
|
||||||
|
};
|
|
@ -0,0 +1,62 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
import { actions } from '../../conversationWatchers';
|
||||||
|
import types from '../../../mutation-types';
|
||||||
|
|
||||||
|
const commit = jest.fn();
|
||||||
|
global.axios = axios;
|
||||||
|
jest.mock('axios');
|
||||||
|
|
||||||
|
describe('#actions', () => {
|
||||||
|
describe('#get', () => {
|
||||||
|
it('sends correct actions if API is success', async () => {
|
||||||
|
axios.get.mockResolvedValue({ data: { id: 1 } });
|
||||||
|
await actions.show({ commit }, { conversationId: 1 });
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG, { isFetching: true }],
|
||||||
|
[
|
||||||
|
types.SET_CONVERSATION_WATCHERS,
|
||||||
|
{ conversationId: 1, data: { id: 1 } },
|
||||||
|
],
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG, { isFetching: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('sends correct actions if API is error', async () => {
|
||||||
|
axios.get.mockRejectedValue({ message: 'Incorrect header' });
|
||||||
|
await expect(
|
||||||
|
actions.show({ commit }, { conversationId: 1 })
|
||||||
|
).rejects.toThrow(Error);
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG, { isFetching: true }],
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG, { isFetching: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#update', () => {
|
||||||
|
it('sends correct actions if API is success', async () => {
|
||||||
|
axios.patch.mockResolvedValue({ data: [{ id: 2 }] });
|
||||||
|
await actions.update(
|
||||||
|
{ commit },
|
||||||
|
{ conversationId: 2, userIds: [{ id: 2 }] }
|
||||||
|
);
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG, { isUpdating: true }],
|
||||||
|
[
|
||||||
|
types.SET_CONVERSATION_WATCHERS,
|
||||||
|
{ conversationId: 2, data: [{ id: 2 }] },
|
||||||
|
],
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG, { isUpdating: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('sends correct actions if API is error', async () => {
|
||||||
|
axios.patch.mockRejectedValue({ message: 'Incorrect header' });
|
||||||
|
await expect(
|
||||||
|
actions.update({ commit }, { conversationId: 1, content: 'hi' })
|
||||||
|
).rejects.toThrow(Error);
|
||||||
|
expect(commit.mock.calls).toEqual([
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG, { isUpdating: true }],
|
||||||
|
[types.SET_CONVERSATION_WATCHERS_UI_FLAG, { isUpdating: false }],
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,14 @@
|
||||||
|
export const data = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Uno',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Dos',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Tres',
|
||||||
|
},
|
||||||
|
];
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { getters } from '../../conversationWatchers';
|
||||||
|
import watchersData from './fixtures';
|
||||||
|
|
||||||
|
describe('#getters', () => {
|
||||||
|
it('getByConversationId', () => {
|
||||||
|
const state = { records: { 1: watchersData } };
|
||||||
|
expect(getters.getByConversationId(state)(1)).toEqual(watchersData);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('getUIFlags', () => {
|
||||||
|
const state = {
|
||||||
|
uiFlags: {
|
||||||
|
isFetching: false,
|
||||||
|
isUpdating: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
expect(getters.getUIFlags(state)).toEqual({
|
||||||
|
isFetching: false,
|
||||||
|
isUpdating: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,37 @@
|
||||||
|
import types from '../../../mutation-types';
|
||||||
|
import { mutations } from '../../conversationWatchers';
|
||||||
|
|
||||||
|
describe('#mutations', () => {
|
||||||
|
describe('#SET_CONVERSATION_WATCHERS', () => {
|
||||||
|
it('sets an individual record', () => {
|
||||||
|
let state = {
|
||||||
|
records: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
mutations[types.SET_CONVERSATION_WATCHERS](state, {
|
||||||
|
data: [],
|
||||||
|
conversationId: 1,
|
||||||
|
});
|
||||||
|
expect(state.records).toEqual({ 1: [] });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#SET_CONVERSATION_WATCHERS_UI_FLAG', () => {
|
||||||
|
it('set ui flags', () => {
|
||||||
|
let state = {
|
||||||
|
uiFlags: {
|
||||||
|
isFetching: true,
|
||||||
|
isUpdating: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mutations[types.SET_CONVERSATION_WATCHERS_UI_FLAG](state, {
|
||||||
|
isFetching: false,
|
||||||
|
});
|
||||||
|
expect(state.uiFlags).toEqual({
|
||||||
|
isFetching: false,
|
||||||
|
isUpdating: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -258,4 +258,7 @@ export default {
|
||||||
ADD_MACRO: 'ADD_MACRO',
|
ADD_MACRO: 'ADD_MACRO',
|
||||||
EDIT_MACRO: 'EDIT_MACRO',
|
EDIT_MACRO: 'EDIT_MACRO',
|
||||||
DELETE_MACRO: 'DELETE_MACRO',
|
DELETE_MACRO: 'DELETE_MACRO',
|
||||||
|
|
||||||
|
SET_CONVERSATION_WATCHERS_UI_FLAG: 'SET_CONVERSATION_WATCHERS_UI_FLAG',
|
||||||
|
SET_CONVERSATION_WATCHERS: 'SET_CONVERSATION_WATCHERS',
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue