Skip to content

Commit 210519c

Browse files
First pass reviewed
1 parent 05236db commit 210519c

49 files changed

Lines changed: 282 additions & 246 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/components/AIStateIndicator/hooks/useAIState.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useEffect, useState } from 'react';
2-
import type { AIState, Channel, Event } from 'stream-chat';
2+
import type { AIState, Channel } from 'stream-chat';
33

44
export const AIStates = {
55
Error: 'AI_STATE_ERROR',
@@ -23,7 +23,7 @@ export const useAIState = (channel?: Channel): { aiState: AIState } => {
2323
return;
2424
}
2525

26-
const indicatorChangedListener = channel.on('ai_indicator.update', (event: Event) => {
26+
const indicatorChangedListener = channel.on('ai_indicator.update', (event) => {
2727
const { cid } = event;
2828
const state = event.ai_state as AIState;
2929
if (channel.cid === cid) {

src/components/Attachment/Audio.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import type { Attachment } from 'stream-chat';
2+
import type { Attachment, VoiceRecordingAttachment } from 'stream-chat';
33

44
import {
55
FileSizeIndicator as DefaultFileSizeIndicator,
@@ -87,9 +87,8 @@ const audioPlayerStateSelector = (state: AudioPlayerState) => ({
8787
* Audio attachment with play/pause button and progress bar
8888
*/
8989
export const Audio = (props: AudioProps) => {
90-
const {
91-
attachment: { asset_url, duration, file_size, mime_type, title },
92-
} = props;
90+
const { asset_url, custom, title } = props.attachment as VoiceRecordingAttachment;
91+
const { duration, file_size, mime_type, waveform_data } = custom;
9392

9493
/**
9594
* Introducing message context. This could be breaking change, therefore the fallback to {} is provided.
@@ -111,7 +110,7 @@ export const Audio = (props: AudioProps) => {
111110
`${threadList ? (message.parent_id ?? message.id) : ''}${message.id}`,
112111
src: asset_url,
113112
title,
114-
waveformData: props.attachment.waveform_data,
113+
waveformData: waveform_data,
115114
});
116115

117116
return audioPlayer ? <AudioAttachmentUI audioPlayer={audioPlayer} /> : null;

src/components/Attachment/FileAttachment.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const FileAttachment = ({ attachment }: FileAttachmentProps) => {
1616
const { AttachmentFileIcon, FileSizeIndicator = DefaultFileSizeIndicator } =
1717
useComponentContext();
1818
const FileIconComponent = AttachmentFileIcon ?? FileIcon;
19+
const { file_size, mime_type } = attachment.custom;
1920
return (
2021
<div
2122
className='str-chat__message-attachment-file--item'
@@ -24,7 +25,7 @@ export const FileAttachment = ({ attachment }: FileAttachmentProps) => {
2425
<FileIconComponent
2526
className='str-chat__file-icon'
2627
fileName={attachment.title}
27-
mimeType={attachment.mime_type}
28+
mimeType={mime_type}
2829
/>
2930
<div className='str-chat__message-attachment-file--item__info'>
3031
<div className='str-chat__message-attachment-file--item__first-row'>
@@ -36,7 +37,7 @@ export const FileAttachment = ({ attachment }: FileAttachmentProps) => {
3637
</div>
3738
</div>
3839
<div className='str-chat__message-attachment-file--item__data'>
39-
<FileSizeIndicator fileSize={attachment.file_size} />
40+
<FileSizeIndicator fileSize={file_size} />
4041
</div>
4142
</div>
4243
<DownloadButton

src/components/Attachment/LinkPreview/CardAudio.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,17 @@ const AudioWidget = ({ mimeType, src }: { src: string; mimeType?: string }) => {
8585
);
8686
};
8787

88-
export const CardAudio = ({
89-
attachment: {
88+
export const CardAudio = ({ attachment }: AudioProps) => {
89+
const {
9090
asset_url,
9191
author_name,
92-
mime_type,
92+
custom,
9393
og_scrape_url,
9494
text,
9595
title,
9696
title_link,
97-
},
98-
}: AudioProps) => {
97+
} = attachment;
98+
const { mime_type } = custom;
9999
const url = title_link || og_scrape_url;
100100
const dataTestId = 'card-audio-widget';
101101
const rootClassName = 'str-chat__message-attachment-card-audio-widget';

src/components/Attachment/VoiceRecording.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import type { Attachment } from 'stream-chat';
2+
import type { Attachment, VoiceRecordingAttachment } from 'stream-chat';
33

44
import { FileSizeIndicator as DefaultFileSizeIndicator } from './components';
55
import { FileIcon } from '../FileIcon';
@@ -103,14 +103,13 @@ export const VoiceRecordingPlayer = ({
103103
playbackRates,
104104
}: VoiceRecordingPlayerProps) => {
105105
const { t } = useTranslationContext();
106+
const { asset_url, title = t('Voice message') } = attachment;
106107
const {
107-
asset_url,
108108
duration = 0,
109109
file_size,
110110
mime_type,
111-
title = t('Voice message'),
112111
waveform_data,
113-
} = attachment;
112+
} = (attachment as VoiceRecordingAttachment).custom;
114113

115114
/**
116115
* Introducing message context. This could be breaking change, therefore the fallback to {} is provided.
@@ -143,27 +142,28 @@ export type QuotedVoiceRecordingProps = Pick<VoiceRecordingProps, 'attachment'>;
143142

144143
export const QuotedVoiceRecording = ({ attachment }: QuotedVoiceRecordingProps) => {
145144
const { FileSizeIndicator = DefaultFileSizeIndicator } = useComponentContext();
145+
const { duration, file_size, mime_type } = (attachment as VoiceRecordingAttachment).custom;
146146
return (
147147
<div className={rootClassName} data-testid='quoted-voice-recording-widget'>
148148
<div className='str-chat__message-attachment__voice-recording-widget__metadata'>
149149
<div className='str-chat__message-attachment__voice-recording-widget__audio-state'>
150150
<div className='str-chat__message-attachment__voice-recording-widget__timer'>
151-
{attachment.duration ? (
151+
{duration ? (
152152
<DurationDisplay
153-
duration={attachment.duration}
153+
duration={duration}
154154
isPlaying={false}
155155
secondsElapsed={undefined}
156156
/>
157157
) : (
158158
<FileSizeIndicator
159-
fileSize={attachment.file_size}
159+
fileSize={file_size}
160160
maximumFractionDigits={0}
161161
/>
162162
)}
163163
</div>
164164
</div>
165165
</div>
166-
<FileIcon mimeType={attachment.mime_type} />
166+
<FileIcon mimeType={mime_type} />
167167
</div>
168168
);
169169
};

src/components/Badge/MediaBadge.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { IconMicrophoneSolid, IconVideoFill } from '../Icons';
22
import React, { type ComponentType } from 'react';
3-
import type { LocalAttachment } from 'stream-chat';
3+
import type { LocalAttachment, LocalVoiceRecordingAttachment } from 'stream-chat';
44
import clsx from 'clsx';
55

66
export type MediaBadgeVariant = 'video' | 'voice-recording' | string;
@@ -17,14 +17,15 @@ const MediaBadgeVariantToIcon: Record<MediaBadgeVariant, ComponentType> = {
1717

1818
export const MediaBadge = ({ attachment, variant }: MediaBadgeProps) => {
1919
const Icon = MediaBadgeVariantToIcon[variant];
20+
const { duration } = (attachment as LocalVoiceRecordingAttachment).custom;
2021
return (
2122
<div
2223
className={clsx('str-chat__media-badge', {
2324
[`str-chat__media-badge--${variant}`]: variant,
2425
})}
2526
>
2627
{Icon && <Icon />}
27-
{attachment.duration ? <div>{attachment.duration}</div> : null}
28+
{duration ? <div>{duration}</div> : null}
2829
</div>
2930
);
3031
};

src/components/Channel/Channel.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -350,10 +350,11 @@ const ChannelInner = (
350350
);
351351

352352
const handleEvent = async (event: Event) => {
353-
if (event.message) {
353+
const message = (event as Extract<Event, { message?: unknown }>).message;
354+
if (message) {
354355
dispatch({
355356
channel,
356-
message: event.message,
357+
message,
357358
type: 'updateThreadOnEvent',
358359
});
359360
}
@@ -761,7 +762,7 @@ const ChannelInner = (
761762
await channel.query(
762763
{
763764
messages: {
764-
created_at_around: channelUnreadUiState.last_read.toISOString(),
765+
created_at_around: channelUnreadUiState.last_read,
765766
limit: queryMessageLimit,
766767
},
767768
},
@@ -786,9 +787,8 @@ const ChannelInner = (
786787
);
787788
return;
788789
}
789-
const firstMessageTimestamp = new Date(
790-
firstMessageWithCreationDate.created_at as string,
791-
).getTime();
790+
const firstMessageTimestamp =
791+
firstMessageWithCreationDate.created_at.getTime();
792792
if (lastReadTimestamp < firstMessageTimestamp) {
793793
// whole channel is unread
794794
firstUnreadMessageId = firstMessageWithCreationDate.id;
@@ -876,7 +876,10 @@ const ChannelInner = (
876876
if (doDeleteMessageRequest) {
877877
deletedMessage = await doDeleteMessageRequest(message, options);
878878
} else {
879-
const result = await client.deleteMessage(message.id, options);
879+
const result = await client.deleteMessage({
880+
id: message.id,
881+
...options,
882+
});
880883
deletedMessage = result.message;
881884
}
882885

@@ -911,7 +914,7 @@ const ChannelInner = (
911914
if (doSendMessageRequest) {
912915
messageResponse = await doSendMessageRequest(channel, message, options);
913916
} else {
914-
messageResponse = await channel.sendMessage(message, options);
917+
messageResponse = await channel.sendMessage({ message, ...options });
915918
}
916919

917920
let existingMessage: LocalMessage | undefined = undefined;
@@ -1075,9 +1078,10 @@ const ChannelInner = (
10751078
const oldestMessageId = oldMessages[0]?.id;
10761079

10771080
try {
1078-
const queryResponse = await channel.getReplies(parentId, {
1081+
const queryResponse = await channel.getReplies({
10791082
id_lt: oldestMessageId,
10801083
limit,
1084+
parent_id: parentId,
10811085
});
10821086

10831087
const threadHasMoreMessages = hasMoreMessagesProbably(

src/components/Channel/hooks/useCreateChannelStateContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ export const useCreateChannelStateContext = (
140140
}),
141141
// eslint-disable-next-line react-hooks/exhaustive-deps
142142
[
143-
channel.data?.name, // otherwise ChannelHeader will not be updated
143+
channel.data?.custom?.name,
144144
channelId,
145145
channelUnreadUiState,
146146
error,

src/components/ChannelList/ChannelList.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
ChannelOptions,
88
ChannelSort,
99
Event,
10+
EventPayload,
1011
SearchControllerState,
1112
} from 'stream-chat';
1213

@@ -44,7 +45,7 @@ import { useStableId } from '../UtilityComponents/useStableId';
4445

4546
const DEFAULT_FILTERS = {};
4647
const DEFAULT_OPTIONS = {};
47-
const DEFAULT_SORT = {};
48+
const DEFAULT_SORT: ChannelSort = [];
4849

4950
const searchControllerStateSelector = (nextValue: SearchControllerState) => ({
5051
searchIsActive: nextValue.isActive,
@@ -228,9 +229,12 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
228229
);
229230

230231
if (!customActiveChannelObject) {
231-
[customActiveChannelObject] = await client.queryChannels({
232-
id: customActiveChannel,
233-
});
232+
[customActiveChannelObject] = await client.queryChannelsAndHydrate(
233+
{
234+
filter_conditions: { id: customActiveChannel },
235+
},
236+
{ withResponse: false },
237+
);
234238
}
235239

236240
if (customActiveChannelObject) {
@@ -308,18 +312,19 @@ const UnMemoizedChannelList = (props: ChannelListProps) => {
308312
useConnectionRecoveredListener(forceUpdate);
309313

310314
useEffect(() => {
311-
const handleEvent = (event: Event) => {
315+
const handleEvent = (event: EventPayload<'channel.deleted' | 'channel.hidden'>) => {
312316
if (event.cid === channel?.cid) {
313317
setActiveChannel();
314318
}
315319
};
316320

317-
client.on('channel.deleted', handleEvent);
318-
client.on('channel.hidden', handleEvent);
321+
const subscriptions = [
322+
client.on('channel.deleted', handleEvent),
323+
client.on('channel.hidden', handleEvent),
324+
];
319325

320326
return () => {
321-
client.off('channel.deleted', handleEvent);
322-
client.off('channel.hidden', handleEvent);
327+
subscriptions.forEach((subscription) => subscription.unsubscribe());
323328
};
324329
// eslint-disable-next-line react-hooks/exhaustive-deps
325330
}, [channel?.cid]);

src/components/ChannelList/ChannelListUI.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, { useRef } from 'react';
22
import type { PropsWithChildren } from 'react';
3-
import type { APIErrorResponse, Channel, ErrorFromResponse } from 'stream-chat';
3+
import type { APIErrorResponse, Channel, StreamAPIError } from 'stream-chat';
44

55
import { LoadingChannels } from '../Loading/LoadingChannels';
66
import { NullComponent } from '../UtilityComponents';
@@ -9,7 +9,7 @@ import { useComponentContext, useTranslationContext } from '../../context';
99

1010
export type ChannelListUIProps = {
1111
/** Whether the channel query request returned an errored response */
12-
error: ErrorFromResponse<APIErrorResponse> | null;
12+
error: StreamAPIError<APIErrorResponse> | null;
1313
/** The channels currently loaded in the list, only defined if `sendChannelsToList` on `ChannelList` is true */
1414
loadedChannels?: Channel[];
1515
/** Whether the channels are currently loading */

0 commit comments

Comments
 (0)