@sendbird/uikit-utils 2.3.0 → 2.4.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 (52) hide show
  1. package/lib/commonjs/hooks/index.js +38 -1
  2. package/lib/commonjs/hooks/index.js.map +1 -1
  3. package/lib/commonjs/hooks/react-native.js +5 -7
  4. package/lib/commonjs/hooks/react-native.js.map +1 -1
  5. package/lib/commonjs/index.js +25 -1
  6. package/lib/commonjs/index.js.map +1 -1
  7. package/lib/commonjs/sendbird/channel.js +29 -1
  8. package/lib/commonjs/sendbird/channel.js.map +1 -1
  9. package/lib/commonjs/sendbird/message.js +56 -1
  10. package/lib/commonjs/sendbird/message.js.map +1 -1
  11. package/lib/commonjs/sendbird/user.js +0 -6
  12. package/lib/commonjs/sendbird/user.js.map +1 -1
  13. package/lib/commonjs/shared/index.js +12 -0
  14. package/lib/commonjs/shared/index.js.map +1 -1
  15. package/lib/commonjs/types.js.map +1 -1
  16. package/lib/commonjs/ui-format/openChannel.js +22 -0
  17. package/lib/commonjs/ui-format/openChannel.js.map +1 -0
  18. package/lib/module/hooks/index.js +29 -1
  19. package/lib/module/hooks/index.js.map +1 -1
  20. package/lib/module/hooks/react-native.js +6 -8
  21. package/lib/module/hooks/react-native.js.map +1 -1
  22. package/lib/module/index.js +8 -1
  23. package/lib/module/index.js.map +1 -1
  24. package/lib/module/sendbird/channel.js +23 -1
  25. package/lib/module/sendbird/channel.js.map +1 -1
  26. package/lib/module/sendbird/message.js +51 -1
  27. package/lib/module/sendbird/message.js.map +1 -1
  28. package/lib/module/sendbird/user.js +0 -4
  29. package/lib/module/sendbird/user.js.map +1 -1
  30. package/lib/module/shared/index.js +10 -0
  31. package/lib/module/shared/index.js.map +1 -1
  32. package/lib/module/types.js.map +1 -1
  33. package/lib/module/ui-format/openChannel.js +10 -0
  34. package/lib/module/ui-format/openChannel.js.map +1 -0
  35. package/lib/typescript/src/hooks/index.d.ts +3 -0
  36. package/lib/typescript/src/index.d.ts +7 -2
  37. package/lib/typescript/src/sendbird/channel.d.ts +10 -1
  38. package/lib/typescript/src/sendbird/message.d.ts +3 -0
  39. package/lib/typescript/src/sendbird/user.d.ts +0 -2
  40. package/lib/typescript/src/shared/index.d.ts +6 -0
  41. package/lib/typescript/src/types.d.ts +8 -3
  42. package/lib/typescript/src/ui-format/openChannel.d.ts +3 -0
  43. package/package.json +4 -4
  44. package/src/hooks/index.ts +31 -1
  45. package/src/hooks/react-native.ts +6 -8
  46. package/src/index.ts +17 -1
  47. package/src/sendbird/channel.ts +33 -2
  48. package/src/sendbird/message.ts +54 -1
  49. package/src/sendbird/user.ts +0 -7
  50. package/src/shared/index.ts +10 -0
  51. package/src/types.ts +17 -2
  52. package/src/ui-format/openChannel.ts +11 -0
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
2
  import type { DependencyList } from 'react';
3
- import { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
3
+ import { useCallback, useEffect, useLayoutEffect, useReducer, useRef, useState } from 'react';
4
4
 
5
5
  type Destructor = () => void;
6
6
  type AsyncEffectCallback = () => void | Destructor | Promise<void> | Promise<Destructor>;
@@ -13,6 +13,11 @@ export const useUniqId = (key: string) => {
13
13
  })[0];
14
14
  };
15
15
 
