Skip to content

Commit 1a5cf36

Browse files
authored
fix: Keep scroll if context menu is opened when receiving messages (#433)
Refactor * Replace `FrozenNotification`, `UnreadCount` (Also notification bar), and `LoadingPlaceHolder` into the `MessageList` component from `ChannelUI` Bugfix * Do not `scrollIntoBottom` if the message is not reached the bottom scrollIntoBottom is a function moving scroll when a new message is received * Do not `handleScroll` when a message is initially mounted handleScroll is a function moving scroll when the last message's layout is changed
1 parent 7f42d2f commit 1a5cf36

File tree

14 files changed

+411
-182
lines changed

14 files changed

+411
-182
lines changed

src/smart-components/Channel/components/ChannelHeader/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ import { useChannelContext } from '../../context/ChannelProvider';
1313
import { useMediaQueryContext } from '../../../../lib/MediaQueryContext';
1414
import { noop } from '../../../../utils/utils'
1515

16-
const ChannelHeader: React.FC = () => {
16+
interface ChannelHeaderProps {
17+
className?: string;
18+
}
19+
20+
const ChannelHeader: React.FC<ChannelHeaderProps> = ({
21+
className = '',
22+
}) => {
1723
const globalStore = useSendbirdStateContext();
1824
const userId = globalStore?.config?.userId;
1925
const theme = globalStore?.config?.theme;
@@ -33,7 +39,7 @@ const ChannelHeader: React.FC = () => {
3339

3440
const { stringSet } = useContext(LocalizationContext);
3541
return (
36-
<div className="sendbird-chat-header">
42+
<div className={`sendbird-chat-header ${className}`}>
3743
<div className="sendbird-chat-header__left">
3844
{
3945
isMobile && (

src/smart-components/Channel/components/ChannelUI/index.tsx

Lines changed: 14 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import './channel-ui.scss';
22

3-
import React, { useEffect, useState } from 'react';
3+
import React from 'react';
44
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
55

66
import { useChannelContext } from '../../context/ChannelProvider';
@@ -9,11 +9,8 @@ import ConnectionStatus from '../../../../ui/ConnectionStatus';
99
import ChannelHeader from '../ChannelHeader';
1010
import MessageList from '../MessageList';
1111
import TypingIndicator from '../TypingIndicator';
12-
import FrozenNotification from '../FrozenNotification';
13-
import UnreadCount from '../UnreadCount';
1412
import MessageInputWrapper from '../MessageInput';
1513
import { RenderCustomSeparatorProps, RenderMessageProps } from '../../../../types';
16-
import * as messageActionTypes from '../../context/dux/actionTypes';
1714

1815
export interface ChannelUIProps {
1916
isLoading?: boolean;
@@ -23,9 +20,9 @@ export interface ChannelUIProps {
2320
renderChannelHeader?: () => React.ReactElement;
2421
renderMessage?: (props: RenderMessageProps) => React.ReactElement;
2522
renderMessageInput?: () => React.ReactElement;
26-
renderFileUploadIcon?: () => React.ReactElement;
27-
renderVoiceMessageIcon?: () => React.ReactElement;
28-
renderSendMessageIcon?: () => React.ReactElement;
23+
renderFileUploadIcon?: () => React.ReactElement;
24+
renderVoiceMessageIcon?: () => React.ReactElement;
25+
renderSendMessageIcon?: () => React.ReactElement;
2926
renderTypingIndicator?: () => React.ReactElement;
3027
renderCustomSeparator?: (props: RenderCustomSeparatorProps) => React.ReactElement;
3128
}
@@ -45,28 +42,9 @@ const ChannelUI: React.FC<ChannelUIProps> = ({
4542
renderSendMessageIcon,
4643
}: ChannelUIProps) => {
4744
const {
48-
currentGroupChannel,
4945
channelUrl,
5046
isInvalid,
51-
unreadSince,
52-
loading,
53-
setInitialTimeStamp,
54-
setAnimatedMessageId,
55-
setHighLightedMessageId,
56-
scrollRef,
57-
messagesDispatcher,
58-
disableMarkAsRead,
5947
} = useChannelContext();
60-
const [unreadCount, setUnreadCount] = useState(0);
61-
useEffect(() => {
62-
// simple debounce to avoid flicker of UnreadCount badge
63-
const handler = setTimeout(() => {
64-
setUnreadCount(currentGroupChannel?.unreadMessageCount);
65-
}, 1000);
66-
return () => {
67-
clearTimeout(handler);
68-
}
69-
}, [currentGroupChannel?.unreadMessageCount]);
7048

7149
const globalStore = useSendbirdStateContext();
7250
const sdkError = globalStore?.stores?.sdkStore?.error;
@@ -122,62 +100,16 @@ const ChannelUI: React.FC<ChannelUIProps> = ({
122100
}
123101
return (
124102
<div className='sendbird-conversation'>
125-
{
126-
renderChannelHeader?.() || (
127-
<ChannelHeader />
128-
)
129-
}
130-
{
131-
currentGroupChannel?.isFrozen && (
132-
<FrozenNotification />
133-
)
134-
}
135-
{
136-
unreadCount > 0 && (
137-
<UnreadCount
138-
count={unreadCount}
139-
time={unreadSince}
140-
onClick={() => {
141-
setUnreadCount(0);
142-
if (scrollRef?.current?.scrollTop) {
143-
scrollRef.current.scrollTop = scrollRef?.current?.scrollHeight - scrollRef?.current?.offsetHeight;
144-
}
145-
if (!disableMarkAsRead) {
146-
try {
147-
currentGroupChannel?.markAsRead();
148-
} catch {
149-
//
150-
}
151-
messagesDispatcher({
152-
type: messageActionTypes.MARK_AS_READ,
153-
payload: { channel: currentGroupChannel },
154-
});
155-
}
156-
setInitialTimeStamp(null);
157-
setAnimatedMessageId(null);
158-
setHighLightedMessageId(null);
159-
}}
160-
/>
161-
)
162-
}
163-
{
164-
loading
165-
? (
166-
<div className="sendbird-conversation">
167-
{
168-
renderPlaceholderLoader?.() || (
169-
<PlaceHolder type={PlaceHolderTypes.LOADING} />
170-
)
171-
}
172-
</div>
173-
) : (
174-
<MessageList
175-
renderMessage={renderMessage}
176-
renderPlaceholderEmpty={renderPlaceholderEmpty}
177-
renderCustomSeparator={renderCustomSeparator}
178-
/>
179-
)
180-
}
103+
{renderChannelHeader?.() || (
104+
<ChannelHeader className="sendbird-conversation__channel-header" />
105+
)}
106+
<MessageList
107+
className="sendbird-conversation__message-list"
108+
renderMessage={renderMessage}
109+
renderPlaceholderEmpty={renderPlaceholderEmpty}
110+
renderCustomSeparator={renderCustomSeparator}
111+
renderPlaceholderLoader={renderPlaceholderLoader}
112+
/>
181113
<div className="sendbird-conversation__footer">
182114
{
183115
renderMessageInput?.() || (

src/smart-components/Channel/components/FrozenNotification/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@ import './frozen-notification.scss';
55
import { LocalizationContext } from '../../../../lib/LocalizationContext';
66
import Label, { LabelTypography } from '../../../../ui/Label';
77

8-
const FrozenNotification = (): JSX.Element => {
8+
interface FrozenNotificationProps {
9+
className?: string;
10+
}
11+
12+
const FrozenNotification = ({
13+
className = '',
14+
}: FrozenNotificationProps): React.ReactElement => {
915
const { stringSet } = useContext(LocalizationContext);
1016
return (
11-
<div className="sendbird-notification sendbird-notification--frozen">
17+
<div className={`sendbird-notification sendbird-notification--frozen ${className}`}>
1218
<Label
1319
className="sendbird-notification__text"
1420
type={LabelTypography.CAPTION_2}

src/smart-components/Channel/components/Message/index.tsx

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import React, {
88
import type { FileMessage } from '@sendbird/chat/message';
99
import format from 'date-fns/format';
1010

11+
import useDidMountEffect from '../../../../utils/useDidMountEffect';
1112
import SuggestedMentionList from '../SuggestedMentionList';
1213
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
1314
import { useChannelContext } from '../../context/ChannelProvider';
@@ -39,19 +40,17 @@ type MessageUIProps = {
3940
};
4041

4142
// todo: Refactor this component, is too complex now
42-
const Message = (props: MessageUIProps): React.FC<MessageUIProps> | React.ReactElement => {
43-
const {
44-
message,
45-
hasSeparator,
46-
chainTop,
47-
chainBottom,
48-
handleScroll,
49-
renderCustomSeparator,
50-
renderEditInput,
51-
renderMessage,
52-
renderMessageContent,
53-
} = props;
54-
43+
const Message = ({
44+
message,
45+
hasSeparator,
46+
chainTop,
47+
chainBottom,
48+
handleScroll,
49+
renderCustomSeparator,
50+
renderEditInput,
51+
renderMessage,
52+
renderMessageContent,
53+
}: MessageUIProps): React.ReactElement => {
5554
const { dateLocale } = useLocalization();
5655
const globalStore = useSendbirdStateContext();
5756
const {
@@ -130,8 +129,10 @@ const Message = (props: MessageUIProps): React.FC<MessageUIProps> | React.ReactE
130129
}));
131130
}, [mentionedUserIds]);
132131

133-
useLayoutEffect(() => {
134-
handleScroll?.();
132+
useDidMountEffect(() => {
133+
if (currentGroupChannel?.lastMessage?.messageId === message?.messageId) {
134+
handleScroll?.();
135+
}
135136
}, [showEdit, message?.reactions?.length]);
136137

137138
useLayoutEffect(() => {

0 commit comments

Comments
 (0)