UNPKG

@sendbird/uikit-react

Version:

Sendbird UIKit for React: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.

782 lines (776 loc) 44.7 kB
import { _ as __assign, a as __awaiter, b as __generator } from './bundle-yl5d1NoZ.js'; import React__default, { useCallback, useContext, useMemo, useRef, useState, useLayoutEffect, createContext, useEffect } from 'react'; import { MessageMetaArray, ReplyType } from '@sendbird/chat/message'; import { MessageFilter } from '@sendbird/chat/groupChannel'; import { useIIFE, useGroupChannelMessages, useAsyncEffect, useAsyncLayoutEffect } from '@sendbird/uikit-tools'; import { U as UserProfileProvider } from './bundle-B0s_McF0.js'; import { p as pubSubFactory } from './bundle-D1nuDKhb.js'; import { s as shimExports, u as useStore, c as createStore } from './bundle-BUYU9H94.js'; import { g as getMessageTopOffset, d as isContextMenuClosed } from './bundle-CzwYTfhQ.js'; import { u as useSendbird } from './bundle-i_3w58Zd.js'; import { g as getIsReactionEnabled } from './bundle-BSy5MmTl.js'; import { g as getCaseResolvedReplyType, a as getCaseResolvedThreadReplySelectType } from './bundle-DK3-aB7E.js'; import { P as PUBSUB_TOPICS, b as PublishingModuleType, p as pubSubTopics } from './bundle-BOykFtQ3.js'; import { T as ThreadReplySelectType } from './bundle-BEx1sWnS.js'; import { u as useDeepCompareEffect } from './bundle-BmoSvBYM.js'; import { d as deleteNullish } from './bundle-MlG9piGf.js'; import { CollectionEventSource } from '@sendbird/chat'; import { K } from './bundle-DEuCwnTn.js'; import { a as VOICE_MESSAGE_FILE_NAME, b as VOICE_MESSAGE_MIME_TYPE, i as META_ARRAY_VOICE_DURATION_KEY, j as META_ARRAY_MESSAGE_TYPE_KEY, k as META_ARRAY_MESSAGE_TYPE_VALUE__VOICE } from './bundle-CqLLOVG5.js'; var pass = function (value) { return value; }; /** * @description This hook controls common processes related to message sending, updating. * */ function useMessageActions(params) { var _this = this; var _a = params.onBeforeSendUserMessage, onBeforeSendUserMessage = _a === void 0 ? pass : _a, _b = params.onBeforeSendFileMessage, onBeforeSendFileMessage = _b === void 0 ? pass : _b, _c = params.onBeforeUpdateUserMessage, onBeforeUpdateUserMessage = _c === void 0 ? pass : _c, _d = params.onBeforeSendVoiceMessage, onBeforeSendVoiceMessage = _d === void 0 ? pass : _d, _e = params.onBeforeSendMultipleFilesMessage, onBeforeSendMultipleFilesMessage = _e === void 0 ? pass : _e, sendFileMessage = params.sendFileMessage, sendMultipleFilesMessage = params.sendMultipleFilesMessage, sendUserMessage = params.sendUserMessage, updateUserMessage = params.updateUserMessage, updateFileMessage = params.updateFileMessage, resendMessage = params.resendMessage, deleteMessage = params.deleteMessage, resetNewMessages = params.resetNewMessages, scrollToBottom = params.scrollToBottom, quoteMessage = params.quoteMessage, replyType = params.replyType, currentChannel = params.currentChannel; var _f = useSendbird().state, eventHandlers = _f.eventHandlers, pubSub = _f.config.pubSub; var buildInternalMessageParams = useCallback(function (basicParams) { var messageParams = __assign({}, basicParams); if (params.quoteMessage && replyType !== 'NONE') { messageParams.isReplyToChannel = true; messageParams.parentMessageId = quoteMessage === null || quoteMessage === void 0 ? void 0 : quoteMessage.messageId; } return messageParams; }, [replyType, quoteMessage]); // This is a hack for the hotfix of following issue // https://sendbird.atlassian.net/browse/SBISSUE-17029 var asyncScrollToBottom = useCallback(function () { setTimeout(scrollToBottom, 0); }, [scrollToBottom]); var processParams = useCallback(function (handler, params, type) { return __awaiter(_this, void 0, void 0, function () { var result, error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4 /*yield*/, handler(params)]; case 1: result = _a.sent(); return [2 /*return*/, (result === undefined ? params : result)]; case 2: error_1 = _a.sent(); if (typeof (eventHandlers === null || eventHandlers === void 0 ? void 0 : eventHandlers.message) === 'object') { K(type) .with('file', 'voice', function () { var _a, _b, _c, _d; if (params.file) { (_b = (_a = eventHandlers.message).onFileUploadFailed) === null || _b === void 0 ? void 0 : _b.call(_a, error_1); } (_d = (_c = eventHandlers.message).onSendMessageFailed) === null || _d === void 0 ? void 0 : _d.call(_c, params, error_1); }) .with('multipleFiles', function () { var _a, _b, _c, _d; if (params.fileInfoList) { (_b = (_a = eventHandlers.message).onFileUploadFailed) === null || _b === void 0 ? void 0 : _b.call(_a, error_1); } (_d = (_c = eventHandlers.message).onSendMessageFailed) === null || _d === void 0 ? void 0 : _d.call(_c, params, error_1); }) .with('user', function () { var _a, _b; (_b = (_a = eventHandlers.message).onSendMessageFailed) === null || _b === void 0 ? void 0 : _b.call(_a, params, error_1); }) .with('update', function () { var _a, _b; (_b = (_a = eventHandlers.message).onUpdateMessageFailed) === null || _b === void 0 ? void 0 : _b.call(_a, params, error_1); }) .exhaustive(); } throw error_1; case 3: return [2 /*return*/]; } }); }); }, [eventHandlers]); return { sendUserMessage: useCallback(function (params) { return __awaiter(_this, void 0, void 0, function () { var internalParams, processedParams, message; return __generator(this, function (_a) { switch (_a.label) { case 0: internalParams = buildInternalMessageParams(params); return [4 /*yield*/, processParams(onBeforeSendUserMessage, internalParams, 'user')]; case 1: processedParams = _a.sent(); return [4 /*yield*/, sendUserMessage(processedParams, asyncScrollToBottom)]; case 2: message = _a.sent(); pubSub.publish(PUBSUB_TOPICS.SEND_USER_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.CHANNEL], }); return [2 /*return*/, message]; } }); }); }, [buildInternalMessageParams, sendUserMessage, scrollToBottom, processParams]), sendFileMessage: useCallback(function (params) { return __awaiter(_this, void 0, void 0, function () { var internalParams, processedParams, message; return __generator(this, function (_a) { switch (_a.label) { case 0: internalParams = buildInternalMessageParams(params); return [4 /*yield*/, processParams(onBeforeSendFileMessage, internalParams, 'file')]; case 1: processedParams = _a.sent(); return [4 /*yield*/, sendFileMessage(processedParams, asyncScrollToBottom)]; case 2: message = _a.sent(); pubSub.publish(PUBSUB_TOPICS.SEND_FILE_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.CHANNEL], }); return [2 /*return*/, message]; } }); }); }, [buildInternalMessageParams, sendFileMessage, scrollToBottom, processParams]), sendMultipleFilesMessage: useCallback(function (params) { return __awaiter(_this, void 0, void 0, function () { var internalParams, processedParams, message; return __generator(this, function (_a) { switch (_a.label) { case 0: internalParams = buildInternalMessageParams(params); return [4 /*yield*/, processParams(onBeforeSendMultipleFilesMessage, internalParams, 'multipleFiles')]; case 1: processedParams = _a.sent(); return [4 /*yield*/, sendMultipleFilesMessage(processedParams, asyncScrollToBottom)]; case 2: message = _a.sent(); pubSub.publish(PUBSUB_TOPICS.SEND_FILE_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.CHANNEL], }); return [2 /*return*/, message]; } }); }); }, [buildInternalMessageParams, sendMultipleFilesMessage, scrollToBottom, processParams]), sendVoiceMessage: useCallback(function (params, duration) { return __awaiter(_this, void 0, void 0, function () { var internalParams, processedParams; return __generator(this, function (_a) { switch (_a.label) { case 0: internalParams = buildInternalMessageParams(__assign(__assign({}, params), { fileName: VOICE_MESSAGE_FILE_NAME, mimeType: VOICE_MESSAGE_MIME_TYPE, metaArrays: [ new MessageMetaArray({ key: META_ARRAY_VOICE_DURATION_KEY, value: ["".concat(duration)], }), new MessageMetaArray({ key: META_ARRAY_MESSAGE_TYPE_KEY, value: [META_ARRAY_MESSAGE_TYPE_VALUE__VOICE], }), ] })); return [4 /*yield*/, processParams(onBeforeSendVoiceMessage, internalParams, 'voice')]; case 1: processedParams = _a.sent(); return [2 /*return*/, sendFileMessage(processedParams, asyncScrollToBottom)]; } }); }); }, [buildInternalMessageParams, sendFileMessage, scrollToBottom, processParams]), updateUserMessage: useCallback(function (messageId, params) { return __awaiter(_this, void 0, void 0, function () { var internalParams, processedParams; return __generator(this, function (_a) { switch (_a.label) { case 0: internalParams = buildInternalMessageParams(params); return [4 /*yield*/, processParams(onBeforeUpdateUserMessage, internalParams, 'update')]; case 1: processedParams = _a.sent(); return [2 /*return*/, updateUserMessage(messageId, processedParams) .then(function (message) { pubSub.publish(PUBSUB_TOPICS.UPDATE_USER_MESSAGE, { channel: currentChannel, message: message, publishingModules: [PublishingModuleType.CHANNEL], }); return message; })]; } }); }); }, [buildInternalMessageParams, updateUserMessage, processParams, currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url]), updateFileMessage: updateFileMessage, resendMessage: resendMessage, deleteMessage: deleteMessage, resetNewMessages: resetNewMessages, }; } var useGroupChannel = function () { var _a, _b, _c; var store = useContext(GroupChannelContext); if (!store) throw new Error('useGroupChannel must be used within a GroupChannelProvider'); var config = useSendbird().state.config; var markAsReadScheduler = config.markAsReadScheduler; var state = shimExports.useSyncExternalStore(store.subscribe, store.getState); var setAnimatedMessageId = useCallback(function (messageId) { store.setState(function (state) { return (__assign(__assign({}, state), { animatedMessageId: messageId })); }); }, []); var setIsScrollBottomReached = useCallback(function (isReached) { store.setState(function (state) { return (__assign(__assign({}, state), { isScrollBottomReached: isReached })); }); }, []); var scrollToBottom = useCallback(function (animated) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: if (!state.scrollRef.current) return [2 /*return*/]; setAnimatedMessageId(null); setIsScrollBottomReached(true); if (!(config.isOnline && state.hasNext())) return [3 /*break*/, 2]; return [4 /*yield*/, state.resetWithStartingPoint(Number.MAX_SAFE_INTEGER)]; case 1: _a.sent(); _a.label = 2; case 2: state.scrollPubSub.publish('scrollToBottom', { animated: animated }); if (state.currentChannel && !state.hasNext()) { state.resetNewMessages(); if (!state.disableMarkAsRead) { if (!config.groupChannel.enableMarkAsUnread && state.currentChannel.myMemberState !== 'none') { markAsReadScheduler.push(state.currentChannel); } } } return [2 /*return*/]; } }); }); }, [state.scrollRef.current, config.isOnline, markAsReadScheduler, config.groupChannel.enableMarkAsUnread]); var markAsReadAll = useCallback(function (channel) { if (config.isOnline && !state.disableMarkAsRead && channel) { markAsReadScheduler === null || markAsReadScheduler === void 0 ? void 0 : markAsReadScheduler.push(channel); } }, [config.isOnline, state.disableMarkAsRead]); var scrollToMessage = useCallback(function (createdAt, messageId, messageFocusAnimated, scrollAnimated) { return __awaiter(void 0, void 0, void 0, function () { var element, parentNode, clickHandler, message, topOffset; return __generator(this, function (_a) { switch (_a.label) { case 0: element = state.scrollRef.current; parentNode = element === null || element === void 0 ? void 0 : element.parentNode; clickHandler = { activate: function () { if (!element || !parentNode) return; element.style.pointerEvents = 'auto'; parentNode.style.cursor = 'auto'; }, deactivate: function () { if (!element || !parentNode) return; element.style.pointerEvents = 'none'; parentNode.style.cursor = 'wait'; }, }; clickHandler.deactivate(); setAnimatedMessageId(null); message = state.messages.find(function (it) { return it.messageId === messageId || it.createdAt === createdAt; }); if (!message) return [3 /*break*/, 1]; topOffset = getMessageTopOffset(message.createdAt); if (topOffset) state.scrollPubSub.publish('scroll', { top: topOffset, animated: scrollAnimated }); if (messageFocusAnimated !== null && messageFocusAnimated !== void 0 ? messageFocusAnimated : true) setAnimatedMessageId(messageId); return [3 /*break*/, 3]; case 1: if (!state.initialized) return [3 /*break*/, 3]; return [4 /*yield*/, state.resetWithStartingPoint(createdAt)]; case 2: _a.sent(); setTimeout(function () { var topOffset = getMessageTopOffset(createdAt); if (topOffset) { state.scrollPubSub.publish('scroll', { top: topOffset, lazy: false, animated: scrollAnimated, }); } if (messageFocusAnimated !== null && messageFocusAnimated !== void 0 ? messageFocusAnimated : true) setAnimatedMessageId(messageId); }); _a.label = 3; case 3: clickHandler.activate(); return [2 /*return*/]; } }); }); }, [ setAnimatedMessageId, state.initialized, state.scrollRef.current, (_a = state.messages) === null || _a === void 0 ? void 0 : _a.map(function (it) { return it === null || it === void 0 ? void 0 : it.messageId; }), ]); var toggleReaction = useCallback(function (message, emojiKey, isReacted) { if (!state.currentChannel) return; if (isReacted) { state.currentChannel.deleteReaction(message, emojiKey) .catch(function (error) { var _a; (_a = config.logger) === null || _a === void 0 ? void 0 : _a.warning('Failed to delete reaction:', error); }); } else { state.currentChannel.addReaction(message, emojiKey) .catch(function (error) { var _a; (_a = config.logger) === null || _a === void 0 ? void 0 : _a.warning('Failed to add reaction:', error); }); } }, [(_b = state.currentChannel) === null || _b === void 0 ? void 0 : _b.deleteReaction, (_c = state.currentChannel) === null || _c === void 0 ? void 0 : _c.addReaction]); var messageActions = useMessageActions(__assign(__assign({}, state), { scrollToBottom: scrollToBottom })); var setCurrentChannel = useCallback(function (channel) { store.setState(function (state) { return (__assign(__assign({}, state), { currentChannel: channel, fetchChannelError: null, quoteMessage: null, animatedMessageId: null, nicknamesMap: channel ? new Map(channel.members.map(function (_a) { var userId = _a.userId, nickname = _a.nickname; return [userId, nickname]; })) : new Map() })); }, true); }, []); var handleChannelError = useCallback(function (error) { store.setState(function (state) { return (__assign(__assign({}, state), { currentChannel: null, fetchChannelError: error, quoteMessage: null, animatedMessageId: null })); }); }, []); var setQuoteMessage = useCallback(function (message) { store.setState(function (state) { return (__assign(__assign({}, state), { quoteMessage: message })); }); }, []); var setReadStateChanged = useCallback(function (readState) { store.setState(function (state) { return (__assign(__assign({}, state), { readState: readState })); }); }, []); var setFirstUnreadMessageId = useCallback(function (messageId) { store.setState(function (state) { return (__assign(__assign({}, state), { firstUnreadMessageId: messageId })); }); }, []); var actions = useMemo(function () { return __assign({ setCurrentChannel: setCurrentChannel, handleChannelError: handleChannelError, markAsReadAll: markAsReadAll, markAsUnread: state.markAsUnread, setReadStateChanged: setReadStateChanged, setFirstUnreadMessageId: setFirstUnreadMessageId, setQuoteMessage: setQuoteMessage, scrollToBottom: scrollToBottom, scrollToMessage: scrollToMessage, toggleReaction: toggleReaction, setAnimatedMessageId: setAnimatedMessageId, setIsScrollBottomReached: setIsScrollBottomReached }, messageActions); }, [ setCurrentChannel, handleChannelError, markAsReadAll, state.markAsUnread, setReadStateChanged, setFirstUnreadMessageId, setQuoteMessage, scrollToBottom, scrollToMessage, toggleReaction, setAnimatedMessageId, setIsScrollBottomReached, messageActions, ]); return { state: state, actions: actions }; }; function useMessageListScroll(behavior, deps) { if (deps === void 0) { deps = []; } var scrollRef = useRef(null); var scrollPositionRef = useRef(0); var scrollDistanceFromBottomRef = useRef(0); var scrollPubSub = useState(function () { return pubSubFactory({ publishSynchronous: true }); })[0]; var setIsScrollBottomReached = useGroupChannel().actions.setIsScrollBottomReached; // SideEffect: Reset scroll state useLayoutEffect(function () { scrollPositionRef.current = 0; scrollDistanceFromBottomRef.current = 0; setIsScrollBottomReached(true); if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight; }, deps); useLayoutEffect(function () { var unsubscribes = []; unsubscribes.push(scrollPubSub.subscribe('scrollToBottom', function (_a) { var resolve = _a.resolve, animated = _a.animated; runCallback(function () { if (!scrollRef.current) { if (resolve) resolve(); return; } if (scrollRef.current.scroll) { scrollRef.current.scroll({ top: scrollRef.current.scrollHeight, behavior: getScrollBehavior(behavior, animated) }); } else { scrollRef.current.scrollTop = scrollRef.current.scrollHeight; } // Update data by manual update scrollDistanceFromBottomRef.current = 0; setIsScrollBottomReached(true); if (resolve) resolve(); }); })); unsubscribes.push(scrollPubSub.subscribe('scroll', function (_a) { var top = _a.top, animated = _a.animated, lazy = _a.lazy, resolve = _a.resolve; runCallback(function () { if (!scrollRef.current || typeof top !== 'number') { resolve === null || resolve === void 0 ? void 0 : resolve(); return; } var _a = scrollRef.current, scrollTop = _a.scrollTop, scrollHeight = _a.scrollHeight, clientHeight = _a.clientHeight; if (scrollRef.current.scroll) { scrollRef.current.scroll({ top: top, behavior: getScrollBehavior(behavior, animated) }); } else { scrollRef.current.scrollTop = top; } // Update data by manual update scrollDistanceFromBottomRef.current = Math.max(0, scrollHeight - scrollTop - clientHeight); setIsScrollBottomReached(scrollDistanceFromBottomRef.current === 0); resolve === null || resolve === void 0 ? void 0 : resolve(); }, lazy); })); return function () { unsubscribes.forEach(function (_a) { var remove = _a.remove; return remove(); }); }; }, [behavior]); return { scrollRef: scrollRef, scrollPubSub: scrollPubSub, scrollDistanceFromBottomRef: scrollDistanceFromBottomRef, scrollPositionRef: scrollPositionRef, }; } function runCallback(callback, lazy) { if (lazy === void 0) { lazy = true; } if (lazy) { setTimeout(function () { callback(); }); } else { callback(); } } function getScrollBehavior(behavior, animated) { if (typeof animated === 'boolean') return animated ? 'smooth' : 'auto'; return behavior; } var initialState = function () { return ({ currentChannel: null, channelUrl: '', fetchChannelError: null, nicknamesMap: new Map(), initialized: false, loading: true, messages: [], quoteMessage: null, animatedMessageId: null, isScrollBottomReached: true, readState: null, scrollRef: { current: null }, scrollDistanceFromBottomRef: { current: 0 }, scrollPositionRef: { current: 0 }, messageInputRef: { current: null }, isReactionEnabled: false, isMessageGroupingEnabled: true, isMultipleFilesMessageEnabled: false, showSearchIcon: true, replyType: 'NONE', threadReplySelectType: ThreadReplySelectType.PARENT, disableMarkAsRead: false, scrollBehavior: 'auto', scrollPubSub: null, }); }; var GroupChannelContext = createContext(null); var createGroupChannelStore = function (props) { return createStore(__assign(__assign({}, initialState()), props)); }; var InternalGroupChannelProvider = function (props) { var children = props.children; var defaultProps = deleteNullish({ channelUrl: props === null || props === void 0 ? void 0 : props.channelUrl, renderUserProfile: props === null || props === void 0 ? void 0 : props.renderUserProfile, disableUserProfile: props === null || props === void 0 ? void 0 : props.disableUserProfile, onUserProfileMessage: props === null || props === void 0 ? void 0 : props.onUserProfileMessage, onStartDirectMessage: props === null || props === void 0 ? void 0 : props.onStartDirectMessage, isReactionEnabled: props === null || props === void 0 ? void 0 : props.isReactionEnabled, isMessageGroupingEnabled: props === null || props === void 0 ? void 0 : props.isMessageGroupingEnabled, isMultipleFilesMessageEnabled: props === null || props === void 0 ? void 0 : props.isMultipleFilesMessageEnabled, showSearchIcon: props === null || props === void 0 ? void 0 : props.showSearchIcon, threadReplySelectType: props === null || props === void 0 ? void 0 : props.threadReplySelectType, disableMarkAsRead: props === null || props === void 0 ? void 0 : props.disableMarkAsRead, scrollBehavior: props === null || props === void 0 ? void 0 : props.scrollBehavior, forceLeftToRightMessageLayout: props === null || props === void 0 ? void 0 : props.forceLeftToRightMessageLayout, startingPoint: props === null || props === void 0 ? void 0 : props.startingPoint, animatedMessageId: props === null || props === void 0 ? void 0 : props.animatedMessageId, onMessageAnimated: props === null || props === void 0 ? void 0 : props.onMessageAnimated, messageListQueryParams: props === null || props === void 0 ? void 0 : props.messageListQueryParams, filterEmojiCategoryIds: props === null || props === void 0 ? void 0 : props.filterEmojiCategoryIds, onBeforeSendUserMessage: props === null || props === void 0 ? void 0 : props.onBeforeSendUserMessage, onBeforeSendFileMessage: props === null || props === void 0 ? void 0 : props.onBeforeSendFileMessage, onBeforeSendVoiceMessage: props === null || props === void 0 ? void 0 : props.onBeforeSendVoiceMessage, onBeforeSendMultipleFilesMessage: props === null || props === void 0 ? void 0 : props.onBeforeSendMultipleFilesMessage, onBeforeUpdateUserMessage: props === null || props === void 0 ? void 0 : props.onBeforeUpdateUserMessage, onBeforeDownloadFileMessage: props === null || props === void 0 ? void 0 : props.onBeforeDownloadFileMessage, onBackClick: props === null || props === void 0 ? void 0 : props.onBackClick, onChatHeaderActionClick: props === null || props === void 0 ? void 0 : props.onChatHeaderActionClick, onReplyInThreadClick: props === null || props === void 0 ? void 0 : props.onReplyInThreadClick, onSearchClick: props === null || props === void 0 ? void 0 : props.onSearchClick, onQuoteMessageClick: props === null || props === void 0 ? void 0 : props.onQuoteMessageClick, renderUserMentionItem: props === null || props === void 0 ? void 0 : props.renderUserMentionItem, }); var storeRef = useRef(createGroupChannelStore(defaultProps)); return (React__default.createElement(GroupChannelContext.Provider, { value: storeRef.current }, children)); }; var GroupChannelManager = function (props) { var _a, _b, _c; var channelUrl = props.channelUrl, children = props.children, moduleReactionEnabled = props.isReactionEnabled, moduleReplyType = props.replyType, moduleThreadReplySelectType = props.threadReplySelectType, _d = props.isMessageGroupingEnabled, isMessageGroupingEnabled = _d === void 0 ? true : _d, isMultipleFilesMessageEnabled = props.isMultipleFilesMessageEnabled, showSearchIcon = props.showSearchIcon, _e = props.disableMarkAsRead, disableMarkAsRead = _e === void 0 ? false : _e, _f = props.scrollBehavior, scrollBehavior = _f === void 0 ? 'auto' : _f, startingPoint = props.startingPoint, _animatedMessageId = props.animatedMessageId, messageListQueryParams = props.messageListQueryParams, onBeforeSendUserMessage = props.onBeforeSendUserMessage, onBeforeSendFileMessage = props.onBeforeSendFileMessage, onBeforeSendVoiceMessage = props.onBeforeSendVoiceMessage, onBeforeSendMultipleFilesMessage = props.onBeforeSendMultipleFilesMessage, onBeforeUpdateUserMessage = props.onBeforeUpdateUserMessage, onBeforeDownloadFileMessage = props.onBeforeDownloadFileMessage, onMessageAnimated = props.onMessageAnimated, onBackClick = props.onBackClick, onChatHeaderActionClick = props.onChatHeaderActionClick, onReplyInThreadClick = props.onReplyInThreadClick, onSearchClick = props.onSearchClick, onQuoteMessageClick = props.onQuoteMessageClick, renderUserMentionItem = props.renderUserMentionItem, filterEmojiCategoryIds = props.filterEmojiCategoryIds; var _g = useGroupChannel(), state = _g.state, actions = _g.actions; var updateState = useGroupChannelStore().updateState; var _h = useSendbird().state, config = _h.config, stores = _h.stores; var sdkStore = stores.sdkStore; var userId = config.userId, markAsReadScheduler = config.markAsReadScheduler, logger = config.logger, pubSub = config.pubSub; // ScrollHandler initialization var _j = useMessageListScroll(scrollBehavior, [(_a = state.currentChannel) === null || _a === void 0 ? void 0 : _a.url]), scrollRef = _j.scrollRef, scrollPubSub = _j.scrollPubSub, scrollDistanceFromBottomRef = _j.scrollDistanceFromBottomRef, scrollPositionRef = _j.scrollPositionRef; var isScrollBottomReached = state.isScrollBottomReached; // Configuration resolution var resolvedReplyType = getCaseResolvedReplyType(moduleReplyType !== null && moduleReplyType !== void 0 ? moduleReplyType : config.groupChannel.replyType).upperCase; var resolvedThreadReplySelectType = getCaseResolvedThreadReplySelectType(moduleThreadReplySelectType !== null && moduleThreadReplySelectType !== void 0 ? moduleThreadReplySelectType : config.groupChannel.threadReplySelectType).upperCase; var replyType = getCaseResolvedReplyType(moduleReplyType !== null && moduleReplyType !== void 0 ? moduleReplyType : config.groupChannel.replyType).upperCase; var resolvedIsReactionEnabled = getIsReactionEnabled({ channel: state.currentChannel, config: config, moduleLevel: moduleReactionEnabled, }); var chatReplyType = useIIFE(function () { if (replyType === 'NONE') return ReplyType.NONE; return ReplyType.ONLY_REPLY_TO_CHANNEL; }); var markAsUnreadSourceRef = useRef(undefined); var markAsUnread = useCallback(function (message, source) { var _a, _b, _c, _d; if (!config.groupChannel.enableMarkAsUnread) return; if (!state.currentChannel) { (_a = logger === null || logger === void 0 ? void 0 : logger.error) === null || _a === void 0 ? void 0 : _a.call(logger, 'GroupChannelProvider: channel is required for markAsUnread'); return; } try { if (state.currentChannel.markAsUnread) { state.currentChannel.markAsUnread(message); (_b = logger === null || logger === void 0 ? void 0 : logger.info) === null || _b === void 0 ? void 0 : _b.call(logger, 'GroupChannelProvider: markAsUnread called for message', { messageId: message.messageId, source: source || 'unknown', }); markAsUnreadSourceRef.current = source || 'internal'; } else { (_c = logger === null || logger === void 0 ? void 0 : logger.error) === null || _c === void 0 ? void 0 : _c.call(logger, 'GroupChannelProvider: markAsUnread method not available in current SDK version'); } } catch (error) { (_d = logger === null || logger === void 0 ? void 0 : logger.error) === null || _d === void 0 ? void 0 : _d.call(logger, 'GroupChannelProvider: markAsUnread failed', error); } }, [state.currentChannel, logger, config.groupChannel.enableMarkAsUnread]); // Message Collection setup var messageDataSource = useGroupChannelMessages(sdkStore.sdk, state.currentChannel, { startingPoint: startingPoint, replyType: chatReplyType, collectionCreator: getCollectionCreator(state.currentChannel, messageListQueryParams), shouldCountNewMessages: function () { return !isScrollBottomReached; }, markAsRead: function (channels) { if (!config.groupChannel.enableMarkAsUnread) { if (isScrollBottomReached && !disableMarkAsRead) { channels.forEach(function (it) { return markAsReadScheduler.push(it); }); } } }, onMessagesReceived: function (messages) { if (isScrollBottomReached && isContextMenuClosed() // Note: this shouldn't happen ideally, but it happens on re-rendering GroupChannelManager // even though the next messages and the current messages length are the same. // So added this condition to check if they are the same to prevent unnecessary calling scrollToBottom action && messages.length !== state.messages.length) { setTimeout(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { return [2 /*return*/, actions.scrollToBottom(true)]; }); }); }, 10); } }, onChannelDeleted: function () { actions.setCurrentChannel(null); onBackClick === null || onBackClick === void 0 ? void 0 : onBackClick(); }, onCurrentUserBanned: function () { actions.setCurrentChannel(null); onBackClick === null || onBackClick === void 0 ? void 0 : onBackClick(); }, onChannelUpdated: function (channel, ctx) { if (ctx.source === CollectionEventSource.EVENT_CHANNEL_UNREAD && ctx.userIds.includes(userId)) { actions.setReadStateChanged('unread'); } if (ctx.source === CollectionEventSource.EVENT_CHANNEL_READ && ctx.userIds.includes(userId)) { actions.setReadStateChanged('read'); } actions.setCurrentChannel(channel); }, logger: logger, }); // Channel initialization useAsyncEffect(function () { return __awaiter(void 0, void 0, void 0, function () { var channel, error_1; var _a; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!(sdkStore.initialized && channelUrl)) return [3 /*break*/, 4]; _b.label = 1; case 1: _b.trys.push([1, 3, , 4]); return [4 /*yield*/, sdkStore.sdk.groupChannel.getChannel(channelUrl)]; case 2: channel = _b.sent(); actions.setCurrentChannel(channel); return [3 /*break*/, 4]; case 3: error_1 = _b.sent(); actions.handleChannelError(error_1); (_a = logger === null || logger === void 0 ? void 0 : logger.error) === null || _a === void 0 ? void 0 : _a.call(logger, 'GroupChannelProvider: error when fetching channel', error_1); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }, [sdkStore.initialized, sdkStore.sdk, channelUrl]); // Message sync effect useAsyncLayoutEffect(function () { return __awaiter(void 0, void 0, void 0, function () { var handleExternalMessage, subscriptions; return __generator(this, function (_a) { if (messageDataSource.initialized) { actions.scrollToBottom(); } handleExternalMessage = function (data) { var _a; if (data.channel.url === ((_a = state.currentChannel) === null || _a === void 0 ? void 0 : _a.url)) { actions.scrollToBottom(true); } }; if ((pubSub === null || pubSub === void 0 ? void 0 : pubSub.subscribe) === undefined) return [2 /*return*/]; subscriptions = [ pubSub.subscribe(pubSubTopics.SEND_USER_MESSAGE, handleExternalMessage), pubSub.subscribe(pubSubTopics.SEND_FILE_MESSAGE, handleExternalMessage), ]; return [2 /*return*/, function () { subscriptions.forEach(function (subscription) { return subscription.remove(); }); }]; }); }); }, [messageDataSource.initialized, (_b = state.currentChannel) === null || _b === void 0 ? void 0 : _b.url]); // Starting point handling useEffect(function () { if (typeof startingPoint === 'number' && messageDataSource.initialized) { actions.scrollToMessage(startingPoint, 0, false, false); } }, [messageDataSource.initialized, startingPoint]); // Animated message handling useEffect(function () { if (_animatedMessageId) { actions.setAnimatedMessageId(_animatedMessageId); } }, [_animatedMessageId]); // State update effect var eventHandlers = useMemo(function () { return ({ onBeforeSendUserMessage: onBeforeSendUserMessage, onBeforeSendFileMessage: onBeforeSendFileMessage, onBeforeSendVoiceMessage: onBeforeSendVoiceMessage, onBeforeSendMultipleFilesMessage: onBeforeSendMultipleFilesMessage, onBeforeUpdateUserMessage: onBeforeUpdateUserMessage, onBeforeDownloadFileMessage: onBeforeDownloadFileMessage, onBackClick: onBackClick, onChatHeaderActionClick: onChatHeaderActionClick, onReplyInThreadClick: onReplyInThreadClick, onSearchClick: onSearchClick, onQuoteMessageClick: onQuoteMessageClick, onMessageAnimated: onMessageAnimated, }); }, [ onBeforeSendUserMessage, onBeforeSendFileMessage, onBeforeSendVoiceMessage, onBeforeSendMultipleFilesMessage, onBeforeUpdateUserMessage, onBeforeDownloadFileMessage, onBackClick, onChatHeaderActionClick, onReplyInThreadClick, onSearchClick, onQuoteMessageClick, onMessageAnimated, ]); var renderProps = useMemo(function () { return ({ renderUserMentionItem: renderUserMentionItem, filterEmojiCategoryIds: filterEmojiCategoryIds, }); }, [renderUserMentionItem, filterEmojiCategoryIds]); var configurations = useMemo(function () { return ({ isReactionEnabled: resolvedIsReactionEnabled, isMessageGroupingEnabled: isMessageGroupingEnabled, isMultipleFilesMessageEnabled: isMultipleFilesMessageEnabled, replyType: resolvedReplyType, threadReplySelectType: resolvedThreadReplySelectType, showSearchIcon: showSearchIcon !== null && showSearchIcon !== void 0 ? showSearchIcon : config.groupChannelSettings.enableMessageSearch, disableMarkAsRead: disableMarkAsRead, scrollBehavior: scrollBehavior, }); }, [ resolvedIsReactionEnabled, isMessageGroupingEnabled, isMultipleFilesMessageEnabled, resolvedReplyType, resolvedThreadReplySelectType, showSearchIcon, disableMarkAsRead, scrollBehavior, config.groupChannelSettings.enableMessageSearch, ]); var scrollState = useMemo(function () { return ({ scrollRef: scrollRef, scrollPubSub: scrollPubSub, scrollDistanceFromBottomRef: scrollDistanceFromBottomRef, scrollPositionRef: scrollPositionRef, isScrollBottomReached: isScrollBottomReached, }); }, [ scrollRef, scrollPubSub, scrollDistanceFromBottomRef, scrollPositionRef, isScrollBottomReached, ]); useDeepCompareEffect(function () { updateState(__assign(__assign(__assign(__assign(__assign(__assign({ // Channel state channelUrl: channelUrl, currentChannel: state.currentChannel }, configurations), scrollState), eventHandlers), renderProps), messageDataSource), { markAsUnread: markAsUnread, markAsUnreadSourceRef: markAsUnreadSourceRef })); }, [ channelUrl, (_c = state.currentChannel) === null || _c === void 0 ? void 0 : _c.serialize(), configurations, scrollState, eventHandlers, renderProps, messageDataSource.initialized, messageDataSource.loading, messageDataSource.messages.map(function (it) { return it.serialize(); }), ]); return children; }; var GroupChannelProvider = function (props) { return (React__default.createElement(InternalGroupChannelProvider, __assign({ key: props.channelUrl }, props), React__default.createElement(GroupChannelManager, __assign({}, props), React__default.createElement(UserProfileProvider, __assign({}, props), props.children)))); }; /** * A specialized hook for GroupChannel state management * @returns {ReturnType<typeof createStore<GroupChannelState>>} */ var useGroupChannelStore = function () { return useStore(GroupChannelContext, function (state) { return state; }, initialState()); }; // Keep this function for backward compatibility. var useGroupChannelContext = function () { var _a = useGroupChannel(), state = _a.state, actions = _a.actions; return __assign(__assign({}, state), actions); }; function getCollectionCreator(groupChannel, messageListQueryParams) { return function (defaultParams) { var params = __assign(__assign(__assign({}, defaultParams), { prevResultLimit: 30, nextResultLimit: 30 }), messageListQueryParams); return groupChannel.createMessageCollection(__assign(__assign({}, params), { filter: new MessageFilter(params) })); }; } export { GroupChannelContext as G, InternalGroupChannelProvider as I, GroupChannelProvider as a, useGroupChannelContext as b, GroupChannelManager as c, useGroupChannel as u }; //# sourceMappingURL=bundle-CmmJVpwV.js.map