Sort contacts and conversations alphabetically when composing message

This commit is contained in:
trevor-signal 2023-06-21 12:33:59 -04:00 committed by GitHub
parent 65b6d9c2bc
commit 83c1acedd8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 87 additions and 12 deletions

View file

@ -30,7 +30,10 @@ import { deconstructLookup } from '../../util/deconstructLookup';
import type { PropsDataType as TimelinePropsType } from '../../components/conversation/Timeline'; import type { PropsDataType as TimelinePropsType } from '../../components/conversation/Timeline';
import { assertDev } from '../../util/assert'; import { assertDev } from '../../util/assert';
import { isConversationUnregistered } from '../../util/isConversationUnregistered'; import { isConversationUnregistered } from '../../util/isConversationUnregistered';
import { filterAndSortConversationsByRecent } from '../../util/filterAndSortConversations'; import {
filterAndSortConversationsAlphabetically,
filterAndSortConversationsByRecent,
} from '../../util/filterAndSortConversations';
import type { ContactNameColorType } from '../../types/Colors'; import type { ContactNameColorType } from '../../types/Colors';
import { ContactNameColors } from '../../types/Colors'; import { ContactNameColors } from '../../types/Colors';
import type { AvatarDataType } from '../../types/Avatar'; import type { AvatarDataType } from '../../types/Avatar';
@ -648,7 +651,11 @@ export const getFilteredComposeContacts = createSelector(
contacts: ReadonlyArray<ConversationType>, contacts: ReadonlyArray<ConversationType>,
regionCode: string | undefined regionCode: string | undefined
): Array<ConversationType> => { ): Array<ConversationType> => {
return filterAndSortConversationsByRecent(contacts, searchTerm, regionCode); return filterAndSortConversationsAlphabetically(
contacts,
searchTerm,
regionCode
);
} }
); );
@ -667,7 +674,7 @@ export const getFilteredComposeGroups = createSelector(
memberships: ReadonlyArray<unknown>; memberships: ReadonlyArray<unknown>;
} }
> => { > => {
return filterAndSortConversationsByRecent( return filterAndSortConversationsAlphabetically(
groups, groups,
searchTerm, searchTerm,
regionCode regionCode

View file

@ -923,10 +923,10 @@ describe('both/state/selectors/conversations-extra', () => {
const ids = result.map(contact => contact.id); const ids = result.map(contact => contact.id);
assert.deepEqual(ids, [ assert.deepEqual(ids, [
'our-conversation-id',
'convo-1', 'convo-1',
'convo-5', 'convo-5',
'convo-6', 'convo-6',
'our-conversation-id',
]); ]);
}); });

View file

@ -4,16 +4,19 @@
import { assert } from 'chai'; import { assert } from 'chai';
import { getDefaultConversation } from '../helpers/getDefaultConversation'; import { getDefaultConversation } from '../helpers/getDefaultConversation';
import { filterAndSortConversationsByRecent } from '../../util/filterAndSortConversations'; import {
filterAndSortConversationsAlphabetically,
filterAndSortConversationsByRecent,
} from '../../util/filterAndSortConversations';
describe('filterAndSortConversationsByRecent', () => { describe('filterAndSortConversations', () => {
const conversations = [ const conversations = [
getDefaultConversation({ getDefaultConversation({
title: '+16505551234', title: '+16505551234',
activeAt: 1, activeAt: 1,
}), }),
getDefaultConversation({ getDefaultConversation({
title: 'Abraham Lincoln', title: 'The Abraham Lincoln Club',
activeAt: 4, activeAt: 4,
}), }),
getDefaultConversation({ getDefaultConversation({
@ -33,22 +36,50 @@ describe('filterAndSortConversationsByRecent', () => {
}), }),
]; ];
it('sorts by recency when no search term is provided', () => { it('filterAndSortConversationsByRecent sorts by recency when no search term is provided', () => {
const titles = filterAndSortConversationsByRecent( const titles = filterAndSortConversationsByRecent(
conversations, conversations,
'', '',
'US' 'US'
).map(contact => contact.title); ).map(contact => contact.title);
assert.sameMembers(titles, [ assert.sameOrderedMembers(titles, [
'+16505551234', 'The Abraham Lincoln Club',
'George Washington',
'Boxing Club', 'Boxing Club',
'Abraham Lincoln', 'George Washington',
'+16505551234',
'Not recent', 'Not recent',
'A long long long title ending with burrito', 'A long long long title ending with burrito',
]); ]);
}); });
it('filterAndSortConversationsAlphabetically sorts by title when no search term is provided', () => {
const titles = filterAndSortConversationsAlphabetically(
conversations,
'',
'US'
).map(contact => contact.title);
assert.sameOrderedMembers(titles, [
'A long long long title ending with burrito',
'Boxing Club',
'George Washington',
'Not recent',
'The Abraham Lincoln Club',
'+16505551234',
]);
});
it('filterAndSortConversationsAlphabetically sorts by title when a search term is provided', () => {
const titles = filterAndSortConversationsAlphabetically(
conversations,
'club',
'US'
).map(contact => contact.title);
assert.sameOrderedMembers(titles, [
'Boxing Club',
'The Abraham Lincoln Club',
]);
});
it('finds a conversation when the search term is at the end of a long title', () => { it('finds a conversation when the search term is at the end of a long title', () => {
const titles = filterAndSortConversationsByRecent( const titles = filterAndSortConversationsByRecent(
conversations, conversations,

View file

@ -163,3 +163,40 @@ export function filterAndSortConversationsByRecent(
return a.activeAt && !b.activeAt ? -1 : 1; return a.activeAt && !b.activeAt ? -1 : 1;
}); });
} }
function startsWithLetter(title: string) {
// Uses \p, the unicode character class escape, to check if a the first character is a
// letter
return /^\p{Letter}/u.test(title);
}
function sortAlphabetically(a: ConversationType, b: ConversationType) {
// Sort alphabetically with conversations starting with a letter first (and phone
// numbers last)
const aStartsWithLetter = startsWithLetter(a.title);
const bStartsWithLetter = startsWithLetter(b.title);
if (aStartsWithLetter && !bStartsWithLetter) {
return -1;
}
if (!aStartsWithLetter && bStartsWithLetter) {
return 1;
}
return a.title.localeCompare(b.title);
}
export function filterAndSortConversationsAlphabetically(
conversations: ReadonlyArray<ConversationType>,
searchTerm: string,
regionCode: string | undefined
): Array<ConversationType> {
if (searchTerm.length) {
const withoutUnknown = conversations.filter(item => item.titleNoDefault);
return searchConversations(withoutUnknown, searchTerm, regionCode)
.slice()
.map(result => result.item)
.sort(sortAlphabetically);
}
return conversations.concat().sort(sortAlphabetically);
}