feat: Advanced conversation sort options (#8532)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
@@ -269,7 +269,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
activeAssigneeTab: wootConstants.ASSIGNEE_TYPE.ME,
|
activeAssigneeTab: wootConstants.ASSIGNEE_TYPE.ME,
|
||||||
activeStatus: wootConstants.STATUS_TYPE.OPEN,
|
activeStatus: wootConstants.STATUS_TYPE.OPEN,
|
||||||
activeSortBy: wootConstants.SORT_BY_TYPE.LATEST,
|
activeSortBy: wootConstants.SORT_BY_TYPE.LAST_ACTIVITY_AT_DESC,
|
||||||
showAdvancedFilters: false,
|
showAdvancedFilters: false,
|
||||||
advancedFilterTypes: advancedFilterTypes.map(filter => ({
|
advancedFilterTypes: advancedFilterTypes.map(filter => ({
|
||||||
...filter,
|
...filter,
|
||||||
@@ -553,7 +553,10 @@ export default {
|
|||||||
const { conversations_filter_by: filterBy = {} } = this.uiSettings;
|
const { conversations_filter_by: filterBy = {} } = this.uiSettings;
|
||||||
const { status, order_by: orderBy } = filterBy;
|
const { status, order_by: orderBy } = filterBy;
|
||||||
this.activeStatus = status || wootConstants.STATUS_TYPE.OPEN;
|
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() {
|
onClickOpenAddFoldersModal() {
|
||||||
this.showAddFoldersModal = true;
|
this.showAddFoldersModal = true;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
type="sort"
|
type="sort"
|
||||||
:selected-value="sortFilter"
|
:selected-value="sortFilter"
|
||||||
:items="chatSortItems"
|
:items="chatSortItems"
|
||||||
path-prefix="CHAT_LIST.CHAT_SORT_FILTER_ITEMS"
|
path-prefix="CHAT_LIST.SORT_ORDER_ITEMS"
|
||||||
@onChangeFilter="onChangeFilter"
|
@onChangeFilter="onChangeFilter"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -58,7 +58,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
showActionsDropdown: false,
|
showActionsDropdown: false,
|
||||||
chatStatusItems: this.$t('CHAT_LIST.CHAT_STATUS_FILTER_ITEMS'),
|
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: {
|
computed: {
|
||||||
@@ -70,7 +70,9 @@ export default {
|
|||||||
return this.chatStatusFilter || wootConstants.STATUS_TYPE.OPEN;
|
return this.chatStatusFilter || wootConstants.STATUS_TYPE.OPEN;
|
||||||
},
|
},
|
||||||
sortFilter() {
|
sortFilter() {
|
||||||
return this.chatSortFilter || wootConstants.SORT_BY_TYPE.LATEST;
|
return (
|
||||||
|
this.chatSortFilter || wootConstants.SORT_BY_TYPE.LAST_ACTIVITY_AT_DESC
|
||||||
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|||||||
@@ -13,10 +13,14 @@ export default {
|
|||||||
ALL: 'all',
|
ALL: 'all',
|
||||||
},
|
},
|
||||||
SORT_BY_TYPE: {
|
SORT_BY_TYPE: {
|
||||||
LATEST: 'latest',
|
LAST_ACTIVITY_AT_ASC: 'last_activity_at_asc',
|
||||||
CREATED_AT: 'sort_on_created_at',
|
LAST_ACTIVITY_AT_DESC: 'last_activity_at_desc',
|
||||||
PRIORITY: 'sort_on_priority',
|
CREATED_AT_ASC: 'created_at_asc',
|
||||||
WATIING_SINCE: 'waiting_since',
|
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: {
|
ARTICLE_STATUS_TYPES: {
|
||||||
DRAFT: 0,
|
DRAFT: 0,
|
||||||
|
|||||||
@@ -51,18 +51,30 @@
|
|||||||
"ACTIVE": "Last activity"
|
"ACTIVE": "Last activity"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"CHAT_SORT_FILTER_ITEMS": {
|
"SORT_ORDER_ITEMS": {
|
||||||
"latest": {
|
"last_activity_at_asc": {
|
||||||
"TEXT": "Last activity"
|
"TEXT": "Last activity: Oldest first"
|
||||||
},
|
},
|
||||||
"sort_on_created_at": {
|
"last_activity_at_desc": {
|
||||||
"TEXT": "Created at"
|
"TEXT": "Last activity: Newest first"
|
||||||
},
|
},
|
||||||
"sort_on_priority": {
|
"created_at_desc": {
|
||||||
"TEXT": "Priority"
|
"TEXT": "Created at: Newest first"
|
||||||
},
|
},
|
||||||
"sort_on_waiting_since": {
|
"created_at_asc": {
|
||||||
"TEXT": "Pending Response"
|
"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": {
|
"ATTACHMENTS": {
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import {
|
import { MESSAGE_TYPE } from 'shared/constants/messages';
|
||||||
MESSAGE_TYPE,
|
import { applyPageFilters, sortComparator } from './helpers';
|
||||||
CONVERSATION_PRIORITY_ORDER,
|
|
||||||
} from 'shared/constants/messages';
|
|
||||||
import { applyPageFilters } from './helpers';
|
|
||||||
|
|
||||||
export const getSelectedChatConversation = ({
|
export const getSelectedChatConversation = ({
|
||||||
allConversations,
|
allConversations,
|
||||||
@@ -10,36 +7,9 @@ export const getSelectedChatConversation = ({
|
|||||||
}) =>
|
}) =>
|
||||||
allConversations.filter(conversation => conversation.id === selectedChatId);
|
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 = {
|
const getters = {
|
||||||
getAllConversations: ({ allConversations, chatSortFilter }) => {
|
getAllConversations: ({ allConversations, chatSortFilter: sortKey }) => {
|
||||||
return allConversations.sort(sortComparator[chatSortFilter]);
|
return allConversations.sort((a, b) => sortComparator(a, b, sortKey));
|
||||||
},
|
},
|
||||||
getSelectedChat: ({ selectedChatId, allConversations }) => {
|
getSelectedChat: ({ selectedChatId, allConversations }) => {
|
||||||
const selectedChat = allConversations.find(
|
const selectedChat = allConversations.find(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { CONVERSATION_PRIORITY_ORDER } from 'shared/constants/messages';
|
||||||
|
|
||||||
export const findPendingMessageIndex = (chat, message) => {
|
export const findPendingMessageIndex = (chat, message) => {
|
||||||
const { echo_id: tempMessageId } = message;
|
const { echo_id: tempMessageId } = message;
|
||||||
return chat.messages.findIndex(
|
return chat.messages.findIndex(
|
||||||
@@ -59,3 +61,53 @@ export const applyPageFilters = (conversation, filters) => {
|
|||||||
|
|
||||||
return shouldFilter;
|
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);
|
||||||
|
};
|
||||||
|
|||||||
@@ -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', () => {
|
it('order conversations based on created at', () => {
|
||||||
const state = {
|
const state = {
|
||||||
allConversations: [
|
allConversations: [
|
||||||
@@ -67,7 +110,7 @@ describe('#getters', () => {
|
|||||||
last_activity_at: 1466424480,
|
last_activity_at: 1466424480,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
chatSortFilter: 'sort_on_created_at',
|
chatSortFilter: 'created_at_last',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(getters.getAllConversations(state)).toEqual([
|
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', () => {
|
it('order conversations based on default order', () => {
|
||||||
const state = {
|
const state = {
|
||||||
allConversations: [
|
allConversations: [
|
||||||
@@ -159,7 +246,7 @@ describe('#getters', () => {
|
|||||||
last_activity_at: 1466421280,
|
last_activity_at: 1466421280,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
chatSortFilter: 'sort_on_priority',
|
chatSortFilter: 'priority_first',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(getters.getAllConversations(state)).toEqual([
|
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', () => {
|
it('order conversations based on waiting_since', () => {
|
||||||
const state = {
|
const state = {
|
||||||
allConversations: [
|
allConversations: [
|
||||||
@@ -214,7 +363,7 @@ describe('#getters', () => {
|
|||||||
waiting_since: 1683645800,
|
waiting_since: 1683645800,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
chatSortFilter: 'sort_on_waiting_since',
|
chatSortFilter: 'waiting_since_last',
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(getters.getAllConversations(state)).toEqual([
|
expect(getters.getAllConversations(state)).toEqual([
|
||||||
|
|||||||
@@ -28,11 +28,10 @@ export const CONVERSATION_PRIORITY = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const CONVERSATION_PRIORITY_ORDER = {
|
export const CONVERSATION_PRIORITY_ORDER = {
|
||||||
urgent: 1,
|
urgent: 4,
|
||||||
high: 2,
|
high: 3,
|
||||||
medium: 3,
|
medium: 2,
|
||||||
low: 4,
|
low: 1,
|
||||||
null: 5,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Size in mega bytes
|
// Size in mega bytes
|
||||||
|
|||||||
Reference in New Issue
Block a user