From 60a312ace596f283c7dc6b02b509991580a6c849 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Wed, 13 Dec 2023 09:29:31 +0530 Subject: [PATCH] feat: Advanced conversation sort options (#8532) Co-authored-by: Pranav Raj S --- .../dashboard/components/ChatList.vue | 7 +- .../conversation/ConversationBasicFilter.vue | 8 +- app/javascript/dashboard/constants/globals.js | 12 +- .../dashboard/i18n/locale/en/chatlist.json | 30 +++- .../store/modules/conversations/getters.js | 38 +---- .../store/modules/conversations/helpers.js | 52 ++++++ .../specs/conversations/getters.spec.js | 155 +++++++++++++++++- app/javascript/shared/constants/messages.js | 9 +- 8 files changed, 251 insertions(+), 60 deletions(-) diff --git a/app/javascript/dashboard/components/ChatList.vue b/app/javascript/dashboard/components/ChatList.vue index 9835fadf3..7d76b3303 100644 --- a/app/javascript/dashboard/components/ChatList.vue +++ b/app/javascript/dashboard/components/ChatList.vue @@ -269,7 +269,7 @@ export default { return { activeAssigneeTab: wootConstants.ASSIGNEE_TYPE.ME, activeStatus: wootConstants.STATUS_TYPE.OPEN, - activeSortBy: wootConstants.SORT_BY_TYPE.LATEST, + activeSortBy: wootConstants.SORT_BY_TYPE.LAST_ACTIVITY_AT_DESC, showAdvancedFilters: false, advancedFilterTypes: advancedFilterTypes.map(filter => ({ ...filter, @@ -553,7 +553,10 @@ export default { const { conversations_filter_by: filterBy = {} } = this.uiSettings; const { status, order_by: orderBy } = filterBy; this.activeStatus = status || wootConstants.STATUS_TYPE.OPEN; - this.activeSortBy = orderBy || wootConstants.SORT_BY_TYPE.LATEST; + this.activeSortBy = + Object.keys(wootConstants.SORT_BY_TYPE).find( + sortField => sortField === orderBy + ) || wootConstants.SORT_BY_TYPE.LAST_ACTIVITY_AT_DESC; }, onClickOpenAddFoldersModal() { this.showAddFoldersModal = true; diff --git a/app/javascript/dashboard/components/widgets/conversation/ConversationBasicFilter.vue b/app/javascript/dashboard/components/widgets/conversation/ConversationBasicFilter.vue index 01a6bb442..f424fb693 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ConversationBasicFilter.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ConversationBasicFilter.vue @@ -34,7 +34,7 @@ type="sort" :selected-value="sortFilter" :items="chatSortItems" - path-prefix="CHAT_LIST.CHAT_SORT_FILTER_ITEMS" + path-prefix="CHAT_LIST.SORT_ORDER_ITEMS" @onChangeFilter="onChangeFilter" /> @@ -58,7 +58,7 @@ export default { return { showActionsDropdown: false, chatStatusItems: this.$t('CHAT_LIST.CHAT_STATUS_FILTER_ITEMS'), - chatSortItems: this.$t('CHAT_LIST.CHAT_SORT_FILTER_ITEMS'), + chatSortItems: this.$t('CHAT_LIST.SORT_ORDER_ITEMS'), }; }, computed: { @@ -70,7 +70,9 @@ export default { return this.chatStatusFilter || wootConstants.STATUS_TYPE.OPEN; }, sortFilter() { - return this.chatSortFilter || wootConstants.SORT_BY_TYPE.LATEST; + return ( + this.chatSortFilter || wootConstants.SORT_BY_TYPE.LAST_ACTIVITY_AT_DESC + ); }, }, methods: { diff --git a/app/javascript/dashboard/constants/globals.js b/app/javascript/dashboard/constants/globals.js index d0e00dbe7..303f828cd 100644 --- a/app/javascript/dashboard/constants/globals.js +++ b/app/javascript/dashboard/constants/globals.js @@ -13,10 +13,14 @@ export default { ALL: 'all', }, SORT_BY_TYPE: { - LATEST: 'latest', - CREATED_AT: 'sort_on_created_at', - PRIORITY: 'sort_on_priority', - WATIING_SINCE: 'waiting_since', + LAST_ACTIVITY_AT_ASC: 'last_activity_at_asc', + LAST_ACTIVITY_AT_DESC: 'last_activity_at_desc', + CREATED_AT_ASC: 'created_at_asc', + CREATED_AT_DESC: 'created_at_desc', + PRIORITY_ASC: 'priority_asc', + PRIORITY_DESC: 'priority_desc', + WAITING_SINCE_ASC: 'waiting_since_asc', + WAITING_SINCE_DESC: 'waiting_since_desc', }, ARTICLE_STATUS_TYPES: { DRAFT: 0, diff --git a/app/javascript/dashboard/i18n/locale/en/chatlist.json b/app/javascript/dashboard/i18n/locale/en/chatlist.json index 9c973b199..1458bf58a 100644 --- a/app/javascript/dashboard/i18n/locale/en/chatlist.json +++ b/app/javascript/dashboard/i18n/locale/en/chatlist.json @@ -51,18 +51,30 @@ "ACTIVE": "Last activity" } }, - "CHAT_SORT_FILTER_ITEMS": { - "latest": { - "TEXT": "Last activity" + "SORT_ORDER_ITEMS": { + "last_activity_at_asc": { + "TEXT": "Last activity: Oldest first" }, - "sort_on_created_at": { - "TEXT": "Created at" + "last_activity_at_desc": { + "TEXT": "Last activity: Newest first" }, - "sort_on_priority": { - "TEXT": "Priority" + "created_at_desc": { + "TEXT": "Created at: Newest first" }, - "sort_on_waiting_since": { - "TEXT": "Pending Response" + "created_at_asc": { + "TEXT": "Created at: Oldest first" + }, + "priority_desc": { + "TEXT": "Priority: Highest first" + }, + "priority_asc": { + "TEXT": "Priority: Lowest first" + }, + "waiting_since_asc": { + "TEXT": "Pending Response: Longest first" + }, + "waiting_since_desc": { + "TEXT": "Pending Response: Shortest first" } }, "ATTACHMENTS": { diff --git a/app/javascript/dashboard/store/modules/conversations/getters.js b/app/javascript/dashboard/store/modules/conversations/getters.js index e8dbd7341..62e9ef4ef 100644 --- a/app/javascript/dashboard/store/modules/conversations/getters.js +++ b/app/javascript/dashboard/store/modules/conversations/getters.js @@ -1,8 +1,5 @@ -import { - MESSAGE_TYPE, - CONVERSATION_PRIORITY_ORDER, -} from 'shared/constants/messages'; -import { applyPageFilters } from './helpers'; +import { MESSAGE_TYPE } from 'shared/constants/messages'; +import { applyPageFilters, sortComparator } from './helpers'; export const getSelectedChatConversation = ({ allConversations, @@ -10,36 +7,9 @@ export const getSelectedChatConversation = ({ }) => allConversations.filter(conversation => conversation.id === selectedChatId); -const sortComparator = { - latest: (a, b) => b.last_activity_at - a.last_activity_at, - sort_on_created_at: (a, b) => a.created_at - b.created_at, - sort_on_priority: (a, b) => { - return ( - CONVERSATION_PRIORITY_ORDER[a.priority] - - CONVERSATION_PRIORITY_ORDER[b.priority] - ); - }, - sort_on_waiting_since: (a, b) => { - if (!a.waiting_since && !b.waiting_since) { - return a.created_at - b.created_at; - } - - if (!a.waiting_since) { - return 1; - } - - if (!b.waiting_since) { - return -1; - } - - return a.waiting_since - b.waiting_since; - }, -}; - -// getters const getters = { - getAllConversations: ({ allConversations, chatSortFilter }) => { - return allConversations.sort(sortComparator[chatSortFilter]); + getAllConversations: ({ allConversations, chatSortFilter: sortKey }) => { + return allConversations.sort((a, b) => sortComparator(a, b, sortKey)); }, getSelectedChat: ({ selectedChatId, allConversations }) => { const selectedChat = allConversations.find( diff --git a/app/javascript/dashboard/store/modules/conversations/helpers.js b/app/javascript/dashboard/store/modules/conversations/helpers.js index 910dca31b..8f01de272 100644 --- a/app/javascript/dashboard/store/modules/conversations/helpers.js +++ b/app/javascript/dashboard/store/modules/conversations/helpers.js @@ -1,3 +1,5 @@ +import { CONVERSATION_PRIORITY_ORDER } from 'shared/constants/messages'; + export const findPendingMessageIndex = (chat, message) => { const { echo_id: tempMessageId } = message; return chat.messages.findIndex( @@ -59,3 +61,53 @@ export const applyPageFilters = (conversation, filters) => { return shouldFilter; }; + +const SORT_OPTIONS = { + last_activity_at_asc: ['sortOnLastActivityAt', 'asc'], + last_activity_at_desc: ['sortOnLastActivityAt', 'desc'], + created_at_asc: ['sortOnCreatedAt', 'asc'], + created_at_desc: ['sortOnCreatedAt', 'desc'], + priority_asc: ['sortOnPriority', 'asc'], + priority_desc: ['sortOnPriority', 'desc'], + waiting_since_asc: ['sortOnWaitingSince', 'asc'], + waiting_since_desc: ['sortOnWaitingSince', 'desc'], +}; +const sortAscending = (valueA, valueB) => valueA - valueB; +const sortDescending = (valueA, valueB) => valueB - valueA; + +const getSortOrderFunction = sortOrder => + sortOrder === 'asc' ? sortAscending : sortDescending; + +const sortConfig = { + sortOnLastActivityAt: (a, b, sortDirection) => + getSortOrderFunction(sortDirection)(a.last_activity_at, b.last_activity_at), + + sortOnCreatedAt: (a, b, sortDirection) => + getSortOrderFunction(sortDirection)(a.created_at, b.created_at), + + sortOnPriority: (a, b, sortDirection) => { + const DEFAULT_FOR_NULL = sortDirection === 'asc' ? 5 : 0; + + const p1 = CONVERSATION_PRIORITY_ORDER[a.priority] || DEFAULT_FOR_NULL; + const p2 = CONVERSATION_PRIORITY_ORDER[b.priority] || DEFAULT_FOR_NULL; + + return getSortOrderFunction(sortDirection)(p1, p2); + }, + + sortOnWaitingSince: (a, b, sortDirection) => { + const sortFunc = getSortOrderFunction(sortDirection); + if (!a.waiting_since || !b.waiting_since) { + if (!a.waiting_since && !b.waiting_since) { + return sortFunc(a.created_at, b.created_at); + } + return sortFunc(a.waiting_since ? 0 : 1, b.waiting_since ? 0 : 1); + } + + return sortFunc(a.waiting_since, b.waiting_since); + }, +}; + +export const sortComparator = (a, b, sortKey) => { + const [sortMethod, sortDirection] = SORT_OPTIONS[sortKey] || []; + return sortConfig[sortMethod](a, b, sortDirection); +}; diff --git a/app/javascript/dashboard/store/modules/specs/conversations/getters.spec.js b/app/javascript/dashboard/store/modules/specs/conversations/getters.spec.js index a4eaef4ba..a32cc853e 100644 --- a/app/javascript/dashboard/store/modules/specs/conversations/getters.spec.js +++ b/app/javascript/dashboard/store/modules/specs/conversations/getters.spec.js @@ -47,6 +47,49 @@ describe('#getters', () => { }, ]); }); + it('order conversations based on last activity with ascending order', () => { + const state = { + allConversations: [ + { + id: 1, + messages: [ + { + content: 'test1', + }, + ], + created_at: 2466424490, + last_activity_at: 2466424490, + }, + { + id: 2, + messages: [{ content: 'test2' }], + created_at: 1466424480, + last_activity_at: 1466424480, + }, + ], + chatSortFilter: 'latest_last', + }; + + expect(getters.getAllConversations(state)).toEqual([ + { + id: 2, + messages: [{ content: 'test2' }], + created_at: 1466424480, + last_activity_at: 1466424480, + }, + { + id: 1, + messages: [ + { + content: 'test1', + }, + ], + created_at: 2466424490, + last_activity_at: 2466424490, + }, + ]); + }); + it('order conversations based on created at', () => { const state = { allConversations: [ @@ -67,7 +110,7 @@ describe('#getters', () => { last_activity_at: 1466424480, }, ], - chatSortFilter: 'sort_on_created_at', + chatSortFilter: 'created_at_last', }; expect(getters.getAllConversations(state)).toEqual([ @@ -89,6 +132,50 @@ describe('#getters', () => { }, ]); }); + + it('order conversations based on created at with descending order', () => { + const state = { + allConversations: [ + { + id: 1, + messages: [ + { + content: 'test1', + }, + ], + created_at: 1683645801, // Tuesday, 9 May 2023 + last_activity_at: 2466424490, + }, + { + id: 2, + messages: [{ content: 'test2' }], + created_at: 1652109801, // Monday, 9 May 2022 + last_activity_at: 1466424480, + }, + ], + chatSortFilter: 'created_at_first', + }; + + expect(getters.getAllConversations(state)).toEqual([ + { + id: 1, + messages: [ + { + content: 'test1', + }, + ], + created_at: 1683645801, + last_activity_at: 2466424490, + }, + { + id: 2, + messages: [{ content: 'test2' }], + created_at: 1652109801, + last_activity_at: 1466424480, + }, + ]); + }); + it('order conversations based on default order', () => { const state = { allConversations: [ @@ -159,7 +246,7 @@ describe('#getters', () => { last_activity_at: 1466421280, }, ], - chatSortFilter: 'sort_on_priority', + chatSortFilter: 'priority_first', }; expect(getters.getAllConversations(state)).toEqual([ @@ -190,6 +277,68 @@ describe('#getters', () => { }, ]); }); + + it('order conversations based on with descending order', () => { + const state = { + allConversations: [ + { + id: 1, + messages: [ + { + content: 'test1', + }, + ], + priority: 'low', + created_at: 1683645801, + last_activity_at: 2466424490, + }, + { + id: 2, + messages: [{ content: 'test2' }], + priority: 'urgent', + created_at: 1652109801, + last_activity_at: 1466424480, + }, + { + id: 3, + messages: [{ content: 'test3' }], + priority: 'medium', + created_at: 1652109801, + last_activity_at: 1466421280, + }, + ], + chatSortFilter: 'priority_last', + }; + + expect(getters.getAllConversations(state)).toEqual([ + { + id: 1, + messages: [ + { + content: 'test1', + }, + ], + priority: 'low', + created_at: 1683645801, + last_activity_at: 2466424490, + }, + { + id: 3, + messages: [{ content: 'test3' }], + priority: 'medium', + created_at: 1652109801, + last_activity_at: 1466421280, + }, + { + id: 2, + messages: [{ content: 'test2' }], + priority: 'urgent', + created_at: 1652109801, + last_activity_at: 1466424480, + }, + ]); + }); + it('order conversations based on waiting_since', () => { const state = { allConversations: [ @@ -214,7 +363,7 @@ describe('#getters', () => { waiting_since: 1683645800, }, ], - chatSortFilter: 'sort_on_waiting_since', + chatSortFilter: 'waiting_since_last', }; expect(getters.getAllConversations(state)).toEqual([ diff --git a/app/javascript/shared/constants/messages.js b/app/javascript/shared/constants/messages.js index b53ca6826..b3ef11e1b 100644 --- a/app/javascript/shared/constants/messages.js +++ b/app/javascript/shared/constants/messages.js @@ -28,11 +28,10 @@ export const CONVERSATION_PRIORITY = { }; export const CONVERSATION_PRIORITY_ORDER = { - urgent: 1, - high: 2, - medium: 3, - low: 4, - null: 5, + urgent: 4, + high: 3, + medium: 2, + low: 1, }; // Size in mega bytes