16
+ export const useUniqHandlerId = (name: string) => {
17
+ const id = useUniqId(name);
18
+ return `${name}_${id}`;
19
+ };
20
+
16
21
  export const useForceUpdate = () => {
17
22
  const [, updater] = useState(0);
18
23
  return useCallback(() => updater((prev) => prev + 1), []);
@@ -72,3 +77,28 @@ export const useFreshCallback = <T extends (...args: any[]) => any>(callback: T)
72
77
  ref.current = callback;
73
78
  return useCallback(((...args) => ref.current(...args)) as T, []);
74
79
  };
80
+
81
+ export const useDebounceEffect = (action: () => void, delay: number, deps: DependencyList = []) => {
82
+ const timeoutRef = useRef<NodeJS.Timeout>();
83
+
84
+ useEffect(() => {
85
+ timeoutRef.current = setTimeout(async () => {
86
+ try {
87
+ await action();
88
+ } finally {
89
+ timeoutRef.current = undefined;
90
+ }
91
+ }, delay);
92
+
93
+ return () => {
94
+ if (timeoutRef.current) {
95
+ clearTimeout(timeoutRef.current);
96
+ timeoutRef.current = undefined;
97
+ }
98
+ };
99
+ }, [delay, ...deps]);
100
+ };
101
+
102
+ export const usePartialState = <S>(initialState: S) => {
103
+ return useReducer((prev: S, state: Partial<S>) => ({ ...prev, ...state }), initialState);
104
+ };
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo, useRef } from 'react';
1
+ import { useEffect, useRef } from 'react';
2
2
  import { AppState, AppStateEvent, AppStateStatus } from 'react-native';
3
3
  import { EdgeInsets, useSafeAreaInsets } from 'react-native-safe-area-context';
4
4
 
@@ -22,13 +22,11 @@ export const useSafeAreaPadding = <
22
22
  edges: T[],
23
23
  ): Result => {
24
24
  const safeAreaInsets = useSafeAreaInsets();
25
- return useMemo(() => {
26
- return edges.reduce((map, edge) => {
27
- const paddingKey = edgePaddingMap[edge];
28
- map[paddingKey] = safeAreaInsets[edge];
29
- return map;
30
- }, {} as { [key in EdgePaddingMap[T]]: EdgeInsets[T] });
31
- }, edges) as Result;
25
+ return edges.reduce((map, edge) => {
26
+ const paddingKey = edgePaddingMap[edge];
27
+ map[paddingKey] = safeAreaInsets[edge];
28
+ return map;
29
+ }, {} as { [key in EdgePaddingMap[T]]: EdgeInsets[T] }) as Result;
32
30
  };
33
31
 
34
32
  type AppStateListener = (status: AppStateStatus) => void;
package/src/index.ts CHANGED
@@ -24,6 +24,7 @@ export * from './shared';
24
24
  export * from './hooks';
25
25
  export * from './hooks/react-native';
26
26
  export * from './ui-format/groupChannel';
27
+ export * from './ui-format/openChannel';
27
28
  export * from './ui-format/common';
28
29
  export * from './sendbird/channel';
29
30
  export * from './sendbird/message';
@@ -34,9 +35,19 @@ export const NOOP: () => void = () => void 0;
34
35
  export const ASYNC_NOOP = async () => void 0;
35
36
  export const PASS = <T>(val: T) => val;
36
37
  export const toMegabyte = (byte: number) => byte / 1024 / 1024;
37
- export const isFunction = <T>(param?: T): param is NonNullable<T> => typeof param === 'function';
38
+ export const isFunction = (param?: unknown): param is Function => typeof param === 'function';
39
+
40
+ export function ifThenOr<T>(cond: boolean, then: T): T | undefined;
41
+ export function ifThenOr<T, V>(cond: boolean, then: T, or: V): T | V;
42
+ export function ifThenOr(cond: boolean, then: unknown, or?: unknown) {
43
+ if (cond) return then;
44
+ return or;
45
+ }
46
+
38
47
  export const SBErrorCode = {
39
48
  NON_AUTHORIZED: 400108,
49
+ CHANNEL_NOT_FOUND_SERVER: 400201,
50
+ CHANNEL_NOT_FOUND_SDK: 900500,
40
51
  };
