Skip to content

Commit cd510de

Browse files
committed
fix: useChannelPreviewData types
1 parent 89f9f48 commit cd510de

File tree

4 files changed

+83
-53
lines changed

4 files changed

+83
-53
lines changed

package/src/components/ChannelPreview/hooks/useChannelPreviewData.ts

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,44 @@
1-
import { useEffect, useMemo, useState } from 'react';
1+
import { type SetStateAction, useEffect, useMemo, useState } from 'react';
22

33
import throttle from 'lodash/throttle';
4-
import type { Channel, ChannelState, Event, MessageResponse, StreamChat } from 'stream-chat';
4+
import type { Channel, Event, LocalMessage, MessageResponse, StreamChat } from 'stream-chat';
55

66
import { useIsChannelMuted } from './useIsChannelMuted';
77

88
import { useLatestMessagePreview } from './useLatestMessagePreview';
99

1010
import { useChannelsContext } from '../../../contexts';
11+
import { useStableCallback } from '../../../hooks';
12+
13+
const setLastMessageThrottleTimeout = 500;
14+
const setLastMessageThrottleOptions = { leading: true, trailing: true };
15+
16+
const refreshUnreadCountThrottleTimeout = 400;
17+
const refreshUnreadCountThrottleOptions = setLastMessageThrottleOptions;
18+
19+
type LastMessageType = LocalMessage | MessageResponse;
1120

1221
export const useChannelPreviewData = (
1322
channel: Channel,
1423
client: StreamChat,
1524
forceUpdateOverride?: number,
1625
) => {
1726
const [forceUpdate, setForceUpdate] = useState(0);
18-
const [lastMessage, setLastMessage] = useState<
19-
ReturnType<ChannelState['formatMessage']> | MessageResponse
20-
>(channel.state.messages[channel.state.messages.length - 1]);
27+
const [lastMessage, setLastMessageInner] = useState<LastMessageType>(
28+
() => channel.state.messages[channel.state.messages.length - 1],
29+
);
30+
const throttledSetLastMessage = useMemo(
31+
() =>
32+
throttle(
33+
(newLastMessage: SetStateAction<LastMessageType>) => setLastMessageInner(newLastMessage),
34+
setLastMessageThrottleTimeout,
35+
setLastMessageThrottleOptions,
36+
),
37+
[],
38+
);
39+
const setLastMessage = useStableCallback((newLastMessage: SetStateAction<LastMessageType>) =>
40+
throttledSetLastMessage(newLastMessage),
41+
);
2142
const [unread, setUnread] = useState(channel.countUnread());
2243
const { muted } = useIsChannelMuted(channel);
2344
const { forceUpdate: contextForceUpdate } = useChannelsContext();
@@ -26,29 +47,50 @@ export const useChannelPreviewData = (
2647
const channelLastMessage = channel.lastMessage();
2748
const channelLastMessageString = `${channelLastMessage?.id}${channelLastMessage?.updated_at}`;
2849

50+
const refreshUnreadCount = useMemo(
51+
() =>
52+
throttle(
53+
() => {
54+
if (muted) {
55+
setUnread(0);
56+
} else {
57+
setUnread(channel.countUnread());
58+
}
59+
},
60+
refreshUnreadCountThrottleTimeout,
61+
refreshUnreadCountThrottleOptions,
62+
),
63+
[channel, muted],
64+
);
65+
2966
useEffect(() => {
3067
const unsubscribe = channel.messageComposer.registerDraftEventSubscriptions();
3168
return () => unsubscribe();
3269
}, [channel.messageComposer]);
3370

3471
useEffect(() => {
3572
const { unsubscribe } = client.on('notification.mark_read', () => {
36-
setUnread(channel.countUnread());
73+
refreshUnreadCount();
3774
});
3875
return unsubscribe;
39-
}, [channel, client]);
76+
}, [client, refreshUnreadCount]);
4077

