Skip to content

Commit d8532b7

Browse files
committed
chore: update @sendbird/chat to v4.18.0 and refactor unread messages handling
1 parent 12c11d4 commit d8532b7

File tree

16 files changed

+134
-78
lines changed

16 files changed

+134
-78
lines changed

docs-validation/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
"@react-native-firebase/messaging": "^14.7.0",
1616
"@react-navigation/native": "^6.1.17",
1717
"@react-navigation/native-stack": "^6.10.0",
18-
"@sendbird/chat": "^4.16.0",
18+
"@sendbird/chat": "^4.18.0",
1919
"date-fns": "^4.1.0",
2020
"react": "18.2.0",
2121
"react-native": "0.74.3",

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
]
9999
},
100100
"resolutions": {
101-
"@sendbird/chat": "4.16.5",
101+
"@sendbird/chat": "4.18.0",
102102
"@types/react": "^18"
103103
}
104104
}

packages/uikit-chat-hooks/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
"typescript": "5.2.2"
5656
},
5757
"peerDependencies": {
58-
"@sendbird/chat": "^4.16.0",
58+
"@sendbird/chat": "^4.18.0",
5959
"react": ">=16.13.1"
6060
},
6161
"react-native-builder-bob": {

packages/uikit-react-native/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
"@react-native-community/netinfo": ">=9.3.0",
112112
"@react-native-documents/picker": ">=10.0.0",
113113
"@react-native-firebase/messaging": ">=14.4.0",
114-
"@sendbird/chat": "^4.16.0",
114+
"@sendbird/chat": "^4.18.0",
115115
"@sendbird/react-native-scrollview-enhancer": "*",
116116
"date-fns": ">=2.28.0",
117117
"expo-av": ">=12.0.4",

packages/uikit-react-native/src/components/ChannelMessageList/index.tsx

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
5050
channel: T;
5151
messages: SendbirdMessage[];
5252
newMessages: SendbirdMessage[];
53+
unreadFirstMessage?: SendbirdMessage;
5354
unreadMessageCount: number;
5455
searchItem?: { startingPoint: number };
5556

@@ -61,7 +62,7 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
6162

6263
onPressNewMessagesButton: (animated?: boolean) => void;
6364
onPressScrollToBottomButton: (animated?: boolean) => void;
64-
onPressUnreadMessagesButton: (animated?: boolean) => void;
65+
onPressUnreadMessagesFloatingCloseButton: () => void;
6566

6667
onEditMessage: (message: HandleableMessage) => void;
6768
onReplyMessage?: (message: HandleableMessage) => void; // only available on group channel
@@ -76,6 +77,7 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
7677
message: SendbirdMessage;
7778
prevMessage?: SendbirdMessage;
7879
nextMessage?: SendbirdMessage;
80+
unreadFirstMessage?: SendbirdMessage;
7981
onPress?: () => void;
8082
onLongPress?: () => void;
8183
onPressParentMessage?: ChannelMessageListProps<T>['onPressParentMessage'];
@@ -92,11 +94,11 @@ export type ChannelMessageListProps<T extends SendbirdGroupChannel | SendbirdOpe
9294
| null
9395
| ((props: { visible: boolean; onPress: () => void; newMessages: SendbirdMessage[] }) => React.ReactElement | null);
9496
renderScrollToBottomButton: null | ((props: { visible: boolean; onPress: () => void }) => React.ReactElement | null);
95-
renderUnreadMessagesButton:
97+
renderUnreadMessagesFloating:
9698
| null
9799
| ((props: {
98100
visible: boolean;
99-
onPress: () => void;
101+
onPressClose: () => void;
100102
unreadMessageCount: number;
101103
}) => React.ReactElement | null);
102104
flatListComponent?: React.ComponentType<FlatListProps<SendbirdMessage>>;
@@ -118,12 +120,13 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
118120
onPressMediaMessage,
119121
onPressParentMessage,
120122
currentUserId,
121-
renderUnreadMessagesButton,
123+
renderUnreadMessagesFloating,
122124
renderNewMessagesButton,
123125
renderScrollToBottomButton,
124126
renderMessage,
125127
messages,
126128
newMessages,
129+
unreadFirstMessage,
127130
unreadMessageCount,
128131
enableMessageGrouping,
129132
onScrolledAwayFromBottom,
@@ -134,7 +137,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
134137
flatListProps,
135138
onPressNewMessagesButton,
136139
onPressScrollToBottomButton,
137-
onPressUnreadMessagesButton,
140+
onPressUnreadMessagesFloatingCloseButton,
138141
}: ChannelMessageListProps<T>,
139142
ref: React.ForwardedRef<FlatList<SendbirdMessage>>,
140143
) => {
@@ -159,6 +162,7 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
159162
message: item,
160163
prevMessage: messages[index + 1],
161164
nextMessage: messages[index - 1],
165+
unreadFirstMessage: unreadFirstMessage,
162166
onPress,
163167
onLongPress,
164168
onPressParentMessage,
@@ -178,11 +182,11 @@ const ChannelMessageList = <T extends SendbirdGroupChannel | SendbirdOpenChannel
178182
{!channel.isFrozen && (
179183
<ChannelFrozenBanner style={styles.frozenBanner} text={STRINGS.LABELS.CHANNEL_MESSAGE_LIST_FROZEN} />
180184
)}
181-
{renderUnreadMessagesButton && (
185+
{renderUnreadMessagesFloating && (
182186
<View style={[!channel.isFrozen ? styles.unreadMsgButtonWhenFrozen : styles.unreadMsgButton, safeAreaLayout]}>
183-
{renderUnreadMessagesButton({
184-
visible:unreadMessageCount > 0,
185-
onPress: () => onPressUnreadMessagesButton(),
187+
{renderUnreadMessagesFloating({
188+
visible: unreadMessageCount > 0,
189+
onPressClose: () => onPressUnreadMessagesFloatingCloseButton(),
186190
unreadMessageCount,
187191
})}
188192
</View>
@@ -350,6 +354,11 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
350354
title: STRINGS.LABELS.CHANNEL_MESSAGE_COPY,
351355
onPress: () => onCopyText(message),
352356
}),
357+
markAsUnread: (message: HandleableMessage) => ({
358+
icon: 'mark-as-unread' as const,
359+
title: STRINGS.LABELS.CHANNEL_MESSAGE_MARK_AS_UNREAD,
360+
onPress: () => onMarkAsUnread(message),
361+
}),
353362
edit: (message: HandleableMessage) => ({
354363
icon: 'edit' as const,
355364
title: STRINGS.LABELS.CHANNEL_MESSAGE_EDIT,
@@ -378,16 +387,14 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
378387
title: STRINGS.LABELS.CHANNEL_MESSAGE_SAVE,
379388
onPress: () => onDownloadFile(message),
380389
}),
381-
markAsUnread: (message: HandleableMessage) => ({
382-
icon: 'mark-as-unread' as const,
383-
title: STRINGS.LABELS.CHANNEL_MESSAGE_MARK_AS_UNREAD,
384-
onPress: () => onMarkAsUnread(message),
385-
}),
386390
};
387391

388392
if (message.isUserMessage()) {
389393
sheetItems.push(menu.copy(message));
390394
if (!channel.isEphemeral) {
395+
if (channel.isGroupChannel() && sbOptions.uikitWithAppInfo.groupChannel.channel.enableMarkAsUnread) {
396+
sheetItems.push(menu.markAsUnread(message));
397+
}
391398
if (isMyMessage(message, currentUserId) && message.sendingStatus === 'succeeded') {
392399
sheetItems.push(menu.edit(message));
393400
sheetItems.push(menu.delete(message));
@@ -398,9 +405,6 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
398405
} else if (sbOptions.uikit.groupChannel.channel.replyType === 'quote_reply') {
399406
sheetItems.push(menu.reply(message));
400407
}
401-
if (sbOptions.uikitWithAppInfo.groupChannel.channel.enableMarkAsUnread) {
402-
sheetItems.push(menu.markAsUnread(message));
403-
}
404408
}
405409
}
406410
}

packages/uikit-react-native/src/components/GroupChannelMessageRenderer/GroupChannelMessageNewMessagesSeparator.tsx renamed to packages/uikit-react-native/src/components/GroupChannelMessageRenderer/GroupChannelMessageNewMessageSeparator.tsx

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,25 @@ import { StyleSheet, View } from 'react-native';
33

44
import { Box, Text, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
55

6+
import { useLocalization } from '../../hooks/useContext';
7+
68
type Props = {
7-
isUnreadFirstMessage: boolean;
9+
shouldRenderMessageSeparator?: boolean;
810
};
911

10-
const GroupChannelMessageNewMessagesSeparator = ({ isUnreadFirstMessage }: Props) => {
11-
if (!isUnreadFirstMessage) return null;
12+
const GroupChannelMessageNewMessageSeparator = ({ shouldRenderMessageSeparator }: Props) => {
13+
if (!shouldRenderMessageSeparator) return null;
1214

1315
const { select, palette } = useUIKitTheme();
16+
const { STRINGS } = useLocalization();
1417

1518
return (
1619
<View style={styles.container}>
17-
<Box backgroundColor={select({ light: palette.primary300, dark: palette.primary300 })} style={styles.line} />
18-
<Text caption3 color={select({ light: palette.primary300, dark: palette.primary300 })} style={styles.label}>
19-
New messages
20+
<Box backgroundColor={select({ light: palette.primary300, dark: palette.primary200 })} style={styles.line} />
21+
<Text caption3 color={select({ light: palette.primary300, dark: palette.primary200 })} style={styles.label}>
22+
{STRINGS.GROUP_CHANNEL.LIST_NEW_MESSAGE_SEPARATOR}
2023
</Text>
21-
<Box backgroundColor={select({ light: palette.primary300, dark: palette.primary300 })} style={styles.line} />
24+
<Box backgroundColor={select({ light: palette.primary300, dark: palette.primary200 })} style={styles.line} />
2225
</View>
2326
);
2427
};
@@ -40,4 +43,4 @@ const styles = StyleSheet.create({
4043
},
4144
});
4245

43-
export default React.memo(GroupChannelMessageNewMessagesSeparator);
46+
export default React.memo(GroupChannelMessageNewMessageSeparator);

packages/uikit-react-native/src/components/GroupChannelMessageRenderer/index.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useContext, useEffect, useRef } from 'react';
1+
import React, { useContext, useEffect, useMemo, useRef } from 'react';
22

33
import type { GroupChannelMessageProps, RegexTextPattern } from '@sendbird/uikit-react-native-foundation';
44
import {
@@ -30,7 +30,7 @@ import { TypingIndicatorType } from '../../types';
3030
import { ReactionAddons } from '../ReactionAddons';
3131
import GroupChannelMessageDateSeparator from './GroupChannelMessageDateSeparator';
3232
import GroupChannelMessageFocusAnimation from './GroupChannelMessageFocusAnimation';
33-
import GroupChannelMessageNewMessagesSeparator from './GroupChannelMessageNewMessagesSeparator';
33+
import GroupChannelMessageNewMessageSeparator from './GroupChannelMessageNewMessageSeparator';
3434
import GroupChannelMessageOutgoingStatus from './GroupChannelMessageOutgoingStatus';
3535
import GroupChannelMessageParentMessage from './GroupChannelMessageParentMessage';
3636
import GroupChannelMessageReplyInfo from './GroupChannelMessageReplyInfo';
@@ -47,6 +47,7 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
4747
focused,
4848
prevMessage,
4949
nextMessage,
50+
unreadFirstMessage,
5051
hideParentMessage,
5152
}) => {
5253
const handlers = useSBUHandlers();
@@ -311,10 +312,17 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
311312
}
312313
});
313314

315+
const shouldRenderMessageSeparator = useMemo(() => {
316+
if (sbOptions.uikitWithAppInfo.groupChannel.channel.enableMarkAsUnread && unreadFirstMessage) {
317+
return message.messageId === unreadFirstMessage.messageId;
318+
}
319+
return false;
320+
}, [sbOptions.uikitWithAppInfo.groupChannel.channel.enableMarkAsUnread, unreadFirstMessage?.messageId]);
321+
314322
return (
315323
<Box paddingHorizontal={16} marginBottom={messageGap}>
316324
<GroupChannelMessageDateSeparator message={message} prevMessage={prevMessage} />
317-
<GroupChannelMessageNewMessagesSeparator isUnreadFirstMessage={true} />
325+
<GroupChannelMessageNewMessageSeparator shouldRenderMessageSeparator={shouldRenderMessageSeparator} />
318326
<GroupChannelMessageFocusAnimation focused={focused}>{renderMessage()}</GroupChannelMessageFocusAnimation>
319327
</Box>
320328
);

packages/uikit-react-native/src/components/UnreadMessagesButton.tsx renamed to packages/uikit-react-native/src/components/UnreadMessagesFloating.tsx

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,56 @@
11
import React from 'react';
2-
import { Platform, TouchableOpacity } from 'react-native';
2+
import { Platform, TouchableOpacity, View } from 'react-native';
3+
4+
import { Icon, Text, createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
35

4-
import { Text, createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
56
import { useLocalization } from '../hooks/useContext';
67

78
type Props = {
89
unreadMessageCount: number;
910
visible: boolean;
10-
onPress: () => void;
11+
onPressClose: () => void;
1112
};
12-
const UnreadMessagesButton = ({ unreadMessageCount, visible, onPress }: Props) => {
13+
const UnreadMessagesFloating = ({ unreadMessageCount, visible, onPressClose }: Props) => {
1314
const { STRINGS } = useLocalization();
1415
const { select, palette } = useUIKitTheme();
1516
if (unreadMessageCount <= 0 || !visible) return null;
1617
return (
17-
<TouchableOpacity
18-
activeOpacity={0.8}
19-
onPress={onPress}
18+
<View
2019
style={[
2120
styles.container,
2221
{ backgroundColor: select({ dark: palette.background400, light: palette.background50 }) },
2322
]}
2423
>
2524
<Text body2 color={select({ dark: palette.onBackgroundDark02, light: palette.onBackgroundLight02 })}>
26-
{STRINGS.GROUP_CHANNEL.LIST_BUTTON_UNREAD_MSG(unreadMessageCount)}
25+
{STRINGS.GROUP_CHANNEL.LIST_FLOATING_UNREAD_MSG(unreadMessageCount)}
2726
</Text>
28-
</TouchableOpacity>
27+
<TouchableOpacity onPress={onPressClose} style={{ marginLeft: 4 }}>
28+
<Icon icon={'close'} size={14} />
29+
</TouchableOpacity>
30+
</View>
2931
);
3032
};
3133

3234
const styles = createStyleSheet({
3335
container: {
34-
paddingHorizontal: 12,
35-
paddingVertical: 10,
36+
flexDirection: 'row',
37+
justifyContent: 'flex-start',
38+
alignItems: 'center',
39+
paddingHorizontal: 16,
40+
paddingVertical: 12,
3641
borderRadius: 20,
3742
...Platform.select({
3843
android: {
39-
elevation: 4,
44+
elevation: 3,
4045
},
4146
ios: {
4247
shadowColor: 'black',
43-
shadowRadius: 4,
48+
shadowRadius: 3,
4449
shadowOffset: { width: 0, height: 4 },
45-
shadowOpacity: 0.3,
50+
shadowOpacity: 0.08,
4651
},
4752
}),
4853
},
4954
});
50-
export default React.memo(UnreadMessagesButton);
55+
56+
export default React.memo(UnreadMessagesFloating);

packages/uikit-react-native/src/domain/groupChannel/component/GroupChannelMessageList.tsx

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useContext, useEffect } from 'react';
1+
import React, { useContext, useEffect, useMemo, useRef } from 'react';
22

33
import { useToast } from '@sendbird/uikit-react-native-foundation';
44
import { useGroupChannelHandler } from '@sendbird/uikit-tools';
@@ -7,7 +7,7 @@ import {
77
SendbirdSendableMessage,
88
isDifferentChannel,
99
useFreshCallback,
10-
useIsFirstMount, Logger,
10+
useIsFirstMount,
1111
} from '@sendbird/uikit-utils';
1212

1313
import ChannelMessageList from '../../../components/ChannelMessageList';
@@ -66,11 +66,6 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
6666
}
6767
});
6868

