Skip to content

Commit 31372a7

Browse files
authored
Merge pull request #198 from sendbird/feat/open-url-interface
[CLNP-5024] feat: added sbu handlers interface
2 parents 311c0b8 + 47fff47 commit 31372a7

File tree

9 files changed

+153
-98
lines changed

9 files changed

+153
-98
lines changed

packages/uikit-react-native/src/components/ChannelMessageList/index.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,13 @@ import {
3030
} from '@sendbird/uikit-utils';
3131

3232
import type { UserProfileContextType } from '../../contexts/UserProfileCtx';
33-
import { useLocalization, usePlatformService, useSendbirdChat, useUserProfile } from '../../hooks/useContext';
34-
import SBUUtils from '../../libs/SBUUtils';
33+
import {
34+
useLocalization,
35+
usePlatformService,
36+
useSBUHandlers,
37+
useSendbirdChat,
38+
useUserProfile,
39+
} from '../../hooks/useContext';
3540
import ChatFlatList from '../ChatFlatList';
3641
import { ReactionAddons } from '../ReactionAddons';
3742

@@ -216,6 +221,7 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
216221
| 'onResendFailedMessage'
217222
| 'onPressMediaMessage'
218223
>): CreateMessagePressActions => {
224+
const handlers = useSBUHandlers();
219225
const { colors } = useUIKitTheme();
220226
const { STRINGS } = useLocalization();
221227
const toast = useToast();
@@ -265,9 +271,8 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
265271
const fileType = getFileType(message.type || getFileExtension(message.name));
266272
if (['image', 'video', 'audio'].includes(fileType)) {
267273
onPressMediaMessage?.(message, () => onDeleteMessage(message), getAvailableUriFromFileMessage(message));
268-
} else {
269-
SBUUtils.openURL(message.url);
270274
}
275+
handlers.onOpenFileURL(message.url);
271276
}
272277
};
273278

packages/uikit-react-native/src/components/ChannelThreadMessageList/index.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,13 @@ import {
3030
} from '@sendbird/uikit-utils';
3131

3232
import type { UserProfileContextType } from '../../contexts/UserProfileCtx';
33-
import { useLocalization, usePlatformService, useSendbirdChat, useUserProfile } from '../../hooks/useContext';
34-
import SBUUtils from '../../libs/SBUUtils';
33+
import {
34+
useLocalization,
35+
usePlatformService,
36+
useSBUHandlers,
37+
useSendbirdChat,
38+
useUserProfile,
39+
} from '../../hooks/useContext';
3540
import { ReactionAddons } from '../ReactionAddons';
3641
import ThreadChatFlatList from '../ThreadChatFlatList';
3742

@@ -194,6 +199,7 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
194199
ChannelThreadMessageListProps<T>,
195200
'channel' | 'currentUserId' | 'onEditMessage' | 'onDeleteMessage' | 'onResendFailedMessage' | 'onPressMediaMessage'
196201
>): CreateMessagePressActions => {
202+
const handlers = useSBUHandlers();
197203
const { colors } = useUIKitTheme();
198204
const { STRINGS } = useLocalization();
199205
const toast = useToast();
@@ -243,9 +249,8 @@ const useCreateMessagePressActions = <T extends SendbirdGroupChannel | SendbirdO
243249
const fileType = getFileType(message.type || getFileExtension(message.name));
244250
if (['image', 'video', 'audio'].includes(fileType)) {
245251
onPressMediaMessage?.(message, () => onDeleteMessage(message), getAvailableUriFromFileMessage(message));
246-
} else {
247-
SBUUtils.openURL(message.url);
248252
}
253+
handlers.onOpenFileURL(message.url);
249254
}
250255
};
251256

