Files
chatwoot/app/javascript/dashboard/helper/specs/sidebarSort.spec.js
T
d8a16278b9 fix: added ordering capability for sidebar sections folders, teams, channels and labels (CW-7193) (#14609)
## Description

* Added the ability to sort for 4 sub-sections under conversations
folders, teams, channels and labels.
* the sort options are basically created at, alphabetical and unread
counts along with both directions.
* for folders we don't have an unread count, so we sort it by only
created and alphabetical.
* all the sort preferences are stored on the frontend - easiest
implementation for now.

Fixes # CW-7193

## Type of change

Please delete options that are not relevant.

- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality not to work as expected)
- [ ] This change requires a documentation update

## How Has This Been Tested?

Tested this locally by visually verifying the changes. Also ran the
newly added tests for component level changes.

Here is the screenshot of the changes:

Added the sort option to sub sections in the conversation sidebar:
<img width="282" height="848" alt="Screenshot 2026-06-02 at 1 58 12 AM"
src="https://github.com/user-attachments/assets/4a7c6061-86e3-438a-92ae-ee643a0128b6"
/>

The sort options looks like this:
<img width="783" height="698" alt="Screenshot 2026-06-02 at 1 58 49 AM"
src="https://github.com/user-attachments/assets/a15bb0a7-b810-4423-a88c-fbd84d0476c0"
/>


## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin <iamsivin@gmail.com>
2026-06-15 21:34:19 +05:30

206 lines
5.4 KiB
JavaScript

