@sendbird/uikit-react-native
Version:
Sendbird UIKit for React Native: A feature-rich and customizable chat UI kit with messaging, channel management, and user authentication.
302 lines (301 loc) • 15.1 kB
JavaScript
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import React, { useLayoutEffect, useMemo, useRef, useState } from 'react';
import { Platform } from 'react-native';
import { SafeAreaProvider } from 'react-native-safe-area-context';
import SendbirdChat, { DeviceOsPlatform, SendbirdPlatform, SendbirdProduct } from '@sendbird/chat';
import { GroupChannelModule } from '@sendbird/chat/groupChannel';
import { OpenChannelModule } from '@sendbird/chat/openChannel';
import { DialogProvider, Header, HeaderStyleProvider, LightUIKitTheme, ToastProvider, UIKitThemeProvider } from '@sendbird/uikit-react-native-foundation';
import { UIKitConfigProvider } from '@sendbird/uikit-tools';
import { Logger, NOOP, useIsFirstMount } from '@sendbird/uikit-utils';
import { LocalizationContext, LocalizationProvider } from '../contexts/LocalizationCtx';
import { PlatformServiceProvider } from '../contexts/PlatformServiceCtx';
import { ReactionProvider } from '../contexts/ReactionCtx';
import { SendbirdChatProvider } from '../contexts/SendbirdChatCtx';
import { UserProfileProvider } from '../contexts/UserProfileCtx';
import EmojiManager from '../libs/EmojiManager';
import ImageCompressionConfig from '../libs/ImageCompressionConfig';
import InternalLocalCacheStorage from '../libs/InternalLocalCacheStorage';
import MentionConfig from '../libs/MentionConfig';
import MentionManager from '../libs/MentionManager';
import VoiceMessageConfig from '../libs/VoiceMessageConfig';
import VoiceMessageStatusManager from '../libs/VoiceMessageStatusManager';
import StringSetEn from '../localization/StringSet.en';
import SBUDynamicModule from '../platform/dynamicModule';
import VERSION from '../version';
import InternalErrorBoundaryContainer from './InternalErrorBoundaryContainer';
const NetInfo = SBUDynamicModule.get('@react-native-community/netinfo', 'warn');
export const SendbirdUIKit = Object.freeze({
VERSION,
PLATFORM: Platform.OS.toLowerCase(),
DEFAULT: {
AUTO_PUSH_TOKEN_REGISTRATION: true,
USE_USER_ID_FOR_NICKNAME: false,
IMAGE_COMPRESSION: true
}
});
const chatOmitKeys = ['appId', 'newInstance', 'modules', 'debugMode', 'appVersion', 'localCacheEnabled', 'useAsyncStorageStore', 'useMMKVStorageStore'];
function sanitizeChatOptions(chatOptions) {
const opts = {
...chatOptions
};
chatOmitKeys.forEach(key => delete opts[key]);
return opts;
}
const SendbirdUIKitContainer = props => {
const {
children,
appId,
chatOptions,
uikitOptions,
platformServices,
localization,
styles,
errorBoundary,
toast,
userProfile,
reaction
} = props;
if (!chatOptions.localCacheStorage) {
throw new Error('SendbirdUIKitContainer: chatOptions.localCacheStorage is required');
} else if ('getItem' in chatOptions.localCacheStorage) {
Logger.warn('SendbirdUIKitContainer: localCacheStorage for `AsyncStorage` is deprecated. Please use `MMKV` instead.');
}
const defaultStringSet = (localization === null || localization === void 0 ? void 0 : localization.stringSet) ?? StringSetEn;
const isFirstMount = useIsFirstMount();
const unsubscribes = useRef([]);
const [internalStorage] = useState(() => new InternalLocalCacheStorage(chatOptions.localCacheStorage));
const [sdkInstance, setSdkInstance] = useState(() => {
const sendbird = initializeSendbird(appId, sanitizeChatOptions(chatOptions));
unsubscribes.current = sendbird.unsubscribes;
return sendbird.chatSDK;
});
const {
imageCompressionConfig,
voiceMessageConfig,
mentionConfig
} = useConfigInstance(props);
const emojiManager = useMemo(() => new EmojiManager(internalStorage), [internalStorage]);
const mentionManager = useMemo(() => new MentionManager(mentionConfig), [mentionConfig]);
const voiceMessageStatusManager = useMemo(() => new VoiceMessageStatusManager(), []);
useLayoutEffect(() => {
if (!isFirstMount) {
const sendbird = initializeSendbird(appId, sanitizeChatOptions(chatOptions));
setSdkInstance(sendbird.chatSDK);
unsubscribes.current = sendbird.unsubscribes;
}
return () => {
unsubscribes.current.forEach(u => {
try {
u();
} catch {}
});
};
}, [appId, internalStorage]);
const renderChildren = () => {
if (errorBoundary !== null && errorBoundary !== void 0 && errorBoundary.disabled) {
return children;
} else {
return /*#__PURE__*/React.createElement(InternalErrorBoundaryContainer, errorBoundary, children);
}
};
return /*#__PURE__*/React.createElement(SafeAreaProvider, null, /*#__PURE__*/React.createElement(UIKitConfigProvider, {
storage: internalStorage,
localConfigs: {
common: uikitOptions === null || uikitOptions === void 0 ? void 0 : uikitOptions.common,
groupChannel: {
channel: {
...(uikitOptions === null || uikitOptions === void 0 ? void 0 : uikitOptions.groupChannel),
enableReactionsSupergroup: undefined
},
channelList: uikitOptions === null || uikitOptions === void 0 ? void 0 : uikitOptions.groupChannelList,
setting: uikitOptions === null || uikitOptions === void 0 ? void 0 : uikitOptions.groupChannelSettings
},
openChannel: {
channel: uikitOptions === null || uikitOptions === void 0 ? void 0 : uikitOptions.openChannel
}
}
}, /*#__PURE__*/React.createElement(SendbirdChatProvider, {
sdkInstance: sdkInstance,
emojiManager: emojiManager,
mentionManager: mentionManager,
imageCompressionConfig: imageCompressionConfig,
voiceMessageConfig: voiceMessageConfig,
voiceMessageStatusManager: voiceMessageStatusManager,
enableAutoPushTokenRegistration: chatOptions.enableAutoPushTokenRegistration ?? SendbirdUIKit.DEFAULT.AUTO_PUSH_TOKEN_REGISTRATION,
enableUseUserIdForNickname: chatOptions.enableUseUserIdForNickname ?? SendbirdUIKit.DEFAULT.USE_USER_ID_FOR_NICKNAME,
enableImageCompression: chatOptions.enableImageCompression ?? SendbirdUIKit.DEFAULT.IMAGE_COMPRESSION
}, /*#__PURE__*/React.createElement(LocalizationProvider, {
stringSet: defaultStringSet
}, /*#__PURE__*/React.createElement(PlatformServiceProvider, {
fileService: platformServices.file,
notificationService: platformServices.notification,
clipboardService: platformServices.clipboard,
mediaService: platformServices.media,
playerService: platformServices.player,
recorderService: platformServices.recorder,
voiceMessageConfig: voiceMessageConfig
}, /*#__PURE__*/React.createElement(UIKitThemeProvider, {
theme: (styles === null || styles === void 0 ? void 0 : styles.theme) ?? LightUIKitTheme
}, /*#__PURE__*/React.createElement(HeaderStyleProvider, {
HeaderComponent: (styles === null || styles === void 0 ? void 0 : styles.HeaderComponent) ?? Header,
defaultTitleAlign: (styles === null || styles === void 0 ? void 0 : styles.defaultHeaderTitleAlign) ?? 'left',
statusBarTranslucent: (styles === null || styles === void 0 ? void 0 : styles.statusBarTranslucent) ?? true
}, /*#__PURE__*/React.createElement(ToastProvider, {
dismissTimeout: toast === null || toast === void 0 ? void 0 : toast.dismissTimeout
}, /*#__PURE__*/React.createElement(UserProfileProvider, _extends({}, userProfile, {
statusBarTranslucent: (styles === null || styles === void 0 ? void 0 : styles.statusBarTranslucent) ?? true
}), /*#__PURE__*/React.createElement(ReactionProvider, reaction, /*#__PURE__*/React.createElement(LocalizationContext.Consumer, null, value => {
const STRINGS = (value === null || value === void 0 ? void 0 : value.STRINGS) || defaultStringSet;
return /*#__PURE__*/React.createElement(DialogProvider, {
defaultLabels: {
alert: {
ok: STRINGS.DIALOG.ALERT_DEFAULT_OK
},
prompt: {
ok: STRINGS.DIALOG.PROMPT_DEFAULT_OK,
cancel: STRINGS.DIALOG.PROMPT_DEFAULT_CANCEL,
placeholder: STRINGS.DIALOG.PROMPT_DEFAULT_PLACEHOLDER
}
}
}, renderChildren());
})))))))))));
};
const initializeSendbird = (appId, options) => {
let chatSDK;
const unsubscribes = [];
const {
localCacheStorage,
onInitialized,
...chatInitParams
} = options;
const isMMKVStorage = ('getString' in localCacheStorage);
chatSDK = SendbirdChat.init({
...chatInitParams,
appId,
newInstance: true,
modules: [new GroupChannelModule(), new OpenChannelModule()],
localCacheEnabled: true,
useMMKVStorageStore: isMMKVStorage ? localCacheStorage : undefined,
useAsyncStorageStore: !isMMKVStorage ? localCacheStorage : undefined
});
if (onInitialized) {
chatSDK = onInitialized(chatSDK);
}
const platform = getDeviceOSPlatform();
if (SendbirdUIKit.VERSION && platform) {
const deviceOSInfo = {
platform,
version: String(Platform.Version)
};
const customData = {
platform_version: getReactNativeVersion()
};
const uikitExtension = {
product: SendbirdProduct.UIKIT_CHAT,
version: SendbirdUIKit.VERSION,
platform: SendbirdPlatform.REACT_NATIVE
};
chatSDK.addSendbirdExtensions([uikitExtension], deviceOSInfo, customData);
chatSDK.addExtension('sb_uikit', SendbirdUIKit.VERSION);
}
if (SendbirdUIKit.PLATFORM) {
chatSDK.addExtension('device-os-platform', SendbirdUIKit.PLATFORM);
}
if (NetInfo !== null && NetInfo !== void 0 && NetInfo.addEventListener) {
var _chatSDK$setOnlineLis, _chatSDK, _chatSDK$setOfflineLi, _chatSDK2;
try {
// NOTE: For removing buggy behavior of NetInfo.addEventListener
// When you first add an event listener, it is assumed that the initialization of the internal event detector is done simultaneously.
// In other words, when you call the first event listener two events are triggered immediately
// - the one that is called when adding the event listener
// - and the internal initialization event
NetInfo.addEventListener(NOOP)();
} catch {}
const listener = (callback, callbackType) => {
let callCount = 0;
const unsubscribe = NetInfo.addEventListener(state => {
const online = Boolean(state.isConnected) || Boolean(state.isInternetReachable);
// NOTE: When NetInfo.addEventListener is called
// the event is immediately triggered regardless of whether the event actually occurred.
// This is why it filters the first event.
if (callCount === 0) {
callCount++;
return;
}
if (online && callbackType === 'online') callback();
if (!online && callbackType === 'offline') callback();
});
unsubscribes.push(unsubscribe);
return unsubscribe;
};
(_chatSDK$setOnlineLis = (_chatSDK = chatSDK).setOnlineListener) === null || _chatSDK$setOnlineLis === void 0 ? void 0 : _chatSDK$setOnlineLis.call(_chatSDK, onOnline => listener(onOnline, 'online'));
(_chatSDK$setOfflineLi = (_chatSDK2 = chatSDK).setOfflineListener) === null || _chatSDK$setOfflineLi === void 0 ? void 0 : _chatSDK$setOfflineLi.call(_chatSDK2, onOffline => listener(onOffline, 'offline'));
}
return {
chatSDK,
unsubscribes
};
};
function getDeviceOSPlatform() {
switch (Platform.OS) {
case 'android':
return DeviceOsPlatform.ANDROID;
case 'ios':
return DeviceOsPlatform.IOS;
case 'web':
return DeviceOsPlatform.WEB;
case 'windows':
return DeviceOsPlatform.WINDOWS;
default:
return undefined;
}
}
function getReactNativeVersion() {
const {
major,
minor,
patch
} = Platform.constants.reactNativeVersion;
return `${major}.${minor}.${patch}`;
}
const useConfigInstance = _ref => {
var _voiceMessage$recorde3, _voiceMessage$recorde4;
let {
imageCompression,
userMention,
voiceMessage
} = _ref;
const mentionConfig = useMemo(() => {
return new MentionConfig({
mentionLimit: (userMention === null || userMention === void 0 ? void 0 : userMention.mentionLimit) || MentionConfig.DEFAULT.MENTION_LIMIT,
suggestionLimit: (userMention === null || userMention === void 0 ? void 0 : userMention.suggestionLimit) || MentionConfig.DEFAULT.SUGGESTION_LIMIT,
debounceMills: (userMention === null || userMention === void 0 ? void 0 : userMention.debounceMills) ?? MentionConfig.DEFAULT.DEBOUNCE_MILLS,
delimiter: MentionConfig.DEFAULT.DELIMITER,
trigger: MentionConfig.DEFAULT.TRIGGER
});
}, [userMention === null || userMention === void 0 ? void 0 : userMention.mentionLimit, userMention === null || userMention === void 0 ? void 0 : userMention.suggestionLimit, userMention === null || userMention === void 0 ? void 0 : userMention.debounceMills]);
const imageCompressionConfig = useMemo(() => {
return new ImageCompressionConfig({
compressionRate: (imageCompression === null || imageCompression === void 0 ? void 0 : imageCompression.compressionRate) || ImageCompressionConfig.DEFAULT.COMPRESSION_RATE,
width: imageCompression === null || imageCompression === void 0 ? void 0 : imageCompression.width,
height: imageCompression === null || imageCompression === void 0 ? void 0 : imageCompression.height
});
}, [imageCompression === null || imageCompression === void 0 ? void 0 : imageCompression.compressionRate, imageCompression === null || imageCompression === void 0 ? void 0 : imageCompression.width, imageCompression === null || imageCompression === void 0 ? void 0 : imageCompression.height]);
const voiceMessageConfig = useMemo(() => {
var _voiceMessage$recorde, _voiceMessage$recorde2;
return new VoiceMessageConfig({
recorder: {
minDuration: (voiceMessage === null || voiceMessage === void 0 ? void 0 : (_voiceMessage$recorde = voiceMessage.recorder) === null || _voiceMessage$recorde === void 0 ? void 0 : _voiceMessage$recorde.minDuration) ?? VoiceMessageConfig.DEFAULT.RECORDER.MIN_DURATION,
maxDuration: (voiceMessage === null || voiceMessage === void 0 ? void 0 : (_voiceMessage$recorde2 = voiceMessage.recorder) === null || _voiceMessage$recorde2 === void 0 ? void 0 : _voiceMessage$recorde2.maxDuration) ?? VoiceMessageConfig.DEFAULT.RECORDER.MAX_DURATION
}
});
}, [voiceMessage === null || voiceMessage === void 0 ? void 0 : (_voiceMessage$recorde3 = voiceMessage.recorder) === null || _voiceMessage$recorde3 === void 0 ? void 0 : _voiceMessage$recorde3.minDuration, voiceMessage === null || voiceMessage === void 0 ? void 0 : (_voiceMessage$recorde4 = voiceMessage.recorder) === null || _voiceMessage$recorde4 === void 0 ? void 0 : _voiceMessage$recorde4.maxDuration]);
return {
mentionConfig,
imageCompressionConfig,
voiceMessageConfig
};
};
export default SendbirdUIKitContainer;
//# sourceMappingURL=SendbirdUIKitContainer.js.map