Skip to content

Commit a4d6d83

Browse files
authored
feat: allow to search for channels only (#2625)
1 parent 6bd855b commit a4d6d83

File tree

2 files changed

+117
-41
lines changed

2 files changed

+117
-41
lines changed

Diff for: src/components/ChannelSearch/__tests__/ChannelSearch.test.js

+50
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,56 @@ describe('ChannelSearch', () => {
187187
jest.useRealTimers();
188188
});
189189

190+
it('search is performed on channels only', async () => {
191+
const limit = 8;
192+
const otherUsers = Array.from({ length: limit }, generateUser);
193+
jest.useFakeTimers('modern');
194+
const client = await getTestClientWithUser(user);
195+
jest.spyOn(client, 'queryUsers').mockResolvedValue({ users: [...otherUsers, user] });
196+
jest.spyOn(client, 'queryChannels').mockResolvedValue([channelResponseData]);
197+
198+
const { typeText } = await renderSearch({
199+
client,
200+
props: { searchForChannels: true, searchForUsers: false },
201+
});
202+
await act(() => {
203+
typeText(typedText);
204+
});
205+
206+
await act(() => {
207+
jest.advanceTimersByTime(1000);
208+
});
209+
210+
expect(client.queryUsers).not.toHaveBeenCalled();
211+
expect(client.queryChannels).toHaveBeenCalledTimes(1);
212+
jest.useRealTimers();
213+
});
214+
215+
it('search is not performed on channels neither users', async () => {
216+
const limit = 8;
217+
const otherUsers = Array.from({ length: limit }, generateUser);
218+
jest.useFakeTimers('modern');
219+
const client = await getTestClientWithUser(user);
220+
jest.spyOn(client, 'queryUsers').mockResolvedValue({ users: [...otherUsers, user] });
221+
jest.spyOn(client, 'queryChannels').mockResolvedValue([channelResponseData]);
222+
223+
const { typeText } = await renderSearch({
224+
client,
225+
props: { searchForChannels: false, searchForUsers: false },
226+
});
227+
await act(() => {
228+
typeText(typedText);
229+
});
230+
231+
await act(() => {
232+
jest.advanceTimersByTime(1000);
233+
});
234+
235+
expect(client.queryUsers).not.toHaveBeenCalled();
236+
expect(client.queryChannels).not.toHaveBeenCalled();
237+
jest.useRealTimers();
238+
});
239+
190240
it('does not perform search queries when the search is disabled', async () => {
191241
jest.useFakeTimers('modern');
192242
const client = await getTestClientWithUser(user);

Diff for: src/components/ChannelSearch/hooks/useChannelSearch.ts

+67-41
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ export type ChannelSearchParams<
7070
) => Promise<void> | void;
7171
/** The number of milliseconds to debounce the search query. The default interval is 200ms. */
7272
searchDebounceIntervalMs?: number;
73-
/** Boolean to search for channels as well as users in the server query, default is false and just searches for users */
73+
/** Boolean to search for channels in the server query, default is false and just searches for users */
7474
searchForChannels?: boolean;
75+
/** Boolean to search for users in the server query, default is true and just searches for users */
76+
searchForUsers?: boolean;
7577
/** Custom search function to override the default implementation */
7678
searchFunction?: (
7779
params: ChannelSearchFunctionParams<StreamChatGenerics>,
@@ -99,6 +101,7 @@ export const useChannelSearch = <
99101
onSelectResult,
100102
searchDebounceIntervalMs = 300,
101103
searchForChannels = false,
104+
searchForUsers = true,
102105
searchFunction,
103106
searchQueryParams,
104107
setChannels,
@@ -110,10 +113,7 @@ export const useChannelSearch = <
110113
const [results, setResults] = useState<Array<ChannelOrUserResponse<StreamChatGenerics>>>([]);
111114
const [searching, setSearching] = useState(false);
112115

113-
const searchQueryPromiseInProgress = useRef<
114-
| Promise<UsersAPIResponse<StreamChatGenerics>>
115-
| Promise<[Channel<StreamChatGenerics>[], UsersAPIResponse<StreamChatGenerics>]>
116-
>(undefined);
116+
const searchQueryPromiseInProgress = useRef<boolean>(false);
117117
const shouldIgnoreQueryResults = useRef(false);
118118

119119
const inputRef = useRef<HTMLInputElement | null>(null);
@@ -124,9 +124,7 @@ export const useChannelSearch = <
124124
setResults([]);
125125
setSearching(false);
126126

127-
if (searchQueryPromiseInProgress.current) {
128-
shouldIgnoreQueryResults.current = true;
129-
}
127+
shouldIgnoreQueryResults.current = searchQueryPromiseInProgress.current;
130128
}, []);
131129

132130
const activateSearch = useCallback(() => {
@@ -210,41 +208,59 @@ export const useChannelSearch = <
210208

211209
const getChannels = useCallback(
212210
async (text: string) => {
211+
if (!searchForChannels && !searchForUsers) return;
213212
let results: ChannelOrUserResponse<StreamChatGenerics>[] = [];
213+
const promises: Array<
214+
Promise<Channel<StreamChatGenerics>[]> | Promise<UsersAPIResponse<StreamChatGenerics>>
215+
> = [];
214216
try {
215-
const userQueryPromise = client.queryUsers(
216-
// @ts-expect-error
217-
{
218-
$or: [{ id: { $autocomplete: text } }, { name: { $autocomplete: text } }],
219-
...searchQueryParams?.userFilters?.filters,
220-
},
221-
{ id: 1, ...searchQueryParams?.userFilters?.sort },
222-
{ limit: 8, ...searchQueryParams?.userFilters?.options },
223-
);
224-
225-
if (!searchForChannels) {
226-
searchQueryPromiseInProgress.current = userQueryPromise;
227-
const { users } = await searchQueryPromiseInProgress.current;
228-
results = users.filter((u) => u.id !== client.user?.id);
229-
} else {
230-
const channelQueryPromise = client.queryChannels(
231-
// @ts-expect-error
232-
{
233-
name: { $autocomplete: text },
234-
...searchQueryParams?.channelFilters?.filters,
235-
},
236-
searchQueryParams?.channelFilters?.sort || {},
237-
{ limit: 5, ...searchQueryParams?.channelFilters?.options },
217+
if (searchForChannels) {
218+
promises.push(
219+
client.queryChannels(
220+
// @ts-expect-error
221+
{
222+
members: { $in: [client.userID] },
223+
name: { $autocomplete: text },
224+
...searchQueryParams?.channelFilters?.filters,
225+
},
226+
searchQueryParams?.channelFilters?.sort || {},
227+
{ limit: 5, ...searchQueryParams?.channelFilters?.options },
228+
),
238229
);
230+
}
239231

240-
searchQueryPromiseInProgress.current = Promise.all([
241-
channelQueryPromise,
242-
userQueryPromise,
243-
]);
244-
245-
const [channels, { users }] = await searchQueryPromiseInProgress.current;
232+
if (searchForUsers) {
233+
promises.push(
234+
client.queryUsers(
235+
// @ts-expect-error
236+
{
237+
$or: [{ id: { $autocomplete: text } }, { name: { $autocomplete: text } }],
238+
...searchQueryParams?.userFilters?.filters,
239+
},
240+
{ id: 1, ...searchQueryParams?.userFilters?.sort },
241+
{ limit: 8, ...searchQueryParams?.userFilters?.options },
242+
),
243+
);
244+
}
246245

247-
results = [...channels, ...users.filter((u) => u.id !== client.user?.id)];
246+
if (promises.length) {
247+
searchQueryPromiseInProgress.current = true;
248+
249+
const resolved = await Promise.all(promises);
250+
251+
if (searchForChannels && searchForUsers) {
252+
const [channels, { users }] = resolved as [
253+
Channel<StreamChatGenerics>[],
254+
UsersAPIResponse<StreamChatGenerics>,
255+
];
256+
results = [...channels, ...users.filter((u) => u.id !== client.user?.id)];
257+
} else if (searchForChannels) {
258+
const [channels] = resolved as [Channel<StreamChatGenerics>[]];
259+
results = [...channels];
260+
} else if (searchForUsers) {
261+
const [{ users }] = resolved as [UsersAPIResponse<StreamChatGenerics>];
262+
results = [...users.filter((u) => u.id !== client.user?.id)];
263+
}
248264
}
249265
} catch (error) {
250266
console.error(error);
@@ -257,9 +273,9 @@ export const useChannelSearch = <
257273
shouldIgnoreQueryResults.current = false;
258274
}
259275

260-
searchQueryPromiseInProgress.current = undefined;
276+
searchQueryPromiseInProgress.current = false;
261277
},
262-
[client, searchForChannels, searchQueryParams],
278+
[client, searchForChannels, searchForUsers, searchQueryParams],
263279
);
264280

265281
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -282,6 +298,8 @@ export const useChannelSearch = <
282298
},
283299
event,
284300
);
301+
} else if (!searchForChannels && !searchForUsers) {
302+
return;
285303
} else if (event.target.value) {
286304
setSearching(true);
287305
setQuery(event.target.value);
@@ -292,7 +310,15 @@ export const useChannelSearch = <
292310
}
293311
onSearchCallback?.(event);
294312
},
295-
[clearState, disabled, scheduleGetChannels, onSearchCallback, searchFunction],
313+
[
314+
clearState,
315+
disabled,
316+
scheduleGetChannels,
317+
onSearchCallback,
318+
searchForChannels,
319+
searchForUsers,
320+
searchFunction,
321+
],
296322
);
297323

298324
return {

0 commit comments

Comments
 (0)