Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/lib/Sendbird/context/SendbirdContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createStore } from '../../../utils/storeManager';
import { initialState } from './initialState';
import { SendbirdState } from '../types';
import { useStore } from '../../../hooks/useStore';
import { TwoDepthPartial } from '../../../utils/typeHelpers/partialDeep';

/**
* SendbirdContext
Expand All @@ -12,7 +13,25 @@ export const SendbirdContext = React.createContext<ReturnType<typeof createStore
/**
* Create store for Sendbird context
*/
export const createSendbirdContextStore = () => createStore(initialState);
export const createSendbirdContextStore = (props?: TwoDepthPartial<SendbirdState>) => createStore({
config: {
...initialState.config,
...props?.config,
},
stores: {
...initialState.stores,
...props?.stores,
},
eventHandlers: {
...initialState.eventHandlers,
...props?.eventHandlers,
},
emojiManager: initialState.emojiManager,
utils: {
...initialState.utils,
...props?.utils,
},
});

/**
* A specialized hook for Ssendbird state management
Expand Down
84 changes: 67 additions & 17 deletions src/lib/Sendbird/context/SendbirdProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@ import React, { ReactElement, useEffect, useMemo, useRef, useState } from 'react
import { useUIKitConfig } from '@sendbird/uikit-tools';

/* Types */
import type { ImageCompressionOptions, SendbirdProviderProps, SendbirdStateConfig } from '../types';
import {
ImageCompressionOptions,
Logger,
SendbirdProviderProps,
SendbirdState,
SendbirdStateConfig,
} from '../types';

