## Description Adds the account-level `unread_count_for_filters` feature flag as the dark-launch gate for filtered sidebar unread counts. This reuses the deprecated `quoted_email_reply` flag slot, resets the reused bit for existing accounts, and removes stale defaults so new accounts do not reference the old flag. This also adds the feature where we are now calculating the unread counts for built in filters like mentions, participating and unattended along with unread count for saved filters/folders. Closes [CW-7262](https://linear.app/chatwoot/issue/CW-7262/unread-counts-for-filters-folders) ## Type of change - [ ] 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
235 lines
6.5 KiB
JavaScript
235 lines
6.5 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]: 'unsupported_sort',
|
|
});
|
|
|
|
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('keeps folder unread count options when filtered unread counts are enabled', () => {
|
|
const options = getSidebarSortOptions(SIDEBAR_SORT_SECTIONS.FOLDERS, {
|
|
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);
|
|
});
|
|
|
|
it('removes folder unread count options when filtered unread counts are disabled', () => {
|
|
const options = getSidebarSortOptions(SIDEBAR_SORT_SECTIONS.FOLDERS, {
|
|
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);
|
|
});
|
|
|
|
it('falls back to alphabetical sort for folders when filtered unread counts are disabled', () => {
|
|
const sortBy = resolveSidebarSort(
|
|
SIDEBAR_SORT_SECTIONS.FOLDERS,
|
|
SIDEBAR_SORT_KEYS.UNREAD_COUNT_DESC,
|
|
{ hasUnreadCounts: false }
|
|
);
|
|
|
|
expect(sortBy).toBe(SIDEBAR_SORT_KEYS.ALPHABETICAL_ASC);
|
|
});
|
|
});
|