Skip to content

Commit 74cf07e

Browse files
committed
feat: replace StreamMessage and MessageToSend with LocalMessage and RenderedMessage
1 parent ebe89a4 commit 74cf07e

File tree

68 files changed

+626
-785
lines changed

Some content is hidden

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

68 files changed

+626
-785
lines changed

src/components/Channel/Channel.tsx

Lines changed: 47 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { ComponentProps, PropsWithChildren } from 'react';
12
import React, {
23
useCallback,
34
useEffect,
@@ -11,7 +12,7 @@ import clsx from 'clsx';
1112
import debounce from 'lodash.debounce';
1213
import defaultsDeep from 'lodash.defaultsdeep';
1314
import throttle from 'lodash.throttle';
14-
import type { ComponentProps, PropsWithChildren } from 'react';
15+
import { localMessageToNewMessagePayload } from 'stream-chat';
1516
import type {
1617
APIErrorResponse,
1718
ChannelAPIResponse,
@@ -21,15 +22,14 @@ import type {
2122
ErrorFromResponse,
2223
Event,
2324
EventAPIResponse,
25+
LocalMessage,
2426
Message,
2527
MessageResponse,
2628
SendMessageAPIResponse,
2729
SendMessageOptions,
2830
Channel as StreamChannel,
2931
StreamChat,
3032
Thread,
31-
UpdatedMessage,
32-
UserResponse,
3333
} from 'stream-chat';
3434

3535
import { initialState, makeChannelReducer } from './channelState';
@@ -50,8 +50,6 @@ import type {
5050
ChannelNotifications,
5151
ComponentContextValue,
5252
MarkReadWrapperOptions,
53-
MessageToSend,
54-
StreamMessage,
5553
} from '../../context';
5654
import {
5755
ChannelActionProvider,
@@ -77,12 +75,7 @@ import {
7775
useChannelContainerClasses,
7876
useImageFlagEmojisOnWindowsClass,
7977
} from './hooks/useChannelContainerClasses';
80-
import {
81-
findInMsgSetByDate,
82-
findInMsgSetById,
83-
generateMessageId,
84-
makeAddNotifications,
85-
} from './utils';
78+
import { findInMsgSetByDate, findInMsgSetById, makeAddNotifications } from './utils';
8679
import { useThreadContext } from '../Threads';
8780
import { getChannel } from '../../utils';
8881

@@ -166,10 +159,6 @@ type ChannelPropsForwardedToComponentContext = Pick<
166159
| 'StreamedMessageText'
167160
>;
168161

169-
const isUserResponseArray = (
170-
output: string[] | UserResponse[],
171-
): output is UserResponse[] => (output as UserResponse[])[0]?.id != null;
172-
173162
export type ChannelProps = ChannelPropsForwardedToComponentContext & {
174163
// todo: move to MessageComposer configuration
175164
/** List of accepted file types */
@@ -186,7 +175,7 @@ export type ChannelProps = ChannelPropsForwardedToComponentContext & {
186175
*/
187176
channelQueryOptions?: ChannelQueryOptions;
188177
/** Custom action handler to override the default `client.deleteMessage(message.id)` function */
189-
doDeleteMessageRequest?: (message: StreamMessage) => Promise<MessageResponse>;
178+
doDeleteMessageRequest?: (message: LocalMessage) => Promise<MessageResponse>;
190179
/** Custom action handler to override the default `channel.markRead` request function (advanced usage only) */
191180
doMarkReadRequest?: (
192181
channel: StreamChannel,
@@ -201,7 +190,7 @@ export type ChannelProps = ChannelPropsForwardedToComponentContext & {
201190
/** Custom action handler to override the default `client.updateMessage` request function (advanced usage only) */
202191
doUpdateMessageRequest?: (
203192
cid: string,
204-
updatedMessage: UpdatedMessage,
193+
updatedMessage: LocalMessage | MessageResponse,
205194
options?: UpdateMessageOptions,
206195
) => ReturnType<StreamChat['updateMessage']>;
207196
/** If true, chat users will be able to drag and drop file uploads to the entire channel window */
@@ -943,7 +932,7 @@ const ChannelInner = (
943932
);
944933

945934
const deleteMessage = useCallback(
946-
async (message: StreamMessage): Promise<MessageResponse> => {
935+
async (message: LocalMessage): Promise<MessageResponse> => {
947936
if (!message?.id) {
948937
throw new Error('Cannot delete a message - missing message ID.');
949938
}
@@ -960,9 +949,9 @@ const ChannelInner = (
960949
[client, doDeleteMessageRequest],
961950
);
962951

963-
const updateMessage = (updatedMessage: MessageToSend | StreamMessage) => {
952+
const updateMessage = (updatedMessage: MessageResponse | LocalMessage) => {
964953
// add the message to the local channel state
965-
channel.state.addMessageSorted(updatedMessage as MessageResponse, true);
954+
channel.state.addMessageSorted(updatedMessage, true);
966955

967956
dispatch({
968957
channel,
@@ -971,43 +960,28 @@ const ChannelInner = (
971960
});
972961
};
973962

974-
const doSendMessage = async (
975-
message: MessageToSend | StreamMessage,
976-
customMessageData?: Partial<Message>,
977-
options?: SendMessageOptions,
978-
) => {
979-
const { attachments, id, mentioned_users = [], parent_id, text } = message;
980-
981-
// channel.sendMessage expects an array of user id strings
982-
const mentions = isUserResponseArray(mentioned_users)
983-
? mentioned_users.map(({ id }) => id)
984-
: mentioned_users;
985-
986-
const messageData = {
987-
attachments,
988-
id,
989-
mentioned_users: mentions,
990-
parent_id,
991-
// todo: move to message composer
992-
// quoted_message_id:
993-
// parent_id === quotedMessage?.parent_id ? quotedMessage?.id : undefined,
994-
text,
995-
...customMessageData,
996-
} as Message;
997-
963+
const doSendMessage = async ({
964+
localMessage,
965+
message,
966+
options,
967+
}: {
968+
localMessage: LocalMessage;
969+
message: Message;
970+
options?: SendMessageOptions;
971+
}) => {
998972
try {
999973
let messageResponse: void | SendMessageAPIResponse;
1000974

1001975
if (doSendMessageRequest) {
1002-
messageResponse = await doSendMessageRequest(channel, messageData, options);
976+
messageResponse = await doSendMessageRequest(channel, message, options);
1003977
} else {
1004-
messageResponse = await channel.sendMessage(messageData, options);
978+
messageResponse = await channel.sendMessage(message, options);
1005979
}
1006980

1007-
let existingMessage;
981+
let existingMessage: LocalMessage | undefined = undefined;
1008982
for (let i = channel.state.messages.length - 1; i >= 0; i--) {
1009983
const msg = channel.state.messages[i];
1010-
if (msg.id && msg.id === messageData.id) {
984+
if (msg.id && msg.id === message.id) {
1011985
existingMessage = msg;
1012986
break;
1013987
}
@@ -1051,79 +1025,61 @@ const ChannelInner = (
10511025
error.message.includes('already exists')
10521026
) {
10531027
updateMessage({
1054-
...message,
1028+
...localMessage,
10551029
status: 'received',
10561030
});
10571031
} else {
10581032
updateMessage({
1059-
...message,
1033+
...localMessage,
10601034
error: parsedError,
1061-
errorStatusCode: parsedError.status || undefined,
10621035
status: 'failed',
10631036
});
10641037

10651038
thread?.upsertReplyLocally({
10661039
message: {
1067-
...message,
1068-
// @ts-expect-error error is local
1040+
...localMessage,
10691041
error: parsedError,
1070-
errorStatusCode: parsedError.status || undefined,
10711042
status: 'failed',
10721043
},
10731044
});
10741045
}
10751046
}
10761047
};
10771048

1078-
const sendMessage = async (
1079-
{ attachments = [], mentioned_users = [], parent, text = '' }: MessageToSend,
1080-
customMessageData?: Partial<Message>,
1081-
options?: SendMessageOptions,
1082-
) => {
1049+
const sendMessage = async ({
1050+
localMessage,
1051+
message,
1052+
options,
1053+
}: {
1054+
localMessage: LocalMessage;
1055+
message: Message;
1056+
options?: SendMessageOptions;
1057+
}) => {
10831058
channel.state.filterErrorMessages();
10841059

1085-
const messagePreview = {
1086-
attachments,
1087-
created_at: new Date(),
1088-
html: text,
1089-
id: customMessageData?.id ?? generateMessageId({ client }),
1090-
mentioned_users,
1091-
parent_id: parent?.id,
1092-
reactions: [],
1093-
status: 'sending',
1094-
text,
1095-
type: 'regular',
1096-
user: client.user,
1097-
};
1098-
10991060
thread?.upsertReplyLocally({
1100-
// @ts-expect-error message type mismatch
1101-
message: messagePreview,
1061+
message: localMessage,
11021062
});
11031063

1104-
updateMessage(messagePreview);
1064+
updateMessage(localMessage);
11051065

1106-
await doSendMessage(messagePreview, customMessageData, options);
1066+
await doSendMessage({ localMessage, message, options });
11071067
};
11081068

1109-
const retrySendMessage = async (message: StreamMessage) => {
1069+
const retrySendMessage = async (localMessage: LocalMessage) => {
11101070
updateMessage({
1111-
...message,
1112-
errorStatusCode: undefined,
1071+
...localMessage,
1072+
error: null,
11131073
status: 'sending',
11141074
});
11151075

1116-
if (message.attachments) {
1117-
// remove scraped attachments added during the message composition in MessageInput to prevent sync issues
1118-
message.attachments = message.attachments.filter(
1119-
(attachment) => !attachment.og_scrape_url,
1120-
);
1121-
}
1122-
1123-
await doSendMessage(message);
1076+
await doSendMessage({
1077+
localMessage,
1078+
message: localMessageToNewMessagePayload(localMessage),
1079+
});
11241080
};
11251081

1126-
const removeMessage = (message: StreamMessage) => {
1082+
const removeMessage = (message: LocalMessage) => {
11271083
channel.state.removeMessage(message);
11281084

11291085
dispatch({
@@ -1135,7 +1091,7 @@ const ChannelInner = (
11351091

11361092
/** THREAD */
11371093

1138-
const openThread = (message: StreamMessage, event?: React.BaseSyntheticEvent) => {
1094+
const openThread = (message: LocalMessage, event?: React.BaseSyntheticEvent) => {
11391095
event?.preventDefault();
11401096
// todo: revisit how to open a thread
11411097

@@ -1162,7 +1118,7 @@ const ChannelInner = (
11621118
threadInstance: t,
11631119
type: 'openThread',
11641120
});
1165-
client.threads.addThread(t);
1121+
// client.threads.addThread(t);
11661122
});
11671123
};
11681124

src/components/Channel/channelState.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import type {
22
Channel,
3+
LocalMessage,
34
MessageResponse,
45
ChannelState as StreamChannelState,
56
Thread,
67
} from 'stream-chat';
78

8-
import type { ChannelState, StreamMessage } from '../../context/ChannelStateContext';
9+
import type { ChannelState } from '../../context/ChannelStateContext';
910

1011
export type ChannelStateReducerAction =
1112
| {
@@ -35,12 +36,12 @@ export type ChannelStateReducerAction =
3536
}
3637
| {
3738
hasMore: boolean;
38-
messages: StreamMessage[];
39+
messages: LocalMessage[];
3940
type: 'loadMoreFinished';
4041
}
4142
| {
4243
hasMoreNewer: boolean;
43-
messages: StreamMessage[];
44+
messages: LocalMessage[];
4445
type: 'loadMoreNewerFinished';
4546
}
4647
| {
@@ -50,7 +51,7 @@ export type ChannelStateReducerAction =
5051
}
5152
| {
5253
channel: Channel;
53-
message: StreamMessage;
54+
message: LocalMessage;
5455
type: 'openThread';
5556
threadInstance?: Thread;
5657
}
@@ -67,7 +68,7 @@ export type ChannelStateReducerAction =
6768
type: 'setLoadingMoreNewer';
6869
}
6970
| {
70-
message: StreamMessage;
71+
message: LocalMessage;
7172
type: 'setThread';
7273
}
7374
| {
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,26 @@
1-
import type { StreamChat, UpdatedMessage } from 'stream-chat';
1+
import type { LocalMessage, MessageResponse, StreamChat } from 'stream-chat';
22

33
import { useChatContext } from '../../../context/ChatContext';
44
import type { UpdateMessageOptions } from '../../../types/types';
55

66
type UpdateHandler = (
77
cid: string,
8-
updatedMessage: UpdatedMessage,
8+
updatedMessage: LocalMessage | MessageResponse,
99
options?: UpdateMessageOptions,
1010
) => ReturnType<StreamChat['updateMessage']>;
1111

1212
export const useEditMessageHandler = (doUpdateMessageRequest?: UpdateHandler) => {
1313
const { channel, client } = useChatContext('useEditMessageHandler');
1414

15-
return (updatedMessage: UpdatedMessage, options?: UpdateMessageOptions) => {
15+
return (
16+
updatedMessage: LocalMessage | MessageResponse,
17+
options?: UpdateMessageOptions,
18+
) => {
1619
if (doUpdateMessageRequest && channel) {
1720
return Promise.resolve(
1821
doUpdateMessageRequest(channel.cid, updatedMessage, options),
1922
);
2023
}
21-
return client.updateMessage(updatedMessage, undefined, options);
24+
return client.updateMessage(updatedMessage, options);
2225
};
2326
};

src/components/ChannelPreview/ChannelPreview.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import throttle from 'lodash.throttle';
22
import React, { useEffect, useMemo, useState } from 'react';
33
import type { ReactNode } from 'react';
4-
import type { Channel, Event } from 'stream-chat';
4+
import type { Channel, Event, LocalMessage } from 'stream-chat';
55

66
import { ChannelPreviewMessenger } from './ChannelPreviewMessenger';
77
import { useIsChannelMuted } from './hooks/useIsChannelMuted';
@@ -14,7 +14,6 @@ import type { MessageDeliveryStatus } from './hooks/useMessageDeliveryStatus';
1414
import type { ChatContextValue } from '../../context/ChatContext';
1515
import type { ChannelAvatarProps } from '../Avatar/ChannelAvatar';
1616
import type { GroupChannelDisplayInfo } from './utils';
17-
import type { StreamMessage } from '../../context/ChannelStateContext';
1817
import type { TranslationContextValue } from '../../context/TranslationContext';
1918

2019
export type ChannelPreviewUIComponentProps = ChannelPreviewProps & {
@@ -25,7 +24,7 @@ export type ChannelPreviewUIComponentProps = ChannelPreviewProps & {
2524
/** Title of Channel to display */
2625
groupChannelDisplayInfo?: GroupChannelDisplayInfo;
2726
/** The last message received in a channel */
28-
lastMessage?: StreamMessage;
27+
lastMessage?: LocalMessage;
2928
/** @deprecated Use latestMessagePreview prop instead. */
3029
latestMessage?: ReactNode;
3130
/** Latest message preview to display, will be a string or JSX element supporting markdown. */
@@ -86,7 +85,7 @@ export const ChannelPreview = (props: ChannelPreviewProps) => {
8685
channel,
8786
});
8887

89-
const [lastMessage, setLastMessage] = useState<StreamMessage>(
88+
const [lastMessage, setLastMessage] = useState<LocalMessage>(
9089
channel.state.messages[channel.state.messages.length - 1],
9190
);
9291
const [unread, setUnread] = useState(0);

0 commit comments

Comments
 (0)