69-
const onPressUnreadMessagesCloseButton = useFreshCallback(async () => {
70-
await props.channel.markAsRead();
71-
Logger.log('onPressUnreadMessagesCloseButton');
72-
});
73-
7469
useGroupChannelHandler(sdk, {
7570
onReactionUpdated(channel, event) {
7671
if (isDifferentChannel(channel, props.channel)) return;
@@ -81,6 +76,9 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
8176
lazyScrollToBottom({ animated: true, timeout: 250 });
8277
}
8378
},
79+
onChannelChanged(channel) {
80+
if (isDifferentChannel(channel, props.channel)) return;
81+
},
8482
});
8583

8684
useEffect(() => {
@@ -157,6 +155,22 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
157155
},
158156
);
159157

158+
const shouldRenderUnreadMessagesFloatingRef = useRef(props.channel.unreadMessageCount > 0);
159+
const onPressUnreadMessagesCloseButton = useFreshCallback(async () => {
160+
shouldRenderUnreadMessagesFloatingRef.current = false;
161+
});
162+
163+
const unreadFirstMessageRef = useRef<SendbirdMessage | undefined>(undefined);
164+
const unreadFirstMessage = useMemo(() => {
165+
if (!unreadFirstMessageRef.current) {
166+
const foundUnreadMessage = props.messages.find((msg) => msg.createdAt - 1 === props.channel.myLastRead);
167+
if (foundUnreadMessage) {
168+
unreadFirstMessageRef.current = foundUnreadMessage;
169+
}
170+
}
171+
return unreadFirstMessageRef.current;
172+
}, [props.messages, props.channel.myLastRead]);
173+
160174
return (
161175
<ChannelMessageList
162176
{...props}
@@ -167,7 +181,8 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
167181
onPressParentMessage={onPressParentMessage}
168182
onPressNewMessagesButton={scrollToBottom}
169183
onPressScrollToBottomButton={scrollToBottom}
170-
onPressUnreadMessagesButton={onPressUnreadMessagesCloseButton}
184+
onPressUnreadMessagesFloatingCloseButton={onPressUnreadMessagesCloseButton}
185+
unreadFirstMessage={unreadFirstMessage}
171186
unreadMessageCount={props.channel.unreadMessageCount}
172187
/>
173188
);

0 commit comments

Comments
 (0)