@sendbird/uikit-react-native 1.1.1 → 2.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/README.md +1 -1
  2. package/lib/commonjs/components/ChatFlatList.js +10 -8
  3. package/lib/commonjs/components/ChatFlatList.js.map +1 -1
  4. package/lib/commonjs/components/FileViewer.js +8 -3
  5. package/lib/commonjs/components/FileViewer.js.map +1 -1
  6. package/lib/commonjs/components/MessageRenderer/FileMessage/ImageFileMessage.js +47 -15
  7. package/lib/commonjs/components/MessageRenderer/FileMessage/ImageFileMessage.js.map +1 -1
  8. package/lib/commonjs/components/MessageRenderer/FileMessage/VideoFileMessage.js +51 -34
  9. package/lib/commonjs/components/MessageRenderer/FileMessage/VideoFileMessage.js.map +1 -1
  10. package/lib/commonjs/components/MessageRenderer/MessageIncomingSenderName.js +2 -1
  11. package/lib/commonjs/components/MessageRenderer/MessageIncomingSenderName.js.map +1 -1
  12. package/lib/commonjs/components/MessageRenderer/UserMessage/OpenGraphUserMessage.js +3 -1
  13. package/lib/commonjs/components/MessageRenderer/UserMessage/OpenGraphUserMessage.js.map +1 -1
  14. package/lib/commonjs/components/MessageRenderer/index.js +7 -2
  15. package/lib/commonjs/components/MessageRenderer/index.js.map +1 -1
  16. package/lib/commonjs/containers/SendbirdUIKitContainer.js +12 -15
  17. package/lib/commonjs/containers/SendbirdUIKitContainer.js.map +1 -1
  18. package/lib/commonjs/contexts/SendbirdChat.js +9 -9
  19. package/lib/commonjs/contexts/SendbirdChat.js.map +1 -1
  20. package/lib/commonjs/domain/groupChannel/component/GroupChannelInput/SendInput.js +39 -6
  21. package/lib/commonjs/domain/groupChannel/component/GroupChannelInput/SendInput.js.map +1 -1
  22. package/lib/commonjs/domain/groupChannel/component/GroupChannelInput/index.js +4 -4
  23. package/lib/commonjs/domain/groupChannel/component/GroupChannelInput/index.js.map +1 -1
  24. package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
  25. package/lib/commonjs/domain/groupChannelList/component/GroupChannelListList.js +4 -2
  26. package/lib/commonjs/domain/groupChannelList/component/GroupChannelListList.js.map +1 -1
  27. package/lib/commonjs/domain/groupChannelSettings/component/GroupChannelSettingsInfo.js +1 -1
  28. package/lib/commonjs/domain/groupChannelSettings/component/GroupChannelSettingsInfo.js.map +1 -1
  29. package/lib/commonjs/domain/groupChannelSettings/component/GroupChannelSettingsMenu.js +4 -2
  30. package/lib/commonjs/domain/groupChannelSettings/component/GroupChannelSettingsMenu.js.map +1 -1
  31. package/lib/commonjs/domain/groupChannelSettings/module/moduleContext.js +44 -13
  32. package/lib/commonjs/domain/groupChannelSettings/module/moduleContext.js.map +1 -1
  33. package/lib/commonjs/domain/groupChannelUserList/types.js.map +1 -1
  34. package/lib/commonjs/fragments/createGroupChannelCreateFragment.js +7 -6
  35. package/lib/commonjs/fragments/createGroupChannelCreateFragment.js.map +1 -1
  36. package/lib/commonjs/fragments/createGroupChannelFragment.js +12 -12
  37. package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
  38. package/lib/commonjs/fragments/createGroupChannelListFragment.js +1 -1
  39. package/lib/commonjs/fragments/createGroupChannelListFragment.js.map +1 -1
  40. package/lib/commonjs/fragments/createGroupChannelMembersFragment.js +4 -4
  41. package/lib/commonjs/fragments/createGroupChannelMembersFragment.js.map +1 -1
  42. package/lib/commonjs/hooks/useConnection.js +35 -34
  43. package/lib/commonjs/hooks/useConnection.js.map +1 -1
  44. package/lib/commonjs/hooks/usePushTokenRegistration.js +2 -2
  45. package/lib/commonjs/hooks/usePushTokenRegistration.js.map +1 -1
  46. package/lib/commonjs/index.js +10 -1
  47. package/lib/commonjs/index.js.map +1 -1
  48. package/lib/commonjs/libs/InternalLocalCacheStorage.js +8 -0
  49. package/lib/commonjs/libs/InternalLocalCacheStorage.js.map +1 -1
  50. package/lib/commonjs/libs/SBUError.js +41 -0
  51. package/lib/commonjs/libs/SBUError.js.map +1 -0
  52. package/lib/commonjs/libs/SBUUtils.js +20 -0
  53. package/lib/commonjs/libs/SBUUtils.js.map +1 -0
  54. package/lib/commonjs/localization/StringSet.type.js +6 -0
  55. package/lib/commonjs/localization/StringSet.type.js.map +1 -1
  56. package/lib/commonjs/platform/createFileService.expo.js +6 -4
  57. package/lib/commonjs/platform/createFileService.expo.js.map +1 -1
  58. package/lib/commonjs/platform/createFileService.native.js +18 -8
  59. package/lib/commonjs/platform/createFileService.native.js.map +1 -1
  60. package/lib/commonjs/platform/types.js +4 -0
  61. package/lib/commonjs/platform/types.js.map +1 -1
  62. package/lib/commonjs/version.js +1 -1
  63. package/lib/commonjs/version.js.map +1 -1
  64. package/lib/module/components/ChatFlatList.js +10 -8
  65. package/lib/module/components/ChatFlatList.js.map +1 -1
  66. package/lib/module/components/FileViewer.js +9 -4
  67. package/lib/module/components/FileViewer.js.map +1 -1
  68. package/lib/module/components/MessageRenderer/FileMessage/ImageFileMessage.js +48 -17
  69. package/lib/module/components/MessageRenderer/FileMessage/ImageFileMessage.js.map +1 -1
  70. package/lib/module/components/MessageRenderer/FileMessage/VideoFileMessage.js +52 -35
  71. package/lib/module/components/MessageRenderer/FileMessage/VideoFileMessage.js.map +1 -1
  72. package/lib/module/components/MessageRenderer/MessageIncomingSenderName.js +2 -1
  73. package/lib/module/components/MessageRenderer/MessageIncomingSenderName.js.map +1 -1
  74. package/lib/module/components/MessageRenderer/UserMessage/OpenGraphUserMessage.js +3 -1
  75. package/lib/module/components/MessageRenderer/UserMessage/OpenGraphUserMessage.js.map +1 -1
  76. package/lib/module/components/MessageRenderer/index.js +7 -2
  77. package/lib/module/components/MessageRenderer/index.js.map +1 -1
  78. package/lib/module/containers/SendbirdUIKitContainer.js +10 -15
  79. package/lib/module/containers/SendbirdUIKitContainer.js.map +1 -1
  80. package/lib/module/contexts/SendbirdChat.js +10 -10
  81. package/lib/module/contexts/SendbirdChat.js.map +1 -1
  82. package/lib/module/domain/groupChannel/component/GroupChannelInput/SendInput.js +38 -7
  83. package/lib/module/domain/groupChannel/component/GroupChannelInput/SendInput.js.map +1 -1
  84. package/lib/module/domain/groupChannel/component/GroupChannelInput/index.js +5 -5
  85. package/lib/module/domain/groupChannel/component/GroupChannelInput/index.js.map +1 -1
  86. package/lib/module/domain/groupChannel/types.js.map +1 -1
  87. package/lib/module/domain/groupChannelList/component/GroupChannelListList.js +3 -2
  88. package/lib/module/domain/groupChannelList/component/GroupChannelListList.js.map +1 -1
  89. package/lib/module/domain/groupChannelSettings/component/GroupChannelSettingsInfo.js +1 -1
  90. package/lib/module/domain/groupChannelSettings/component/GroupChannelSettingsInfo.js.map +1 -1
  91. package/lib/module/domain/groupChannelSettings/component/GroupChannelSettingsMenu.js +3 -2
  92. package/lib/module/domain/groupChannelSettings/component/GroupChannelSettingsMenu.js.map +1 -1
  93. package/lib/module/domain/groupChannelSettings/module/moduleContext.js +43 -14
  94. package/lib/module/domain/groupChannelSettings/module/moduleContext.js.map +1 -1
  95. package/lib/module/domain/groupChannelUserList/types.js.map +1 -1
  96. package/lib/module/fragments/createGroupChannelCreateFragment.js +7 -6
  97. package/lib/module/fragments/createGroupChannelCreateFragment.js.map +1 -1
  98. package/lib/module/fragments/createGroupChannelFragment.js +12 -12
  99. package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
  100. package/lib/module/fragments/createGroupChannelListFragment.js +1 -1
  101. package/lib/module/fragments/createGroupChannelListFragment.js.map +1 -1
  102. package/lib/module/fragments/createGroupChannelMembersFragment.js +4 -4
  103. package/lib/module/fragments/createGroupChannelMembersFragment.js.map +1 -1
  104. package/lib/module/hooks/useConnection.js +35 -35
  105. package/lib/module/hooks/useConnection.js.map +1 -1
  106. package/lib/module/hooks/usePushTokenRegistration.js +2 -2
  107. package/lib/module/hooks/usePushTokenRegistration.js.map +1 -1
  108. package/lib/module/index.js +1 -0
  109. package/lib/module/index.js.map +1 -1
  110. package/lib/module/libs/InternalLocalCacheStorage.js +7 -0
  111. package/lib/module/libs/InternalLocalCacheStorage.js.map +1 -1
  112. package/lib/module/libs/SBUError.js +32 -0
  113. package/lib/module/libs/SBUError.js.map +1 -0
  114. package/lib/module/libs/SBUUtils.js +10 -0
  115. package/lib/module/libs/SBUUtils.js.map +1 -0
  116. package/lib/module/localization/StringSet.type.js +6 -0
  117. package/lib/module/localization/StringSet.type.js.map +1 -1
  118. package/lib/module/platform/createFileService.expo.js +5 -4
  119. package/lib/module/platform/createFileService.expo.js.map +1 -1
  120. package/lib/module/platform/createFileService.native.js +18 -9
  121. package/lib/module/platform/createFileService.native.js.map +1 -1
  122. package/lib/module/platform/types.js +1 -1
  123. package/lib/module/platform/types.js.map +1 -1
  124. package/lib/module/version.js +1 -1
  125. package/lib/module/version.js.map +1 -1
  126. package/lib/typescript/src/components/MessageRenderer/UserMessage/OpenGraphUserMessage.d.ts +2 -2
  127. package/lib/typescript/src/components/MessageRenderer/index.d.ts +1 -1
  128. package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +1 -1
  129. package/lib/typescript/src/contexts/SendbirdChat.d.ts +1 -1
  130. package/lib/typescript/src/domain/groupChannel/component/GroupChannelInput/index.d.ts +3 -3
  131. package/lib/typescript/src/domain/groupChannel/component/GroupChannelMessageList.d.ts +6 -6
  132. package/lib/typescript/src/domain/groupChannel/types.d.ts +3 -3
  133. package/lib/typescript/src/domain/groupChannelUserList/types.d.ts +2 -2
  134. package/lib/typescript/src/hooks/useContext.d.ts +5 -5
  135. package/lib/typescript/src/index.d.ts +1 -0
  136. package/lib/typescript/src/libs/InternalLocalCacheStorage.d.ts +2 -0
  137. package/lib/typescript/src/libs/SBUError.d.ts +14 -0
  138. package/lib/typescript/src/libs/SBUUtils.d.ts +3 -0
  139. package/lib/typescript/src/localization/StringSet.type.d.ts +3 -0
  140. package/lib/typescript/src/platform/types.d.ts +2 -1
  141. package/lib/typescript/src/version.d.ts +1 -1
  142. package/package.json +8 -8
  143. package/src/components/ChatFlatList.tsx +5 -4
  144. package/src/components/FileViewer.tsx +12 -4
  145. package/src/components/MessageRenderer/FileMessage/ImageFileMessage.tsx +55 -12
  146. package/src/components/MessageRenderer/FileMessage/VideoFileMessage.tsx +38 -30
  147. package/src/components/MessageRenderer/MessageIncomingSenderName.tsx +1 -1
  148. package/src/components/MessageRenderer/UserMessage/OpenGraphUserMessage.tsx +5 -3
  149. package/src/components/MessageRenderer/index.tsx +5 -2
  150. package/src/containers/SendbirdUIKitContainer.tsx +13 -9
  151. package/src/contexts/SendbirdChat.tsx +18 -13
  152. package/src/domain/groupChannel/component/GroupChannelInput/SendInput.tsx +28 -4
  153. package/src/domain/groupChannel/component/GroupChannelInput/index.tsx +5 -5
  154. package/src/domain/groupChannel/types.ts +6 -6
  155. package/src/domain/groupChannelList/component/GroupChannelListList.tsx +3 -2
  156. package/src/domain/groupChannelSettings/component/GroupChannelSettingsInfo.tsx +1 -1
  157. package/src/domain/groupChannelSettings/component/GroupChannelSettingsMenu.tsx +3 -2
  158. package/src/domain/groupChannelSettings/module/moduleContext.tsx +33 -18
  159. package/src/domain/groupChannelUserList/types.ts +3 -3
  160. package/src/fragments/createGroupChannelCreateFragment.tsx +8 -7
  161. package/src/fragments/createGroupChannelFragment.tsx +4 -12
  162. package/src/fragments/createGroupChannelListFragment.tsx +1 -1
  163. package/src/fragments/createGroupChannelMembersFragment.tsx +4 -3
  164. package/src/hooks/useConnection.ts +40 -43
  165. package/src/hooks/usePushTokenRegistration.ts +2 -2
  166. package/src/index.ts +1 -0
  167. package/src/libs/InternalLocalCacheStorage.ts +5 -0
  168. package/src/libs/SBUError.ts +26 -0
  169. package/src/libs/SBUUtils.ts +9 -0
  170. package/src/localization/StringSet.type.ts +10 -0
  171. package/src/platform/createFileService.expo.ts +5 -4
  172. package/src/platform/createFileService.native.ts +17 -9
  173. package/src/platform/types.ts +3 -1
  174. package/src/version.ts +1 -1