/* Providers */
import VoiceMessageProvider from '../../VoiceMessageProvider';
Expand Down Expand Up @@ -33,10 +39,10 @@ import { DEFAULT_MULTIPLE_FILES_MESSAGE_LIMIT, DEFAULT_UPLOAD_SIZE_LIMIT, VOICE_
import { EmojiReactionListRoot, MenuRoot } from '../../../ui/ContextMenu';

import useSendbird from './hooks/useSendbird';
import { SendbirdContext, useSendbirdStore } from './SendbirdContext';
import { createStore } from '../../../utils/storeManager';
import { initialState } from './initialState';
import { createSendbirdContextStore, SendbirdContext, useSendbirdStore } from './SendbirdContext';
import useDeepCompareEffect from '../../../hooks/useDeepCompareEffect';
import { deleteNullish } from '../../../utils/utils';
import { TwoDepthPartial } from '../../../utils/typeHelpers/partialDeep';

/**
* SendbirdContext - Manager
Expand All @@ -49,6 +55,7 @@ const SendbirdContextManager = ({
customWebSocketHost,
configureSession,
theme = 'light',
logger,
config = {},
nickname = '',
colorSet,
Expand All @@ -68,11 +75,10 @@ const SendbirdContextManager = ({
eventHandlers,
htmlTextDirection = 'ltr',
forceLeftToRightMessageLayout = false,
}: SendbirdProviderProps): ReactElement => {
}: SendbirdProviderProps & { logger: Logger }): ReactElement => {
const onStartDirectMessage = _onStartDirectMessage ?? _onUserProfileMessage;
const { logLevel = '', userMention = {}, isREMUnitEnabled = false, pubSub: customPubSub } = config;
const { userMention = {}, isREMUnitEnabled = false, pubSub: customPubSub } = config;
const { isMobile } = useMediaQueryContext();
const [logger, setLogger] = useState(LoggerFactory(logLevel as LogLevel));
const [pubSub] = useState(customPubSub ?? pubSubFactory<PUBSUB_TOPICS, SBUGlobalPubSubTopicPayloadUnion>());

const { state, updateState } = useSendbirdStore();
Expand Down Expand Up @@ -121,11 +127,6 @@ const SendbirdContextManager = ({
actions.disconnect({ logger });
});

// to create a pubsub to communicate between parent and child
useEffect(() => {
setLogger(LoggerFactory(logLevel as LogLevel));
}, [logLevel]);

// should move to reducer
const [currentTheme, setCurrentTheme] = useState(theme);
useEffect(() => {
Expand Down Expand Up @@ -365,8 +366,49 @@ const SendbirdContextManager = ({
return null;
};

const InternalSendbirdProvider = ({ children, stringSet, breakpoint, dateLocale }) => {
const storeRef = useRef(createStore(initialState));
const InternalSendbirdProvider = (props: SendbirdProviderProps & { logger: Logger }) => {
const {
children,
stringSet,
breakpoint,
dateLocale,
} = props;

const defaultProps: TwoDepthPartial<SendbirdState> = deleteNullish({
config: {
renderUserProfile: props?.renderUserProfile,
onStartDirectMessage: props?.onStartDirectMessage,
allowProfileEdit: props?.allowProfileEdit,
appId: props?.appId,
userId: props?.userId,
accessToken: props?.accessToken,
theme: props?.theme,
htmlTextDirection: props?.htmlTextDirection,
forceLeftToRightMessageLayout: props?.forceLeftToRightMessageLayout,
pubSub: props?.config?.pubSub,
logger: props?.logger,
userListQuery: props?.userListQuery,
voiceRecord: {
maxRecordingTime: props?.voiceRecord?.maxRecordingTime ?? VOICE_RECORDER_DEFAULT_MAX,
minRecordingTime: props?.voiceRecord?.minRecordingTime ?? VOICE_RECORDER_DEFAULT_MIN,
},
userMention: {
maxMentionCount: props?.config?.userMention?.maxMentionCount || 10,
maxSuggestionCount: props?.config?.userMention?.maxSuggestionCount || 15,
},
imageCompression: {
compressionRate: 0.7,
outputFormat: 'preserve',
...props?.imageCompression,
},
disableMarkAsDelivered: props?.disableMarkAsDelivered,
isMultipleFilesMessageEnabled: props?.isMultipleFilesMessageEnabled,
},
eventHandlers: props?.eventHandlers,
});

const storeRef = useRef(createSendbirdContextStore(defaultProps));

const localeStringSet = useMemo(() => {
return { ...getStringSet('en'), ...stringSet };
}, [stringSet]);
Expand All @@ -391,11 +433,19 @@ const InternalSendbirdProvider = ({ children, stringSet, breakpoint, dateLocale
};

export const SendbirdContextProvider = (props: SendbirdProviderProps) => {
const { children } = props;
const { children, config } = props;
const logLevel = config?.logLevel;

const [logger, setLogger] = useState(LoggerFactory(logLevel as LogLevel));

// to create a pubsub to communicate between parent and child
useEffect(() => {
setLogger(LoggerFactory(logLevel as LogLevel));
}, [logLevel]);

return (
<InternalSendbirdProvider stringSet={props.stringSet} breakpoint={props.breakpoint} dateLocale={props.dateLocale} >
<SendbirdContextManager {...props} />
<InternalSendbirdProvider {...props} logger={logger} >
<SendbirdContextManager {...props} logger={logger} />
{children}
</InternalSendbirdProvider>
);
Expand Down
28 changes: 23 additions & 5 deletions src/modules/ChannelSettings/context/ChannelSettingsProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useStore } from '../../../hooks/useStore';
import { useChannelHandler } from './hooks/useChannelHandler';

import uuidv4 from '../../../utils/uuid';
import { classnames } from '../../../utils/utils';
import { classnames, deleteNullish } from '../../../utils/utils';
import { createStore } from '../../../utils/storeManager';
import { UserProfileProvider } from '../../../lib/UserProfileContext';
import useSendbird from '../../../lib/Sendbird/context/hooks/useSendbird';
Expand Down Expand Up @@ -103,9 +103,27 @@ const ChannelSettingsManager = ({
return null;
};

const createChannelSettingsStore = () => createStore(initialState);
const InternalChannelSettingsProvider = ({ children }) => {
const storeRef = useRef(createChannelSettingsStore());
const createChannelSettingsStore = (props?: Partial<ChannelSettingsState>) => createStore({
...initialState,
...props,
});

const InternalChannelSettingsProvider = (props: ChannelSettingsContextProps) => {
const { children } = props;

const defaultProps: Partial<ChannelSettingsState> = deleteNullish({
channelUrl: props?.channelUrl,
onCloseClick: props?.onCloseClick,
onLeaveChannel: props?.onLeaveChannel,
onChannelModified: props?.onChannelModified,
onBeforeUpdateChannel: props?.onBeforeUpdateChannel,
renderUserListItem: props?.renderUserListItem,
queries: props?.queries,
overrideInviteUser: props?.overrideInviteUser,
});

const storeRef = useRef(createChannelSettingsStore(defaultProps));

return (
<ChannelSettingsContext.Provider value={storeRef.current}>
{children}
Expand All @@ -116,7 +134,7 @@ const InternalChannelSettingsProvider = ({ children }) => {
const ChannelSettingsProvider = (props: ChannelSettingsContextProps) => {
const { children, className } = props;
return (
<InternalChannelSettingsProvider>
<InternalChannelSettingsProvider {...props}>
<ChannelSettingsManager {...props} />
<UserProfileProvider {...props}>
<div className={classnames('sendbird-channel-settings', className)}>
Expand Down
2 changes: 1 addition & 1 deletion src/modules/ChannelSettings/context/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ export interface ChannelSettingsState extends CommonChannelSettingsProps {
export interface ChannelSettingsContextProps extends
CommonChannelSettingsProps,
Pick<UserProfileProviderProps, 'renderUserProfile' | 'disableUserProfile'> {
children?: React.ReactElement;
children?: ReactNode;
className?: string;
}
24 changes: 20 additions & 4 deletions src/modules/CreateChannel/context/CreateChannelProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { createStore } from '../../../utils/storeManager';
import { useStore } from '../../../hooks/useStore';
import useCreateChannel from './useCreateChannel';
import useSendbird from '../../../lib/Sendbird/context/hooks/useSendbird';
import { deleteNullish } from '../../../utils/utils';

const CreateChannelContext = React.createContext<ReturnType<typeof createStore<CreateChannelState>> | null>(null);

Expand Down Expand Up @@ -139,16 +140,31 @@ const CreateChannelProvider: React.FC<CreateChannelProviderProps> = (props: Crea
const { children } = props;

return (
<InternalCreateChannelProvider>
<InternalCreateChannelProvider {...props}>
<CreateChannelManager {...props} />
{children}
</InternalCreateChannelProvider>
);
};

const createCreateChannelStore = () => createStore(initialState);
const InternalCreateChannelProvider: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
const storeRef = useRef(createCreateChannelStore());
const createCreateChannelStore = (props?: Partial<CreateChannelState>) => createStore({
...initialState,
...props,
});

const InternalCreateChannelProvider: React.FC<React.PropsWithChildren<unknown>> = (props: CreateChannelProviderProps) => {
const { children } = props;

const defaultProps: Partial<CreateChannelState> = deleteNullish({
userListQuery: props?.userListQuery,
onCreateChannelClick: props?.onCreateChannelClick,
onChannelCreated: props?.onChannelCreated,
onBeforeCreateChannel: props?.onBeforeCreateChannel,
onCreateChannel: props?.onCreateChannel,
overrideInviteUser: props?.overrideInviteUser,
});

const storeRef = useRef(createCreateChannelStore(defaultProps));

return (
<CreateChannelContext.Provider value={storeRef.current}>
Expand Down
47 changes: 44 additions & 3 deletions src/modules/GroupChannel/context/GroupChannelProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import type {
} from './types';
import useSendbird from '../../../lib/Sendbird/context/hooks/useSendbird';
import useDeepCompareEffect from '../../../hooks/useDeepCompareEffect';
import { deleteNullish } from '../../../utils/utils';

const initialState = {
currentChannel: null,
Expand Down Expand Up @@ -60,8 +61,48 @@ const initialState = {

export const GroupChannelContext = createContext<ReturnType<typeof createStore<GroupChannelState>> | null>(null);

export const InternalGroupChannelProvider: React.FC<React.PropsWithChildren<unknown>> = ({ children }) => {
const storeRef = useRef(createStore(initialState));
const createGroupChannelStore = (props?: Partial<GroupChannelState>) => createStore({
...initialState,
...props,
});

export const InternalGroupChannelProvider = (props: GroupChannelProviderProps) => {
const { children } = props;

const defaultProps: Partial<GroupChannelState> = deleteNullish({
channelUrl: props?.channelUrl,
renderUserProfile: props?.renderUserProfile,
disableUserProfile: props?.disableUserProfile,
onUserProfileMessage: props?.onUserProfileMessage,
onStartDirectMessage: props?.onStartDirectMessage,
isReactionEnabled: props?.isReactionEnabled,
isMessageGroupingEnabled: props?.isMessageGroupingEnabled,
isMultipleFilesMessageEnabled: props?.isMultipleFilesMessageEnabled,
showSearchIcon: props?.showSearchIcon,
threadReplySelectType: props?.threadReplySelectType,
disableMarkAsRead: props?.disableMarkAsRead,
scrollBehavior: props?.scrollBehavior,
forceLeftToRightMessageLayout: props?.forceLeftToRightMessageLayout,
startingPoint: props?.startingPoint,
animatedMessageId: props?.animatedMessageId,
onMessageAnimated: props?.onMessageAnimated,
messageListQueryParams: props?.messageListQueryParams,
filterEmojiCategoryIds: props?.filterEmojiCategoryIds,
onBeforeSendUserMessage: props?.onBeforeSendUserMessage,
onBeforeSendFileMessage: props?.onBeforeSendFileMessage,
onBeforeSendVoiceMessage: props?.onBeforeSendVoiceMessage,
onBeforeSendMultipleFilesMessage: props?.onBeforeSendMultipleFilesMessage,
onBeforeUpdateUserMessage: props?.onBeforeUpdateUserMessage,
onBeforeDownloadFileMessage: props?.onBeforeDownloadFileMessage,
onBackClick: props?.onBackClick,
onChatHeaderActionClick: props?.onChatHeaderActionClick,
onReplyInThreadClick: props?.onReplyInThreadClick,
onSearchClick: props?.onSearchClick,
onQuoteMessageClick: props?.onQuoteMessageClick,
renderUserMentionItem: props?.renderUserMentionItem,
});

const storeRef = useRef(createGroupChannelStore(defaultProps));

return (
<GroupChannelContext.Provider value={storeRef.current}>
Expand Down Expand Up @@ -319,7 +360,7 @@ const GroupChannelManager :React.FC<React.PropsWithChildren<GroupChannelProvider

const GroupChannelProvider: React.FC<GroupChannelProviderProps> = (props) => {
return (
<InternalGroupChannelProvider>
<InternalGroupChannelProvider {...props}>
<GroupChannelManager {...props}>
<UserProfileProvider {...props}>
{props.children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ describe('useGroupChannel', () => {
it('provides initial state', () => {
const { result } = renderHook(() => useGroupChannel(), { wrapper });

expect(result.current.state).toEqual(expect.objectContaining({
expect(result.current.state).toMatchObject({
currentChannel: null,
channelUrl: mockChannel.url,
fetchChannelError: null,
quoteMessage: null,
animatedMessageId: null,
isScrollBottomReached: true,
}));
});
});

it('updates channel state', () => {
Expand Down
Loading