Skip to content

Commit 4611fe9

Browse files
git-babelHoonBaek
authored andcommitted
[CLNP-5046] Migrate ThreadProvider to the new state management pattern (#1250)
### Overview This PR migrate ThreadProvider and related files to the new state management pattern. ### Changelog * `ThreadProvider` is migrated, and `useThread()` hook is introduced. * Removed `ThreadDispatcher` usages in ThreadProvider; it is replaced with the new state-action pattern of `useThread()`. * `PubSub` of `config` still remains. It is out of scope of this PR. ### Remaining tasks * Add unit tests and integration tests. ### FurtherConcern * Handling hook * The previous `ThreadProvider` contained several custom hooks. Those hooks retrieved state and actions through `useThreadContext()` * Due to that, replacing `useThreadContext()` to new `useThread()` faced a problem. Those hooks �conatin `useThread()`, `useThread()` contains the hooks. So it makes cycle. * For now, I moved all functionality of the hooks to the `useThread()`, but it looks wrong. Any good way to handle this?
1 parent 3f59614 commit 4611fe9

29 files changed

+1252
-1076
lines changed

src/modules/Thread/components/ParentMessageInfo/ParentMessageInfoItem.tsx

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import Icon, { IconTypes, IconColors } from '../../../../ui/Icon';
2828
import TextButton from '../../../../ui/TextButton';
2929
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
3030
import EmojiReactions from '../../../../ui/EmojiReactions';
31-
import { useThreadContext } from '../../context/ThreadProvider';
3231
import VoiceMessageItemBody from '../../../../ui/VoiceMessageItemBody';
3332
import TextFragment from '../../../Message/components/TextFragment';
3433
import { tokenizeMessage } from '../../../Message/utils/tokens/tokenize';
@@ -39,6 +38,7 @@ import { useFileInfoListWithUploaded } from '../../../Channel/context/hooks/useF
3938
import { Colors } from '../../../../utils/color';
4039
import type { OnBeforeDownloadFileMessageType } from '../../../GroupChannel/context/types';
4140
import { openURL } from '../../../../utils/utils';
41+
import useThread from '../../context/useThread';
4242

4343
export interface ParentMessageInfoItemProps {
4444
className?: string;
@@ -59,12 +59,16 @@ export default function ParentMessageInfoItem({
5959
const currentUserId = stores?.userStore?.user?.userId;
6060
const { stringSet } = useLocalization();
6161
const {
62-
currentChannel,
63-
emojiContainer,
64-
nicknamesMap,
65-
toggleReaction,
66-
filterEmojiCategoryIds,
67-
} = useThreadContext();
62+
state: {
63+
currentChannel,
64+
emojiContainer,
65+
nicknamesMap,
66+
filterEmojiCategoryIds,
67+
},
68+
actions: {
69+
toggleReaction,
70+
},
71+
} = useThread();
6872
const { isMobile } = useMediaQueryContext();
6973

7074
const isReactionEnabled = config.groupChannel.enableReactions;

src/modules/Thread/components/ParentMessageInfo/index.tsx

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { getSenderName, SendableMessageType } from '../../../../utils';
1010
import { getIsReactionEnabled } from '../../../../utils/getIsReactionEnabled';
1111
import { useLocalization } from '../../../../lib/LocalizationContext';
1212
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
13-
import { useThreadContext } from '../../context/ThreadProvider';
1413
import { useUserProfileContext } from '../../../../lib/UserProfileContext';
1514
import SuggestedMentionList from '../SuggestedMentionList';
1615

@@ -32,6 +31,7 @@ import { getCaseResolvedReplyType } from '../../../../lib/utils/resolvedReplyTyp
3231
import { classnames } from '../../../../utils/utils';
3332
import { MessageMenu, MessageMenuProps } from '../../../../ui/MessageMenu';
3433
import useElementObserver from '../../../../hooks/useElementObserver';
34+
import useThread from '../../context/useThread';
3535

3636
export interface ParentMessageInfoProps {
3737
className?: string;
@@ -49,20 +49,24 @@ export default function ParentMessageInfo({
4949
const userId = stores.userStore.user?.userId ?? '';
5050
const { dateLocale, stringSet } = useLocalization();
5151
const {
52-
currentChannel,
53-
parentMessage,
54-
allThreadMessages,
55-
emojiContainer,
56-
toggleReaction,
57-
updateMessage,
58-
deleteMessage,
59-
onMoveToParentMessage,
60-
onHeaderActionClick,
61-
isMuted,
62-
isChannelFrozen,
63-
onBeforeDownloadFileMessage,
64-
filterEmojiCategoryIds,
65-
} = useThreadContext();
52+
state: {
53+
currentChannel,
54+
parentMessage,
55+
allThreadMessages,
56+
emojiContainer,
57+
onMoveToParentMessage,
58+
onHeaderActionClick,
59+
isMuted,
60+
isChannelFrozen,
61+
onBeforeDownloadFileMessage,
62+
filterEmojiCategoryIds,
63+
},
64+
actions: {
65+
toggleReaction,
66+
updateMessage,
67+
deleteMessage,
68+
},
69+
} = useThread();
6670
const { isMobile } = useMediaQueryContext();
6771

6872
const isMenuMounted = useElementObserver(

src/modules/Thread/components/RemoveMessageModal.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import React, { useContext } from 'react';
33
import Modal from '../../../ui/Modal';
44
import { ButtonTypes } from '../../../ui/Button';
55
import { LocalizationContext } from '../../../lib/LocalizationContext';
6-
import { useThreadContext } from '../context/ThreadProvider';
76
import { SendableMessageType } from '../../../utils';
87
import { getModalDeleteMessageTitle } from '../../../ui/Label/stringFormatterUtils';
8+
import useThread from '../context/useThread';
99

1010
export interface RemoveMessageProps {
1111
onCancel: () => void; // rename to onClose
@@ -21,8 +21,10 @@ const RemoveMessage: React.FC<RemoveMessageProps> = (props: RemoveMessageProps)
2121
} = props;
2222
const { stringSet } = useContext(LocalizationContext);
2323
const {
24-
deleteMessage,
25-
} = useThreadContext();
24+
actions: {
25+
deleteMessage,
26+
},
27+
} = useThread();
2628
return (
2729
<Modal
2830
type={ButtonTypes.DANGER}

src/modules/Thread/components/SuggestedMentionList.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
import React from 'react';
22
import type { SuggestedMentionListViewProps } from '../../GroupChannel/components/SuggestedMentionList/SuggestedMentionListView';
33
import SuggestedMentionListView from '../../GroupChannel/components/SuggestedMentionList/SuggestedMentionListView';
4-
import { useThreadContext } from '../context/ThreadProvider';
4+
import useThread from '../context/useThread';
55

66
export type SuggestedMentionListProps = Omit<SuggestedMentionListViewProps, 'currentChannel'>;
77

88
export const SuggestedMentionList = (props: SuggestedMentionListProps) => {
9-
const { currentChannel } = useThreadContext();
9+
const {
10+
state: {
11+
currentChannel,
12+
},
13+
} = useThread();
1014
return (
1115
<SuggestedMentionListView
1216
{...props}

src/modules/Thread/components/ThreadList/ThreadListItem.tsx

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import DateSeparator from '../../../../ui/DateSeparator';
77
import Label, { LabelTypography, LabelColors } from '../../../../ui/Label';
88
import RemoveMessage from '../RemoveMessageModal';
99
import FileViewer from '../../../../ui/FileViewer';
10-
import { useThreadContext } from '../../context/ThreadProvider';
1110
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
1211
import SuggestedMentionList from '../SuggestedMentionList';
1312
import MessageInput from '../../../../ui/MessageInput';
@@ -22,6 +21,7 @@ import { User } from '@sendbird/chat';
2221
import { getCaseResolvedReplyType } from '../../../../lib/utils/resolvedReplyType';
2322
import { classnames } from '../../../../utils/utils';
2423
import { MessageComponentRenderers } from '../../../../ui/MessageContent';
24+
import useThread from '../../context/useThread';
2525

2626
export interface ThreadListItemProps extends MessageComponentRenderers {
2727
className?: string;
@@ -47,21 +47,24 @@ export default function ThreadListItem(props: ThreadListItemProps): React.ReactE
4747
const { isOnline, userMention, logger, groupChannel } = config;
4848
const userId = stores?.userStore?.user?.userId;
4949
const { dateLocale, stringSet } = useLocalization();
50-
const threadContext = useThreadContext?.();
5150
const {
52-
currentChannel,
53-
nicknamesMap,
54-
emojiContainer,
55-
toggleReaction,
56-
threadListState,
57-
updateMessage,
58-
resendMessage,
59-
deleteMessage,
60-
isMuted,
61-
isChannelFrozen,
62-
onBeforeDownloadFileMessage,
63-
} = threadContext;
64-
const openingMessage = threadContext?.message;
51+
state: {
52+
message: openingMessage,
53+
currentChannel,
54+
nicknamesMap,
55+
emojiContainer,
56+
threadListState,
57+
isMuted,
58+
isChannelFrozen,
59+
onBeforeDownloadFileMessage,
60+
},
61+
actions: {
62+
toggleReaction,
63+
updateMessage,
64+
resendMessage,
65+
deleteMessage,
66+
},
67+
} = useThread();
6568

6669
const [showEdit, setShowEdit] = useState(false);
6770
const [showRemove, setShowRemove] = useState(false);

src/modules/Thread/components/ThreadList/ThreadListItemContent.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
2727
import { ThreadMessageKind } from '../../../../ui/MultipleFilesMessageItemBody';
2828
import { useThreadMessageKindKeySelector } from '../../../Channel/context/hooks/useThreadMessageKindKeySelector';
2929
import { useFileInfoListWithUploaded } from '../../../Channel/context/hooks/useFileInfoListWithUploaded';
30-
import { useThreadContext } from '../../context/ThreadProvider';
3130
import { classnames, deleteNullish } from '../../../../utils/utils';
3231
import { MessageMenu, MessageMenuProps } from '../../../../ui/MessageMenu';
3332
import useElementObserver from '../../../../hooks/useElementObserver';
@@ -36,6 +35,7 @@ import MessageProfile, { MessageProfileProps } from '../../../../ui/MessageConte
3635
import MessageBody, { CustomSubcomponentsProps, MessageBodyProps } from '../../../../ui/MessageContent/MessageBody';
3736
import { MessageHeaderProps, MessageHeader } from '../../../../ui/MessageContent/MessageHeader';
3837
import { MobileBottomSheetProps } from '../../../../ui/MobileMenu/types';
38+
import useThread from '../../context/useThread';
3939

4040
export interface ThreadListItemContentProps extends MessageComponentRenderers {
4141
className?: string;
@@ -109,7 +109,15 @@ export default function ThreadListItemContent(props: ThreadListItemContentProps)
109109
document.getElementById(EMOJI_MENU_ROOT_ID),
110110
],
111111
);
112-
const { deleteMessage, onBeforeDownloadFileMessage, filterEmojiCategoryIds } = useThreadContext();
112+
const {
113+
state: {
114+
onBeforeDownloadFileMessage,
115+
filterEmojiCategoryIds,
116+
},
117+
actions: {
118+
deleteMessage,
119+
},
120+
} = useThread();
113121

114122
const isByMe = (userId === (message as SendableMessageType)?.sender?.userId)
115123
|| ((message as SendableMessageType)?.sendingStatus === 'pending')
@@ -120,7 +128,7 @@ export default function ThreadListItemContent(props: ThreadListItemContentProps)
120128
);
121129
const supposedHoverClassName = isMenuMounted ? 'sendbird-mouse-hover' : '';
122130
const isReactionEnabledInChannel = isReactionEnabled && !channel?.isEphemeral;
123-
const isOgMessageEnabledInGroupChannel = channel.isGroupChannel() && config.groupChannel.enableOgtag;
131+
const isOgMessageEnabledInGroupChannel = channel?.isGroupChannel() && config.groupChannel.enableOgtag;
124132

125133
// Mobile
126134
const mobileMenuRef = useRef(null);

src/modules/Thread/components/ThreadList/index.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import './index.scss';
55

66
import type { SendableMessageType } from '../../../../utils';
77
import ThreadListItem, { ThreadListItemProps } from './ThreadListItem';
8-
import { useThreadContext } from '../../context/ThreadProvider';
98
import { compareMessagesForGrouping } from '../../../../utils/messages';
109
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
1110
import { isSameDay } from 'date-fns';
1211
import { MessageProvider } from '../../../Message/context/MessageProvider';
1312
import { getCaseResolvedReplyType } from '../../../../lib/utils/resolvedReplyType';
13+
import useThread from '../../context/useThread';
1414

1515
export interface ThreadListProps {
1616
className?: string;
@@ -30,10 +30,12 @@ export default function ThreadList({
3030
const { config } = useSendbirdStateContext();
3131
const { userId } = config;
3232
const {
33-
currentChannel,
34-
allThreadMessages,
35-
localThreadMessages,
36-
} = useThreadContext();
33+
state: {
34+
currentChannel,
35+
allThreadMessages,
36+
localThreadMessages,
37+
},
38+
} = useThread();
3739

3840
return (
3941
<div className={`sendbird-thread-list ${className}`}>

src/modules/Thread/components/ThreadMessageInput/index.tsx

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import './index.scss';
55

66
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
77
import { useMediaQueryContext } from '../../../../lib/MediaQueryContext';
8-
import { useThreadContext } from '../../context/ThreadProvider';
98
import { useLocalization } from '../../../../lib/LocalizationContext';
109

1110
import MessageInput from '../../../../ui/MessageInput';
@@ -19,6 +18,7 @@ import { useHandleUploadFiles } from '../../../Channel/context/hooks/useHandleUp
1918
import { isDisabledBecauseFrozen, isDisabledBecauseMuted } from '../../../Channel/context/utils';
2019
import { User } from '@sendbird/chat';
2120
import { classnames } from '../../../../utils/utils';
21+
import useThread from '../../context/useThread';
2222

2323
export interface ThreadMessageInputProps {
2424
className?: string;
@@ -45,23 +45,27 @@ const ThreadMessageInput = (
4545
const { isMobile } = useMediaQueryContext();
4646
const { stringSet } = useLocalization();
4747
const { isOnline, userMention, logger, groupChannel } = config;
48-
const threadContext = useThreadContext();
48+
const threadContext = useThread();
4949
const {
50-
currentChannel,
51-
parentMessage,
52-
sendMessage,
53-
sendFileMessage,
54-
sendVoiceMessage,
55-
sendMultipleFilesMessage,
56-
isMuted,
57-
isChannelFrozen,
58-
allThreadMessages,
50+
state: {
51+
currentChannel,
52+
parentMessage,
53+
isMuted,
54+
isChannelFrozen,
55+
allThreadMessages,
56+
},
57+
actions: {
58+
sendMessage,
59+
sendFileMessage,
60+
sendVoiceMessage,
61+
sendMultipleFilesMessage,
62+
},
5963
} = threadContext;
6064
const messageInputRef = useRef();
6165

6266
const isMentionEnabled = groupChannel.enableMention;
6367
const isVoiceMessageEnabled = groupChannel.enableVoiceMessage;
64-
const isMultipleFilesMessageEnabled = threadContext.isMultipleFilesMessageEnabled ?? config.isMultipleFilesMessageEnabled;
68+
const isMultipleFilesMessageEnabled = threadContext.state.isMultipleFilesMessageEnabled ?? config.isMultipleFilesMessageEnabled;
6569

6670
const threadInputDisabled = props.disabled
6771
|| !isOnline

src/modules/Thread/components/ThreadUI/index.tsx

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import './index.scss';
55
import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext';
66
import { useLocalization } from '../../../../lib/LocalizationContext';
77
import { getChannelTitle } from '../../../GroupChannel/components/GroupChannelHeader/utils';
8-
import { useThreadContext } from '../../context/ThreadProvider';
98
import { ParentMessageStateTypes, ThreadListStateTypes } from '../../types';
109
import ParentMessageInfo from '../ParentMessageInfo';
1110
import ThreadHeader from '../ThreadHeader';
@@ -19,6 +18,7 @@ import { isAboutSame } from '../../context/utils';
1918
import { MessageProvider } from '../../../Message/context/MessageProvider';
2019
import { SendableMessageType, getHTMLTextDirection } from '../../../../utils';
2120
import { classnames } from '../../../../utils/utils';
21+
import useThread from '../../context/useThread';
2222

2323
export interface ThreadUIProps {
2424
renderHeader?: () => React.ReactElement;
@@ -59,18 +59,22 @@ const ThreadUI: React.FC<ThreadUIProps> = ({
5959
stringSet,
6060
} = useLocalization();
6161
const {
62-
currentChannel,
63-
allThreadMessages,
64-
parentMessage,
65-
parentMessageState,
66-
threadListState,
67-
hasMorePrev,
68-
hasMoreNext,
69-
fetchPrevThreads,
70-
fetchNextThreads,
71-
onHeaderActionClick,
72-
onMoveToParentMessage,
73-
} = useThreadContext();
62+
state: {
63+
currentChannel,
64+
allThreadMessages,
65+
parentMessage,
66+
parentMessageState,
67+
threadListState,
68+
hasMorePrev,
69+
hasMoreNext,
70+
onHeaderActionClick,
71+
onMoveToParentMessage,
72+
},
73+
actions: {
74+
fetchPrevThreads,
75+
fetchNextThreads,
76+
},
77+
} = useThread();
7478
const replyCount = allThreadMessages.length;
7579
const isByMe = currentUserId === parentMessage?.sender?.userId;
7680

0 commit comments

Comments
 (0)