packages/uikit-react-native/src/components/GroupChannelMessageRenderer/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ import {
2525
import { VOICE_MESSAGE_META_ARRAY_DURATION_KEY } from '../../constants';
2626
import { GroupChannelContexts } from '../../domain/groupChannel/module/moduleContext';
2727
import type { GroupChannelProps } from '../../domain/groupChannel/types';
28-
import { useLocalization, usePlatformService, useSendbirdChat } from '../../hooks/useContext';
29-
import SBUUtils from '../../libs/SBUUtils';
28+
import { useLocalization, usePlatformService, useSBUHandlers, useSendbirdChat } from '../../hooks/useContext';
3029
import { TypingIndicatorType } from '../../types';
3130
import { ReactionAddons } from '../ReactionAddons';
3231
import GroupChannelMessageDateSeparator from './GroupChannelMessageDateSeparator';
@@ -49,6 +48,7 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
4948
nextMessage,
5049
hideParentMessage,
5150
}) => {
51+
const handlers = useSBUHandlers();
5252
const playerUnsubscribes = useRef<(() => void)[]>([]);
5353
const { palette } = useUIKitTheme();
5454
const { sbOptions, currentUser, mentionManager, voiceMessageStatusManager } = useSendbirdChat();
@@ -98,7 +98,7 @@ const GroupChannelMessageRenderer: GroupChannelProps['Fragment']['renderMessage'
9898
variant,
9999
onPress,
100100
onLongPress,
101-
onPressURL: (url) => SBUUtils.openURL(url),
101+
onPressURL: (url) => handlers.onOpenURL(url),
102102
onPressAvatar: () => {
103103
if ('sender' in message) onShowUserProfile?.(message.sender);
104104
},

packages/uikit-react-native/src/components/OpenChannelMessageRenderer/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ import {
1212
} from '@sendbird/uikit-utils';
1313

1414
import type { OpenChannelProps } from '../../domain/openChannel/types';
15-
import { useLocalization, usePlatformService, useSendbirdChat } from '../../hooks/useContext';
16-
import SBUUtils from '../../libs/SBUUtils';
15+
import { useLocalization, usePlatformService, useSBUHandlers, useSendbirdChat } from '../../hooks/useContext';
1716
import OpenChannelMessageDateSeparator from './OpenChannelMessageDateSeparator';
1817

1918
const OpenChannelMessageRenderer: OpenChannelProps['Fragment']['renderMessage'] = ({
@@ -26,6 +25,7 @@ const OpenChannelMessageRenderer: OpenChannelProps['Fragment']['renderMessage']
2625
prevMessage,
2726
nextMessage,
2827
}) => {
28+
const handlers = useSBUHandlers();
2929
const { sbOptions } = useSendbirdChat();
3030
const { STRINGS } = useLocalization();
3131
const { mediaService } = usePlatformService();
@@ -35,7 +35,7 @@ const OpenChannelMessageRenderer: OpenChannelProps['Fragment']['renderMessage']
3535
channel,
3636
onPress,
3737
onLongPress,
38-
onPressURL: (url) => SBUUtils.openURL(url),
38+
onPressURL: (url) => handlers.onOpenURL(url),
3939
onPressAvatar: () => 'sender' in message && onShowUserProfile?.(message.sender, { hideMessageButton: true }),
4040
grouped: groupWithPrev,
4141
strings: {

packages/uikit-react-native/src/components/ThreadParentMessageRenderer/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import {
1111
} from '@sendbird/uikit-utils';
1212

1313
import { VOICE_MESSAGE_META_ARRAY_DURATION_KEY } from '../../constants';
14-
import SBUUtils from '../../libs/SBUUtils';
15-
import { usePlatformService, useSendbirdChat } from './../../hooks/useContext';
14+
import { usePlatformService, useSBUHandlers, useSendbirdChat } from './../../hooks/useContext';
1615
import ThreadParentMessageFile from './ThreadParentMessage.file';
1716
import ThreadParentMessageFileImage from './ThreadParentMessage.file.image';
1817
import ThreadParentMessageFileVideo from './ThreadParentMessage.file.video';
@@ -33,6 +32,7 @@ export type ThreadParentMessageRendererProps<AdditionalProps = unknown> = {
3332
} & AdditionalProps;
3433

3534
const ThreadParentMessageRenderer = (props: ThreadParentMessageRendererProps) => {
35+
const handlers = useSBUHandlers();
3636
const playerUnsubscribes = useRef<(() => void)[]>([]);
3737
const { sbOptions, currentUser, mentionManager } = useSendbirdChat();
3838
const { palette } = useUIKitTheme();
@@ -50,7 +50,7 @@ const ThreadParentMessageRenderer = (props: ThreadParentMessageRendererProps) =>
5050
};
5151

5252
const messageProps: ThreadParentMessageRendererProps = {
53-
onPressURL: (url) => SBUUtils.openURL(url),
53+
onPressURL: (url) => handlers.onOpenURL(url),
5454
onToggleVoiceMessage: async (state, setState) => {
5555
if (isVoiceMessage(parentMessage) && parentMessage.sendingStatus === 'succeeded') {
5656
if (playerService.uri === parentMessage.url) {

packages/uikit-react-native/src/containers/SendbirdUIKitContainer.tsx

Lines changed: 89 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
import { LocalizationContext, LocalizationProvider } from '../contexts/LocalizationCtx';
3333
import { PlatformServiceProvider } from '../contexts/PlatformServiceCtx';
3434
import { ReactionProvider } from '../contexts/ReactionCtx';
35+
import { type SBUHandlers, SBUHandlersProvider } from '../contexts/SBUHandlersCtx';
3536
import type { ChatRelatedFeaturesInUIKit } from '../contexts/SendbirdChatCtx';
3637
import { SendbirdChatProvider } from '../contexts/SendbirdChatCtx';
3738
import { UserProfileProvider } from '../contexts/UserProfileCtx';
@@ -41,6 +42,7 @@ import ImageCompressionConfig from '../libs/ImageCompressionConfig';
4142
import InternalLocalCacheStorage from '../libs/InternalLocalCacheStorage';
4243
import MentionConfig, { MentionConfigInterface } from '../libs/MentionConfig';
4344
import MentionManager from '../libs/MentionManager';
45+
import SBUUtils from '../libs/SBUUtils';
4446
import VoiceMessageConfig, { VoiceMessageConfigInterface } from '../libs/VoiceMessageConfig';
4547
import VoiceMessageStatusManager from '../libs/VoiceMessageStatusManager';
4648
import StringSetEn from '../localization/StringSet.en';
@@ -131,6 +133,7 @@ export type SendbirdUIKitContainerProps = React.PropsWithChildren<{
131133
onError?: (props: ErrorBoundaryProps) => void;
132134
ErrorInfoComponent?: (props: ErrorBoundaryProps) => React.ReactNode;
133135
};
136+
handlers?: Partial<SBUHandlers>;
134137
toast?: {
135138
dismissTimeout?: number;
136139
};
@@ -159,6 +162,7 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
159162
localization,
160163
styles,
161164
errorBoundary,
165+
handlers,
162166
toast,
163167
userProfile,
164168
reaction,
@@ -213,85 +217,93 @@ const SendbirdUIKitContainer = (props: SendbirdUIKitContainerProps) => {
213217
}
214218
};
215219

220+
const sbuHandlers: SBUHandlers = {
221+
onOpenURL: SBUUtils.openURL,
222+
onOpenFileURL: SBUUtils.openURL,
223+
...handlers,
224+
};
225+
216226
return (
217-
<SafeAreaProvider>
218-
<UIKitConfigProvider
219-
storage={internalStorage}
220-
localConfigs={{
221-
common: uikitOptions?.common,
222-
groupChannel: {
223-
channel: { ...uikitOptions?.groupChannel, enableReactionsSupergroup: undefined },
224-
channelList: uikitOptions?.groupChannelList,
225-
setting: uikitOptions?.groupChannelSettings,
226-
},
227-
openChannel: {
228-
channel: uikitOptions?.openChannel,
229-
},
230-
}}
231-
>
232-
<SendbirdChatProvider
233-
sdkInstance={sdkInstance}
234-
emojiManager={emojiManager}
235-
mentionManager={mentionManager}
236-
imageCompressionConfig={imageCompressionConfig}
237-
voiceMessageConfig={voiceMessageConfig}
238-
voiceMessageStatusManager={voiceMessageStatusManager}
239-
enableAutoPushTokenRegistration={
240-
chatOptions.enableAutoPushTokenRegistration ?? SendbirdUIKit.DEFAULT.AUTO_PUSH_TOKEN_REGISTRATION
241-
}
242-
enableUseUserIdForNickname={
243-
chatOptions.enableUseUserIdForNickname ?? SendbirdUIKit.DEFAULT.USE_USER_ID_FOR_NICKNAME
244-
}
245-
enableImageCompression={chatOptions.enableImageCompression ?? SendbirdUIKit.DEFAULT.IMAGE_COMPRESSION}
227+
<SBUHandlersProvider {...sbuHandlers}>
228+
<SafeAreaProvider>
229+
<UIKitConfigProvider
230+
storage={internalStorage}
231+
localConfigs={{
232+
common: uikitOptions?.common,
233+
groupChannel: {
234+
channel: { ...uikitOptions?.groupChannel, enableReactionsSupergroup: undefined },
235+
channelList: uikitOptions?.groupChannelList,
236+
setting: uikitOptions?.groupChannelSettings,
237+
},
238+
openChannel: {
239+
channel: uikitOptions?.openChannel,
240+
},
241+
}}
246242
>
247-
<LocalizationProvider stringSet={defaultStringSet}>
248-
<PlatformServiceProvider
249-
fileService={platformServices.file}
250-
notificationService={platformServices.notification}
251-
clipboardService={platformServices.clipboard}
252-
mediaService={platformServices.media}
253-
playerService={platformServices.player}
254-
recorderService={platformServices.recorder}
255-
voiceMessageConfig={voiceMessageConfig}
256-
>
257-
<UIKitThemeProvider theme={styles?.theme ?? LightUIKitTheme}>
258-
<HeaderStyleProvider
259-
HeaderComponent={styles?.HeaderComponent ?? Header}
260-
defaultTitleAlign={styles?.defaultHeaderTitleAlign ?? 'left'}
261-
statusBarTranslucent={styles?.statusBarTranslucent ?? true}
262-
>
263-
<ToastProvider dismissTimeout={toast?.dismissTimeout}>
264-
<UserProfileProvider {...userProfile} statusBarTranslucent={styles?.statusBarTranslucent ?? true}>
265-
<ReactionProvider {...reaction}>
266-
<LocalizationContext.Consumer>
267-
{(value) => {
268-
const STRINGS = value?.STRINGS || defaultStringSet;
269-
return (
270-
<DialogProvider
271-
defaultLabels={{
272-
alert: { ok: STRINGS.DIALOG.ALERT_DEFAULT_OK },
273-
prompt: {
274-
ok: STRINGS.DIALOG.PROMPT_DEFAULT_OK,
275-
cancel: STRINGS.DIALOG.PROMPT_DEFAULT_CANCEL,
276-
placeholder: STRINGS.DIALOG.PROMPT_DEFAULT_PLACEHOLDER,
277-
},
278-
}}
279-
>
280-
{renderChildren()}
281-
</DialogProvider>
282-
);
283-
}}
284-
</LocalizationContext.Consumer>
285-
</ReactionProvider>
286-
</UserProfileProvider>
287-
</ToastProvider>
288-
</HeaderStyleProvider>
289-
</UIKitThemeProvider>
290-
</PlatformServiceProvider>
291-
</LocalizationProvider>
292-
</SendbirdChatProvider>
293-
</UIKitConfigProvider>
294-
</SafeAreaProvider>
243+
<SendbirdChatProvider
244+
sdkInstance={sdkInstance}
245+
emojiManager={emojiManager}
246+
mentionManager={mentionManager}
247+
imageCompressionConfig={imageCompressionConfig}
248+
voiceMessageConfig={voiceMessageConfig}
249+
voiceMessageStatusManager={voiceMessageStatusManager}
250+
enableAutoPushTokenRegistration={
251+
chatOptions.enableAutoPushTokenRegistration ?? SendbirdUIKit.DEFAULT.AUTO_PUSH_TOKEN_REGISTRATION
252+
}
253+
enableUseUserIdForNickname={
254+
chatOptions.enableUseUserIdForNickname ?? SendbirdUIKit.DEFAULT.USE_USER_ID_FOR_NICKNAME
255+
}
256+
enableImageCompression={chatOptions.enableImageCompression ?? SendbirdUIKit.DEFAULT.IMAGE_COMPRESSION}
257+
>
258+
<LocalizationProvider stringSet={defaultStringSet}>
259+
<PlatformServiceProvider
260+
fileService={platformServices.file}
261+
notificationService={platformServices.notification}
262+
clipboardService={platformServices.clipboard}
263+
mediaService={platformServices.media}
264+
playerService={platformServices.player}
265+
recorderService={platformServices.recorder}
266+
voiceMessageConfig={voiceMessageConfig}
267+
>
268+
<UIKitThemeProvider theme={styles?.theme ?? LightUIKitTheme}>
269+
<HeaderStyleProvider
270+
HeaderComponent={styles?.HeaderComponent ?? Header}
271+
defaultTitleAlign={styles?.defaultHeaderTitleAlign ?? 'left'}
272+
statusBarTranslucent={styles?.statusBarTranslucent ?? true}
273+
>
274+
<ToastProvider dismissTimeout={toast?.dismissTimeout}>
275+
<UserProfileProvider {...userProfile} statusBarTranslucent={styles?.statusBarTranslucent ?? true}>
276+
<ReactionProvider {...reaction}>
277+
<LocalizationContext.Consumer>
278+
{(value) => {
279+
const STRINGS = value?.STRINGS || defaultStringSet;
280+
return (
281+
<DialogProvider
282+
defaultLabels={{
283+
alert: { ok: STRINGS.DIALOG.ALERT_DEFAULT_OK },
284+
prompt: {
285+
ok: STRINGS.DIALOG.PROMPT_DEFAULT_OK,
286+
cancel: STRINGS.DIALOG.PROMPT_DEFAULT_CANCEL,
287+
placeholder: STRINGS.DIALOG.PROMPT_DEFAULT_PLACEHOLDER,
288+
},
289+
}}
290+
>
291+
{renderChildren()}
292+
</DialogProvider>
293+
);
294+
}}
295+
</LocalizationContext.Consumer>
296+
</ReactionProvider>
297+
</UserProfileProvider>
298+
</ToastProvider>
299+
</HeaderStyleProvider>
300+
</UIKitThemeProvider>
301+
</PlatformServiceProvider>
302+
</LocalizationProvider>
303+
</SendbirdChatProvider>
304+
</UIKitConfigProvider>
305+
</SafeAreaProvider>
306+
</SBUHandlersProvider>
295307
);
296308
};
297309

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React from 'react';
2+
3+
export interface SBUHandlers {
4+
/**
5+
* Callback function to handle opening a URL.
6+
* This is triggered when a URL needs to be opened.
7+
*/
8+
onOpenURL: (url: string) => void;
9+
10+
/**
11+
* Callback function to handle opening a file URL.
12+
* This is triggered when a file URL needs to be opened.
13+
*
14+
* Note that this function is also called redundantly
15+
* when `onPressMediaMessage` handler is triggered by clicking on media messages containing images, videos, or audio.
16+
*/
17+
onOpenFileURL: (url: string) => void;
18+
}
19+
20+
type Props = React.PropsWithChildren<SBUHandlers>;
21+
22+
export type SBUHandlersContextType = SBUHandlers;
23+
24+
export const SBUHandlersContext = React.createContext<SBUHandlersContextType | null>(null);
25+
export const SBUHandlersProvider = ({ children, onOpenURL, onOpenFileURL }: Props) => {
26+
return <SBUHandlersContext.Provider value={{ onOpenURL, onOpenFileURL }}>{children}</SBUHandlersContext.Provider>;
27+
};

0 commit comments

Comments
 (0)