Skip to content

Commit 422600f

Browse files
committed
Merge branch 'master' into feat/search-channel-by-message-text
# Conflicts: # package.json # yarn.lock
2 parents ed3f7da + 1c445de commit 422600f

File tree

13 files changed

+203
-56
lines changed

13 files changed

+203
-56
lines changed

CHANGELOG.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,29 @@
1+
## [12.11.1](https://github.com/GetStream/stream-chat-react/compare/v12.11.0...v12.11.1) (2025-02-11)
2+
3+
4+
### Bug Fixes
5+
6+
* **handleMemberUpdated:** consider both pinned and archived channels ([#2638](https://github.com/GetStream/stream-chat-react/issues/2638)) ([ae66de8](https://github.com/GetStream/stream-chat-react/commit/ae66de8d3c5ed78fbe5aa5388ebf8a1b8e90a9e9))
7+
8+
## [12.11.0](https://github.com/GetStream/stream-chat-react/compare/v12.10.0...v12.11.0) (2025-02-07)
9+
10+
11+
### Bug Fixes
12+
13+
* change useStateStore to use useSyncExternalStore ([#2573](https://github.com/GetStream/stream-chat-react/issues/2573)) ([6f2de4e](https://github.com/GetStream/stream-chat-react/commit/6f2de4ebd8e8a5b9668b44bb0204ea695c48ff01))
14+
* make `channel.visible` respect archived and pinned channels ([#2633](https://github.com/GetStream/stream-chat-react/issues/2633)) ([2d2e2e5](https://github.com/GetStream/stream-chat-react/commit/2d2e2e56e6aff92a00d3dd2e6da8c5f7b64698e1))
15+
16+
17+
### Features
18+
19+
* allow custom ReactionsListModal ([#2632](https://github.com/GetStream/stream-chat-react/issues/2632)) ([a428dc9](https://github.com/GetStream/stream-chat-react/commit/a428dc938388947b1f7e51fde3dd579eba76ea2f))
20+
* allow to search for channels only ([#2625](https://github.com/GetStream/stream-chat-react/issues/2625)) ([a4d6d83](https://github.com/GetStream/stream-chat-react/commit/a4d6d83cf7c63f3284f0e0c3d0689f64ae725323))
21+
22+
23+
### Chores
24+
25+
* **deps:** upgrade @stream-io/stream-chat-css to version 5.7.0 ([#2636](https://github.com/GetStream/stream-chat-react/issues/2636)) ([8b7cfba](https://github.com/GetStream/stream-chat-react/commit/8b7cfba7140588f5fd1d727b48b7e6c7da5d99fe))
26+
127
## [12.10.0](https://github.com/GetStream/stream-chat-react/compare/v12.9.0...v12.10.0) (2025-01-28)
228

329

src/components/Channel/Channel.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ type ChannelPropsForwardedToComponentContext<
150150
| 'reactionOptions'
151151
| 'ReactionSelector'
152152
| 'ReactionsList'
153+
| 'ReactionsListModal'
153154
| 'SendButton'
154155
| 'StartRecordingAudioButton'
155156
| 'ThreadHead'
@@ -1358,6 +1359,7 @@ const ChannelInner = <
13581359
reactionOptions: props.reactionOptions,
13591360
ReactionSelector: props.ReactionSelector,
13601361
ReactionsList: props.ReactionsList,
1362+
ReactionsListModal: props.ReactionsListModal,
13611363
SendButton: props.SendButton,
13621364
StartRecordingAudioButton: props.StartRecordingAudioButton,
13631365
StopAIGenerationButton: props.StopAIGenerationButton,
@@ -1417,6 +1419,7 @@ const ChannelInner = <
14171419
props.QuotedPoll,
14181420
props.ReactionSelector,
14191421
props.ReactionsList,
1422+
props.ReactionsListModal,
14201423
props.SendButton,
14211424
props.StartRecordingAudioButton,
14221425
props.ThreadHead,

src/components/ChannelList/hooks/useChannelListShape.ts

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { Dispatch, SetStateAction, useCallback, useEffect, useMemo, useRef } from 'react';
44
import { Channel, Event, ExtendableGenerics } from 'stream-chat';
5-
import uniqBy from 'lodash.uniqby';
65

76
import {
87
extractSortValue,
@@ -68,7 +67,9 @@ type HandleChannelHiddenParameters<SCG extends ExtendableGenerics> = BaseParamet
6867
RepeatedParameters<SCG>;
6968

7069
type HandleChannelVisibleParameters<SCG extends ExtendableGenerics> =
71-
BaseParameters<SCG> & RepeatedParameters<SCG>;
70+
BaseParameters<SCG> &
71+
RepeatedParameters<SCG> &
72+
Required<Pick<ChannelListProps<SCG>, 'sort' | 'filters'>>;
7273

7374
type HandleChannelTruncatedParameters<SCG extends ExtendableGenerics> =
7475
BaseParameters<SCG> & RepeatedParameters<SCG>;
@@ -194,7 +195,6 @@ export const useChannelListShapeDefaults = <SCG extends ExtendableGenerics>() =>
194195
moveChannelUpwards({
195196
channels,
196197
channelToMove: channel,
197-
channelToMoveIndexWithinChannels: -1,
198198
sort,
199199
}),
200200
);
@@ -239,7 +239,6 @@ export const useChannelListShapeDefaults = <SCG extends ExtendableGenerics>() =>
239239
moveChannelUpwards({
240240
channels,
241241
channelToMove: channel,
242-
channelToMoveIndexWithinChannels: -1,
243242
sort,
244243
}),
245244
);
@@ -286,6 +285,11 @@ export const useChannelListShapeDefaults = <SCG extends ExtendableGenerics>() =>
286285
const considerPinnedChannels = shouldConsiderPinnedChannels(sort);
287286
const considerArchivedChannels = shouldConsiderArchivedChannels(filters);
288287

288+
// `pinned_at` nor `archived` properties are set or channel list order is locked, return early
289+
if ((!considerPinnedChannels && !considerArchivedChannels) || lockChannelOrder) {
290+
return;
291+
}
292+
289293
const pinnedAtSort = extractSortValue({ atIndex: 0, sort, targetKey: 'pinned_at' });
290294

291295
setChannels((currentChannels) => {
@@ -297,9 +301,6 @@ export const useChannelListShapeDefaults = <SCG extends ExtendableGenerics>() =>
297301
const isTargetChannelArchived = isChannelArchived(targetChannel);
298302
const isTargetChannelPinned = isChannelPinned(targetChannel);
299303

300-
// handle pinning
301-
if (!considerPinnedChannels || lockChannelOrder) return currentChannels;
302-
303304
const newChannels = [...currentChannels];
304305

305306
if (targetChannelExistsWithinList) {
@@ -353,20 +354,36 @@ export const useChannelListShapeDefaults = <SCG extends ExtendableGenerics>() =>
353354
async ({
354355
customHandler,
355356
event,
357+
filters,
356358
setChannels,
359+
sort,
357360
}: HandleChannelVisibleParameters<SCG>) => {
358361
if (typeof customHandler === 'function') {
359362
return customHandler(setChannels, event);
360363
}
361364

362-
if (event.type && event.channel_type && event.channel_id) {
363-
const channel = await getChannel({
364-
client,
365-
id: event.channel_id,
366-
type: event.channel_type,
367-
});
368-
setChannels((channels) => uniqBy([channel, ...channels], 'cid'));
365+
if (!event.channel) {
366+
return;
367+
}
368+
369+
const channel = await getChannel({
370+
client,
371+
id: event.channel.id,
372+
type: event.channel.type,
373+
});
374+
375+
const considerArchivedChannels = shouldConsiderArchivedChannels(filters);
376+
if (isChannelArchived(channel) && considerArchivedChannels && !filters.archived) {
377+
return;
369378
}
379+
380+
setChannels((channels) =>
381+
moveChannelUpwards({
382+
channels,
383+
channelToMove: channel,
384+
sort,
385+
}),
386+
);
370387
},
371388
[client],
372389
);
@@ -586,7 +603,9 @@ export const usePrepareShapeHandlers = <SCG extends ExtendableGenerics>({
586603
defaults.handleChannelVisible({
587604
customHandler: onChannelVisible,
588605
event,
606+
filters,
589607
setChannels,
608+
sort,
590609
});
591610
break;
592611
case 'channel.truncated':

src/components/MediaRecorder/classes/MediaRecorderController.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,18 @@ import {
1717
} from '../../ReactFileUtilities';
1818
import { TranslationContextValue } from '../../../context';
1919
import { defaultTranslatorFunction } from '../../../i18n';
20-
import { isSafari } from '../../../utils/browsers';
2120
import { mergeDeepUndefined } from '../../../utils/mergeDeep';
2221

2322
import type { LocalVoiceRecordingAttachment } from '../../MessageInput';
2423
import type { DefaultStreamChatGenerics } from '../../../types';
2524

26-
const RECORDED_MIME_TYPE_BY_BROWSER = {
25+
export const RECORDED_MIME_TYPE_BY_BROWSER = {
2726
audio: {
2827
others: 'audio/webm',
2928
safari: 'audio/mp4;codecs=mp4a.40.2',
3029
},
3130
} as const;
3231

33-
export const DEFAULT_MEDIA_RECORDER_CONFIG: MediaRecorderConfig = {
34-
mimeType: isSafari()
35-
? RECORDED_MIME_TYPE_BY_BROWSER.audio.safari
36-
: RECORDED_MIME_TYPE_BY_BROWSER.audio.others,
37-
} as const;
38-
3932
export const DEFAULT_AUDIO_TRANSCODER_CONFIG: TranscoderConfig = {
4033
sampleRate: 16000,
4134
} as const;
@@ -120,7 +113,11 @@ export class MediaRecorderController<
120113

121114
this.mediaRecorderConfig = mergeDeepUndefined(
122115
{ ...config?.mediaRecorderConfig },
123-
DEFAULT_MEDIA_RECORDER_CONFIG,
116+
{
117+
mimeType: MediaRecorder.isTypeSupported('audio/webm')
118+
? RECORDED_MIME_TYPE_BY_BROWSER.audio.others
119+
: RECORDED_MIME_TYPE_BY_BROWSER.audio.safari,
120+
},
124121
);
125122

126123
this.transcoderConfig = mergeDeepUndefined(

src/components/MediaRecorder/classes/__tests__/MediaRecorderController.test.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import * as transcoder from '../../transcode';
33
import * as wavTranscoder from '../../transcode/wav';
44
import {
55
DEFAULT_AUDIO_TRANSCODER_CONFIG,
6-
DEFAULT_MEDIA_RECORDER_CONFIG,
76
MediaRecorderController,
87
MediaRecordingState,
8+
RECORDED_MIME_TYPE_BY_BROWSER,
99
RecordingAttachmentType,
1010
} from '../MediaRecorderController';
1111
import {
@@ -92,10 +92,27 @@ describe('MediaRecorderController', () => {
9292
});
9393
afterEach(jest.clearAllMocks);
9494

95-
it('provides defaults on initiation', () => {
95+
it('provides defaults on initiation (non-Safari)', () => {
9696
const controller = new MediaRecorderController();
9797
expect(controller.mediaRecorderConfig).toStrictEqual(
98-
expect.objectContaining(DEFAULT_MEDIA_RECORDER_CONFIG),
98+
expect.objectContaining({ mimeType: RECORDED_MIME_TYPE_BY_BROWSER.audio.others }),
99+
);
100+
expect(controller.transcoderConfig).toStrictEqual(
101+
expect.objectContaining(DEFAULT_AUDIO_TRANSCODER_CONFIG),
102+
);
103+
expect(controller.amplitudeRecorderConfig).toStrictEqual(
104+
expect.objectContaining(DEFAULT_AMPLITUDE_RECORDER_CONFIG),
105+
);
106+
expect(controller.t).toStrictEqual(defaultTranslatorFunction);
107+
expect(controller.mediaType).toStrictEqual('audio');
108+
expect(controller.customGenerateRecordingTitle).toBeUndefined();
109+
});
110+
111+
it('provides defaults on initiation (Safari)', () => {
112+
MediaRecorder.isTypeSupported.mockReturnValueOnce(false);
113+
const controller = new MediaRecorderController();
114+
expect(controller.mediaRecorderConfig).toStrictEqual(
115+
expect.objectContaining({ mimeType: RECORDED_MIME_TYPE_BY_BROWSER.audio.safari }),
99116
);
100117
expect(controller.transcoderConfig).toStrictEqual(
101118
expect.objectContaining(DEFAULT_AUDIO_TRANSCODER_CONFIG),
@@ -151,7 +168,7 @@ describe('MediaRecorderController', () => {
151168
const controller = new MediaRecorderController({ generateRecordingTitle });
152169
expect(controller.customGenerateRecordingTitle).toStrictEqual(generateRecordingTitle);
153170
expect(controller.mediaRecorderConfig).toStrictEqual(
154-
expect.objectContaining(DEFAULT_MEDIA_RECORDER_CONFIG),
171+
expect.objectContaining({ mimeType: RECORDED_MIME_TYPE_BY_BROWSER.audio.others }),
155172
);
156173
expect(controller.transcoderConfig).toStrictEqual(
157174
expect.objectContaining(DEFAULT_AUDIO_TRANSCODER_CONFIG),

src/components/MediaRecorder/hooks/__tests__/useMediaRecorder.test.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { TranslationProvider } from '../../../../context';
22
import { renderHook } from '@testing-library/react';
33
import React from 'react';
44
import { useMediaRecorder } from '../useMediaRecorder';
5-
import { EventEmitterMock } from '../../../../mock-builders/browser';
5+
import { EventEmitterMock, MediaRecorderMock } from '../../../../mock-builders/browser';
66
import { act } from '@testing-library/react';
77
import { DEFAULT_AMPLITUDE_RECORDER_CONFIG } from '../../classes/AmplitudeRecorder';
88
import { DEFAULT_AUDIO_TRANSCODER_CONFIG } from '../../classes';
99
import { generateVoiceRecordingAttachment } from '../../../../mock-builders';
1010

11+
window.MediaRecorder = MediaRecorderMock;
12+
1113
const handleSubmit = jest.fn();
1214
const uploadAttachment = jest.fn();
1315

@@ -27,8 +29,8 @@ const render = async (params = {}) => {
2729
<TranslationProvider value={translationContext}>{children}</TranslationProvider>
2830
);
2931
let result;
30-
await act(() => {
31-
result = renderHook(() => useMediaRecorder({ enabled: true, ...params }), {
32+
await act(async () => {
33+
result = await renderHook(() => useMediaRecorder({ enabled: true, ...params }), {
3234
wrapper,
3335
});
3436
});

src/components/Reactions/ReactionsList.tsx

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
import React, { useState } from 'react';
22
import clsx from 'clsx';
33

4-
import type { ReactionGroupResponse, ReactionResponse } from 'stream-chat';
5-
4+
import {
5+
ReactionsListModal as DefaultReactionsListModal,
6+
ReactionsListModalProps,
7+
} from './ReactionsListModal';
68
import { useProcessReactions } from './hooks/useProcessReactions';
9+
import {
10+
MessageContextValue,
11+
useComponentContext,
12+
useTranslationContext,
13+
} from '../../context';
14+
15+
import { MAX_MESSAGE_REACTIONS_TO_FETCH } from '../Message/hooks';
16+
17+
import type { ReactionGroupResponse, ReactionResponse, ReactionSort } from 'stream-chat';
718
import type { DefaultStreamChatGenerics } from '../../types/types';
819
import type { ReactionOptions } from './reactionOptions';
920
import type {
1021
ReactionDetailsComparator,
1122
ReactionsComparator,
1223
ReactionType,
1324
} from './types';
14-
import { ReactionsListModal } from './ReactionsListModal';
15-
import { MessageContextValue, useTranslationContext } from '../../context';
16-
import { MAX_MESSAGE_REACTIONS_TO_FETCH } from '../Message/hooks';
1725

1826
export type ReactionsListProps<
1927
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
@@ -44,7 +52,7 @@ export type ReactionsListProps<
4452
/** Comparator function to sort the list of reacted users
4553
* @deprecated use `reactionDetailsSort` instead
4654
*/
47-
sortReactionDetails?: ReactionDetailsComparator;
55+
sortReactionDetails?: ReactionDetailsComparator<StreamChatGenerics>;
4856
/** Comparator function to sort reactions, defaults to chronological order */
4957
sortReactions?: ReactionsComparator;
5058
};
@@ -67,6 +75,7 @@ const UnMemoizedReactionsList = <
6775
const [selectedReactionType, setSelectedReactionType] =
6876
useState<ReactionType<StreamChatGenerics> | null>(null);
6977
const { t } = useTranslationContext('ReactionsList');
78+
const { ReactionsListModal = DefaultReactionsListModal } = useComponentContext();
7079

7180
const handleReactionButtonClick = (reactionType: string) => {
7281
if (totalReactionCount > MAX_MESSAGE_REACTIONS_TO_FETCH) {
@@ -126,13 +135,25 @@ const UnMemoizedReactionsList = <
126135
</div>
127136
{selectedReactionType !== null && (
128137
<ReactionsListModal
129-
handleFetchReactions={handleFetchReactions}
138+
handleFetchReactions={
139+
handleFetchReactions as (
140+
reactionType?: string,
141+
sort?: ReactionSort<StreamChatGenerics>,
142+
) => Promise<Array<ReactionResponse<StreamChatGenerics>>>
143+
}
130144
onClose={() => setSelectedReactionType(null)}
131-
onSelectedReactionTypeChange={setSelectedReactionType}
145+
onSelectedReactionTypeChange={
146+
setSelectedReactionType as ReactionsListModalProps['onSelectedReactionTypeChange']
147+
}
132148
open={selectedReactionType !== null}
133149
reactions={existingReactions}
134150
selectedReactionType={selectedReactionType}
135-
sortReactionDetails={sortReactionDetails}
151+
sortReactionDetails={
152+
sortReactionDetails as (
153+
a: ReactionResponse<StreamChatGenerics>,
154+
b: ReactionResponse<StreamChatGenerics>,
155+
) => number
156+
}
136157
/>
137158
)}
138159
</>

src/components/Reactions/ReactionsListModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { MessageContextValue, useMessageContext } from '../../context';
1111
import { DefaultStreamChatGenerics } from '../../types/types';
1212
import { ReactionSort } from 'stream-chat';
1313

14-
type ReactionsListModalProps<
14+
export type ReactionsListModalProps<
1515
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics,
1616
> = ModalProps &
1717
Partial<

0 commit comments

Comments
 (0)