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.
		
		
		
		
		
			
		
			
				
	
	
		
			125 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			125 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;
 | 
						|
});
 |