agora-appbuilder-core 4.0.30 → 4.0.31-beta-1

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 (31) hide show
  1. package/package.json +1 -1
  2. package/template/customization-api/sub-components.ts +1 -0
  3. package/template/defaultConfig.js +2 -2
  4. package/template/package.json +1 -1
  5. package/template/src/components/ChatContext.ts +3 -0
  6. package/template/src/components/Controls.tsx +51 -18
  7. package/template/src/components/Navbar.tsx +29 -1
  8. package/template/src/components/chat/chatConfigure.native.tsx +85 -25
  9. package/template/src/components/chat/chatConfigure.tsx +99 -9
  10. package/template/src/components/chat-messages/useChatMessages.tsx +5 -0
  11. package/template/src/components/chat-ui/useChatUIControls.tsx +21 -0
  12. package/template/src/components/room-info/useRoomInfo.tsx +12 -0
  13. package/template/src/pages/Create.tsx +25 -1
  14. package/template/src/pages/video-call/VideoCallMobileView.tsx +3 -2
  15. package/template/src/pages/video-call/VideoCallScreen.tsx +3 -1
  16. package/template/src/subComponents/ChatBubble.tsx +387 -110
  17. package/template/src/subComponents/ChatContainer.tsx +20 -2
  18. package/template/src/subComponents/ChatInput.native.tsx +93 -14
  19. package/template/src/subComponents/ChatInput.tsx +41 -7
  20. package/template/src/subComponents/caption/Caption.tsx +14 -2
  21. package/template/src/subComponents/caption/CaptionContainer.tsx +24 -3
  22. package/template/src/subComponents/caption/CaptionText.tsx +13 -1
  23. package/template/src/subComponents/chat/ChatActionMenu.tsx +40 -3
  24. package/template/src/subComponents/chat/ChatAttachment.native.tsx +4 -2
  25. package/template/src/subComponents/chat/ChatEmoji.native.tsx +181 -22
  26. package/template/src/subComponents/chat/ChatEmoji.tsx +4 -3
  27. package/template/src/subComponents/chat/ChatQuickActionsMenu.tsx +69 -33
  28. package/template/src/subComponents/chat/ChatSendButton.tsx +42 -1
  29. package/template/src/subComponents/chat/PinnedMessage.tsx +198 -0
  30. package/template/src/utils/useCreateRoom.ts +23 -4
  31. package/template/src/utils/useJoinRoom.ts +76 -23
@@ -19,7 +19,6 @@ import {
19
19
  useChatUIControls,
20
20
  } from '../../components/chat-ui/useChatUIControls';
21
21
  import {logger, LogSource} from '../../logger/AppBuilderLogger';
22
- import {err} from 'react-native-svg/lib/typescript/xml';
23
22
 
24
23
  export interface FileObj {
25
24
  url: string;
@@ -42,6 +41,8 @@ interface chatConfigureContextInterface {
42
41
  ) => void;
43
42
  addReaction: (messageId: string, reaction: string) => void;
44
43
  removeReaction: (messageId: string, reaction: string) => void;
44
+ pinMessage: (messageId: string) => void;
45
+ unPinMessage: (messageId: string) => void;
45
46
  }
46
47
 
47
48
  export const chatConfigureContext =
@@ -55,6 +56,8 @@ export const chatConfigureContext =
55
56
  deleteAttachment: () => {},
56
57
  addReaction: () => {},
57
58
  removeReaction: () => {},
59
+ pinMessage: () => {},
60
+ unPinMessage: () => {},
58
61
  });
59
62
 
