Adds unread message bubbles for widget (#943)

Co-authored-by: Sojan <sojan@pepalo.com>
Co-authored-by: Pranav Raj S <pranav@thoughtwoot.com>
This commit is contained in:
Nithin David Thomas
2020-07-08 00:04:44 +05:30
committed by GitHub
parent 6a7d810c95
commit 49db9c5d8a
25 changed files with 787 additions and 51 deletions

View File

@@ -11,6 +11,7 @@ const state = {
};
export const getters = {
getHasFetched: $state => $state.uiFlags.hasFetched,
availableAgents: $state =>
$state.records.filter(agent => agent.availability_status === 'online'),
};

View File

@@ -5,6 +5,7 @@ import {
getMessagesAPI,
sendAttachmentAPI,
toggleTyping,
setUserLastSeenAt,
} from 'widget/api/conversation';
import { MESSAGE_TYPE } from 'widget/helpers/constants';
import { playNotificationAudio } from 'shared/helpers/AudioNotificationHelper';
@@ -59,10 +60,22 @@ export const findUndeliveredMessage = (messageInbox, { content }) =>
message => message.content === content && message.status === 'in_progress'
);
export const onNewMessageCreated = data => {
const { message_type: messageType } = data;
const isIncomingMessage = messageType === MESSAGE_TYPE.OUTGOING;
if (isIncomingMessage) {
playNotificationAudio();
}
};
export const DEFAULT_CONVERSATION = 'default';
const state = {
conversations: {},
meta: {
userLastSeenAt: undefined,
},
uiFlags: {
allMessagesLoaded: false,
isFetchingList: false,
@@ -93,6 +106,31 @@ export const getters = {
}));
},
getIsFetchingList: _state => _state.uiFlags.isFetchingList,
getUnreadMessageCount: _state => {
const { userLastSeenAt } = _state.meta;
console.log(userLastSeenAt);
const count = Object.values(_state.conversations).filter(chat => {
const { created_at: createdAt, message_type: messageType } = chat;
const isOutGoing = messageType === MESSAGE_TYPE.OUTGOING;
const hasNotSeen = userLastSeenAt
? createdAt * 1000 > userLastSeenAt * 1000
: true;
return hasNotSeen && isOutGoing;
}).length;
return count;
},
getUnreadTextMessages: (_state, _getters) => {
const unreadCount = _getters.getUnreadMessageCount;
const allMessages = [...Object.values(_state.conversations)];
console.log(unreadCount);
const unreadAgentMessages = allMessages.filter(message => {
const { message_type: messageType } = message;
return messageType === MESSAGE_TYPE.OUTGOING;
});
const maxUnreadCount = Math.min(unreadCount, 3);
const allUnreadMessages = unreadAgentMessages.splice(-maxUnreadCount);
return allUnreadMessages;
},
};
export const actions = {
@@ -112,7 +150,9 @@ export const actions = {
file_type: fileType,
status: 'in_progress',
};
const tempMessage = createTemporaryMessage({ attachments: [attachment] });
const tempMessage = createTemporaryMessage({
attachments: [attachment],
});
commit('pushMessageToConversation', tempMessage);
try {
const { data } = await sendAttachmentAPI(params);
@@ -136,12 +176,9 @@ export const actions = {
}
},
addMessage({ commit }, data) {
if (data.message_type === MESSAGE_TYPE.OUTGOING) {
playNotificationAudio();
}
addMessage: async ({ commit }, data) => {
commit('pushMessageToConversation', data);
onNewMessageCreated(data);
},
updateMessage({ commit }, data) {
@@ -156,7 +193,21 @@ export const actions = {
try {
await toggleTyping(data);
} catch (error) {
// console error
// IgnoreError
}
},
setUserLastSeen: async ({ commit, getters: appGetters }) => {
if (!appGetters.getConversationSize) {
return;
}
const lastSeen = Date.now() / 1000;
try {
commit('setMetaUserLastSeenAt', lastSeen);
await setUserLastSeenAt({ lastSeen });
} catch (error) {
// IgnoreError
}
},
};
@@ -224,6 +275,10 @@ export const mutations = {
const isTyping = status === 'on';
$state.uiFlags.isAgentTyping = isTyping;
},
setMetaUserLastSeenAt($state, lastSeen) {
$state.meta.userLastSeenAt = lastSeen;
},
};
export default {

View File

@@ -17,7 +17,9 @@ export const actions = {
get: async ({ commit }) => {
try {
const { data } = await getConversationAPI();
const { user_last_seen_at: lastSeen } = data;
commit(SET_CONVERSATION_ATTRIBUTES, data);
commit('conversation/setMetaUserLastSeenAt', lastSeen, { root: true });
} catch (error) {
// Ignore error
}

View File

@@ -86,4 +86,12 @@ describe('#actions', () => {
});
});
});
describe('#setUserLastSeen', () => {
it('sends correct mutations', () => {
const lastSeen = Math.abs(Date.now() / 1000);
actions.setUserLastSeen({ commit }, { lastSeen });
expect(commit).toBeCalledWith('setMetaUserLastSeenAt', lastSeen);
});
});
});