@@ -1,4 +1,4 @@
1
- import React, { useEffect, useState } from 'react';
1
+ import React, { useEffect, useRef, useState } from 'react';
2
2
  import { View } from 'react-native';
3
3
 
4
4
  import { Icon, Image, createStyleSheet, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
@@ -7,35 +7,49 @@ import { getAvailableUriFromFileMessage } from '@sendbird/uikit-utils';
7
7
  import { usePlatformService } from '../../../hooks/useContext';
8
8
  import type { FileMessageProps } from './index';
9
9
 
10
- const VideoFileMessage = ({ message }: FileMessageProps) => {
11
- const { colors } = useUIKitTheme();
10
+ const useRetry = (videoFileUrl: string, retryCount = 5) => {
11
+ const [state, setState] = useState({ thumbnail: null as null | string, loading: true });
12
+ const retryCountRef = useRef(0);
13
+ const retryTimeoutRef = useRef<NodeJS.Timeout>();
12
14
 
13
15
  const { mediaService } = usePlatformService();
14
- const fileUrl = getAvailableUriFromFileMessage(message);
15
- const style = [styles.image, { backgroundColor: colors.onBackground04 }];
16
16
 
17
- const [state, setState] = useState({
18
- thumbnail: null as null | string,
19
- loading: true,
20
- imageNotFound: false,
21
- });
17
+ const fetchThumbnail = () => {
18
+ return mediaService?.getVideoThumbnail({ url: videoFileUrl, timeMills: 1000 }).then((result) => {
19
+ setState({ loading: false, thumbnail: result?.path ?? null });
20
+ });
21
+ };
22
22
 
23
23
  useEffect(() => {
24
- mediaService
25
- ?.getVideoThumbnail({ url: fileUrl, timeMills: 1000 })
26
- .then((result) => {
27
- if (result?.path) {
28
- setState((prev) => ({ ...prev, loading: false, thumbnail: result.path }));
29
- } else {
30
- throw new Error('Cannot generate thumbnail');
24
+ if (!state.thumbnail) {
25
+ const reloadReservation = () => {
26
+ if (retryCountRef.current < retryCount) {
27
+ retryTimeoutRef.current = setTimeout(() => {
28
+ retryCountRef.current++;
29
+ reloadReservation();
30
+ fetchThumbnail();
31
+ }, retryCountRef.current * 5000);
31
32
  }
32
- })
33
- .catch(() => {
34
- setState((prev) => ({ ...prev, loading: false, imageNotFound: true }));
35
- });
36
- }, []);
33
+ };
34
+
35
+ return reloadReservation();
36
+ } else {
37
+ return clearTimeout(retryTimeoutRef.current);
38
+ }
39
+ }, [state.thumbnail]);
40
+
41
+ return state;
42
+ };
43
+
44
+ const VideoFileMessage = ({ message }: FileMessageProps) => {
45
+ const { colors } = useUIKitTheme();
46
+
47
+ const fileUrl = getAvailableUriFromFileMessage(message);
48
+ const style = [styles.image, { backgroundColor: colors.onBackground04 }];
49
+
50
+ const { loading, thumbnail } = useRetry(fileUrl);
37
51
 
38
- if (state.loading || state.imageNotFound) {
52
+ if (loading) {
39
53
  return (
40
54
  <View style={[style, styles.container]}>
41
55
  <PlayIcon />
@@ -45,13 +59,7 @@ const VideoFileMessage = ({ message }: FileMessageProps) => {
45
59
 
46
60
  return (
47
61
  <View style={styles.container}>
48
- <Image
49
- source={{ uri: state.thumbnail || fileUrl }}
50
- style={style}
51
- resizeMode={'cover'}
52
- resizeMethod={'resize'}
53
- onError={() => setState((prev) => ({ ...prev, imageNotFound: true }))}
54
- />
62
+ <Image source={{ uri: thumbnail || fileUrl }} style={style} resizeMode={'cover'} resizeMethod={'resize'} />
55
63
  <PlayIcon />
56
64
  </View>
57
65
  );
@@ -18,7 +18,7 @@ const MessageIncomingSenderName = ({ message, grouping }: Props) => {
18
18
  return (
19
19
  <View style={styles.sender}>
20
20
  {(message.isFileMessage() || message.isUserMessage()) && (
21
- <Text caption1 color={colors.ui.message.incoming.enabled.textSenderName}>
21
+ <Text caption1 color={colors.ui.message.incoming.enabled.textSenderName} numberOfLines={1}>
22
22
  {message.sender?.nickname || STRINGS.LABELS.USER_NO_NAME}
23
23
  </Text>
24
24
  )}
@@ -1,7 +1,7 @@
1
1
  import React, { useState } from 'react';
2
2
  import { Linking, TouchableOpacity, View } from 'react-native';
3
- import type Sendbird from 'sendbird';
4
3
 
4
+ import type { OGMetaData } from '@sendbird/chat/message';
5
5
  import {
6
6
  Icon,
7
7
  Image,
@@ -16,7 +16,7 @@ import { useLocalization } from '../../../hooks/useContext';
16
16
  import type { UserMessageProps } from './index';
17
17
 
18
18
  type Props = UserMessageProps & {
19
- ogMetaData: Sendbird.OGMetaData;
19
+ ogMetaData: OGMetaData;
20
20
  };
21
21
  const OpenGraphUserMessage = ({ message, variant, pressed, ogMetaData }: Props) => {
22
22
  const { STRINGS } = useLocalization();
@@ -80,6 +80,8 @@ const OpenGraphUserMessage = ({ message, variant, pressed, ogMetaData }: Props)
80
80
 
81
81
  const styles = createStyleSheet({
82
82
  container: {
83
+ width: 240,
84
+ maxWidth: 240,
83
85
  borderRadius: 16,
84
86
  overflow: 'hidden',
85
87
  },
@@ -93,7 +95,7 @@ const styles = createStyleSheet({
93
95
  paddingBottom: 12,
94
96
  },
95
97
  ogImageContainer: {
96
- width: 240,
98
+ flex: 1,
97
99
  height: 136,
98
100
  },
99
101
  ogImage: {
@@ -107,9 +107,9 @@ const MessageRenderer: GroupChannelProps['Fragment']['renderMessage'] = ({
107
107
  </View>
108
108
  )}
109
109
  {isIncoming && <MessageIncomingAvatar message={message} grouping={groupWithNext} />}
110
- <View>
110
+ <View style={styles.bubbleContainer}>
111
111
  {isIncoming && <MessageIncomingSenderName message={message} grouping={groupWithPrev} />}
112
- <View style={styles.bubbleContainer}>
112
+ <View style={styles.bubbleWrapper}>
113
113
  {messageComponent}
114
114
  {isIncoming && <MessageTime message={message} grouping={groupWithNext} style={styles.timeIncoming} />}
115
115
  </View>
@@ -150,6 +150,9 @@ const styles = createStyleSheet({
150
150
  maxWidth: 240,
151
151
  },
152
152
  bubbleContainer: {
153
+ flexShrink: 1,
154
+ },
155
+ bubbleWrapper: {
153
156
  flexDirection: 'row',
154
157
  alignItems: 'flex-end',
155
158
  },
@@ -1,8 +1,10 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
2
  import { Platform } from 'react-native';
3
3
  import { SafeAreaProvider } from 'react-native-safe-area-context';
4
- import Sendbird from 'sendbird';
5
4
 
5
+ import Sendbird from '@sendbird/chat';
6
+ import { GroupChannelModule } from '@sendbird/chat/groupChannel';
7
+ import { OpenChannelModule } from '@sendbird/chat/openChannel';
6
8
  import type { HeaderStyleContextType, UIKitTheme } from '@sendbird/uikit-react-native-foundation';
7
9
  import {
8
10
  DialogProvider,
@@ -87,23 +89,25 @@ const SendbirdUIKitContainer = ({
87
89
  const getSendbirdSDK = () => {
88
90
  let sdk: SendbirdChatSDK;
89
91
 
90
- if (chatOptions?.localCacheStorage) {
91
- sdk = new Sendbird({ appId, localCacheEnabled: true });
92
- sdk.useAsyncStorageAsDatabase(new InternalLocalCacheStorage(chatOptions.localCacheStorage));
93
- } else {
94
- sdk = new Sendbird({ appId });
95
- }
92
+ sdk = Sendbird.init({
93
+ appId,
94
+ modules: [new GroupChannelModule(), new OpenChannelModule()],
95
+ localCacheEnabled: Boolean(chatOptions?.localCacheStorage),
96
+ // @ts-ignore
97
+ useAsyncStorageStore: chatOptions?.localCacheStorage
98
+ ? new InternalLocalCacheStorage(chatOptions.localCacheStorage)
99
+ : undefined,
100
+ });
96
101
 
97
102
  if (chatOptions?.onInitialized) {
98
103
  sdk = chatOptions?.onInitialized(sdk);
99
104
  }
100
105
 
101
106
  if (SendbirdUIKit.VERSION) {
102
- // @ts-ignore
103
107
  sdk.addExtension('sb_uikit', SendbirdUIKit.VERSION);
104
108
  }
109
+
105
110
  if (SendbirdUIKit.PLATFORM) {
106
- // @ts-ignore
107
111
  sdk.addExtension('device-os-platform', SendbirdUIKit.PLATFORM);
108
112
  }
109
113
 
@@ -2,8 +2,13 @@ import React, { useCallback, useEffect, useState } from 'react';
2
2
  import { AppState, AppStateStatus } from 'react-native';
3
3
 
4
4
  import { useAppFeatures } from '@sendbird/uikit-chat-hooks';
5
- import type { SendbirdChatSDK, SendbirdGroupChannel, SendbirdUser } from '@sendbird/uikit-utils';
6
- import { useForceUpdate } from '@sendbird/uikit-utils';
5
+ import type {
6
+ SendbirdChatSDK,
7
+ SendbirdGroupChannel,
8
+ SendbirdUser,
9
+ SendbirdUserUpdateParams,
10
+ } from '@sendbird/uikit-utils';
11
+ import { confirmAndMarkAsDelivered, useForceUpdate } from '@sendbird/uikit-utils';
7
12
 
8
13
  import type { FileType } from '../platform/types';
9
14
 
@@ -21,7 +26,7 @@ type Context = {
21
26
  setCurrentUser: React.Dispatch<React.SetStateAction<SendbirdUser | undefined>>;
22
27
 
23
28
  // helper functions
24
- updateCurrentUserInfo: (nickname: string, profile?: string | FileType) => Promise<SendbirdUser>;
29
+ updateCurrentUserInfo: (nickname?: string, profile?: string | FileType) => Promise<SendbirdUser>;
25
30
  markAsDeliveredWithChannel: (channel: SendbirdGroupChannel) => void;
26
31
 
27
32
  features: {
@@ -62,16 +67,18 @@ export const SendbirdChatProvider = ({
62
67
 
63
68
  if (!user) throw new Error('Current user is not defined, please connect using `useConnection()` hook first');
64
69
 
65
- if (typeof profile === 'undefined') {
66
- user = await sdkInstance.updateCurrentUserInfo(nickname, sdkInstance.currentUser.profileUrl);
67
- } else if (typeof profile === 'string') {
68
- user = await sdkInstance.updateCurrentUserInfo(nickname, profile);
70
+ const params: SendbirdUserUpdateParams = { nickname };
71
+
72
+ if (typeof profile === 'string') {
73
+ params.profileUrl = profile;
69
74
  } else if (typeof profile === 'object') {
70
- user = await sdkInstance.updateCurrentUserInfoWithProfileImage(nickname, profile);
75
+ params.profileImage = profile;
71
76
  } else {
72
77
  throw new Error(`Cannot update profile, not supported profile type(${typeof profile})`);
73
78
  }
74
79
 
80
+ user = await sdkInstance.updateCurrentUserInfo(params);
81
+
75
82
  setCurrentUser(user);
76
83
  return user;
77
84
  },
@@ -80,9 +87,7 @@ export const SendbirdChatProvider = ({
80
87
 
81
88
  const markAsDeliveredWithChannel: Context['markAsDeliveredWithChannel'] = useCallback(
82
89
  (channel: SendbirdGroupChannel) => {
83
- if (appFeatures.deliveryReceiptEnabled && channel.unreadMessageCount > 0) {
84
- sdkInstance.markAsDelivered(channel.url);
85
- }
90
+ if (appFeatures.deliveryReceiptEnabled) confirmAndMarkAsDelivered(sdkInstance, channel);
86
91
  },
87
92
  [sdkInstance, appFeatures.deliveryReceiptEnabled],
88
93
  );
@@ -90,8 +95,8 @@ export const SendbirdChatProvider = ({
90
95
  useEffect(() => {
91
96
  const listener = (status: AppStateStatus) => {
92
97
  // 'active' | 'background' | 'inactive' | 'unknown' | 'extension';
93
- if (status === 'active') sdkInstance.getConnectionState() === 'CLOSED' && sdkInstance.setForegroundState();
94
- else sdkInstance.getConnectionState() === 'OPEN' && sdkInstance.setBackgroundState();
98
+ if (status === 'active') sdkInstance.connectionState === 'CLOSED' && sdkInstance.setForegroundState();
99
+ else sdkInstance.connectionState === 'OPEN' && sdkInstance.setBackgroundState();
95
100
  };
96
101
 
97
102
  const subscriber = AppState.addEventListener('change', listener);
@@ -5,6 +5,7 @@ import {
5
5
  Icon,
6
6
  TextInput,
7
7
  createStyleSheet,
8
+ useAlert,
8
9
  useBottomSheet,
9
10
  useToast,
10
11
  useUIKitTheme,
@@ -12,6 +13,8 @@ import {
12
13
  import { conditionChaining } from '@sendbird/uikit-utils';
13
14
 
14
15
  import { useLocalization, usePlatformService } from '../../../../hooks/useContext';
16
+ import SBUError from '../../../../libs/SBUError';
17
+ import SBUUtils from '../../../../libs/SBUUtils';
15
18
  import type { GroupChannelProps } from '../../types';
16
19
 
17
20
  type SendInputProps = GroupChannelProps['Input'] & {
@@ -21,9 +24,10 @@ type SendInputProps = GroupChannelProps['Input'] & {
21
24
  };
22
25
  const SendInput = ({ onSendUserMessage, onSendFileMessage, text, setText, disabled }: SendInputProps) => {
23
26
  const { STRINGS } = useLocalization();
24
- const { openSheet } = useBottomSheet();
25
27
  const { fileService } = usePlatformService();
26
28
  const { colors } = useUIKitTheme();
29
+ const { openSheet } = useBottomSheet();
30
+ const { alert } = useAlert();
27
31
  const toast = useToast();
28
32
 
29
33
  const onPressSend = () => {
@@ -39,7 +43,17 @@ const SendInput = ({ onSendUserMessage, onSendFileMessage, text, setText, disabl
39
43
  onPress: async () => {
40
44
  const photo = await fileService.openCamera({
41
45
  mediaType: 'all',
42
- onOpenFailureWithToastMessage: () => toast.show(STRINGS.TOAST.OPEN_CAMERA_ERROR, 'error'),
46
+ onOpenFailure: (error) => {
47
+ if (error.code === SBUError.CODE.ERR_PERMISSIONS_DENIED) {
48
+ alert({
49
+ title: STRINGS.DIALOG.ALERT_PERMISSIONS_TITLE,
50
+ message: STRINGS.DIALOG.ALERT_PERMISSIONS_MESSAGE('camera', 'UIKitSample'),
51
+ buttons: [{ text: STRINGS.DIALOG.ALERT_PERMISSIONS_OK, onPress: () => SBUUtils.openSettings() }],
52
+ });
53
+ } else {
54
+ toast.show(STRINGS.TOAST.OPEN_CAMERA_ERROR, 'error');
55
+ }
56
+ },
43
57
  });
44
58
 
45
59
  if (photo) {
@@ -54,7 +68,17 @@ const SendInput = ({ onSendUserMessage, onSendFileMessage, text, setText, disabl
54
68
  const photo = await fileService.openMediaLibrary({
55
69
  selectionLimit: 1,
56
70
  mediaType: 'all',
57
- onOpenFailureWithToastMessage: () => toast.show(STRINGS.TOAST.OPEN_PHOTO_LIBRARY_ERROR, 'error'),
71
+ onOpenFailure: (error) => {
72
+ if (error.code === SBUError.CODE.ERR_PERMISSIONS_DENIED) {
73
+ alert({
74
+ title: STRINGS.DIALOG.ALERT_PERMISSIONS_TITLE,
75
+ message: STRINGS.DIALOG.ALERT_PERMISSIONS_MESSAGE('device storage', 'UIKitSample'),
76
+ buttons: [{ text: STRINGS.DIALOG.ALERT_PERMISSIONS_OK, onPress: () => SBUUtils.openSettings() }],
77
+ });
78
+ } else {
79
+ toast.show(STRINGS.TOAST.OPEN_PHOTO_LIBRARY_ERROR, 'error');
80
+ }
81
+ },
58
82
  });
59
83
 
60
84
  if (photo && photo[0]) {
@@ -67,7 +91,7 @@ const SendInput = ({ onSendUserMessage, onSendFileMessage, text, setText, disabl
67
91
  icon: 'document',
68
92
  onPress: async () => {
69
93
  const file = await fileService.openDocument({
70
- onOpenFailureWithToastMessage: () => toast.show(STRINGS.TOAST.OPEN_FILES_ERROR, 'error'),
94
+ onOpenFailure: () => toast.show(STRINGS.TOAST.OPEN_FILES_ERROR, 'error'),
71
95
  });
72
96
 
73
97
  if (file) {
@@ -3,7 +3,7 @@ import { KeyboardAvoidingView, Platform, View } from 'react-native';
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
 
5
5
  import { useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
6
- import { groupChannelChatUnavailable, useIIFE } from '@sendbird/uikit-utils';
6
+ import { isGroupChannelChatUnavailable, useIIFE } from '@sendbird/uikit-utils';
7
7
 
8
8
  import { GroupChannelContexts } from '../../module/moduleContext';
9
9
  import type { GroupChannelProps } from '../../types';
@@ -20,7 +20,7 @@ const GroupChannelInput = (props: GroupChannelProps['Input']) => {
20
20
 
21
21
  const [text, setText] = useState('');
22
22
  const textTmpRef = useRef('');
23
- const disabled = groupChannelChatUnavailable(channel);
23
+ const isChatUnavailable = isGroupChannelChatUnavailable(channel);
24
24
 
25
25
  useEffect(() => {
26
26
  if (text.length === 0) channel.endTyping();
@@ -28,13 +28,13 @@ const GroupChannelInput = (props: GroupChannelProps['Input']) => {
28
28
  }, [text]);
29
29
 
30
30
  useEffect(() => {
31
- if (disabled) {
31
+ if (isChatUnavailable) {
32
32
  textTmpRef.current = text;
33
33
  setText('');
34
34
  } else {
35
35
  setText(textTmpRef.current);
36
36
  }
37
- }, [disabled]);
37
+ }, [isChatUnavailable]);
38
38
 
39
39
  const inputMode = useIIFE(() => {
40
40
  if (!editMessage) return 'send';
@@ -49,7 +49,7 @@ const GroupChannelInput = (props: GroupChannelProps['Input']) => {
49
49
  >
50
50
  <View style={{ paddingLeft: left, paddingRight: right, backgroundColor: colors.background }}>
51
51
  <View style={{ justifyContent: 'center', width: '100%' }}>
52
- {inputMode === 'send' && <SendInput {...props} text={text} setText={setText} disabled={disabled} />}
52
+ {inputMode === 'send' && <SendInput {...props} text={text} setText={setText} disabled={isChatUnavailable} />}
53
53
  {inputMode === 'edit' && editMessage && (
54
54
  <EditInput
55
55
  {...props}
@@ -4,12 +4,12 @@ import type { FlatListProps } from 'react-native';
4
4
  import type { UseGroupChannelMessagesOptions } from '@sendbird/uikit-chat-hooks';
5
5
  import type {
6
6
  SendbirdFileMessage,
7
- SendbirdFileMessageParams,
7
+ SendbirdFileMessageCreateParams,
8
8
  SendbirdGroupChannel,
9
9
  SendbirdMessage,
10
10
  SendbirdUser,
11
11
  SendbirdUserMessage,
12
- SendbirdUserMessageParams,
12
+ SendbirdUserMessageCreateParams,
13
13
  } from '@sendbird/uikit-utils';
14
14
 
15
15
  import type { FileType } from '../../platform/types';
@@ -23,11 +23,11 @@ export interface GroupChannelProps {
23
23
  onPressHeaderRight: GroupChannelProps['Header']['onPressHeaderRight'];
24
24
 
25
25
  onBeforeSendFileMessage?: (
26
- params: SendbirdFileMessageParams,
27
- ) => SendbirdFileMessageParams | Promise<SendbirdFileMessageParams>;
26
+ params: SendbirdFileMessageCreateParams,
27
+ ) => SendbirdFileMessageCreateParams | Promise<SendbirdFileMessageCreateParams>;
28
28
  onBeforeSendUserMessage?: (
29
- params: SendbirdUserMessageParams,
30
- ) => SendbirdUserMessageParams | Promise<SendbirdUserMessageParams>;
29
+ params: SendbirdUserMessageCreateParams,
30
+ ) => SendbirdUserMessageCreateParams | Promise<SendbirdUserMessageCreateParams>;
31
31
  onPressMediaMessage?: GroupChannelProps['MessageList']['onPressMediaMessage'];
32
32
 
33
33
  renderMessage?: GroupChannelProps['MessageList']['renderMessage'];
@@ -2,6 +2,7 @@ import React, { useCallback } from 'react';
2
2
  import { FlatList, ListRenderItem } from 'react-native';
3
3
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
 
5
+ import { PushTriggerOption } from '@sendbird/chat';
5
6
  import { useActionMenu, useToast } from '@sendbird/uikit-react-native-foundation';
6
7
  import { PASS, SendbirdGroupChannel, useFreshCallback } from '@sendbird/uikit-utils';
7
8
 
@@ -29,9 +30,9 @@ const GroupChannelListList = ({
29
30
  title: STRINGS.GROUP_CHANNEL_LIST.DIALOG_CHANNEL_NOTIFICATION(channel),
30
31
  onPress: async () => {
31
32
  if (action === 'on') {
32
- await channel.setMyPushTriggerOption('default');
33
+ await channel.setMyPushTriggerOption(PushTriggerOption.DEFAULT);
33
34
  } else {
34
- await channel.setMyPushTriggerOption('off');
35
+ await channel.setMyPushTriggerOption(PushTriggerOption.OFF);
35
36
  }
36
37
  },
37
38
  onError: () => {
@@ -15,7 +15,7 @@ const GroupChannelSettingsInfo = (_: GroupChannelSettingsProps['Info']) => {
15
15
  const { STRINGS } = useLocalization();
16
16
 
17
17
  if (!currentUser) {
18
- Logger.warn('Cannot render GroupChannelSettingsInfo, User is not connected');
18
+ Logger.warn('Cannot render GroupChannelSettingsInfo, please connect using `useConnection()` hook first');
19
19
  return null;
20
20
  }
21
21
 
@@ -1,6 +1,7 @@
1
1
  import React, { useContext } from 'react';
2
2
  import { View } from 'react-native';
3
3
 
4
+ import { PushTriggerOption } from '@sendbird/chat';
4
5
  import type { MenuBarProps } from '@sendbird/uikit-react-native-foundation';
5
6
  import { Icon, MenuBar, Switch, useUIKitTheme } from '@sendbird/uikit-react-native-foundation';
6
7
 
@@ -20,9 +21,9 @@ const GroupChannelSettingsMenu = ({
20
21
 
21
22
  const toggleNotification = async () => {
22
23
  if (channel.myPushTriggerOption === 'off') {
23
- await channel.setMyPushTriggerOption('default');
24
+ await channel.setMyPushTriggerOption(PushTriggerOption.DEFAULT);
24
25
  } else {
25
- await channel.setMyPushTriggerOption('off');
26
+ await channel.setMyPushTriggerOption(PushTriggerOption.OFF);
26
27
  }
27
28
  };
28
29
 
@@ -1,12 +1,12 @@
1
1
  import React, { createContext, useCallback } from 'react';
2
2
 
3
3
  import { useActiveGroupChannel, useChannelHandler } from '@sendbird/uikit-chat-hooks';
4
- import { useActionMenu, useBottomSheet, usePrompt, useToast } from '@sendbird/uikit-react-native-foundation';
4
+ import { useActionMenu, useAlert, useBottomSheet, usePrompt, useToast } from '@sendbird/uikit-react-native-foundation';
5
5
  import {
6
6
  NOOP,
7
+ SendbirdBaseChannel,
7
8
  SendbirdGroupChannel,
8
- SendbirdGroupChannelParams,
9
- SendbirdOpenChannel,
9
+ SendbirdGroupChannelUpdateParams,
10
10
  isDifferentChannel,
11
11
  useForceUpdate,
12
12
  useUniqId,
@@ -14,6 +14,8 @@ import {
14
14
 
15
15
  import ProviderLayout from '../../../components/ProviderLayout';
16
16
  import { useLocalization, usePlatformService, useSendbirdChat } from '../../../hooks/useContext';
17
+ import SBUError from '../../../libs/SBUError';
18
+ import SBUUtils from '../../../libs/SBUUtils';
17
19
  import type { GroupChannelSettingsContextsType, GroupChannelSettingsModule } from '../types';
18
20
 
19
21
  export const GroupChannelSettingsContexts: GroupChannelSettingsContextsType = {
@@ -32,10 +34,11 @@ export const GroupChannelSettingsContextsProvider: GroupChannelSettingsModule['P
32
34
  const { STRINGS } = useLocalization();
33
35
  const { sdk } = useSendbirdChat();
34
36
  const { fileService } = usePlatformService();
37
+ const { alert } = useAlert();
35
38
 
36
39
  const { activeChannel, setActiveChannel } = useActiveGroupChannel(sdk, channel);
37
40
 
38
- const onChannelChanged = (channel: SendbirdGroupChannel | SendbirdOpenChannel) => {
41
+ const onChannelChanged = (channel: SendbirdBaseChannel) => {
39
42
  if (isDifferentChannel(channel, activeChannel) || !channel.isGroupChannel()) return;
40
43
  setActiveChannel(channel);
41
44
  forceUpdate();
@@ -53,7 +56,7 @@ export const GroupChannelSettingsContextsProvider: GroupChannelSettingsModule['P
53
56
  const { openMenu } = useActionMenu();
54
57
 
55
58
  const updateChannel = useCallback(
56
- async (params: SendbirdGroupChannelParams) => {
59
+ async (params: SendbirdGroupChannelUpdateParams) => {
57
60
  const updatedChannel = await activeChannel.updateChannel(params);
58
61
  setActiveChannel(updatedChannel);
59
62
  forceUpdate();
@@ -67,11 +70,7 @@ export const GroupChannelSettingsContextsProvider: GroupChannelSettingsModule['P
67
70
  submitLabel: STRINGS.GROUP_CHANNEL_SETTINGS.DIALOG_CHANGE_NAME_PROMPT_OK,
68
71
  placeholder: STRINGS.GROUP_CHANNEL_SETTINGS.DIALOG_CHANGE_NAME_PROMPT_PLACEHOLDER,
69
72
  defaultValue: activeChannel.name,
70
- onSubmit: async (channelName) => {
71
- const params = new sdk.GroupChannelParams();
72
- params.name = channelName;
73
- await updateChannel(params);
74
- },
73
+ onSubmit: (channelName) => updateChannel({ name: channelName }),
75
74
  });
76
75
  }, [STRINGS, updateChannel, activeChannel.name]);
77
76
 
@@ -84,13 +83,21 @@ export const GroupChannelSettingsContextsProvider: GroupChannelSettingsModule['P
84
83
  onPress: async () => {
85
84
  const file = await fileService.openCamera({
86
85
  mediaType: 'photo',
87
- onOpenFailureWithToastMessage: () => toast.show(STRINGS.TOAST.OPEN_CAMERA_ERROR, 'error'),
86
+ onOpenFailure: (error) => {
87
+ if (error.code === SBUError.CODE.ERR_PERMISSIONS_DENIED) {
88
+ alert({
89
+ title: STRINGS.DIALOG.ALERT_PERMISSIONS_TITLE,
90
+ message: STRINGS.DIALOG.ALERT_PERMISSIONS_MESSAGE('camera', 'UIKitSample'),
91
+ buttons: [{ text: STRINGS.DIALOG.ALERT_PERMISSIONS_OK, onPress: () => SBUUtils.openSettings() }],
92
+ });
93
+ } else {
94
+ toast.show(STRINGS.TOAST.OPEN_CAMERA_ERROR, 'error');
95
+ }
96
+ },
88
97
  });
89
98
  if (!file) return;
90
99
 
91
- const params = new sdk.GroupChannelParams();
92
- params.coverImage = file;
93
- await updateChannel(params);
100
+ await updateChannel({ coverImage: file });
94
101
  },
95
102
  },
96
103
  {
@@ -99,13 +106,21 @@ export const GroupChannelSettingsContextsProvider: GroupChannelSettingsModule['P
99
106
  const files = await fileService.openMediaLibrary({
100
107
  selectionLimit: 1,
101
108
  mediaType: 'photo',
102
- onOpenFailureWithToastMessage: () => toast.show(STRINGS.TOAST.OPEN_PHOTO_LIBRARY_ERROR, 'error'),
109
+ onOpenFailure: (error) => {
110
+ if (error.code === SBUError.CODE.ERR_PERMISSIONS_DENIED) {
111
+ alert({
112
+ title: STRINGS.DIALOG.ALERT_PERMISSIONS_TITLE,
113
+ message: STRINGS.DIALOG.ALERT_PERMISSIONS_MESSAGE('device storage', 'UIKitSample'),
114
+ buttons: [{ text: STRINGS.DIALOG.ALERT_PERMISSIONS_OK, onPress: () => SBUUtils.openSettings() }],
115
+ });
116
+ } else {
117
+ toast.show(STRINGS.TOAST.OPEN_PHOTO_LIBRARY_ERROR, 'error');
118
+ }
119
+ },
103
120
  });
104
121
  if (!files || !files[0]) return;
105
122
 
106
- const params = new sdk.GroupChannelParams();
107
- params.coverImage = files[0];
108
- await updateChannel(params);
123
+ await updateChannel({ coverImage: files[0] });
109
124
  },
110
125
  },
111
126
  ],
@@ -1,5 +1,5 @@
1
1
  import type { UseUserListOptions } from '@sendbird/uikit-chat-hooks';
2
- import type { SendbirdGroupChannel, SendbirdGroupChannelParams } from '@sendbird/uikit-utils';
2
+ import type { SendbirdGroupChannel, SendbirdGroupChannelCreateParams } from '@sendbird/uikit-utils';
3
3
 
4
4
  import type { CommonComponent } from '../../types';
5
5
  import type { GroupChannelType } from '../groupChannelList/types';
@@ -14,9 +14,9 @@ export interface GroupChannelCreateProps<User> {
14
14
  channelType?: GroupChannelType;
15
15
  userIdsGenerator?: (users: User[]) => UserIds;
16
16
  onBeforeCreateChannel?: (
17
- params: SendbirdGroupChannelParams,
17
+ params: SendbirdGroupChannelCreateParams,
18
18
  users: User[],
19
- ) => SendbirdGroupChannelParams | Promise<SendbirdGroupChannelParams>;
19
+ ) => SendbirdGroupChannelCreateParams | Promise<SendbirdGroupChannelCreateParams>;
20
20
  sortComparator?: UseUserListOptions<User>['sortComparator'];
21
21
  queryCreator?: UseUserListOptions<User>['queryCreator'];
22
22
  renderUser?: UserListProps<User>['List']['renderUser'];
@@ -2,7 +2,7 @@ import React from 'react';
2
2
  import { TouchableOpacity } from 'react-native';
3
3
 
4
4
  import { useUserList } from '@sendbird/uikit-chat-hooks';
5
- import { Logger, PASS, SendbirdUser, useFreshCallback } from '@sendbird/uikit-utils';
5
+ import { Logger, PASS, SendbirdGroupChannelCreateParams, SendbirdUser, useFreshCallback } from '@sendbird/uikit-utils';
6
6
 
7
7
  import StatusComposition from '../components/StatusComposition';
8
8
  import UserSelectableBar from '../components/UserSelectableBar';
@@ -95,18 +95,19 @@ const createGroupChannelCreateFragment = <UserType,>(
95
95
  <UserListModule.Header
96
96
  onPressHeaderLeft={onPressHeaderLeft}
97
97
  onPressHeaderRight={async (users) => {
98
- const params = new sdk.GroupChannelParams();
98
+ const params: SendbirdGroupChannelCreateParams = {
99
+ invitedUserIds: userIdsGenerator(users),
100
+ name: '',
101
+ coverUrl: '',
102
+ isDistinct: false,
103
+ };
99
104
 
100
105
  if (channelType === 'BROADCAST') params.isBroadcast = true;
101
106
  if (channelType === 'SUPER_GROUP') params.isSuper = true;
102
107
  if (currentUser) params.operatorUserIds = [currentUser.userId];
103
- params.addUserIds(userIdsGenerator(users));
104
- params.name = '';
105
- params.coverUrl = '';
106
- params.isDistinct = false;
107
108
 
108
109
  const processedParams = await onBeforeCreateChannel(params, users);
109
- const channel = await sdk.GroupChannel.createChannel(processedParams);
110
+ const channel = await sdk.groupChannel.createChannel(processedParams);
110
111
  onCreateChannel(channel);
111
112
  }}
112
113
  />