4178
useEffect(() => {
42-
if (
79+
setLastMessage((prevLastMessage) =>
4380
channelLastMessage &&
44-
(channelLastMessage.id !== lastMessage?.id ||
45-
channelLastMessage.updated_at !== lastMessage?.updated_at)
46-
) {
47-
setLastMessage(channelLastMessage);
48-
}
49-
const newUnreadCount = channel.countUnread();
50-
setUnread(newUnreadCount);
51-
}, [channel, channelLastMessage, channelLastMessageString, channelListForceUpdate, lastMessage]);
81+
(channelLastMessage.id !== prevLastMessage?.id ||
82+
channelLastMessage.updated_at !== prevLastMessage?.updated_at)
83+
? channelLastMessage
84+
: prevLastMessage,
85+
);
86+
refreshUnreadCount();
87+
}, [
88+
channelLastMessage,
89+
channelLastMessageString,
90+
channelListForceUpdate,
91+
setLastMessage,
92+
refreshUnreadCount,
93+
]);
5294

5395
/**
5496
* This effect listens for the `notification.mark_read` event and sets the unread count to 0
@@ -91,18 +133,6 @@ export const useChannelPreviewData = (
91133
return unsubscribe;
92134
}, [client, channel]);
93135

94-
const refreshUnreadCount = useMemo(
95-
() =>
96-
throttle(() => {
97-
if (muted) {
98-
setUnread(0);
99-
} else {
100-
setUnread(channel.countUnread());
101-
}
102-
}, 400),
103-
[channel, muted],
104-
);
105-
106136
/**
107137
* This effect listens for the `message.new`, `message.updated`, `message.deleted`, `message.undeleted`, and `channel.truncated` events
108138
*/
@@ -118,7 +148,7 @@ export const useChannelPreviewData = (
118148
const message = event.message;
119149
if (message && (!message.parent_id || message.show_in_channel)) {
120150
setLastMessage(message);
121-
setUnread(channel.countUnread());
151+
refreshUnreadCount();
122152
}
123153
};
124154

@@ -140,9 +170,13 @@ export const useChannelPreviewData = (
140170
];
141171

142172
return () => listeners.forEach((l) => l.unsubscribe());
143-
}, [channel, refreshUnreadCount, forceUpdate, channelListForceUpdate]);
173+
}, [channel, refreshUnreadCount, forceUpdate, channelListForceUpdate, setLastMessage]);
144174

145-
const latestMessagePreview = useLatestMessagePreview(channel, forceUpdate, lastMessage);
175+
const latestMessagePreview = useLatestMessagePreview(
176+
channel,
177+
forceUpdate,
178+
lastMessage as LocalMessage,
179+
);
146180

147181
return { latestMessagePreview, muted, unread };
148182
};

