@sendbird/uikit-react
Version:
Sendbird UIKit for React: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
800 lines (794 loc) • 46.4 kB
JavaScript
import { _ as __assign, a as __awaiter, b as __generator } from './bundle-DlZj_j5B.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-tDk7wyaM.js';
import { p as pubSubFactory } from './bundle-DPzvLwMf.js';
import { s as shimExports, u as useStore, c as createStore } from './bundle-C1jTnXNH.js';
import { g as getMessageTopOffset, d as isContextMenuClosed } from './bundle-lyBHlixS.js';
import { u as useSendbird } from './bundle-BnaoVUUl.js';
import { g as getIsReactionEnabled } from './bundle-yGY7tz0s.js';
import { g as getCaseResolvedReplyType, a as getCaseResolvedThreadReplySelectType } from './bundle-QUj4_z_2.js';
import { P as PUBSUB_TOPICS, b as PublishingModuleType, p as pubSubTopics } from './bundle-D9lZlE3H.js';
import { T as ThreadReplySelectType } from './bundle-CVos_O7L.js';
import { u as useDeepCompareEffect } from './bundle-CG0xn0QL.js';
import { d as deleteNullish } from './bundle-CaW4IP0_.js';
import { CollectionEventSource } from '@sendbird/chat';
import { K } from './bundle-DZaN4z9l.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-C8kxBudB.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, currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url]),
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, currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url]),
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, currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url]),
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, currentChannel === null || currentChannel === void 0 ? void 0 : currentChannel.url]),
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 !== null)
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 !== null) {
state.scrollPubSub.publish('scroll', {
top: topOffset,
lazy: false,
animated: scrollAnimated,
});
}
if (messageFocusAnimated !== null && messageFocusAnimated !== void 0 ? messageFocusAnimated : true)
setAnimatedMessageId(messageId);
}, 500);
_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 setNewMessageIds = useCallback(function (newMessageIds) {
store.setState(function (state) { return (__assign(__assign({}, state), { newMessageIds: newMessageIds })); });
}, []);
var actions = useMemo(function () {
return __assign({ setCurrentChannel: setCurrentChannel, handleChannelError: handleChannelError, markAsReadAll: markAsReadAll, markAsUnread: state.markAsUnread, setReadStateChanged: setReadStateChanged, setFirstUnreadMessageId: setFirstUnreadMessageId, setNewMessageIds: setNewMessageIds, 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,
autoscrollMessageOverflowToTop: 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,
autoscrollMessageOverflowToTop: props === null || props === void 0 ? void 0 : props.autoscrollMessageOverflowToTop,
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, _d;
var channelUrl = props.channelUrl, children = props.children, moduleReactionEnabled = props.isReactionEnabled, moduleReplyType = props.replyType, moduleThreadReplySelectType = props.threadReplySelectType, _e = props.isMessageGroupingEnabled, isMessageGroupingEnabled = _e === void 0 ? true : _e, isMultipleFilesMessageEnabled = props.isMultipleFilesMessageEnabled, autoscrollMessageOverflowToTop = props.autoscrollMessageOverflowToTop, showSearchIcon = props.showSearchIcon, _f = props.disableMarkAsRead, disableMarkAsRead = _f === void 0 ? false : _f, _g = props.scrollBehavior, scrollBehavior = _g === void 0 ? 'auto' : _g, 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 _h = useGroupChannel(), state = _h.state, actions = _h.actions;
var updateState = useGroupChannelStore().updateState;
var _j = useSendbird().state, config = _j.config, stores = _j.stores;
var sdkStore = stores.sdkStore;
var userId = config.userId, markAsReadScheduler = config.markAsReadScheduler, logger = config.logger, pubSub = config.pubSub;
// ScrollHandler initialization
var _k = useMessageListScroll(scrollBehavior, [(_a = state.currentChannel) === null || _a === void 0 ? void 0 : _a.url]), scrollRef = _k.scrollRef, scrollPubSub = _k.scrollPubSub, scrollDistanceFromBottomRef = _k.scrollDistanceFromBottomRef, scrollPositionRef = _k.scrollPositionRef;
var isScrollBottomReached = state.isScrollBottomReached;
var isAutoscrollMessageOverflowToTop = (_b = autoscrollMessageOverflowToTop !== null && autoscrollMessageOverflowToTop !== void 0 ? autoscrollMessageOverflowToTop : config.autoscrollMessageOverflowToTop) !== null && _b !== void 0 ? _b : false;
// 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) {
if (!isAutoscrollMessageOverflowToTop) {
setTimeout(function () { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) {
return [2 /*return*/, actions.scrollToBottom(true)];
}); }); }, 10);
}
else {
actions.setNewMessageIds(messages.map(function (it) { return it.messageId; }));
}
}
},
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;
// send message
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, (_c = state.currentChannel) === null || _c === void 0 ? void 0 : _c.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 () {
var _a;
return ({
isReactionEnabled: resolvedIsReactionEnabled,
isMessageGroupingEnabled: isMessageGroupingEnabled,
isMultipleFilesMessageEnabled: isMultipleFilesMessageEnabled,
autoscrollMessageOverflowToTop: (_a = autoscrollMessageOverflowToTop !== null && autoscrollMessageOverflowToTop !== void 0 ? autoscrollMessageOverflowToTop : config.autoscrollMessageOverflowToTop) !== null && _a !== void 0 ? _a : false,
replyType: resolvedReplyType,
threadReplySelectType: resolvedThreadReplySelectType,
showSearchIcon: showSearchIcon !== null && showSearchIcon !== void 0 ? showSearchIcon : config.groupChannelSettings.enableMessageSearch,
disableMarkAsRead: disableMarkAsRead,
scrollBehavior: scrollBehavior,
});
}, [
resolvedIsReactionEnabled,
isMessageGroupingEnabled,
isMultipleFilesMessageEnabled,
autoscrollMessageOverflowToTop,
resolvedReplyType,
resolvedThreadReplySelectType,
showSearchIcon,
disableMarkAsRead,
scrollBehavior,
config.groupChannelSettings.enableMessageSearch,
config.autoscrollMessageOverflowToTop,
]);
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,
(_d = state.currentChannel) === null || _d === void 0 ? void 0 : _d.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-CXBvqtFA.js.map