[IMPROVE] Spotlight users order (#4527)
* [IMPROVE] Spotlight users order * minor tweak query * minor tweak removing query and using regex * minor tweak * minor tweak, make ts happy * fix the ts * fix lint and type TSearch
This commit is contained in:
parent
298b779a81
commit
4d62874a9f
|
@ -658,7 +658,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);
|
||||
|
|
|
@ -226,5 +226,8 @@ export const defaultSettings = {
|
|||
},
|
||||
Accounts_AllowDeleteOwnAccount: {
|
||||
type: 'valueAsBoolean'
|
||||
},
|
||||
Number_of_users_autocomplete_suggestions: {
|
||||
type: 'valueAsNumber'
|
||||
}
|
||||
} as const;
|
||||
|
|
|
@ -2,13 +2,16 @@ 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 } from '../../definitions';
|
||||
import { ISearch, ISearchLocal, IUserMessage, SubscriptionType } from '../../definitions';
|
||||
import { isGroupChat } from './helpers';
|
||||
|
||||
export type TSearch = ISearchLocal | IUserMessage | ISearch;
|
||||
|
||||
let debounce: null | ((reason: string) => void) = null;
|
||||
|
||||
export const localSearch = async ({ text = '', filterUsers = true, filterRooms = true }): Promise<ISearchLocal[]> => {
|
||||
export const localSearchSubscription = async ({ text = '', filterUsers = true, filterRooms = true }): Promise<ISearchLocal[]> => {
|
||||
const searchText = text.trim();
|
||||
const db = database.active;
|
||||
const likeString = sanitizeLikeString(searchText);
|
||||
|
@ -41,29 +44,60 @@ 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 = '' }): Promise<IUserMessage[]> => {
|
||||
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<TSearch[]> => {
|
||||
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)[];
|
||||
const data: TSearch[] = localSearchData;
|
||||
|
||||
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[] };
|
||||
|
||||
if (filterUsers) {
|
||||
users
|
||||
.filter((item1, index) => users.findIndex(item2 => item2._id === item1._id) === index) // Remove duplicated data from response
|
||||
.filter(user => !data.some(sub => user.username === sub.name)) // Make sure to remove users already on local database
|
||||
.filter(user => !data.some(sub => 'username' in sub && user.username === sub.username)) // Make sure to remove users already on local database
|
||||
.forEach(user => {
|
||||
data.push({
|
||||
...user,
|
||||
|
@ -77,7 +111,7 @@ export const search = async ({ text = '', filterUsers = true, filterRooms = true
|
|||
if (filterRooms) {
|
||||
rooms.forEach(room => {
|
||||
// Check if it exists on local database
|
||||
const index = data.findIndex(item => item.rid === room._id);
|
||||
const index = data.findIndex(item => 'rid' in item && item.rid === room._id);
|
||||
if (index === -1) {
|
||||
data.push({
|
||||
...room,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
@ -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,
|
||||
|
|
|
@ -13,7 +13,6 @@ import * as List from '../../containers/List';
|
|||
import { sendLoadingEvent } from '../../containers/Loading';
|
||||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import StatusBar from '../../containers/StatusBar';
|
||||
import { ISearch, ISearchLocal } from '../../definitions';
|
||||
import I18n from '../../i18n';
|
||||
import database from '../../lib/database';
|
||||
import UserItem from '../../containers/UserItem';
|
||||
|
@ -23,7 +22,7 @@ import { ChatsStackParamList } from '../../stacks/types';
|
|||
import { useTheme } from '../../theme';
|
||||
import { showErrorAlert } from '../../lib/methods/helpers/info';
|
||||
import log, { events, logEvent } from '../../lib/methods/helpers/log';
|
||||
import { search as searchMethod } from '../../lib/methods';
|
||||
import { search as searchMethod, TSearch } from '../../lib/methods';
|
||||
import { isGroupChat as isGroupChatMethod } from '../../lib/methods/helpers';
|
||||
import { useAppSelector } from '../../lib/hooks';
|
||||
import Header from './Header';
|
||||
|
@ -31,11 +30,9 @@ import Header from './Header';
|
|||
type TRoute = RouteProp<ChatsStackParamList, 'SelectedUsersView'>;
|
||||
type TNavigation = StackNavigationProp<ChatsStackParamList, 'SelectedUsersView'>;
|
||||
|
||||
type TSearchItem = ISearch | ISearchLocal;
|
||||
|
||||
const SelectedUsersView = () => {
|
||||
const [chats, setChats] = useState<ISelectedUser[]>([]);
|
||||
const [search, setSearch] = useState<TSearchItem[]>([]);
|
||||
const [search, setSearch] = useState<TSearch[]>([]);
|
||||
|
||||
const { maxUsers, showButton, title, buttonText, nextAction } = useRoute<TRoute>().params;
|
||||
const navigation = useNavigation<TNavigation>();
|
||||
|
|
Loading…
Reference in New Issue