From 71cc46dfe40f99ec5e65b89a24d90c87b0a31e1a Mon Sep 17 00:00:00 2001 From: William Grant Date: Thu, 23 May 2024 16:57:51 +1000 Subject: [PATCH] feat: search results are now sorted alphabetically without case sensitivity also includes unknown contacts --- ts/node/sql.ts | 16 +++++--- ts/state/ducks/search.ts | 1 - ts/state/selectors/conversations.ts | 2 +- ts/state/selectors/search.ts | 62 +++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/ts/node/sql.ts b/ts/node/sql.ts index 0fa90aed7..fbc9d80b7 100644 --- a/ts/node/sql.ts +++ b/ts/node/sql.ts @@ -710,15 +710,19 @@ function searchConversations(query: string) { const rows = assertGlobalInstance() .prepare( `SELECT * FROM ${CONVERSATIONS_TABLE} WHERE - ( - displayNameInProfile LIKE $displayNameInProfile OR - nickname LIKE $nickname - ) AND active_at > 0 - ORDER BY active_at DESC - LIMIT $limit` + ( + displayNameInProfile LIKE $displayNameInProfile OR + nickname LIKE $nickname OR + (id LIKE $id AND + (displayNameInProfile IS NULL OR displayNameInProfile = '') AND (nickname IS NULL OR nickname = '') + ) + ) AND active_at > 0 + ORDER BY active_at DESC + LIMIT $limit` ) .all({ displayNameInProfile: `%${query}%`, + id: `%${query}%`, nickname: `%${query}%`, limit: 50, }); diff --git a/ts/state/ducks/search.ts b/ts/state/ducks/search.ts index f28109c35..359e9a9e4 100644 --- a/ts/state/ducks/search.ts +++ b/ts/state/ducks/search.ts @@ -83,7 +83,6 @@ async function doSearch(query: string): Promise { queryMessages(processedQuery), ]); const { conversations, contacts } = discussions; - window.log.debug(`WIP: [doSearch] conversations: ${conversations} contacts: ${contacts}`); const contactsAndConversations = _.uniq([...conversations, ...contacts]); const filteredMessages = _.compact(messages); diff --git a/ts/state/selectors/conversations.ts b/ts/state/selectors/conversations.ts index 86ca8d231..d56abfea8 100644 --- a/ts/state/selectors/conversations.ts +++ b/ts/state/selectors/conversations.ts @@ -485,7 +485,7 @@ export const getDirectContactsByName = createSelector( ); const extractedContactsWithDisplayName = sortBy( extractedContacts.filter(m => Boolean(m.displayName)), - 'displayName' + m => m.displayName?.toLowerCase() ); return [...extractedContactsWithDisplayName, ...extractedContactsNoDisplayName]; diff --git a/ts/state/selectors/search.ts b/ts/state/selectors/search.ts index 10f584ef7..b9cfa0b70 100644 --- a/ts/state/selectors/search.ts +++ b/ts/state/selectors/search.ts @@ -1,8 +1,9 @@ import { createSelector } from '@reduxjs/toolkit'; -import { compact, isEmpty } from 'lodash'; +import { compact, isEmpty, sortBy } from 'lodash'; import { StateType } from '../reducer'; +import { UserUtils } from '../../session/utils'; import { MessageResultProps } from '../../types/message'; import { ConversationLookupType } from '../ducks/conversations'; import { SearchStateType } from '../ducks/search'; @@ -67,18 +68,71 @@ export const getSearchResultsContactOnly = createSelector([getSearchResults], se * When type just has a conversationId field, we render a ConversationListItem. * When type is MessageResultProps we render a MessageSearchResult */ -export type SearchResultsMergedListItem = string | { contactConvoId: string } | MessageResultProps; +export type SearchResultsMergedListItem = + | string + | { contactConvoId: string; displayName?: string } + | MessageResultProps; export const getSearchResultsList = createSelector([getSearchResults], searchState => { const { contactsAndConversations, messages } = searchState; const builtList: Array = []; + if (contactsAndConversations.length) { - builtList.push(window.i18n('sessionConversations')); - builtList.push(...contactsAndConversations.map(m => ({ contactConvoId: m.id }))); + const us = UserUtils.getOurPubKeyStrFromCache(); + let usIndex: number = -1; + + for (let i = 0; i < contactsAndConversations.length; i++) { + if (contactsAndConversations[i].id === us) { + usIndex = i; + break; + } + } + + if (usIndex !== -1) { + contactsAndConversations.splice(usIndex, 1); + } + + const idsAndDisplayNames = contactsAndConversations.map(m => ({ + contactConvoId: m.id, + displayName: m.nickname || m.displayNameInProfile, + })); + + const idsWithDisplayNames = sortBy( + idsAndDisplayNames.filter(m => Boolean(m.displayName)), + m => m.displayName?.toLowerCase() + ); + if (idsWithDisplayNames.length) { + // add a break wherever needed + let currentChar = ''; + + idsWithDisplayNames.forEach(m => { + if (m.displayName && m.displayName[0].toLowerCase() !== currentChar) { + currentChar = m.displayName[0].toLowerCase(); + builtList.push(currentChar.toUpperCase()); + } + builtList.push(m); + }); + + if (usIndex !== -1) { + builtList.unshift({ contactConvoId: us, displayName: window.i18n('noteToSelf') }); + } + } + + const idsWithNoDisplayNames = sortBy( + idsAndDisplayNames.filter(m => !m.displayName), + 'id' + ); + if (idsWithNoDisplayNames.length) { + builtList.push(window.i18n('unknown'), ...idsWithNoDisplayNames); + } + + builtList.unshift(window.i18n('sessionConversations')); } + if (messages.length) { builtList.push(window.i18n('messages')); builtList.push(...messages); } + return builtList; });