feat: Add state and mutations for multiple conversation on widget
This commit is contained in:
parent
430c0b1569
commit
fa5d9e8cd7
3 changed files with 519 additions and 0 deletions
36
app/javascript/widget/store/modules/conversation_new/index.js
Executable file
36
app/javascript/widget/store/modules/conversation_new/index.js
Executable file
|
@ -0,0 +1,36 @@
|
||||||
|
import { getters } from './getters';
|
||||||
|
import { actions } from './actions';
|
||||||
|
import { mutations } from './mutations';
|
||||||
|
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [],
|
||||||
|
uiFlags: {
|
||||||
|
byId: {
|
||||||
|
// 1: { allMessagesLoaded: false, isAgentTyping: false, isFetching: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [],
|
||||||
|
uiFlags: {
|
||||||
|
byId: {
|
||||||
|
// 1: { isCreating: false, isPending: false, isDeleting: false },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
uiFlags: {
|
||||||
|
allConversationsLoaded: false,
|
||||||
|
isFetching: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
actions,
|
||||||
|
mutations,
|
||||||
|
};
|
|
@ -0,0 +1,103 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
|
||||||
|
export const mutations = {
|
||||||
|
setUIFlag($state, uiFlags) {
|
||||||
|
$state.uiFlags = {
|
||||||
|
...$state.uiFlags,
|
||||||
|
...uiFlags,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addConversationEntry($state, conversation) {
|
||||||
|
if (!conversation.id) return;
|
||||||
|
|
||||||
|
Vue.set($state.conversations.byId, conversation.id, {
|
||||||
|
...conversation,
|
||||||
|
messages: [],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
addConversationId($state, conversationId) {
|
||||||
|
$state.conversations.allIds.push(conversationId);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateConversationEntry($state, conversation) {
|
||||||
|
if (!conversation.id) return;
|
||||||
|
if (!$state.conversations.allIds.includes(conversation.id)) return;
|
||||||
|
|
||||||
|
Vue.set($state.conversations.byId, conversation.id, conversation);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeConversationEntry($state, conversationId) {
|
||||||
|
if (!conversationId) return;
|
||||||
|
|
||||||
|
Vue.set($state.conversations.byId, conversationId, undefined);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeConversationId($state, conversationId) {
|
||||||
|
$state.conversations.allIds = $state.conversations.allIds.filter(
|
||||||
|
id => id !== conversationId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
setConversationUIFlag($state, { conversationId, uiFlags }) {
|
||||||
|
const flags = $state.conversations.uiFlags.byId[conversationId];
|
||||||
|
$state.conversations.uiFlags.byId[conversationId] = {
|
||||||
|
...flags,
|
||||||
|
...uiFlags,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addMessageIds($state, { conversationId, messages }) {
|
||||||
|
const conversationById = $state.conversations.byId[conversationId];
|
||||||
|
if (!conversationById) return;
|
||||||
|
|
||||||
|
const messageIds = messages.map(message => message.id);
|
||||||
|
const updatedMessageIds = [...conversationById.messages, ...messageIds];
|
||||||
|
Vue.set(conversationById, 'messages', updatedMessageIds);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMessageEntry($state, message) {
|
||||||
|
const messageId = message.id;
|
||||||
|
if (!messageId) return;
|
||||||
|
|
||||||
|
const messageById = $state.messages.byId[messageId];
|
||||||
|
if (!messageById) return;
|
||||||
|
if (messageId !== message.id) return;
|
||||||
|
|
||||||
|
Vue.set($state.messages.byId, messageId, { ...message });
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMessageEntry($state, messageId) {
|
||||||
|
if (!messageId) return;
|
||||||
|
|
||||||
|
Vue.delete($state.messages.byId, messageId);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMessageIdFromConversation($state, { conversationId, messageId }) {
|
||||||
|
if (!messageId || !conversationId) return;
|
||||||
|
|
||||||
|
const conversationById = $state.conversations.byId[conversationId];
|
||||||
|
if (!conversationById) return;
|
||||||
|
|
||||||
|
conversationById.messages = conversationById.messages.filter(
|
||||||
|
id => id !== messageId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeMessageId($state, messageId) {
|
||||||
|
if (!messageId) return;
|
||||||
|
|
||||||
|
$state.messages.allIds = $state.messages.allIds.filter(
|
||||||
|
id => id !== messageId
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
setMessageUIFlag($state, { messageId, uiFlags }) {
|
||||||
|
const flags = $state.messages.uiFlags.byId[messageId];
|
||||||
|
$state.messages.uiFlags.byId[messageId] = {
|
||||||
|
...flags,
|
||||||
|
...uiFlags,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,380 @@
|
||||||
|
import { mutations } from '../../conversation_new/mutations';
|
||||||
|
|
||||||
|
describe('#mutations', () => {
|
||||||
|
describe('#setUIFlag', () => {
|
||||||
|
it('it sets UI flags correctly', () => {
|
||||||
|
const state = {
|
||||||
|
uiFlags: { allConversationsLoaded: false, isFetching: false },
|
||||||
|
};
|
||||||
|
mutations.setUIFlag(state, { isFetching: true });
|
||||||
|
expect(state.uiFlags).toEqual({
|
||||||
|
allConversationsLoaded: false,
|
||||||
|
isFetching: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#addConversationEntry', () => {
|
||||||
|
it('it creates a conversation in store', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.addConversationEntry(state, { id: 420, messages: [] });
|
||||||
|
expect(state.conversations).toEqual({
|
||||||
|
byId: {
|
||||||
|
420: { id: 420, messages: [] },
|
||||||
|
},
|
||||||
|
allIds: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('it creates conversation with empty messages in store', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120 } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.addConversationEntry(state, { id: 420, messages: [] });
|
||||||
|
expect(state.conversations.allIds).toEqual([120]);
|
||||||
|
});
|
||||||
|
it('it does not create a conversation if conversation id is missing', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120 } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.addConversationEntry(state, {});
|
||||||
|
expect(state.conversations.allIds).toEqual([120]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#addConversationId', () => {
|
||||||
|
it('it adds conversation id in store', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.addConversationId(state, 420);
|
||||||
|
expect(state.conversations).toEqual({
|
||||||
|
byId: {},
|
||||||
|
allIds: [420],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#updateConversationEntry', () => {
|
||||||
|
it('it updates an existing conversation in store', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120, channel: 'email' } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.updateConversationEntry(state, {
|
||||||
|
id: 120,
|
||||||
|
channel: 'facebook',
|
||||||
|
});
|
||||||
|
expect(state.conversations).toEqual({
|
||||||
|
byId: {
|
||||||
|
120: { id: 120, channel: 'facebook' },
|
||||||
|
},
|
||||||
|
allIds: [120],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('it does not clears messages in conversation', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120, channel: 'email', messages: [10] } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
messages: {
|
||||||
|
byId: {
|
||||||
|
10: {
|
||||||
|
id: 10,
|
||||||
|
content: 'hi',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
allIds: [10],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.updateConversationEntry(state, {
|
||||||
|
id: 120,
|
||||||
|
channel: 'facebook',
|
||||||
|
});
|
||||||
|
expect(state.messages).toEqual({
|
||||||
|
byId: {
|
||||||
|
10: {
|
||||||
|
id: 10,
|
||||||
|
content: 'hi',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
allIds: [10],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('it does not create a new conversation if conversation id is missing', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120 } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.updateConversationEntry(state, {});
|
||||||
|
expect(state).toEqual({
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120 } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#removeConversationEntry', () => {
|
||||||
|
it('it removes conversation from store', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120 } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.removeConversationEntry(state, 120);
|
||||||
|
expect(state).toEqual({
|
||||||
|
conversations: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#removeConversationId', () => {
|
||||||
|
it('it removes conversation id from store', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120 } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.removeConversationId(state, 120);
|
||||||
|
expect(state).toEqual({
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120 } },
|
||||||
|
allIds: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#setConversationUIFlag', () => {
|
||||||
|
it('it sets UI flag for conversation correctly', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [],
|
||||||
|
uiFlags: {
|
||||||
|
byId: {
|
||||||
|
1: {
|
||||||
|
allMessagesLoaded: false,
|
||||||
|
isAgentTyping: false,
|
||||||
|
isFetching: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.setConversationUIFlag(state, {
|
||||||
|
conversationId: 1,
|
||||||
|
uiFlags: { isFetching: true },
|
||||||
|
});
|
||||||
|
expect(state.conversations.uiFlags.byId[1]).toEqual({
|
||||||
|
allMessagesLoaded: false,
|
||||||
|
isAgentTyping: false,
|
||||||
|
isFetching: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#addMessageIds', () => {
|
||||||
|
it('it adds a list of message ids to existing conversation entry', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120, messages: [] } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
messages: { byId: {}, allIds: [] },
|
||||||
|
};
|
||||||
|
const messages = [
|
||||||
|
{ id: 2, content: 'hi' },
|
||||||
|
{ id: 3, content: 'hello' },
|
||||||
|
];
|
||||||
|
mutations.addMessageIds(state, {
|
||||||
|
conversationId: 120,
|
||||||
|
messages,
|
||||||
|
});
|
||||||
|
expect(state.conversations.byId[120].messages).toEqual([2, 3]);
|
||||||
|
});
|
||||||
|
it('it does not clear existing messages in a conversation', () => {});
|
||||||
|
it('new message id is added as last in allIds message in a conversation', () => {});
|
||||||
|
it('it does not add messages if conversation is not present in store', () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#addMessageIds', () => {
|
||||||
|
it('it adds a list of message ids to existing conversation entry', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120, messages: [] } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
messages: { byId: {}, allIds: [] },
|
||||||
|
};
|
||||||
|
const messages = [
|
||||||
|
{ id: 2, content: 'hi' },
|
||||||
|
{ id: 3, content: 'hello' },
|
||||||
|
];
|
||||||
|
mutations.addMessageIds(state, {
|
||||||
|
conversationId: 120,
|
||||||
|
messages,
|
||||||
|
});
|
||||||
|
expect(state.conversations.byId[120].messages).toEqual([2, 3]);
|
||||||
|
});
|
||||||
|
it('it does not clear existing messages in a conversation', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 120: { id: 120, messages: [2] } },
|
||||||
|
allIds: [120],
|
||||||
|
},
|
||||||
|
messages: { byId: { 2: { id: 2, content: 'hi' } }, allIds: [2] },
|
||||||
|
};
|
||||||
|
const messages = [{ id: 3, content: 'hello' }];
|
||||||
|
mutations.addMessageIds(state, {
|
||||||
|
conversationId: 120,
|
||||||
|
messages,
|
||||||
|
});
|
||||||
|
expect(state.conversations.byId[120].messages).toEqual([2, 3]);
|
||||||
|
});
|
||||||
|
it('it does not add messages if conversation is not present in store', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 12: { id: 12, messages: [2] } },
|
||||||
|
allIds: [12],
|
||||||
|
},
|
||||||
|
messages: { byId: { 2: { id: 2, content: 'hi' } }, allIds: [2] },
|
||||||
|
};
|
||||||
|
const messages = [{ id: 3, content: 'hello' }];
|
||||||
|
mutations.addMessageIds(state, {
|
||||||
|
conversationId: 120,
|
||||||
|
messages,
|
||||||
|
});
|
||||||
|
expect(state.conversations.byId[120]).toEqual(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#updateMessageEntry', () => {
|
||||||
|
it('it updates message in conversation correctly', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 12: { id: 12, messages: [2] } },
|
||||||
|
allIds: [12],
|
||||||
|
},
|
||||||
|
messages: { byId: { 2: { id: 2, content: 'hi' } }, allIds: [2] },
|
||||||
|
};
|
||||||
|
const message = { id: 2, content: 'hello' };
|
||||||
|
mutations.updateMessageEntry(state, message);
|
||||||
|
expect(state.messages.byId[2].content).toEqual('hello');
|
||||||
|
});
|
||||||
|
it('it does not create message if message does not exist in conversation', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 12: { id: 12, messages: [2] } },
|
||||||
|
allIds: [12],
|
||||||
|
},
|
||||||
|
messages: { byId: { 2: { id: 2, content: 'hi' } }, allIds: [2] },
|
||||||
|
};
|
||||||
|
const message = { id: 23, content: 'hello' };
|
||||||
|
mutations.updateMessageEntry(state, message);
|
||||||
|
expect(state.messages.byId[23]).toEqual(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#removeMessageEntry', () => {
|
||||||
|
it('it deletes message in conversation correctly', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 12: { id: 12, messages: [2] } },
|
||||||
|
allIds: [12],
|
||||||
|
},
|
||||||
|
messages: { byId: { 2: { id: 2, content: 'hi' } }, allIds: [2] },
|
||||||
|
};
|
||||||
|
const messageId = 2;
|
||||||
|
mutations.removeMessageEntry(state, messageId);
|
||||||
|
expect(state.messages.byId[2]).toEqual(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#removeMessageId', () => {
|
||||||
|
it('it deletes message id in conversation correctly', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 12: { id: 12, messages: [2] } },
|
||||||
|
allIds: [12],
|
||||||
|
},
|
||||||
|
messages: { byId: { 2: { id: 2, content: 'hi' } }, allIds: [2] },
|
||||||
|
};
|
||||||
|
const messageId = 2;
|
||||||
|
mutations.removeMessageId(state, messageId);
|
||||||
|
expect(state.messages.allIds).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#removeMessageIdFromConversation', () => {
|
||||||
|
it('it deletes message id in conversation correctly', () => {
|
||||||
|
const state = {
|
||||||
|
conversations: {
|
||||||
|
byId: { 12: { id: 12, messages: [2] } },
|
||||||
|
allIds: [12],
|
||||||
|
},
|
||||||
|
messages: { byId: { 2: { id: 2, content: 'hi' } }, allIds: [2] },
|
||||||
|
};
|
||||||
|
const messageId = 2;
|
||||||
|
const conversationId = 12;
|
||||||
|
mutations.removeMessageIdFromConversation(state, {
|
||||||
|
conversationId,
|
||||||
|
messageId,
|
||||||
|
});
|
||||||
|
expect(state.conversations.byId[12].messages).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#setMessageUIFlag', () => {
|
||||||
|
it('it sets UI flag for conversation correctly', () => {
|
||||||
|
const state = {
|
||||||
|
messages: {
|
||||||
|
byId: {},
|
||||||
|
allIds: [],
|
||||||
|
uiFlags: {
|
||||||
|
byId: {
|
||||||
|
1: {
|
||||||
|
isCreating: false,
|
||||||
|
isPending: false,
|
||||||
|
isDeleting: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
mutations.setMessageUIFlag(state, {
|
||||||
|
messageId: 1,
|
||||||
|
uiFlags: { isCreating: true },
|
||||||
|
});
|
||||||
|
expect(state.messages.uiFlags.byId[1]).toEqual({
|
||||||
|
isCreating: true,
|
||||||
|
isPending: false,
|
||||||
|
isDeleting: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue