Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/containers/MessageBox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,8 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
};

getUsers = debounce(async (keyword: any) => {
let res = await search({ text: keyword, filterRooms: false, filterUsers: true });
const { rid } = this.props;
let res = await search({ text: keyword, filterRooms: false, filterUsers: true, rid });
res = [...this.getFixedMentions(keyword), ...res];
this.setState({ mentions: res, mentionLoading: false });
}, 300);
Expand Down
3 changes: 3 additions & 0 deletions app/lib/constants/defaultSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,5 +226,8 @@ export const defaultSettings = {
},
Accounts_AllowDeleteOwnAccount: {
type: 'valueAsBoolean'
},
Number_of_users_autocomplete_suggestions: {
type: 'valueAsNumber'
}
} as const;
53 changes: 47 additions & 6 deletions app/lib/methods/search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import { Q } from '@nozbe/watermelondb';

import { sanitizeLikeString } from '../database/utils';
import database from '../database/index';
import { store as reduxStore } from '../store/auxStore';
import { spotlight } from '../services/restApi';
import { ISearch, ISearchLocal, SubscriptionType, TSubscriptionModel } from '../../definitions';
import { isGroupChat } from './helpers';

let debounce: null | ((reason: string) => void) = null;

export const localSearch = async ({ text = '', filterUsers = true, filterRooms = true }): Promise<TSubscriptionModel[]> => {
export const localSearchSubscription = async ({
text = '',
filterUsers = true,
filterRooms = true
}): Promise<TSubscriptionModel[]> => {
const searchText = text.trim();
const db = database.active;
const likeString = sanitizeLikeString(searchText);
Expand All @@ -31,22 +36,58 @@ export const localSearch = async ({ text = '', filterUsers = true, filterRooms =
return search;
};

export const search = async ({ text = '', filterUsers = true, filterRooms = true }): Promise<(ISearch | ISearchLocal)[]> => {
export const localSearchUsersMessageByRid = async ({ text = '', rid = '' }) => {
const userId = reduxStore.getState().login.user.id;
const numberOfSuggestions = reduxStore.getState().settings.Number_of_users_autocomplete_suggestions as number;
const searchText = text.trim();
const db = database.active;
const likeString = sanitizeLikeString(searchText);
const messages = await db
.get('messages')
.query(
Q.and(Q.where('rid', rid), Q.where('u', Q.notLike(`%${userId}%`)), Q.where('t', null)),
Q.experimentalSortBy('ts', Q.desc),
Q.experimentalTake(50)
)
.fetch();

const regExp = new RegExp(`${likeString}`, 'i');
const users = messages.map(message => message.u);

const usersFromLocal = users
.filter((item1, index) => users.findIndex(item2 => item2._id === item1._id) === index) // Remove duplicated data from response
.filter(user => user?.name?.match(regExp) || user?.username?.match(regExp))
.slice(0, text ? 2 : numberOfSuggestions);

return usersFromLocal;
};

export const search = async ({
text = '',
filterUsers = true,
filterRooms = true,
rid = ''
}): Promise<(ISearch | ISearchLocal)[]> => {
const searchText = text.trim();

if (debounce) {
debounce('cancel');
}

const localSearchData = await localSearch({ text, filterUsers, filterRooms });
const usernames = localSearchData.map(sub => sub.name);
let localSearchData = [];
if (rid) {
localSearchData = await localSearchUsersMessageByRid({ text, rid });
} else {
localSearchData = await localSearchSubscription({ text, filterUsers, filterRooms });
}
const usernames = localSearchData.map(sub => sub.name as string);

const data = localSearchData as (ISearch | ISearchLocal)[];

try {
if (localSearchData.length < 7) {
if (searchText && localSearchData.length < 7) {
const { users, rooms } = (await Promise.race([
spotlight(searchText, usernames, { users: filterUsers, rooms: filterRooms }),
spotlight(searchText, usernames, { users: filterUsers, rooms: filterRooms }, rid),
new Promise((resolve, reject) => (debounce = reject))
])) as { users: ISearch[]; rooms: ISearch[] };

Expand Down
11 changes: 9 additions & 2 deletions app/lib/services/restApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,16 @@ export const forgotPassword = (email: string) =>
export const sendConfirmationEmail = (email: string): Promise<{ message: string; success: boolean }> =>
sdk.methodCallWrapper('sendConfirmationEmail', email);

export const spotlight = (search: string, usernames: string[], type: { users: boolean; rooms: boolean }): Promise<ISpotlight> =>
export const spotlight = (
search: string,
usernames: string[],
type: { users: boolean; rooms: boolean },
rid?: string
): Promise<ISpotlight> =>
// RC 0.51.0
sdk.methodCallWrapper('spotlight', search, usernames, type);
rid
? sdk.methodCallWrapper('spotlight', search, usernames, type, rid)
: sdk.methodCallWrapper('spotlight', search, usernames, type);

export const createDirectMessage = (username: string) =>
// RC 0.59.0
Expand Down
4 changes: 2 additions & 2 deletions app/views/CreateDiscussionView/SelectChannel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import I18n from '../../i18n';
import { getAvatarURL } from '../../lib/methods/helpers/getAvatarUrl';
import { ICreateDiscussionViewSelectChannel } from './interfaces';
import styles from './styles';
import { localSearch } from '../../lib/methods';
import { localSearchSubscription } from '../../lib/methods';
import { getRoomAvatar, getRoomTitle } from '../../lib/methods/helpers';
import { useTheme } from '../../theme';

Expand All @@ -25,7 +25,7 @@ const SelectChannel = ({

const getChannels = async (keyword = '') => {
try {
const res = (await localSearch({ text: keyword, filterUsers: false })) as ISearchLocal[];
const res = (await localSearchSubscription({ text: keyword, filterUsers: false })) as ISearchLocal[];
setChannels(res);
return res.map(channel => ({
value: channel,
Expand Down