diff --git a/src/modules/Channel/context/hooks/useSendFileMessageCallback.ts b/src/modules/Channel/context/hooks/useSendFileMessageCallback.ts index 60e8becc2..8fe8368d6 100644 --- a/src/modules/Channel/context/hooks/useSendFileMessageCallback.ts +++ b/src/modules/Channel/context/hooks/useSendFileMessageCallback.ts @@ -47,11 +47,16 @@ export default function useSendFileMessageCallback( pubSub.publish(topics.SEND_MESSAGE_START, { /* pubSub is used instead of messagesDispatcher to avoid redundantly calling `messageActionTypes.SEND_MESSAGE_START` */ + // TODO: remove data pollution message: { ...pendingMessage, url: URL.createObjectURL(compressedFile), // pending thumbnail message seems to be failed requestState: 'pending', + isUserMessage: pendingMessage.isUserMessage, + isFileMessage: pendingMessage.isFileMessage, + isAdminMessage: pendingMessage.isAdminMessage, + isMultipleFilesMessage: pendingMessage.isMultipleFilesMessage, } as unknown as FileMessage, channel: currentGroupChannel, publishingModules: [PublishingModuleType.CHANNEL], diff --git a/src/modules/OpenChannel/components/OpenChannelMessage/index.tsx b/src/modules/OpenChannel/components/OpenChannelMessage/index.tsx index 85f33bbef..ef9986abd 100644 --- a/src/modules/OpenChannel/components/OpenChannelMessage/index.tsx +++ b/src/modules/OpenChannel/components/OpenChannelMessage/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef, ReactElement, useMemo } from 'react'; +import React, { useState, useRef, ReactElement } from 'react'; import { AdminMessage, FileMessage, UserMessage } from '@sendbird/chat/message'; import { User } from '@sendbird/chat'; import format from 'date-fns/format'; @@ -24,9 +24,7 @@ import { useLocalization } from '../../../../lib/LocalizationContext'; import { CoreMessageType, SendableMessageType } from '../../../../utils'; export type OpenChannelMessageProps = { - renderMessage?: ( - props: RenderMessageProps - ) => React.ElementType; + renderMessage?: (props: RenderMessageProps) => React.ReactElement; message: CoreMessageType; chainTop?: boolean; chainBottom?: boolean; @@ -34,7 +32,7 @@ export type OpenChannelMessageProps = { editDisabled?: boolean; }; -export default function MessagOpenChannelMessageeHoc( +export default function OpenChannelMessage( props: OpenChannelMessageProps, ): ReactElement { const { message, chainTop, chainBottom, hasSeparator, renderMessage } = props; @@ -57,13 +55,6 @@ export default function MessagOpenChannelMessageeHoc( sender = (message as SendableMessageType)?.sender; } - const RenderedMessage = useMemo( - () => (props: RenderMessageProps) => { - return <>{renderMessage ? renderMessage(props) : null}; - }, - [message, renderMessage], - ); - const [showEdit, setShowEdit] = useState(false); const [showRemove, setShowRemove] = useState(false); const [showFileViewer, setShowFileViewer] = useState(false); @@ -80,14 +71,10 @@ export default function MessagOpenChannelMessageeHoc( === SendingMessageStatus.FAILED; } - if (renderMessage && RenderedMessage) { + if (renderMessage) { return (
- + {renderMessage({ message, chainTop, chainBottom })}
); } diff --git a/src/modules/OpenChannel/components/OpenChannelMessageList/index.tsx b/src/modules/OpenChannel/components/OpenChannelMessageList/index.tsx index c8a10c63b..911a708fc 100644 --- a/src/modules/OpenChannel/components/OpenChannelMessageList/index.tsx +++ b/src/modules/OpenChannel/components/OpenChannelMessageList/index.tsx @@ -15,15 +15,15 @@ import useSendbirdStateContext from '../../../../hooks/useSendbirdStateContext'; import { useHandleOnScrollCallback } from '../../../../hooks/useHandleOnScrollCallback'; import { compareMessagesForGrouping } from '../../../../utils/messages'; -export type OpenchannelMessageListProps = { - renderMessage?: (props: RenderMessageProps) => React.ElementType; +export type OpenChannelMessageListProps = { + renderMessage?: (props: RenderMessageProps) => React.ReactElement; renderPlaceHolderEmptyList?: () => React.ReactElement; }; -function OpenchannelMessageList( - props: OpenchannelMessageListProps, - ref: React.RefObject, -): ReactElement { +/** @deprecated * */ +export type OpenchannelMessageListProps = OpenChannelMessageListProps; + +function OpenChannelMessageList(props: OpenChannelMessageListProps, ref: React.RefObject): ReactElement { const { isMessageGroupingEnabled = true, allMessages, @@ -129,4 +129,4 @@ function OpenchannelMessageList( ); } -export default React.forwardRef(OpenchannelMessageList); +export default React.forwardRef(OpenChannelMessageList); diff --git a/src/modules/OpenChannel/components/OpenChannelUI/index.tsx b/src/modules/OpenChannel/components/OpenChannelUI/index.tsx index 940d2f083..6e227e2f0 100644 --- a/src/modules/OpenChannel/components/OpenChannelUI/index.tsx +++ b/src/modules/OpenChannel/components/OpenChannelUI/index.tsx @@ -12,12 +12,15 @@ import OpenChannelMessageList from '../OpenChannelMessageList'; import { RenderMessageProps } from '../../../../types'; export interface OpenChannelUIProps { - renderMessage?: (props: RenderMessageProps) => React.ElementType; + renderMessage?: (props: RenderMessageProps) => React.ReactElement; renderHeader?: () => React.ReactElement; - renderInput?: () => React.ReactElement; + renderMessageInput?: () => React.ReactElement; renderPlaceHolderEmptyList?: () => React.ReactElement; renderPlaceHolderError?: () => React.ReactElement; renderPlaceHolderLoading?: () => React.ReactElement; + + /** @deprecated Please use renderMessageInput instead * */ + renderInput?: () => React.ReactElement; } const COMPONENT_CLASS_NAME = 'sendbird-openchannel-conversation'; @@ -25,10 +28,11 @@ const COMPONENT_CLASS_NAME = 'sendbird-openchannel-conversation'; const OpenChannelUI: React.FC = ({ renderMessage, renderHeader, - renderInput, renderPlaceHolderEmptyList, renderPlaceHolderError, renderPlaceHolderLoading, + renderMessageInput, + renderInput, }: OpenChannelUIProps) => { const { currentOpenChannel, @@ -58,28 +62,18 @@ const OpenChannelUI: React.FC = ({ ); } + const renderInputComponent = renderMessageInput || renderInput; + return (
- { - renderHeader?.() || ( - - ) - } - { - currentOpenChannel?.isFrozen && ( - - ) - } + {renderHeader?.() || } + {currentOpenChannel?.isFrozen && } - { - renderInput?.() || ( - - ) - } + {renderInputComponent?.() || }
); }; diff --git a/src/modules/OpenChannel/context/hooks/useFileUploadCallback.tsx b/src/modules/OpenChannel/context/hooks/useFileUploadCallback.tsx index 9f162f361..5b020c097 100644 --- a/src/modules/OpenChannel/context/hooks/useFileUploadCallback.tsx +++ b/src/modules/OpenChannel/context/hooks/useFileUploadCallback.tsx @@ -104,11 +104,16 @@ function useFileUploadCallback({ messagesDispatcher({ type: messageActionTypes.SENDING_MESSAGE_START, payload: { + // TODO: remove data pollution message: { ...pendingMessage, url: URL.createObjectURL(file), // pending thumbnail message seems to be failed requestState: 'pending', + isUserMessage: pendingMessage.isUserMessage, + isFileMessage: pendingMessage.isFileMessage, + isAdminMessage: pendingMessage.isAdminMessage, + isMultipleFilesMessage: pendingMessage.isMultipleFilesMessage, }, channel: currentOpenChannel, }, diff --git a/src/modules/OpenChannel/index.tsx b/src/modules/OpenChannel/index.tsx index 94a1ff446..170b1a680 100644 --- a/src/modules/OpenChannel/index.tsx +++ b/src/modules/OpenChannel/index.tsx @@ -23,6 +23,7 @@ const OpenChannel: React.FC = (props: OpenChannelProps) => { renderMessage={props?.renderMessage} renderHeader={props?.renderHeader} renderInput={props?.renderInput} + renderMessageInput={props?.renderMessageInput} renderPlaceHolderEmptyList={props?.renderPlaceHolderEmptyList} renderPlaceHolderError={props?.renderPlaceHolderError} renderPlaceHolderLoading={props?.renderPlaceHolderLoading} diff --git a/src/modules/Thread/context/hooks/useSendFileMessage.ts b/src/modules/Thread/context/hooks/useSendFileMessage.ts index 23ddecb6f..b243cbd38 100644 --- a/src/modules/Thread/context/hooks/useSendFileMessage.ts +++ b/src/modules/Thread/context/hooks/useSendFileMessage.ts @@ -56,11 +56,16 @@ export default function useSendFileMessageCallback({ payload: { /* pubSub is used instead of messagesDispatcher to avoid redundantly calling `messageActionTypes.SEND_MESSAGE_START` */ + // TODO: remove data pollution message: { ...pendingMessage, url: URL.createObjectURL(file), // pending thumbnail message seems to be failed requestState: 'pending', + isUserMessage: pendingMessage.isUserMessage, + isFileMessage: pendingMessage.isFileMessage, + isAdminMessage: pendingMessage.isAdminMessage, + isMultipleFilesMessage: pendingMessage.isMultipleFilesMessage, }, }, }); diff --git a/src/modules/Thread/context/hooks/useSendVoiceMessageCallback.ts b/src/modules/Thread/context/hooks/useSendVoiceMessageCallback.ts index 59d372fd4..8cfbd3e82 100644 --- a/src/modules/Thread/context/hooks/useSendVoiceMessageCallback.ts +++ b/src/modules/Thread/context/hooks/useSendVoiceMessageCallback.ts @@ -73,11 +73,16 @@ export const useSendVoiceMessageCallback = ({ payload: { /* pubSub is used instead of messagesDispatcher to avoid redundantly calling `messageActionTypes.SEND_MESSAGE_START` */ + // TODO: remove data pollution message: { ...pendingMessage, url: URL.createObjectURL(file), // pending thumbnail message seems to be failed requestState: 'pending', + isUserMessage: pendingMessage.isUserMessage, + isFileMessage: pendingMessage.isFileMessage, + isAdminMessage: pendingMessage.isAdminMessage, + isMultipleFilesMessage: pendingMessage.isMultipleFilesMessage, }, }, }); diff --git a/src/ui/MessageContent/index.tsx b/src/ui/MessageContent/index.tsx index 8c13bd790..05dc37ee2 100644 --- a/src/ui/MessageContent/index.tsx +++ b/src/ui/MessageContent/index.tsx @@ -8,7 +8,7 @@ import { MessageEmojiMenu, MessageEmojiMenuProps } from '../MessageItemReactionM import Label, { LabelColors, LabelTypography } from '../Label'; import EmojiReactions, { EmojiReactionsProps } from '../EmojiReactions'; -import ClientAdminMessage from '../AdminMessage'; +import AdminMessage from '../AdminMessage'; import QuoteMessage from '../QuoteMessage'; import type { OnBeforeDownloadFileMessageType } from '../../modules/GroupChannel/context/GroupChannelProvider'; @@ -16,8 +16,9 @@ import { CoreMessageType, getClassName, getMessageContentMiddleClassNameByContainerType, + isAdminMessage, isMultipleFilesMessage, - isOGMessage, + isOGMessage, isSendableMessage, isTemplateMessage, isThumbnailMessage, SendableMessageType, @@ -27,7 +28,7 @@ import { LocalizationContext, useLocalization } from '../../lib/LocalizationCont import useSendbirdStateContext from '../../hooks/useSendbirdStateContext'; import { GroupChannel } from '@sendbird/chat/groupChannel'; import { EmojiContainer } from '@sendbird/chat'; -import { AdminMessage, Feedback, FeedbackRating, FileMessage, UserMessage } from '@sendbird/chat/message'; +import { Feedback, FeedbackRating } from '@sendbird/chat/message'; import useLongPress from '../../hooks/useLongPress'; import MobileMenu from '../MobileMenu'; import { useMediaQueryContext } from '../../lib/MediaQueryContext'; @@ -258,8 +259,8 @@ export default function MessageContent(props: MessageContentProps): ReactElement shouldPreventDefault: false, }); - if (message?.isAdminMessage?.() || message?.messageType === 'admin') { - return (); + if (isAdminMessage(message)) { + return (); } return ( @@ -287,16 +288,16 @@ export default function MessageContent(props: MessageContentProps): ReactElement {showOutgoingMenu && (
{renderMessageMenu({ - channel: channel, - message: message as SendableMessageType, - isByMe: isByMe, - replyType: replyType, - disabled: disabled, - showEdit: showEdit, - showRemove: showRemove, - resendMessage: resendMessage, - setQuoteMessage: setQuoteMessage, - setSupposedHover: setSupposedHover, + channel, + message, + isByMe, + replyType, + disabled, + showEdit, + showRemove, + resendMessage, + setQuoteMessage, + setSupposedHover, onReplyInThread: ({ message }) => { if (threadReplySelectType === ThreadReplySelectType.THREAD) { onReplyInThread({ message }); @@ -308,11 +309,11 @@ export default function MessageContent(props: MessageContentProps): ReactElement })} {isReactionEnabledInChannel && ( renderEmojiMenu({ - message: message as SendableMessageType, - userId: userId, - emojiContainer: emojiContainer, - toggleReaction: toggleReaction, - setSupposedHover: setSupposedHover, + message, + userId, + emojiContainer, + toggleReaction, + setSupposedHover, }) )}
@@ -338,13 +339,13 @@ export default function MessageContent(props: MessageContentProps): ReactElement className={getClassName(['sendbird-message-content__middle__quote-message', isByMe ? 'outgoing' : 'incoming', useReplyingClassName])}> (message.parentMessage?.createdAt ?? 0)} onClick={() => { if (replyType === 'THREAD' && threadReplySelectType === ThreadReplySelectType.THREAD) { - onQuoteMessageClick?.({ message: message as SendableMessageType }); + onQuoteMessageClick?.({ message }); } if ( (replyType === 'QUOTE_REPLY' || (replyType === 'THREAD' && threadReplySelectType === ThreadReplySelectType.PARENT)) @@ -377,7 +378,7 @@ export default function MessageContent(props: MessageContentProps): ReactElement >
@@ -402,16 +403,16 @@ export default function MessageContent(props: MessageContentProps): ReactElement {(isReactionEnabledInChannel && message?.reactions?.length > 0) && (
{ renderEmojiReactions({ userId, - message: message as SendableMessageType, + message, channel, isByMe, emojiContainer, @@ -454,7 +455,7 @@ export default function MessageContent(props: MessageContentProps): ReactElement onReplyInThread?.({ message: message as SendableMessageType })} + onClick={() => onReplyInThread?.({ message })} ref={threadRepliesRef} /> )} @@ -526,17 +527,17 @@ export default function MessageContent(props: MessageContentProps): ReactElement {isReactionEnabledInChannel && ( renderEmojiMenu({ className: 'sendbird-message-content-menu__reaction-menu', - message: message as SendableMessageType, - userId: userId, - emojiContainer: emojiContainer, - toggleReaction: toggleReaction, - setSupposedHover: setSupposedHover, + message, + userId, + emojiContainer, + toggleReaction, + setSupposedHover, }) )} {renderMessageMenu({ className: 'sendbird-message-content-menu__normal-menu', channel, - message: message as SendableMessageType, + message, isByMe, replyType, disabled, @@ -558,9 +559,7 @@ export default function MessageContent(props: MessageContentProps): ReactElement )} { - showMenu && ( - message?.isUserMessage?.() || message?.isFileMessage?.() || message?.isMultipleFilesMessage?.() - ) && renderMobileMenuOnLongPress({ + showMenu && isSendableMessage(message) && renderMobileMenuOnLongPress({ parentRef: contentRef, channel, hideMenu: () => { setShowMenu(false); }, @@ -589,7 +588,7 @@ export default function MessageContent(props: MessageContentProps): ReactElement return null; } try { - const allowDownload = await onBeforeDownloadFileMessage({ message: message as FileMessage }); + const allowDownload = await onBeforeDownloadFileMessage({ message }); if (!allowDownload) { e.preventDefault(); logger?.info?.('MessageContent: Not allowed to download.'); diff --git a/src/ui/QuoteMessageInput/QuoteMessageThumbnail.tsx b/src/ui/QuoteMessageInput/QuoteMessageThumbnail.tsx index 189899093..6973d51a3 100644 --- a/src/ui/QuoteMessageInput/QuoteMessageThumbnail.tsx +++ b/src/ui/QuoteMessageInput/QuoteMessageThumbnail.tsx @@ -5,7 +5,8 @@ import Icon, { IconTypes, IconColors } from '../Icon'; import ImageRenderer from '../ImageRenderer'; import { isAudioMessage, - isFileMessage, isImageFileInfo, + isFileMessage, + isImageFileInfo, isImageMessage, isMultipleFilesMessage, isThumbnailMessage, @@ -22,30 +23,19 @@ interface Props { const componentClassname = 'sendbird-quote_message_input__avatar'; export default function QuoteMessageThumbnail({ message }: Props): ReactElement { - if (!isFileMessage(message) && !isMultipleFilesMessage(message) || isVoiceMessage(message as FileMessage)) { + if (!isFileMessage(message) && !isMultipleFilesMessage(message) || isVoiceMessage(message)) { return null; } let thumbnailUrl = getMessageFirstFileThumbnailUrl(message); if (!thumbnailUrl) { - if ( - message.isFileMessage?.() - && ( - isImageMessage(message) - || isVideoMessage(message) - ) - ) { + if (isImageMessage(message) || isVideoMessage(message)) { thumbnailUrl = getMessageFirstFileUrl(message); - } else if ( - message.isMultipleFilesMessage?.() - && ( - message.fileInfoList.length > 0 - && isImageFileInfo((message).fileInfoList[0]) - ) - ) { + } else if (isMultipleFilesMessage(message) && isImageFileInfo(message.fileInfoList?.[0])) { thumbnailUrl = message.fileInfoList[0].url; } } - if (isVideoMessage(message as FileMessage) && thumbnailUrl) { + + if (isVideoMessage(message) && thumbnailUrl) { return (