diff --git a/apps/testing/src/pages/PlaygroundPage.tsx b/apps/testing/src/pages/PlaygroundPage.tsx index 3ea64d6fa..13b7c1e31 100644 --- a/apps/testing/src/pages/PlaygroundPage.tsx +++ b/apps/testing/src/pages/PlaygroundPage.tsx @@ -4,5 +4,11 @@ import { defaultProps } from '../libs/const.ts'; export function PlaygroundPage() { const props = useConfigParams(defaultProps); - return ; + return ; } diff --git a/package.json b/package.json index 27ef0095d..bc83d6853 100644 --- a/package.json +++ b/package.json @@ -70,9 +70,9 @@ "react-dom": "^16.8.6 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "dependencies": { - "@sendbird/chat": "^4.18.0", - "@sendbird/react-uikit-message-template-view": "^0.0.10", - "@sendbird/uikit-tools": "^0.0.10", + "@sendbird/chat": "^4.20.0", + "@sendbird/react-uikit-message-template-view": "^0.0.18", + "@sendbird/uikit-tools": "^0.0.18", "css-vars-ponyfill": "^2.3.2", "date-fns": "^2.16.1", "dompurify": "^3.2.4" diff --git a/src/modules/Channel/context/hooks/useHandleChannelEvents.ts b/src/modules/Channel/context/hooks/useHandleChannelEvents.ts index 99df31eca..e316a8571 100644 --- a/src/modules/Channel/context/hooks/useHandleChannelEvents.ts +++ b/src/modules/Channel/context/hooks/useHandleChannelEvents.ts @@ -121,7 +121,6 @@ function useHandleChannelEvents({ }, onUserMarkedUnread: (channel, userIds) => { logger.info('Channel | useHandleChannelEvents: onUserMarkedUnread', channel, userIds); - // TODO:: MADOKA 이 부분에 대해서 명확하게 확인해야 함. if (compareIds(channel?.url, channelUrl)) { messagesDispatcher({ type: messageActions.MARK_AS_UNREAD, @@ -169,11 +168,13 @@ function useHandleChannelEvents({ }); }, onReactionUpdated: (channel, reactionEvent) => { - logger.info('Channel | useHandleChannelEvents: onReactionUpdated', { channel, reactionEvent }); - messagesDispatcher({ - type: messageActions.ON_REACTION_UPDATED, - payload: reactionEvent, - }); + if (channel.isGroupChannel() && compareIds(channel?.url, channelUrl)) { + logger.info('Channel | useHandleChannelEvents: onReactionUpdated', { channel, reactionEvent }); + messagesDispatcher({ + type: messageActions.ON_REACTION_UPDATED, + payload: reactionEvent, + }); + } }, onChannelChanged: (channel) => { if (channel.isGroupChannel() && compareIds(channel?.url, channelUrl)) { diff --git a/src/modules/GroupChannel/components/MessageList/index.tsx b/src/modules/GroupChannel/components/MessageList/index.tsx index a55a13f60..519ceaf7e 100644 --- a/src/modules/GroupChannel/components/MessageList/index.tsx +++ b/src/modules/GroupChannel/components/MessageList/index.tsx @@ -110,7 +110,7 @@ export const MessageList = (props: GroupChannelMessageListProps) => { // Find the first unread message const firstUnreadMessage = useMemo(() => { - if (!enableMarkAsUnread || !isInitializedRef.current || messages.length === 0 || readState === 'read') { + if (!enableMarkAsUnread || !isInitializedRef.current || messages.length === 0 || readState === 'read' || !currentChannel?.myLastRead) { return undefined; } diff --git a/src/modules/Thread/components/ThreadList/ThreadListItemContent.tsx b/src/modules/Thread/components/ThreadList/ThreadListItemContent.tsx index 89e6ce61e..947e053b9 100644 --- a/src/modules/Thread/components/ThreadList/ThreadListItemContent.tsx +++ b/src/modules/Thread/components/ThreadList/ThreadListItemContent.tsx @@ -332,6 +332,7 @@ export default function ThreadListItemContent(props: ThreadListItemContentProps) toggleReaction, isOpenedFromThread: true, deleteMessage, + resendMessage, onDownloadClick: async (e) => { if (!onBeforeDownloadFileMessage) return; diff --git a/src/modules/Thread/context/hooks/useThreadFetchers.ts b/src/modules/Thread/context/hooks/useThreadFetchers.ts index f34da3a2b..3f1dfce8d 100644 --- a/src/modules/Thread/context/hooks/useThreadFetchers.ts +++ b/src/modules/Thread/context/hooks/useThreadFetchers.ts @@ -30,6 +30,7 @@ function getThreadMessageListParams(params?: Partial) prevResultSize: PREV_THREADS_FETCH_SIZE, nextResultSize: NEXT_THREADS_FETCH_SIZE, includeMetaArray: true, + isInclusive: true, ...params, }; } diff --git a/src/modules/Thread/context/useThread.ts b/src/modules/Thread/context/useThread.ts index 2ec79319c..be328924f 100644 --- a/src/modules/Thread/context/useThread.ts +++ b/src/modules/Thread/context/useThread.ts @@ -10,6 +10,7 @@ import { BaseMessage, MultipleFilesMessage, ReactionEvent, + SendingStatus, UserMessage, } from '@sendbird/chat/message'; import { NEXT_THREADS_FETCH_SIZE, PREV_THREADS_FETCH_SIZE } from '../consts'; @@ -26,6 +27,8 @@ import useUpdateMessageCallback from './hooks/useUpdateMessageCallback'; import useDeleteMessageCallback from './hooks/useDeleteMessageCallback'; import { useThreadFetchers } from './hooks/useThreadFetchers'; +import { cloneDeep } from 'lodash'; + function hasReqId( message: T, ): message is T & { reqId: string } { @@ -56,6 +59,10 @@ const useThread = () => { const sendMessageStatusActions = { sendMessageStart: useCallback((message: SendableMessageType) => store.setState(state => { + if ('sendingStatus' in message) { + (message as SendableMessageType).sendingStatus = SendingStatus.PENDING; + } + return { ...state, localThreadMessages: [ @@ -66,6 +73,10 @@ const useThread = () => { }), [store]), sendMessageSuccess: useCallback((message: SendableMessageType) => store.setState(state => { + if ('sendingStatus' in message) { + (message as SendableMessageType).sendingStatus = SendingStatus.SUCCEEDED; + } + return { ...state, allThreadMessages: [ @@ -81,6 +92,10 @@ const useThread = () => { }), [store]), sendMessageFailure: useCallback((message: SendableMessageType) => store.setState(state => { + if ('sendingStatus' in message) { + (message as SendableMessageType).sendingStatus = SendingStatus.FAILED; + } + return { ...state, localThreadMessages: state.localThreadMessages.map((m) => ( @@ -92,6 +107,10 @@ const useThread = () => { }), [store]), resendMessageStart: useCallback((message: SendableMessageType) => store.setState(state => { + if ('sendingStatus' in message) { + (message as SendableMessageType).sendingStatus = SendingStatus.PENDING; + } + return { ...state, localThreadMessages: state.localThreadMessages.map((m) => ( @@ -235,16 +254,16 @@ const useThread = () => { initializeThreadListSuccess: useCallback((parentMessage: BaseMessage, anchorMessage: SendableMessageType, threadedMessages: BaseMessage[]) => store.setState(state => { const anchorMessageCreatedAt = (!anchorMessage?.messageId) ? parentMessage?.createdAt : anchorMessage?.createdAt; - const anchorIndex = threadedMessages.findIndex((message) => message?.createdAt > anchorMessageCreatedAt); + const anchorIndex = threadedMessages.findIndex((message) => message?.createdAt === anchorMessageCreatedAt); const prevThreadMessages = anchorIndex > -1 ? threadedMessages.slice(0, anchorIndex) : threadedMessages; - const anchorThreadMessage = anchorMessage?.messageId ? [anchorMessage] : []; const nextThreadMessages = anchorIndex > -1 ? threadedMessages.slice(anchorIndex) : []; + return { ...state, threadListState: ThreadListStateTypes.INITIALIZED, hasMorePrev: anchorIndex === -1 || anchorIndex === PREV_THREADS_FETCH_SIZE, hasMoreNext: threadedMessages.length - anchorIndex === NEXT_THREADS_FETCH_SIZE, - allThreadMessages: [prevThreadMessages, anchorThreadMessage, nextThreadMessages].flat() as CoreMessageType[], + allThreadMessages: [...prevThreadMessages, ...nextThreadMessages] as CoreMessageType[], }; }), [store]), @@ -397,18 +416,25 @@ const useThread = () => { }), [store]), onReactionUpdated: useCallback((reactionEvent: ReactionEvent) => store.setState(state => { - if (state?.parentMessage?.messageId === reactionEvent?.messageId) { - state.parentMessage?.applyReactionEvent?.(reactionEvent); + let updatedParentMessage = state.parentMessage; + if (state.parentMessage?.messageId === reactionEvent?.messageId) { + updatedParentMessage = cloneDeep(state.parentMessage as SendableMessageType); + updatedParentMessage.applyReactionEvent(reactionEvent); } + + const updatedMessages = state.allThreadMessages.map((m) => { + if (reactionEvent?.messageId === m?.messageId) { + const updatedMessage = cloneDeep(m as CoreMessageType); + updatedMessage.applyReactionEvent(reactionEvent); + return updatedMessage; + } + return m; + }); + return { ...state, - allThreadMessages: state.allThreadMessages.map((m) => { - if (reactionEvent?.messageId === m?.messageId) { - m?.applyReactionEvent?.(reactionEvent); - return m; - } - return m; - }), + parentMessage: updatedParentMessage, + allThreadMessages: [...updatedMessages], // Create new array reference to trigger re-render }; }), [store]), diff --git a/src/ui/Checkbox/index.scss b/src/ui/Checkbox/index.scss index f7f0df0b3..42e9d731e 100644 --- a/src/ui/Checkbox/index.scss +++ b/src/ui/Checkbox/index.scss @@ -79,4 +79,4 @@ transform: rotate(45deg); } } -/**rtl:end:ignore**/ +/*rtl:end:ignore*/ diff --git a/src/utils/storeManager.ts b/src/utils/storeManager.ts index 2f4f1cf56..dcfb3e0f5 100644 --- a/src/utils/storeManager.ts +++ b/src/utils/storeManager.ts @@ -18,6 +18,7 @@ export function hasStateChanged(prevState: T, updates: Partial): boolean { */ return false; } + return !isEqual(prevState[key as keyof T], value); }); } diff --git a/yarn.lock b/yarn.lock index 5c05c4268..1133c5f17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2747,9 +2747,9 @@ __metadata: languageName: node linkType: hard -"@sendbird/chat@npm:^4.18.0": - version: 4.19.5 - resolution: "@sendbird/chat@npm:4.19.5" +"@sendbird/chat@npm:^4.20.0": + version: 4.20.0 + resolution: "@sendbird/chat@npm:4.20.0" peerDependencies: "@react-native-async-storage/async-storage": ^1.17.6 react-native-mmkv: ">=2.0.0" @@ -2758,29 +2758,28 @@ __metadata: optional: true react-native-mmkv: optional: true - checksum: b67d3b9413ae1b61c4261ef540f7b31b21fec925950a2805ac2cb0eac2c981ec001f8d066bce8fc294d6a104a4ad2a0481c1e907e59fa9bcc8a0081411b729c6 + checksum: ad614ef86f382aab8c41b333e02f6eab87409650c44d3aad9fab8f67ff3b2ffb331b38c84b3d70cc95cc9cd5f47b0ee568fc50257fa6b3aecd118ac304d7c494 languageName: node linkType: hard -"@sendbird/react-uikit-message-template-view@npm:^0.0.10": - version: 0.0.10 - resolution: "@sendbird/react-uikit-message-template-view@npm:0.0.10" +"@sendbird/react-uikit-message-template-view@npm:^0.0.18": + version: 0.0.18 + resolution: "@sendbird/react-uikit-message-template-view@npm:0.0.18" dependencies: - "@sendbird/uikit-message-template": ^0.0.10 + "@sendbird/uikit-message-template": ^0.0.18 peerDependencies: - "@sendbird/chat": ">=4.3.0 <5" react: ">=16.8.6" react-dom: ">=16.8.6" - checksum: aac92fb0b963c4ee3f31eea05839cd49c5ad8561c427b5778731fdf61bcbc18076b329ab2866f12b776e77e9b2a9bfbba12263bcf25d4949a34ab80120548d2f + checksum: 1ce96ee2ff96934aa2d3ce092b2b8799701c5b782e84c04d45fe4dc4cfd3755499de013520edf0f599ce356c941ae1793e5a461d550ecadd14ed5f689f395531 languageName: node linkType: hard -"@sendbird/uikit-message-template@npm:^0.0.10": - version: 0.0.10 - resolution: "@sendbird/uikit-message-template@npm:0.0.10" +"@sendbird/uikit-message-template@npm:^0.0.18": + version: 0.0.18 + resolution: "@sendbird/uikit-message-template@npm:0.0.18" peerDependencies: react: ">=16.8.6" - checksum: 18dfce8f7c83d37a94bc3cbca0f561d7ed10c4367bcb2d2bf9c9192fce8fa06cfd87e8f968c6f3ae6d464a5119338ee5167b1a055b777bd906664a225c7e486f + checksum: c732c8effe55c3cc1f659a41f372e934891828281b03aefc504930bbccfb1ac7c5f7f989217ffeb2dadca98b872aa8bde7fb2c8c92506ce99aba23cf1b89d969 languageName: node linkType: hard @@ -2803,9 +2802,9 @@ __metadata: "@rollup/plugin-node-resolve": ^15.2.3 "@rollup/plugin-replace": ^5.0.4 "@rollup/plugin-typescript": ^11.1.5 - "@sendbird/chat": ^4.18.0 - "@sendbird/react-uikit-message-template-view": ^0.0.10 - "@sendbird/uikit-tools": ^0.0.10 + "@sendbird/chat": ^4.20.0 + "@sendbird/react-uikit-message-template-view": ^0.0.18 + "@sendbird/uikit-tools": ^0.0.18 "@storybook/addon-essentials": ^8.5.0 "@storybook/manager-api": ^8.5.0 "@storybook/react-vite": ^8.5.0 @@ -2870,13 +2869,13 @@ __metadata: languageName: unknown linkType: soft -"@sendbird/uikit-tools@npm:^0.0.10": - version: 0.0.10 - resolution: "@sendbird/uikit-tools@npm:0.0.10" +"@sendbird/uikit-tools@npm:^0.0.18": + version: 0.0.18 + resolution: "@sendbird/uikit-tools@npm:0.0.18" peerDependencies: "@sendbird/chat": ">=4.10.5 <5" react: ">=16.8.6" - checksum: 1b92fe4a5caced7efff4397fdf87912bc958b45f5eae1f986f78961759b18687901cc28bbc6f797a6fb0e1552e56ef5e04a16da0125883f18b00e99fbee5f44b + checksum: 045565a9e0df7bd180e9a88da8d23543dedc7628b892c1f7e052f576dbc3529f4272852d93434b644a58933371a160de467d9534112df9f9622ab07ca3706b55 languageName: node linkType: hard