package/src/components/ChannelPreview/hooks/useLatestMessagePreview.ts

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import { TFunction } from 'i18next';
44
import type {
55
AttachmentManagerState,
66
Channel,
7-
ChannelState,
87
DraftMessage,
9-
MessageResponse,
8+
LocalMessage,
109
PollState,
1110
PollVote,
1211
StreamChat,
@@ -22,10 +21,8 @@ import { useTranslatedMessage } from '../../../hooks/useTranslatedMessage';
2221

2322
import { stringifyMessage } from '../../../utils/utils';
2423

25-
type LatestMessage = ReturnType<ChannelState['formatMessage']> | MessageResponse;
26-
2724
export type LatestMessagePreview = {
28-
messageObject: LatestMessage | undefined;
25+
messageObject: LocalMessage | undefined;
2926
previews: {
3027
bold: boolean;
3128
text: string;
@@ -48,7 +45,7 @@ const selector = (nextValue: PollState): LatestMessagePreviewSelectorReturnType
4845
});
4946

5047
const getMessageSenderName = (
51-
message: LatestMessage | undefined,
48+
message: LocalMessage | undefined,
5249
currentUserId: string | undefined,
5350
t: (key: string) => string,
5451
membersLength: number,
@@ -87,7 +84,7 @@ const getLatestMessageDisplayText = (
8784
channel: Channel,
8885
client: StreamChat,
8986
draftMessage: DraftMessage | undefined,
90-
message: LatestMessage | undefined,
87+
message: LocalMessage | undefined,
9188
t: (key: string) => string,
9289
pollState: LatestMessagePreviewSelectorReturnType | undefined,
9390
) => {
@@ -194,16 +191,18 @@ export enum MessageReadStatus {
194191
NOT_SENT_BY_CURRENT_USER = 0,
195192
UNREAD = 1,
196193
READ = 2,
194+
DELIVERED = 3,
197195
}
198196

199197
const getLatestMessageReadStatus = (
200198
channel: Channel,
201199
client: StreamChat,
202-
message: LatestMessage | undefined,
200+
lastMessage: LocalMessage | undefined,
203201
readEvents: boolean,
204202
): MessageReadStatus => {
205203
const currentUserId = client.userID;
206-
if (!message || currentUserId !== message.user?.id || readEvents === false) {
204+
const isLastMessageOwn = currentUserId === lastMessage?.user?.id;
205+
if (!lastMessage || !isLastMessageOwn || !readEvents) {
207206
return MessageReadStatus.NOT_SENT_BY_CURRENT_USER;
208207
}
209208

@@ -212,10 +211,10 @@ const getLatestMessageReadStatus = (
212211
delete readList[currentUserId];
213212
}
214213

215-
const messageUpdatedAt = message.updated_at
216-
? typeof message.updated_at === 'string'
217-
? new Date(message.updated_at)
218-
: message.updated_at
214+
const messageUpdatedAt = lastMessage.updated_at
215+
? typeof lastMessage.updated_at === 'string'
216+
? new Date(lastMessage.updated_at)
217+
: lastMessage.updated_at
219218
: undefined;
220219

221220
return Object.values(readList).some(
@@ -232,7 +231,7 @@ const getLatestMessagePreview = (params: {
232231
pollState: LatestMessagePreviewSelectorReturnType | undefined;
233232
readEvents: boolean;
234233
t: TFunction;
235-
lastMessage?: ReturnType<ChannelState['formatMessage']> | MessageResponse;
234+
lastMessage?: LocalMessage;
236235
}) => {
237236
const { channel, client, draftMessage, lastMessage, pollState, readEvents, t } = params;
238237

@@ -282,7 +281,7 @@ const stateSelector = (state: AttachmentManagerState) => ({
282281
export const useLatestMessagePreview = (
283282
channel: Channel,
284283
forceUpdate: number,
285-
lastMessage?: ReturnType<ChannelState['formatMessage']> | MessageResponse,
284+
lastMessage?: LocalMessage,
286285
) => {
287286
const { client } = useChatContext();
288287
const { t } = useTranslationContext();
@@ -328,8 +327,6 @@ export const useLatestMessagePreview = (
328327
return read_events;
329328
}, [channelConfigExists, channel]);
330329

331-
const readStatus = getLatestMessageReadStatus(channel, client, translatedLastMessage, readEvents);
332-
333330
const pollId = lastMessage?.poll_id ?? '';
334331
const poll = client.polls.fromState(pollId);
335332
const pollState: LatestMessagePreviewSelectorReturnType =
@@ -352,7 +349,6 @@ export const useLatestMessagePreview = (
352349
draftMessage,
353350
forceUpdate,
354351
readEvents,
355-
readStatus,
356352
latestVotesByOption,
357353
createdBy,
358354
name,

package/src/components/Message/MessageSimple/MessageTextContainer.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ const MessageTextContainerWithContext = (props: MessageTextContainerPropsWithCon
7171
},
7272
} = theme;
7373

74-
const translatedMessage = useTranslatedMessage(message) as LocalMessage;
74+
const translatedMessage = useTranslatedMessage(message);
7575

7676
if (!message.text) {
7777
return null;
@@ -94,7 +94,7 @@ const MessageTextContainerWithContext = (props: MessageTextContainerPropsWithCon
9494
...markdownStyles,
9595
...(onlyEmojis ? onlyEmojiMarkdown : {}),
9696
},
97-
message: translatedMessage,
97+
message: translatedMessage as LocalMessage,
9898
messageOverlay,
9999
messageTextNumberOfLines,
100100
onLongPress,

package/src/hooks/useTranslatedMessage.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import type { LocalMessage, MessageResponse, TranslationLanguages } from 'stream-chat';
1+
import type { LocalMessage, TranslationLanguages } from 'stream-chat';
22

33
import { useTranslationContext } from '../contexts/translationContext/TranslationContext';
44

55
type TranslationKey = `${TranslationLanguages}_text`;
66

7-
export const useTranslatedMessage = (message?: MessageResponse | LocalMessage) => {
7+
export const useTranslatedMessage = (message?: LocalMessage) => {
88
const { userLanguage } = useTranslationContext();
99

1010
const translationKey: TranslationKey = `${userLanguage}_text`;

0 commit comments

Comments
 (0)