41
52
  export const SBErrorMessage = {
42
53
  ACL:
@@ -54,6 +65,7 @@ export type {
54
65
  PartialDeep,
55
66
  Optional,
56
67
  ContextValue,
68
+ OnBeforeHandler,
57
69
  SendbirdMessage,
58
70
  SendbirdChatSDK,
59
71
  SendbirdChannel,
@@ -79,6 +91,7 @@ export type {
79
91
  SendbirdDataPayload,
80
92
  SendbirdPreviousMessageListQuery,
81
93
  SendbirdSendableMessage,
94
+ SendbirdOpenChannelListQuery,
82
95
  SendbirdGroupChannelListQuery,
83
96
  SendbirdGroupChannelUpdateParams,
84
97
  SendbirdUserMessageUpdateParams,
@@ -89,4 +102,7 @@ export type {
89
102
  SendbirdEmojiContainer,
90
103
  SendbirdEmoji,
91
104
  SendbirdEmojiCategory,
105
+ SendbirdOpenChannelUpdateParams,
106
+ SendbirdOpenChannelCreateParams,
107
+ SendbirdParticipant,
92
108
  } from './types';
@@ -1,5 +1,11 @@
1
1
  import { BufferedRequest } from '../shared/bufferedRequest';
2
- import type { SendbirdBaseChannel, SendbirdChannel, SendbirdGroupChannel, SendbirdOpenChannel } from '../types';
2
+ import type {
3
+ SendbirdBaseChannel,
4
+ SendbirdChannel,
5
+ SendbirdGroupChannel,
6
+ SendbirdGroupChannelCreateParams,
7
+ SendbirdOpenChannel,
8
+ } from '../types';
3
9
 
4
10
  /**
5
11
  * Diff utils for channel
@@ -13,12 +19,21 @@ export function isDifferentChannel<T extends SendbirdBaseChannel>(a?: T, b?: T):
13
19
  }
14
20
 
15
21
  export const getGroupChannelChatAvailableState = (channel: SendbirdGroupChannel) => {
16
- const frozen = channel.isFrozen && channel.myRole !== 'operator';
22
+ const isOperator = channel.myRole === 'operator';
23
+ const frozen = channel.isFrozen && !isOperator;
17
24
  const muted = channel.myMutedState === 'muted';
18
25
  const disabled = frozen || muted;
19
26
  return { disabled, frozen, muted };
20
27
  };
21
28
 
29
+ export const getOpenChannelChatAvailableState = async (channel: SendbirdOpenChannel, userId: string) => {
30
+ const isOperator = channel.isOperator(userId);
31
+ const frozen = channel.isFrozen && !isOperator;
32
+ const muted = (await channel.getMyMutedInfo()).isMuted;
33
+ const disabled = frozen || muted;
34
+ return { disabled, frozen, muted };
35
+ };
36
+
22
37
  export const confirmAndMarkAsRead = async (channels: SendbirdBaseChannel[]) => {
23
38
  channels
24
39
  .filter((it): it is SendbirdGroupChannel => it.isGroupChannel() && it.unreadMessageCount > 0)
@@ -50,3 +65,19 @@ export function getOpenChannels(channels: SendbirdChannel[]): SendbirdOpenChanne
50
65
  export function getChannelUniqId(channel: SendbirdChannel) {
51
66
  return channel.url;
52
67
  }
68
+
69
+ export function getDefaultGroupChannelCreateParams(params: {
70
+ invitedUserIds: string[];
71
+ currentUserId?: string;
72
+ }): SendbirdGroupChannelCreateParams {
73
+ const createParams: SendbirdGroupChannelCreateParams = {
74
+ name: '',
75
+ coverUrl: '',
76
+ isDistinct: false,
77
+ invitedUserIds: params.invitedUserIds,
78
+ };
79
+
80
+ if (params.currentUserId) createParams.operatorUserIds = [params.currentUserId];
81
+
82
+ return createParams;
83
+ }
@@ -1,3 +1,4 @@
1
+ import { getFileExtension, getFileType } from '../shared/regex';
1
2
  import type {
2
3
  SendbirdBaseChannel,
3
4
  SendbirdBaseMessage,
@@ -114,9 +115,61 @@ export function parseSendbirdNotification(dataPayload: RawSendbirdDataPayload):
114
115
  }
115
116
 
116
117
  export function shouldRenderReaction(channel: SendbirdBaseChannel, reactionEnabled: boolean) {
117
- return channel.isGroupChannel() && !channel.isBroadcast && !channel.isSuper && reactionEnabled;
118
+ if (channel.isOpenChannel()) {
119
+ return false;
120
+ }
121
+
122
+ if (channel.isGroupChannel()) {
123
+ if (channel.isBroadcast) return false;
124
+ if (channel.isSuper) return false;
125
+ }
126
+
127
+ return reactionEnabled;
118
128
  }
119
129
 
120
130
  export function getReactionCount(reaction: SendbirdReaction) {
121
131
  return reaction.userIds.length;
122
132
  }
133
+
134
+ type MessageType =
135
+ | 'user'
136
+ | 'admin'
137
+ | 'file'
138
+ | 'unknown'
139
+ | `user.${'opengraph'}`
140
+ | `file.${'image' | 'video' | 'audio'}`;
141
+
142
+ export function getFileTypeFromMessage(message: SendbirdFileMessage) {
143
+ return getFileType(message.type || getFileExtension(message.name));
144
+ }
145
+
146
+ export function getMessageType(message: SendbirdMessage): MessageType {
147
+ if (message.isAdminMessage()) {
148
+ return 'admin';
149
+ }
150
+
151
+ if (message.isUserMessage()) {
152
+ if (message.ogMetaData) {
153
+ return 'user.opengraph';
154
+ }
155
+ return 'user';
156
+ }
157
+
158
+ if (message.isFileMessage()) {
159
+ const fileType = getFileTypeFromMessage(message);
160
+ switch (fileType) {
161
+ case 'image':
162
+ case 'video': {
163
+ return `file.${fileType}`;
164
+ }
165
+ case 'audio': {
166
+ return `file.${fileType}`;
167
+ }
168
+ default: {
169
+ return 'file';
170
+ }
171
+ }
172
+ }
173
+
174
+ return 'unknown';
175
+ }
@@ -9,13 +9,6 @@ export function ifOperator(role: Role, then: unknown, or?: unknown) {
9
9
  return or;
10
10
  }
11
11
 
12
- export function ifMuted<T>(muted: boolean, then: T): T | undefined;
13
- export function ifMuted<T, V>(muted: boolean, then: T, or: V): T | V;
14
- export function ifMuted(muted: boolean, then: unknown, or?: unknown) {
15
- if (muted) return then;
16
- return or;
17
- }
18
-
19
12
  export function getUserUniqId<T extends UserStruct>(user: T) {
20
13
  return user.userId;
21
14
  }
@@ -54,3 +54,13 @@ export function shouldCompressImage(filePath: string, compressionEnabled = true)
54
54
  const extension = getFileExtension(filePath);
55
55
  return Boolean(extension.match(/jpg|jpeg|png/i) && compressionEnabled);
56
56
  }
57
+
58
+ /**
59
+ * Returns the picked data from object.
60
+ * */
61
+ export function pick<T extends { [key: string]: unknown }, Keys extends keyof T>(obj: T, keys: Keys[]) {
62
+ return keys.reduce((pickedObj, key) => {
63
+ pickedObj[key] = obj[key];
64
+ return pickedObj;
65
+ }, {} as { [key in Keys]: T[key] });
66
+ }
package/src/types.ts CHANGED
@@ -9,6 +9,7 @@ import type {
9
9
  Emoji,
10
10
  EmojiCategory,
11
11
  EmojiContainer,
12
+ Participant,
12
13
  RestrictedUser,
13
14
  SendbirdError as SBError,
14
15
  User,
@@ -24,7 +25,12 @@ import type {
24
25
  Member,
25
26
  MessageCollection,
26
27
  } from '@sendbird/chat/groupChannel';
27
- import type { ModuleNamespaces, SendableMessage } from '@sendbird/chat/lib/__definition';
28
+ import type {
29
+ ModuleNamespaces,
30
+ OpenChannelCreateParams,
31
+ OpenChannelUpdateParams,
32
+ SendableMessage,
33
+ } from '@sendbird/chat/lib/__definition';
28
34
  import type {
29
35
  AdminMessage,
30
36
  BaseMessage,
@@ -37,7 +43,7 @@ import type {
37
43
  UserMessageCreateParams,
38
44
  UserMessageUpdateParams,
39
45
  } from '@sendbird/chat/message';
40
- import type { OpenChannel, OpenChannelModule } from '@sendbird/chat/openChannel';
46
+ import type { OpenChannel, OpenChannelListQuery, OpenChannelModule } from '@sendbird/chat/openChannel';
41
47
 
42
48
  export type FilterByValueType<T extends object, Type> = {
43
49
  [K in keyof T as T[K] extends Type ? K : never]: T[K];
@@ -65,6 +71,8 @@ export type Optional<T> = T | undefined;
65
71
 
66
72
  export type ContextValue<T extends React.Context<any>> = T extends React.Context<infer V> ? V : never;
67
73
 
74
+ export type OnBeforeHandler<T> = (params: T) => T | Promise<T>;
75
+
68
76
  export interface UserStruct {
69
77
  userId: string;
70
78
  }
@@ -81,12 +89,18 @@ export type SendbirdFileMessageCreateParams = FileMessageCreateParams;
81
89
  export type SendbirdFileMessageUpdateParams = FileMessageUpdateParams;
82
90
  export type SendbirdUserMessageCreateParams = UserMessageCreateParams;
83
91
  export type SendbirdUserMessageUpdateParams = UserMessageUpdateParams;
92
+
84
93
  export type SendbirdGroupChannelCreateParams = GroupChannelCreateParams;
85
94
  export type SendbirdGroupChannelUpdateParams = GroupChannelUpdateParams;
95
+ export type SendbirdOpenChannelCreateParams = OpenChannelCreateParams;
96
+ export type SendbirdOpenChannelUpdateParams = OpenChannelUpdateParams;
97
+
86
98
  export type SendbirdUserUpdateParams = UserUpdateParams;
87
99
  export type SendbirdUser = User;
88
100
  export type SendbirdRestrictedUser = RestrictedUser;
89
101
  export type SendbirdMember = Member;
102
+ export type SendbirdParticipant = Participant;
103
+
90
104
  export type SendbirdGroupChannel = GroupChannel;
91
105
  export type SendbirdBaseChannel = BaseChannel;
92
106
  export type SendbirdOpenChannel = OpenChannel;
@@ -98,6 +112,7 @@ export type SendbirdEmojiContainer = EmojiContainer;
98
112
 
99
113
  export type SendbirdGroupChannelCollection = GroupChannelCollection;
100
114
  export type SendbirdGroupChannelListQuery = GroupChannelListQuery;
115
+ export type SendbirdOpenChannelListQuery = OpenChannelListQuery;
101
116
  export type SendbirdMessageCollection = MessageCollection;
102
117
  export type SendbirdPreviousMessageListQuery = PreviousMessageListQuery;
103
118
 
@@ -0,0 +1,11 @@
1
+ import type { SendbirdOpenChannel } from '../types';
2
+
3
+ export const getOpenChannelTitle = (channel: SendbirdOpenChannel, DEFAULT_CHANNEL_NAME = 'Open Channel') => {
4
+ const trimmedChannelName = channel.name.trim();
5
+ if (trimmedChannelName === '') return DEFAULT_CHANNEL_NAME;
6
+ return trimmedChannelName;
7
+ };
8
+
9
+ export const getOpenChannelParticipants = (channel: SendbirdOpenChannel) => {
10
+ return `${channel.participantCount} participants`;
11
+ };