View File

@@ -262,4 +262,171 @@ describe('#getters', () => {
},
]);
});
describe('getUnreadMessageCount returns', () => {
it('0 if there are no messages and last seen is undefined', () => {
const state = {
conversations: {},
meta: {
userLastSeenAt: undefined,
},
};
expect(getters.getUnreadMessageCount(state)).toEqual(0);
});
it('0 if there are no messages and last seen is present', () => {
const state = {
conversations: {},
meta: {
userLastSeenAt: Date.now(),
},
};
expect(getters.getUnreadMessageCount(state)).toEqual(0);
});
it('unread count if there are messages and last seen is before messages created-at', () => {
const state = {
conversations: {
1: {
id: 1,
content: 'Thanks for the help',
created_at: 1574075964,
message_type: 1,
},
2: {
id: 2,
content: 'Yes, It makes sense',
created_at: 1574092218,
message_type: 1,
},
},
meta: {
userLastSeenAt: 1474075964,
},
};
expect(getters.getUnreadMessageCount(state)).toEqual(2);
});
it('unread count if there are messages and last seen is after messages created-at', () => {
const state = {
conversations: {
1: {
id: 1,
content: 'Thanks for the help',
created_at: 1574075964,
message_type: 1,
},
2: {
id: 2,
content: 'Yes, It makes sense',
created_at: 1574092218,
message_type: 1,
},
3: {
id: 3,
content: 'Yes, It makes sense',
created_at: 1574092218,
message_type: 0,
},
},
meta: {
userLastSeenAt: 1674075964,
},
};
expect(getters.getUnreadMessageCount(state)).toEqual(0);
});
});
describe('getUnreadTextMessages returns', () => {
it('no messages if there are no messages and last seen is undefined', () => {
const state = {
conversations: {},
meta: {
userLastSeenAt: undefined,
},
};
expect(
getters.getUnreadTextMessages(state, { getUnreadMessageCount: 0 })
).toEqual([]);
});
it('0 if there are no messages and last seen is present', () => {
const state = {
conversations: {},
meta: {
userLastSeenAt: Date.now(),
},
};
expect(
getters.getUnreadTextMessages(state, { getUnreadMessageCount: 0 })
).toEqual([]);
});
it('only unread text messages from agent if there are messages and last seen is before messages created-at', () => {
const state = {
conversations: {
1: {
id: 1,
content: 'Thanks for the help',
created_at: 1574075964,
message_type: 1,
},
2: {
id: 2,
content: 'Yes, It makes sense',
created_at: 1574092218,
message_type: 0,
},
},
};
expect(
getters.getUnreadTextMessages(state, { getUnreadMessageCount: 1 })
).toEqual([
{
id: 1,
content: 'Thanks for the help',
created_at: 1574075964,
message_type: 1,
},
]);
});
it('unread messages omitting seen messages ', () => {
const state = {
conversations: {
1: {
id: 1,
content: 'Thanks for the help',
created_at: 1574075964,
message_type: 1,
},
2: {
id: 2,
content: 'Yes, It makes sense',
created_at: 1674075965,
message_type: 1,
},
3: {
id: 3,
content: 'Yes, It makes sense',
created_at: 1574092218,
message_type: 0,
},
},
meta: {
userLastSeenAt: 1674075964,
},
};
expect(
getters.getUnreadTextMessages(state, { getUnreadMessageCount: 1 })
).toEqual([
{
id: 2,
content: 'Yes, It makes sense',
created_at: 1674075965,
message_type: 1,
},
]);
});
});
});

View File

@@ -11,6 +11,7 @@ describe('#actions', () => {
await actions.get({ commit });
expect(commit.mock.calls).toEqual([
['SET_CONVERSATION_ATTRIBUTES', { id: 1, status: 'bot' }],
['conversation/setMetaUserLastSeenAt', undefined, { root: true }],
]);
});
it('doesnot send mutation if api is error', async () => {