You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.9 KiB
TypeScript
124 lines
3.9 KiB
TypeScript
import { createSelector } from '@reduxjs/toolkit';
|
|
import { compact, isEmpty, remove, 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';
|
|
import { getConversationLookup } from './conversations';
|
|
import { ConversationTypeEnum } from '../../models/types';
|
|
|
|
export const getSearch = (state: StateType): SearchStateType => state.search;
|
|
|
|
export const getQuery = (state: StateType): string => getSearch(state).query;
|
|
|
|
export const isSearching = (state: StateType) => {
|
|
return !!getSearch(state)?.query?.trim();
|
|
};
|
|
|
|
const getSearchResults = createSelector(
|
|
[getSearch, getConversationLookup],
|
|
(searchState: SearchStateType, lookup: ConversationLookupType) => {
|
|
return {
|
|
contactsAndGroups: compact(
|
|
searchState.contactsAndGroups
|
|
.filter(id => {
|
|
const value = lookup[id];
|
|
|
|
// on some edges cases, we have an id but no corresponding convo because it matches a query but the conversation was removed.
|
|
// Don't return anything when activeAt is unset (i.e. no current conversations with this user)
|
|
if (!value || value.activeAt === undefined || value.activeAt === 0) {
|
|
// activeAt can be 0 when linking device
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
})
|
|
.map(id => lookup[id])
|
|
),
|
|
messages: compact(searchState.messages),
|
|
searchTerm: searchState.query,
|
|
};
|
|
}
|
|
);
|
|
|
|
export const getSearchTerm = createSelector([getSearchResults], searchResult => {
|
|
return searchResult.searchTerm;
|
|
});
|
|
|
|
export const getSearchResultsIdsOnly = createSelector([getSearchResults], searchState => {
|
|
return {
|
|
...searchState,
|
|
contactsAndGroupsIds: searchState.contactsAndGroups.map(m => m.id),
|
|
};
|
|
});
|
|
|
|
export const getHasSearchResults = createSelector([getSearchResults], searchState => {
|
|
return !isEmpty(searchState.contactsAndGroups) || !isEmpty(searchState.messages);
|
|
});
|
|
|
|
export const getSearchResultsContactOnly = createSelector([getSearchResults], searchState => {
|
|
return searchState.contactsAndGroups.filter(m => m.isPrivate).map(m => m.id);
|
|
});
|
|
|
|
/**
|
|
*
|
|
* When type is string, we render a sectionHeader.
|
|
* 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; displayName?: string }
|
|
| MessageResultProps;
|
|
|
|
export const getSearchResultsList = createSelector([getSearchResults], searchState => {
|
|
const { contactsAndGroups, messages } = searchState;
|
|
const builtList = [];
|
|
|
|
if (contactsAndGroups.length) {
|
|
const contactsWithNameAndType = contactsAndGroups.map(m => ({
|
|
contactConvoId: m.id,
|
|
displayName: m.nickname || m.displayNameInProfile,
|
|
type: m.type,
|
|
}));
|
|
|
|
const groupsAndCommunities = sortBy(
|
|
remove(contactsWithNameAndType, m => m.type === ConversationTypeEnum.GROUP),
|
|
m => m.displayName?.toLowerCase()
|
|
);
|
|
|
|
const contactsStartingWithANumber = sortBy(
|
|
remove(
|
|
contactsWithNameAndType,
|
|
m => !m.displayName || (m.displayName && m.displayName[0].match(/^[0-9]+$/))
|
|
),
|
|
m => m.displayName || m.contactConvoId
|
|
);
|
|
|
|
builtList.push(
|
|
...groupsAndCommunities,
|
|
...contactsWithNameAndType,
|
|
...contactsStartingWithANumber
|
|
);
|
|
|
|
const us = UserUtils.getOurPubKeyStrFromCache();
|
|
const hasUs = remove(builtList, m => m.contactConvoId === us);
|
|
|
|
if (hasUs.length) {
|
|
builtList.unshift({ contactConvoId: us, displayName: window.i18n('noteToSelf') });
|
|
}
|
|
|
|
builtList.unshift(window.i18n('sessionConversations'));
|
|
}
|
|
|
|
if (messages.length) {
|
|
builtList.push(window.i18n('messages'));
|
|
builtList.push(...messages);
|
|
}
|
|
|
|
return builtList;
|
|
});
|