60
63
  const ChatConfigure = ({children}) => {
@@ -62,8 +65,14 @@ const ChatConfigure = ({children}) => {
62
65
  const {data} = useRoomInfo();
63
66
  const connRef = React.useRef(null);
64
67
  const {defaultContent} = useContent();
65
- const {privateChatUser, setUploadStatus, setUploadedFiles, uploadedFiles} =
66
- useChatUIControls();
68
+ const {
69
+ privateChatUser,
70
+ setUploadStatus,
71
+ setUploadedFiles,
72
+ uploadedFiles,
73
+ setPinMsgId,
74
+ setPinnedByUser,
75
+ } = useChatUIControls();
67
76
  const localUid = useLocalUid();
68
77
  const defaultContentRef = React.useRef(defaultContent);
69
78
  const {
@@ -92,6 +101,7 @@ const ChatConfigure = ({children}) => {
92
101
  // Initializes the Web client.
93
102
  newConn = new AgoraChat.connection({
94
103
  appKey: CHAT_APP_KEY,
104
+ isFixedDeviceId: false,
95
105
  });
96
106
  // Logs into Agora Chat.
97
107
  const result = await newConn.open({
@@ -131,6 +141,7 @@ const ChatConfigure = ({children}) => {
131
141
  : message.ext.file_url;
132
142
 
133
143
  const fromUser = message?.from;
144
+ const msgId = message.id;
134
145
 
135
146
  if (message.chatType === SDKChatType.GROUP_CHAT) {
136
147
  showMessageNotification(
@@ -143,12 +154,13 @@ const ChatConfigure = ({children}) => {
143
154
  addMessageToStore(Number(fromUser), {
144
155
  msg: message?.ext?.msg,
145
156
  createdTimestamp: message.time,
146
- msgId: message.id,
157
+ msgId,
147
158
  isDeleted: false,
148
159
  type: ChatMessageType.FILE,
149
160
  url: fileUrl,
150
161
  ext: message.ext.file_ext,
151
162
  fileName: message.ext.file_name,
163
+ replyToMsgId: message.ext?.replyToMsgId,
152
164
  });
153
165
  }
154
166
  if (message.chatType === SDKChatType.SINGLE_CHAT) {
@@ -163,12 +175,13 @@ const ChatConfigure = ({children}) => {
163
175
  {
164
176
  msg: message?.ext?.msg,
165
177
  createdTimestamp: message.time,
166
- msgId: message.id,
178
+ msgId,
167
179
  isDeleted: false,
168
180
  type: ChatMessageType.FILE,
169
181
  url: fileUrl,
170
182
  ext: message.ext.file_ext,
171
183
  fileName: message.ext.file_name,
184
+ replyToMsgId: message.ext?.replyToMsgId,
172
185
  },
173
186
  false,
174
187
  );
@@ -191,6 +204,7 @@ const ChatConfigure = ({children}) => {
191
204
  : message.ext.file_url;
192
205
 
193
206
  const fromUser = message?.from;
207
+ const msgId = message.id;
194
208
 
195
209
  if (message.chatType === SDKChatType.GROUP_CHAT) {
196
210
  showMessageNotification(
@@ -202,12 +216,13 @@ const ChatConfigure = ({children}) => {
202
216
  addMessageToStore(Number(fromUser), {
203
217
  msg: message?.ext?.msg,
204
218
  createdTimestamp: message.time,
205
- msgId: message.id,
219
+ msgId,
206
220
  isDeleted: false,
207
221
  type: ChatMessageType.IMAGE,
208
222
  thumb: fileUrl + '&thumbnail=true',
209
223
  url: fileUrl,
210
224
  fileName: message.ext?.file_name,
225
+ replyToMsgId: message.ext?.replyToMsgId,
211
226
  });
212
227
  }
213
228
  if (message.chatType === SDKChatType.SINGLE_CHAT) {
@@ -224,12 +239,13 @@ const ChatConfigure = ({children}) => {
224
239
  {
225
240
  msg: message?.ext?.msg,
226
241
  createdTimestamp: message.time,
227
- msgId: message.id,
242
+ msgId,
228
243
  isDeleted: false,
229
244
  type: ChatMessageType.IMAGE,
230
245
  thumb: fileUrl + '&thumbnail=true',
231
246
  url: fileUrl,
232
247
  fileName: message.ext?.file_name,
248
+ replyToMsgId: message.ext?.replyToMsgId,
233
249
  },
234
250
  false,
235
251
  );
@@ -248,6 +264,7 @@ const ChatConfigure = ({children}) => {
248
264
  );
249
265
 
250
266
  const fromUser = message?.from;
267
+ const msgId = message.id;
251
268
 
252
269
  if (message.chatType === SDKChatType.GROUP_CHAT) {
253
270
  // show to notifcation- group msg received
@@ -260,9 +277,10 @@ const ChatConfigure = ({children}) => {
260
277
  addMessageToStore(Number(fromUser), {
261
278
  msg: message.msg.replace(/^(\n)+|(\n)+$/g, ''),
262
279
  createdTimestamp: message.time,
263
- msgId: message.id,
280
+ msgId,
264
281
  isDeleted: false,
265
282
  type: ChatMessageType.TXT,
283
+ replyToMsgId: message.ext?.replyToMsgId,
266
284
  });
267
285
  }
268
286
 
@@ -280,9 +298,10 @@ const ChatConfigure = ({children}) => {
280
298
  {
281
299
  msg: message.msg.replace(/^(\n)+|(\n)+$/g, ''),
282
300
  createdTimestamp: message.time,
283
- msgId: message.id,
301
+ msgId,
284
302
  isDeleted: false,
285
303
  type: ChatMessageType.TXT,
304
+ replyToMsgId: message.ext?.replyToMsgId,
286
305
  },
287
306
  false,
288
307
  );
@@ -301,6 +320,12 @@ const ChatConfigure = ({children}) => {
301
320
  onTokenExpired: () => {
302
321
  logger.log(LogSource.Internals, 'CHAT', 'ChatSDK Token expired');
303
322
  },
323
+ // to reciev pin message event
324
+ onMessagePinEvent: options => {
325
+ const {messageId, operation, operatorId} = options;
326
+ operation === 'pin' ? setPinMsgId(messageId) : setPinMsgId('');
327
+ setPinnedByUser(operatorId);
328
+ },
304
329
  onError: error => {
305
330
  logger.error(LogSource.Internals, 'CHAT', 'ChatSDK Error', error);
306
331
  },
@@ -376,6 +401,7 @@ const ChatConfigure = ({children}) => {
376
401
  url: option?.ext?.file_url,
377
402
  ext: option?.ext?.file_ext,
378
403
  fileName: option?.ext?.file_name,
404
+ replyToMsgId: option?.ext?.replyToMsgId,
379
405
  };
380
406
 
381
407
  // update local user message store
@@ -581,6 +607,68 @@ const ChatConfigure = ({children}) => {
581
607
  });
582
608
  }
583
609
  };
610
+
611
+ const pinMessage = (messageId: string) => {
612
+ if (connRef.current) {
613
+ connRef.current
614
+ .pinMessage({
615
+ conversationId: data.chat.group_id,
616
+ conversationType: SDKChatType.GROUP_CHAT,
617
+ messageId,
618
+ })
619
+ .then(res => {
620
+ setPinMsgId(messageId);
621
+ setPinnedByUser(localUid);
622
+ //
623
+ logger.debug(
624
+ LogSource.Internals,
625
+ 'CHAT',
626
+ `Successfully Pinned message with id ${messageId}`,
627
+ res,
628
+ );
629
+ })
630
+ .catch(err => {
631
+ logger.debug(
632
+ LogSource.Internals,
633
+ 'CHAT',
634
+ `Failed to Pin Message with id ${messageId}`,
635
+ err,
636
+ );
637
+ });
638
+ }
639
+ };
640
+
641
+ const unPinMessage = (messageId: string) => {
642
+ if (connRef.current) {
643
+ connRef.current
644
+ .unpinMessage({
645
+ conversationId: data.chat.group_id,
646
+ conversationType: SDKChatType.GROUP_CHAT,
647
+ messageId,
648
+ })
649
+ .then(res => {
650
+ setPinMsgId('');
651
+ logger.debug(
652
+ LogSource.Internals,
653
+ 'CHAT',
654
+ `Successfully Pinned message with id ${messageId}`,
655
+ res,
656
+ );
657
+ })
658
+ .catch(err => {
659
+ logger.debug(
660
+ LogSource.Internals,
661
+ 'CHAT',
662
+ `Failed to Pin Message with id ${messageId}`,
663
+ err,
664
+ );
665
+ });
666
+ }
667
+ };
668
+
669
+ const blockGroupMember = () => {};
670
+
671
+ const unBlockGroupMember = () => {};
584
672
  return (
585
673
  <chatConfigureContext.Provider
586
674
  value={{
@@ -593,6 +681,8 @@ const ChatConfigure = ({children}) => {
593
681
  deleteAttachment,
594
682
  addReaction,
595
683
  removeReaction,
684
+ pinMessage,
685
+ unPinMessage,
596
686
  }}>
597
687
  {children}
598
688
  </chatConfigureContext.Provider>
@@ -97,6 +97,7 @@ export interface messageInterface {
97
97
  fileName?: string;
98
98
  ext?: string;
99
99
  reactions?: Reaction[];
100
+ replyToMsgId?: string;
100
101
  }
101
102
 
102
103
  export enum SDKChatType {
@@ -119,6 +120,7 @@ export interface ChatOption {
119
120
  from_platform?: string;
120
121
  channel?: string;
121
122
  msg?: string;
123
+ replyToMsgId?: string;
122
124
  };
123
125
  url?: string;
124
126
  }
@@ -343,6 +345,7 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
343
345
  url: body?.url,
344
346
  ext: body?.ext,
345
347
  fileName: body?.fileName,
348
+ replyToMsgId: body?.replyToMsgId,
346
349
  },
347
350
  ];
348
351
  });
@@ -369,6 +372,7 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
369
372
  url: body?.url,
370
373
  ext: body?.ext,
371
374
  fileName: body?.fileName,
375
+ replyToMsgId: body?.replyToMsgId,
372
376
  },
373
377
  ])
374
378
  : (newState = {
@@ -385,6 +389,7 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
385
389
  url: body.url,
386
390
  ext: body?.ext,
387
391
  fileName: body?.fileName,
392
+ replyToMsgId: body?.replyToMsgId,
388
393
  },
389
394
  ],
390
395
  });
@@ -58,6 +58,12 @@ export interface ChatUIControlsInterface {
58
58
  _resetTextareaHeight: () => void;
59
59
  _handleHeightChange: () => void;
60
60
  chatInputRef: any;
61
+ replyToMsgId: string;
62
+ setReplyToMsgId: React.Dispatch<SetStateAction<string>>;
63
+ pinMsgId: string;
64
+ setPinMsgId: React.Dispatch<SetStateAction<string>>;
65
+ pinnedByUser: UidType;
66
+ setPinnedByUser: React.Dispatch<SetStateAction<UidType>>;
61
67
  }
62
68
 
63
69
  const ChatUIControlsContext = React.createContext<ChatUIControlsInterface>({
@@ -80,6 +86,12 @@ const ChatUIControlsContext = React.createContext<ChatUIControlsInterface>({
80
86
  _resetTextareaHeight: () => {},
81
87
  _handleHeightChange: () => {},
82
88
  chatInputRef: null,
89
+ replyToMsgId: '',
90
+ setReplyToMsgId: () => {},
91
+ pinMsgId: '',
92
+ setPinMsgId: () => {},
93
+ pinnedByUser: 0,
94
+ setPinnedByUser: () => {},
83
95
  });
84
96
 
85
97
  interface ChatUIControlsProviderProps {
@@ -110,6 +122,9 @@ const ChatUIControlsProvider = (props: ChatUIControlsProviderProps) => {
110
122
  const [uploadedFiles, setUploadedFiles] = useState<File[]>([]);
111
123
  const [inputHeight, setInputHeight] = useState(MIN_HEIGHT);
112
124
  const chatInputRef = useRef(null);
125
+ const [replyToMsgId, setReplyToMsgId] = useState('');
126
+ const [pinMsgId, setPinMsgId] = useState('');
127
+ const [pinnedByUser, setPinnedByUser] = useState<UidType>(0);
113
128
 
114
129
  const _resetTextareaHeight = () => {
115
130
  if (chatInputRef?.current) {
@@ -162,6 +177,12 @@ const ChatUIControlsProvider = (props: ChatUIControlsProviderProps) => {
162
177
  chatInputRef,
163
178
  _resetTextareaHeight,
164
179
  _handleHeightChange,
180
+ replyToMsgId,
181
+ setReplyToMsgId,
182
+ pinMsgId,
183
+ setPinMsgId,
184
+ pinnedByUser,
185
+ setPinnedByUser,
165
186
  }}>
166
187
  {props.children}
167
188
  </ChatUIControlsContext.Provider>
@@ -33,15 +33,27 @@ export interface RoomData {
33
33
  pstn?: {
34
34
  number: string;
35
35
  pin: string;
36
+ error?: {
37
+ code?: number;
38
+ message?: string;
39
+ };
36
40
  };
37
41
  whiteboard?: {
38
42
  room_uuid: string;
39
43
  room_token: string;
44
+ error?: {
45
+ code?: number;
46
+ message?: string;
47
+ };
40
48
  };
41
49
  chat?: {
42
50
  user_token: string;
43
51
  group_id: string;
44
52
  is_group_owner: boolean;
53
+ error?: {
54
+ code?: number;
55
+ message?: string;
56
+ };
45
57
  };
46
58
  isSeparateHostLink: boolean;
47
59
  channel?: string;
@@ -28,7 +28,10 @@ import {useString} from '../utils/useString';
28
28
  import useCreateRoom from '../utils/useCreateRoom';
29
29
  import {CreateProvider} from './create/useCreate';
30
30
  import useJoinRoom from '../utils/useJoinRoom';
31
- import {RoomInfoDefaultValue} from '../components/room-info/useRoomInfo';
31
+ import {
32
+ RoomInfoDefaultValue,
33
+ useRoomInfo,
34
+ } from '../components/room-info/useRoomInfo';
32
35
  import Input from '../atoms/Input';
33
36
  import Toggle from '../atoms/Toggle';
34
37
  import Card from '../atoms/Card';
@@ -59,6 +62,7 @@ import {
59
62
  createRoomSuccessToastSubHeading,
60
63
  } from '../language/default-labels/createScreenLabels';
61
64
  import {LogSource, logger} from '../logger/AppBuilderLogger';
65
+ import {backendErrorCode} from 'src/utils/BackendErrorCode';
62
66
 
63
67
  const Create = () => {
64
68
  const {CreateComponent} = useCustomization(data => {
@@ -90,6 +94,7 @@ const Create = () => {
90
94
  const [coHostToggle, setCoHostToggle] = useState(false);
91
95
  const [roomCreated, setRoomCreated] = useState(false);
92
96
  const createRoomFun = useCreateRoom();
97
+ const {data} = useRoomInfo();
93
98
  const {setRoomInfo} = useSetRoomInfo();
94
99
 
95
100
  const loadingText = useString('loadingText')();
@@ -152,6 +157,25 @@ const Create = () => {
152
157
 
153
158
  const isDesktop = !isMobileUA();
154
159
 
160
+ //Added error toast notification to inform PSTN is not enabled
161
+ useEffect(() => {
162
+ if (data && data?.pstn && data?.pstn?.error) {
163
+ Toast.show({
164
+ leadingIconName: 'alert',
165
+ type: 'error',
166
+ text1: data?.pstn?.error?.message,
167
+ visibilityTime: 1000 * 10,
168
+ primaryBtn: null,
169
+ secondaryBtn: null,
170
+ leadingIcon: null,
171
+ });
172
+ logger.error(LogSource.Internals, 'CREATE_MEETING', 'PSTN Error', {
173
+ message: data?.pstn?.error?.message,
174
+ code: data?.pstn?.error?.code,
175
+ });
176
+ }
177
+ }, [data]);
178
+
155
179
  useEffect(() => {
156
180
  //Generating the random room title for placeholder
157
181
  // setRandomRoomTitle(
@@ -184,6 +184,7 @@ const VideoCallMobileView = props => {
184
184
 
185
185
  const VideoCallView = React.memo(() => {
186
186
  //toolbar changes
187
+
187
188
  const {
188
189
  BottombarComponent,
189
190
  BottombarProps,
@@ -253,7 +254,7 @@ const VideoCallView = React.memo(() => {
253
254
  });
254
255
 
255
256
  return (
256
- <VideocallWrapper>
257
+ <>
257
258
  <ToolbarProvider value={{position: ToolbarPosition.top}}>
258
259
  {Object.keys(TopbarProps)?.length ? (
259
260
  <TopbarComponent items={TopbarProps} includeDefaultItems={false} />
@@ -277,7 +278,7 @@ const VideoCallView = React.memo(() => {
277
278
  )}
278
279
  </ActionSheetProvider>
279
280
  </ToolbarProvider>
280
- </VideocallWrapper>
281
+ </>
281
282
  );
282
283
  });
283
284
 
@@ -329,7 +329,9 @@ const VideoCallScreen = () => {
329
329
  ) : // ) : !isDesktop ? (
330
330
  isMobileUA() ? (
331
331
  // Mobile View
332
- <VideoCallMobileView native={false} />
332
+ <VideocallWrapper>
333
+ <VideoCallMobileView native={false} />
334
+ </VideocallWrapper>
333
335
  ) : (
334
336
  // Desktop View
335
337
  <>