import {
DEFAULT_SIDEBAR_SORT_PREFERENCES,
SIDEBAR_SORT_KEYS,
SIDEBAR_SORT_SECTIONS,
getSidebarSortOptions,
normalizeSidebarSortPreferences,
resolveSidebarSort,
sortSidebarItems,
} from '../sidebarSort';
const items = [
{
id: 1,
name: 'Billing',
created_at: '2024-01-01T00:00:00.000Z',
},
{
id: 3,
name: 'Accounts',
created_at: '2024-03-01T00:00:00.000Z',
},
{
id: 2,
name: 'Support',
created_at: '2024-02-01T00:00:00.000Z',
},
];
describe('#sortSidebarItems', () => {
it('sorts by created date descending', () => {
const sortedItems = sortSidebarItems(items, {
sortBy: SIDEBAR_SORT_KEYS.CREATED_DESC,
labelKey: item => item.name,
});
expect(sortedItems.map(item => item.name)).toEqual([
'Accounts',
'Support',
'Billing',
]);
});
it('sorts by created date ascending', () => {
const sortedItems = sortSidebarItems(items, {
sortBy: SIDEBAR_SORT_KEYS.CREATED_ASC,
labelKey: item => item.name,
});
expect(sortedItems.map(item => item.name)).toEqual([
'Billing',
'Support',
'Accounts',
]);
});
it('falls back to id when created date is not present', () => {
const sortedItems = sortSidebarItems(
items.map(({ created_at: _createdAt, ...item }) => item),
{
sortBy: SIDEBAR_SORT_KEYS.CREATED_DESC,
labelKey: item => item.name,
}
);
expect(sortedItems.map(item => item.id)).toEqual([3, 2, 1]);
});
it('sorts alphabetically from A to Z', () => {
const sortedItems = sortSidebarItems(items, {
sortBy: SIDEBAR_SORT_KEYS.ALPHABETICAL_ASC,
labelKey: item => item.name,
});
expect(sortedItems.map(item => item.name)).toEqual([
'Accounts',
'Billing',
'Support',
]);
});
it('sorts alphabetically from Z to A', () => {
const sortedItems = sortSidebarItems(items, {
sortBy: SIDEBAR_SORT_KEYS.ALPHABETICAL_DESC,
labelKey: item => item.name,
});
expect(sortedItems.map(item => item.name)).toEqual([
'Support',
'Billing',
'Accounts',
]);
});
it('sorts by unread count descending and falls back to alphabetical order', () => {
const unreadCounts = {
1: 3,
2: 3,
3: 7,
};
const sortedItems = sortSidebarItems(items, {
sortBy: SIDEBAR_SORT_KEYS.UNREAD_COUNT_DESC,
labelKey: item => item.name,
unreadCountKey: item => unreadCounts[item.id],
});
expect(sortedItems.map(item => item.name)).toEqual([
'Accounts',
'Billing',
'Support',
]);
});
it('sorts by unread count ascending and falls back to alphabetical order', () => {
const unreadCounts = {
1: 3,
2: 3,
3: 7,
};
const sortedItems = sortSidebarItems(items, {
sortBy: SIDEBAR_SORT_KEYS.UNREAD_COUNT_ASC,
labelKey: item => item.name,
unreadCountKey: item => unreadCounts[item.id],
});
expect(sortedItems.map(item => item.name)).toEqual([
'Billing',
'Support',
'Accounts',
]);
});
});
describe('#normalizeSidebarSortPreferences', () => {
it('keeps valid preferences', () => {
const preferences = normalizeSidebarSortPreferences({
[SIDEBAR_SORT_SECTIONS.FOLDERS]: SIDEBAR_SORT_KEYS.ALPHABETICAL_DESC,
[SIDEBAR_SORT_SECTIONS.TEAMS]: SIDEBAR_SORT_KEYS.CREATED_ASC,
});
expect(preferences).toEqual({
...DEFAULT_SIDEBAR_SORT_PREFERENCES,
[SIDEBAR_SORT_SECTIONS.FOLDERS]: SIDEBAR_SORT_KEYS.ALPHABETICAL_DESC,
[SIDEBAR_SORT_SECTIONS.TEAMS]: SIDEBAR_SORT_KEYS.CREATED_ASC,
});
});
it('falls back to defaults for unsupported preferences', () => {
const preferences = normalizeSidebarSortPreferences({
[SIDEBAR_SORT_SECTIONS.FOLDERS]: SIDEBAR_SORT_KEYS.UNREAD_COUNT_DESC,
});
expect(preferences).toEqual(DEFAULT_SIDEBAR_SORT_PREFERENCES);
});
it('falls back to defaults when stored preferences are null', () => {
expect(normalizeSidebarSortPreferences(null)).toEqual(
DEFAULT_SIDEBAR_SORT_PREFERENCES
);
});
});
describe('#getSidebarSortOptions', () => {
it('keeps unread count options when unread counts are enabled', () => {
const options = getSidebarSortOptions(SIDEBAR_SORT_SECTIONS.TEAMS, {
hasUnreadCounts: true,
});
expect(options).toContain(SIDEBAR_SORT_KEYS.UNREAD_COUNT_DESC);
expect(options).toContain(SIDEBAR_SORT_KEYS.UNREAD_COUNT_ASC);
});
it('removes unread count options when unread counts are disabled', () => {
const options = getSidebarSortOptions(SIDEBAR_SORT_SECTIONS.TEAMS, {
hasUnreadCounts: false,
});
expect(options).not.toContain(SIDEBAR_SORT_KEYS.UNREAD_COUNT_DESC);
expect(options).not.toContain(SIDEBAR_SORT_KEYS.UNREAD_COUNT_ASC);
expect(options).toContain(SIDEBAR_SORT_KEYS.ALPHABETICAL_ASC);
});
});
describe('#resolveSidebarSort', () => {
it('keeps unread count sort when unread counts are enabled', () => {
const sortBy = resolveSidebarSort(
SIDEBAR_SORT_SECTIONS.TEAMS,
SIDEBAR_SORT_KEYS.UNREAD_COUNT_DESC,
{ hasUnreadCounts: true }
);
expect(sortBy).toBe(SIDEBAR_SORT_KEYS.UNREAD_COUNT_DESC);
});
it('falls back to alphabetical sort when unread counts are disabled', () => {
const sortBy = resolveSidebarSort(
SIDEBAR_SORT_SECTIONS.TEAMS,
SIDEBAR_SORT_KEYS.UNREAD_COUNT_DESC,
{ hasUnreadCounts: false }
);
expect(sortBy).toBe(SIDEBAR_SORT_KEYS.ALPHABETICAL_ASC);
});
});