agora-appbuilder-core 4.0.13 → 4.0.14

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 (71) hide show
  1. package/package.json +1 -1
  2. package/template/_package-lock.json +1364 -1576
  3. package/template/android/app/src/main/assets/fonts/icomoon.ttf +0 -0
  4. package/template/customization-api/sub-components.ts +6 -4
  5. package/template/customization-api/types.ts +0 -6
  6. package/template/defaultConfig.js +0 -3
  7. package/template/global.d.ts +0 -3
  8. package/template/ios/Podfile.lock +0 -10
  9. package/template/package-lock.json +1364 -1576
  10. package/template/package.json +0 -4
  11. package/template/src/SDKAppWrapper.tsx +8 -2
  12. package/template/src/app-state/useMessages.ts +9 -49
  13. package/template/src/assets/font-styles.css +125 -289
  14. package/template/src/assets/fonts/icomoon.ttf +0 -0
  15. package/template/src/assets/selection.json +1 -1
  16. package/template/src/atoms/ActionMenu.tsx +2 -5
  17. package/template/src/atoms/CustomIcon.tsx +1 -17
  18. package/template/src/atoms/ImageIcon.tsx +3 -19
  19. package/template/src/atoms/Popup.tsx +4 -13
  20. package/template/src/atoms/ToolbarPreset.tsx +57 -6
  21. package/template/src/auth/AuthProvider.tsx +0 -5
  22. package/template/src/auth/config.ts +3 -12
  23. package/template/src/components/Chat.tsx +1 -7
  24. package/template/src/components/ChatContext.ts +0 -12
  25. package/template/src/components/CommonStyles.ts +2 -2
  26. package/template/src/components/Controls.tsx +57 -29
  27. package/template/src/components/Leftbar.tsx +4 -4
  28. package/template/src/components/Navbar.tsx +54 -29
  29. package/template/src/components/NavbarMobile.tsx +23 -33
  30. package/template/src/components/PinnedVideo.tsx +1 -1
  31. package/template/src/components/RTMConfigure.tsx +0 -1
  32. package/template/src/components/SdkApiContext.tsx +4 -1
  33. package/template/src/components/chat-messages/useChatMessages.tsx +607 -411
  34. package/template/src/components/chat-ui/useChatUIControls.tsx +0 -53
  35. package/template/src/components/meeting-info-invite/MeetingInfoGridTile.tsx +1 -4
  36. package/template/src/components/participants/Participant.tsx +1 -0
  37. package/template/src/components/precall/joinWaitingRoomBtn.native.tsx +1 -6
  38. package/template/src/components/precall/joinWaitingRoomBtn.tsx +1 -6
  39. package/template/src/components/room-info/useRoomInfo.tsx +5 -5
  40. package/template/src/language/default-labels/videoCallScreenLabels.ts +6 -86
  41. package/template/src/pages/VideoCall.tsx +4 -3
  42. package/template/src/pages/video-call/ActionSheetContent.tsx +32 -3
  43. package/template/src/pages/video-call/VideoCallScreenWrapper.tsx +12 -22
  44. package/template/src/pages/video-call/VideoComponent.tsx +11 -5
  45. package/template/src/pages/video-call/index.ts +0 -8
  46. package/template/src/subComponents/ChatBubble.tsx +32 -252
  47. package/template/src/subComponents/ChatContainer.tsx +4 -14
  48. package/template/src/subComponents/ChatInput.ios.tsx +184 -0
  49. package/template/src/subComponents/ChatInput.tsx +100 -276
  50. package/template/src/subComponents/RemoteMutePopup.tsx +131 -12
  51. package/template/src/subComponents/caption/CaptionContainer.tsx +2 -6
  52. package/template/src/subComponents/recording/useRecording.tsx +1 -3
  53. package/template/src/utils/SdkMethodEvents.ts +1 -0
  54. package/template/src/utils/common.tsx +17 -0
  55. package/template/src/utils/index.tsx +0 -30
  56. package/template/src/utils/useEndCall.ts +0 -7
  57. package/template/src/utils/useJoinRoom.ts +7 -33
  58. package/template/android/link-assets-manifest.json +0 -13
  59. package/template/ios/link-assets-manifest.json +0 -13
  60. package/template/src/atoms/InlinePopup.tsx +0 -185
  61. package/template/src/components/chat/chatConfigure.native.tsx +0 -488
  62. package/template/src/components/chat/chatConfigure.tsx +0 -473
  63. package/template/src/subComponents/ChatInput.native.tsx +0 -269
  64. package/template/src/subComponents/chat/ChatActionMenu.tsx +0 -224
  65. package/template/src/subComponents/chat/ChatAttachment.native.tsx +0 -234
  66. package/template/src/subComponents/chat/ChatAttachment.tsx +0 -145
  67. package/template/src/subComponents/chat/ChatEmoji.native.tsx +0 -75
  68. package/template/src/subComponents/chat/ChatEmoji.tsx +0 -181
  69. package/template/src/subComponents/chat/ChatSendButton.tsx +0 -141
  70. package/template/src/subComponents/chat/ChatUploadStatus.tsx +0 -65
  71. package/template/src/subComponents/chat/ImagePopup.tsx +0 -400
@@ -19,10 +19,9 @@ import {
19
19
  ContentInterface,
20
20
  DispatchContext,
21
21
  } from '../../../agora-rn-uikit';
22
- import {
23
- ChatType as ChatType,
24
- useChatUIControls,
25
- } from '../chat-ui/useChatUIControls';
22
+ import events, {PersistanceLevel} from '../../rtm-events-api';
23
+ import {EventNames} from '../../rtm-events';
24
+ import {ChatType, useChatUIControls} from '../chat-ui/useChatUIControls';
26
25
  import {useChatNotification} from '../chat-notification/useChatNotification';
27
26
  import Toast from '../../../react-native-toast-message';
28
27
  import {timeNow} from '../../rtm/utils';
@@ -32,8 +31,6 @@ import {trimText} from '../../utils/common';
32
31
  import {useStringRef} from '../../utils/useString';
33
32
  import {
34
33
  publicChatToastHeading,
35
- publicChatFileToastHeading,
36
- publicChatImgToastHeading,
37
34
  multiplePublicChatToastHeading,
38
35
  multiplePrivateChatToastHeading,
39
36
  privateChatToastHeading,
@@ -41,112 +38,24 @@ import {
41
38
  multiplePublicAndPrivateChatToastSubHeading,
42
39
  multiplePublicChatToastSubHeading,
43
40
  } from '../../language/default-labels/videoCallScreenLabels';
41
+ import {LogSource, logger} from '../../logger/AppBuilderLogger';
42
+
43
+ enum ChatMessageActionEnum {
44
+ Create = 'Create_Chat_Message',
45
+ Update = 'Update_Chat_Message',
46
+ Delete = 'Delete_Chat_Message',
47
+ }
44
48
 
45
49
  interface ChatMessagesProviderProps {
46
50
  children: React.ReactNode;
47
51
  callActive: boolean;
48
52
  }
49
- export enum ChatMessageType {
50
- /**
51
- * Text message.
52
- */
53
- TXT = 'txt',
54
- /**
55
- * Image message.
56
- */
57
- IMAGE = 'img',
58
- /**
59
- * Video message.
60
- */
61
- VIDEO = 'video',
62
- /**
63
- * Location message.
64
- */
65
- LOCATION = 'loc',
66
- /**
67
- * Voice message.
68
- */
69
- VOICE = 'voice',
70
- /**
71
- * File message.
72
- */
73
- FILE = 'file',
74
- /**
75
- * Command message.
76
- */
77
- CMD = 'cmd',
78
- /**
79
- * Custom message.
80
- */
81
- CUSTOM = 'custom',
82
- /**
83
- * Combined message.
84
- */
85
- COMBINE = 'combine',
86
- }
87
-
88
53
  export interface messageInterface {
89
54
  createdTimestamp: number;
90
55
  updatedTimestamp?: number;
91
56
  msg: string;
92
57
  msgId: string;
93
58
  isDeleted: boolean;
94
- type: ChatMessageType;
95
- thumb?: string;
96
- url?: string;
97
- fileName?: string;
98
- ext?: string;
99
- }
100
-
101
- export enum SDKChatType {
102
- SINGLE_CHAT = 'singleChat',
103
- GROUP_CHAT = 'groupChat',
104
- }
105
-
106
- export interface ChatOption {
107
- chatType: SDKChatType;
108
- type: ChatMessageType;
109
- from: string;
110
- to: string;
111
- msg?: string;
112
- file?: object;
113
- ext?: {
114
- file_length: number;
115
- file_ext: string;
116
- file_name: string;
117
- file_url: string;
118
- from_platform?: string;
119
- };
120
- url?: string;
121
- }
122
-
123
- interface ChatMessage {
124
- msgId?: string;
125
- localMsgId?: string;
126
- conversationId?: string;
127
- from?: string;
128
- to?: string;
129
- localTime?: number;
130
- serverTime?: number;
131
- hasDeliverAck?: boolean;
132
- hasReadAck?: boolean;
133
- needGroupAck?: boolean;
134
- groupAckCount?: number;
135
- hasRead?: boolean;
136
- chatType?: number;
137
- direction?: string;
138
- status?: number;
139
- attributes?: any;
140
- body: any;
141
- isChatThread?: boolean;
142
- isOnline?: boolean;
143
- deliverOnlineOnly?: boolean;
144
- receiverList?: string[];
145
- }
146
- export interface MessageStatusCallback {
147
- onProgress?(localMsgId: string, progress: number): void;
148
- onError(localMsgId: string, error: any): void;
149
- onSuccess(message: ChatMessage): void;
150
59
  }
151
60
  export interface messageStoreInterface extends messageInterface {
152
61
  uid: UidType;
@@ -155,35 +64,19 @@ export interface messageStoreInterface extends messageInterface {
155
64
  interface ChatMessagesInterface {
156
65
  messageStore: messageStoreInterface[];
157
66
  privateMessageStore: {[key: string]: messageStoreInterface[]};
158
- addMessageToPrivateStore: (
159
- uid: UidType,
160
- body: messageInterface,
161
- local: boolean,
162
- ) => void;
163
- addMessageToStore: (uid: UidType, body: messageInterface) => void;
164
- showMessageNotification: (
165
- msg: string,
166
- uid: string,
167
- isPrivateMessage?: boolean,
168
- msgType?: ChatMessageType,
169
- ) => void;
67
+ sendChatMessage: (msg: string, toUid?: UidType) => void;
68
+ editChatMessage: (msgId: string, msg: string, toUid?: UidType) => void;
69
+ deleteChatMessage: (msgId: string, toUid?: UidType) => void;
170
70
  openPrivateChat: (toUid: UidType) => void;
171
- removeMessageFromStore: (msgId: string, isMsgRecalled: boolean) => void;
172
- removeMessageFromPrivateStore: (
173
- msgId: string,
174
- isMsgRecalled: boolean,
175
- ) => void;
176
71
  }
177
72
 
178
73
  const ChatMessagesContext = React.createContext<ChatMessagesInterface>({
179
74
  messageStore: [],
180
75
  privateMessageStore: {},
181
- addMessageToStore: () => {},
182
- addMessageToPrivateStore: () => {},
183
- showMessageNotification: () => {},
76
+ sendChatMessage: () => {},
77
+ editChatMessage: () => {},
78
+ deleteChatMessage: () => {},
184
79
  openPrivateChat: () => {},
185
- removeMessageFromStore: () => {},
186
- removeMessageFromPrivateStore: () => {},
187
80
  });
188
81
 
189
82
  const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
@@ -202,9 +95,7 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
202
95
  useChatUIControls();
203
96
  const {setUnreadGroupMessageCount, setUnreadIndividualMessageCount} =
204
97
  useChatNotification();
205
- // to store group msgs
206
98
  const [messageStore, setMessageStore] = useState<messageStoreInterface[]>([]);
207
- // to store private msgs
208
99
  const [privateMessageStore, setPrivateMessageStore] = useState<{
209
100
  [key: string]: messageStoreInterface[];
210
101
  }>({});
@@ -217,7 +108,8 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
217
108
  const groupActiveRef = useRef<boolean>(false);
218
109
  const individualActiveRef = useRef<string | number>();
219
110
 
220
- //i18 labels:
111
+ //public single
112
+ const fromText = useStringRef(publicChatToastHeading);
221
113
 
222
114
  //public multple
223
115
  const multiplePublicChatToastHeadingTT = useStringRef(
@@ -249,32 +141,6 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
249
141
  from: string;
250
142
  }>(multiplePublicAndPrivateChatToastSubHeading);
251
143
 
252
- //public single
253
- const txtToastHeading = useStringRef(publicChatToastHeading);
254
- const imgToastHeading = useStringRef(publicChatImgToastHeading);
255
- const fileToastHeading = useStringRef(publicChatFileToastHeading);
256
-
257
- //commented for v1 release
258
- //const fromText = useString('messageSenderNotificationLabel');
259
- const fromText = (name: string, msgType: ChatMessageType) => {
260
- let text = '';
261
- switch (msgType) {
262
- case ChatMessageType.TXT:
263
- text = txtToastHeading?.current(name);
264
- break;
265
- case ChatMessageType.IMAGE:
266
- text = imgToastHeading?.current(name);
267
- break;
268
- case ChatMessageType.FILE:
269
- text = fileToastHeading?.current(name);
270
- break;
271
- default:
272
- text = txtToastHeading?.current(name);
273
- break;
274
- }
275
- return text;
276
- };
277
-
278
144
  useEffect(() => {
279
145
  callActiveRef.current.callActive = callActive;
280
146
  }, [callActive]);
@@ -296,14 +162,24 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
296
162
  }, [privateChatUser]);
297
163
 
298
164
  const allEqual = arr => arr.every(val => val === arr[0]);
299
- const openPrivateChat = (uidAsNumber: number) => {
165
+ const openPrivateChat = uidAsNumber => {
166
+ //move this logic into ChatContainer
167
+ // setUnreadPrivateMessageCount(
168
+ // unreadPrivateMessageCount -
169
+ // (unreadIndividualMessageCount[uidAsNumber] || 0),
170
+ // );
171
+ // setUnreadIndividualMessageCount((prevState) => {
172
+ // return {
173
+ // ...prevState,
174
+ // [uidAsNumber]: 0,
175
+ // };
176
+ // });
177
+
300
178
  setPrivateChatUser(uidAsNumber);
301
179
  setChatType(ChatType.Private);
302
180
  setSidePanel(SidePanelType.Chat);
303
181
  };
304
182
 
305
- //TODO: check why need
306
-
307
183
  const updateRenderListState = (
308
184
  uid: number,
309
185
  data: Partial<ContentInterface>,
@@ -311,6 +187,379 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
311
187
  dispatch({type: 'UpdateRenderList', value: [uid, data]});
312
188
  };
313
189
 
190
+ React.useEffect(() => {
191
+ const showMessageNotification = (
192
+ msg: string,
193
+ uid: string,
194
+ isPrivateMessage: boolean = false,
195
+ forceStop: boolean = false,
196
+ ) => {
197
+ //don't show group message notification if group chat is open
198
+ if (!isPrivateMessage && groupActiveRef.current) {
199
+ return;
200
+ }
201
+ const uidAsNumber = parseInt(uid);
202
+ //don't show private message notification if private chat is open
203
+ if (isPrivateMessage && uidAsNumber === individualActiveRef.current) {
204
+ return;
205
+ }
206
+ if (forceStop) {
207
+ return;
208
+ }
209
+ clearTimeout(timeoutRef.current);
210
+ isToastVisibleRef.current = true;
211
+ timeoutRef.current = setTimeout(() => {
212
+ isToastVisibleRef.current = false;
213
+ previousNotificationRef.current = [];
214
+ }, 3000);
215
+
216
+ previousNotificationRef.current.push({
217
+ isPrivateMessage: isPrivateMessage,
218
+ fromUid: isPrivateMessage ? uidAsNumber : 0,
219
+ from:
220
+ !isPrivateMessage &&
221
+ //@ts-ignore
222
+ defaultContentRef.current.defaultContent[uidAsNumber]?.name
223
+ ? trimText(
224
+ //@ts-ignore
225
+ defaultContentRef.current.defaultContent[uidAsNumber]?.name,
226
+ )
227
+ : '',
228
+ });
229
+
230
+ const privateMessages = previousNotificationRef.current.filter(
231
+ i => i.isPrivateMessage,
232
+ );
233
+ const publicMessages = previousNotificationRef.current.filter(
234
+ i => !i.isPrivateMessage,
235
+ );
236
+
237
+ //if 1 or more public and private messages
238
+ if (publicMessages && publicMessages.length > 1) {
239
+ const fromNamesArray = publicMessages
240
+ .filter(i => i.from !== undefined && i.from !== null && i.from !== '')
241
+ .map(i => i.from);
242
+ //removing the duplicate names
243
+ const fromNamesArrayUnique = [...new Set(fromNamesArray)];
244
+ //public chat with two name will seperated by "and"
245
+ //public chat with two or more name will have "and more" at the end
246
+ const fromNamesArrayUpdated =
247
+ fromNamesArrayUnique.length > 2
248
+ ? fromNamesArrayUnique
249
+ .slice(0, 2)
250
+ .map((i, index) => (index === 0 ? i + ', ' : i))
251
+ .concat(privateMessages?.length ? ', more' : ' and more')
252
+ : fromNamesArrayUnique.length == 2
253
+ ? fromNamesArrayUnique.map((i, index) =>
254
+ index === 0 ? i + ' and ' : i,
255
+ )
256
+ : fromNamesArrayUnique;
257
+ //converting the names array to string
258
+ const fromNames = fromNamesArrayUpdated.join('');
259
+ Toast.show({
260
+ //@ts-ignore
261
+ update: isToastVisibleRef.current ? true : false,
262
+ primaryBtn: null,
263
+ secondaryBtn: null,
264
+ type: 'info',
265
+ leadingIconName: 'chat-nav',
266
+ text1:
267
+ privateMessages && privateMessages.length
268
+ ? multiplePublicAndPrivateChatToastHeadingTT?.current()
269
+ : multiplePublicChatToastHeadingTT?.current(),
270
+ text2:
271
+ privateMessages && privateMessages.length
272
+ ? //@ts-ignore
273
+ multiplePublicAndPrivateChatToastSubHeadingTT?.current({
274
+ publicChatCount: publicMessages.length,
275
+ privateChatCount: privateMessages.length,
276
+ from: fromNames,
277
+ })
278
+ : //@ts-ignore
279
+ multiplePublicChatToastSubHeadingTT?.current({
280
+ count: publicMessages.length,
281
+ from: fromNames,
282
+ }),
283
+ visibilityTime: 3000,
284
+ onPress: () => {
285
+ if (isPrivateMessage) {
286
+ openPrivateChat(uidAsNumber);
287
+ } else {
288
+ //move this logic into ChatContainer
289
+ // setUnreadGroupMessageCount(0);
290
+ setPrivateChatUser(0);
291
+ setChatType(ChatType.Group);
292
+ setSidePanel(SidePanelType.Chat);
293
+ }
294
+ },
295
+ });
296
+ }
297
+ //if one or more private message and no public messages
298
+ else if (privateMessages && privateMessages.length > 1) {
299
+ Toast.show({
300
+ //@ts-ignore
301
+ update: isToastVisibleRef.current ? true : false,
302
+ primaryBtn: null,
303
+ secondaryBtn: null,
304
+ type: 'info',
305
+ leadingIconName: 'chat-nav',
306
+ text1:
307
+ //@ts-ignore
308
+ multiplePrivateChatToastHeadingTT?.current({
309
+ count: privateMessages.length,
310
+ }),
311
+ text2: ``,
312
+ visibilityTime: 3000,
313
+ onPress: () => {
314
+ const openPrivateChatDetails = allEqual(
315
+ privateMessages.map(i => i.fromUid),
316
+ );
317
+ //if all private message comes from the single user then open details private chat
318
+ if (openPrivateChatDetails) {
319
+ openPrivateChat(privateMessages[0].fromUid);
320
+ }
321
+ //if private message comes from different user then open private tab not the private chatting window
322
+ else {
323
+ //open private tab (not the detail of private chat user)
324
+ setPrivateChatUser(0);
325
+ setChatType(ChatType.Group);
326
+ setSidePanel(SidePanelType.Chat);
327
+ }
328
+ },
329
+ });
330
+ }
331
+ //either 1 public or 1 private message
332
+ else {
333
+ Toast.show({
334
+ //@ts-ignore
335
+ update: isToastVisibleRef.current ? true : false,
336
+ primaryBtn: null,
337
+ secondaryBtn: null,
338
+ type: 'info',
339
+ leadingIconName: 'chat-nav',
340
+ text1: isPrivateMessage
341
+ ? privateMessageLabel?.current()
342
+ : //@ts-ignore
343
+ defaultContentRef.current.defaultContent[uidAsNumber]?.name
344
+ ? fromText?.current(
345
+ trimText(
346
+ //@ts-ignore
347
+ defaultContentRef.current.defaultContent[uidAsNumber]?.name,
348
+ ),
349
+ )
350
+ : '',
351
+ text2: isPrivateMessage
352
+ ? ''
353
+ : msg.length > 30
354
+ ? msg.slice(0, 30) + '...'
355
+ : msg,
356
+ visibilityTime: 3000,
357
+ onPress: () => {
358
+ if (isPrivateMessage) {
359
+ openPrivateChat(uidAsNumber);
360
+ } else {
361
+ //move this logic into ChatContainer
362
+ // setUnreadGroupMessageCount(0);
363
+ setPrivateChatUser(0);
364
+ setChatType(ChatType.Group);
365
+ setSidePanel(SidePanelType.Chat);
366
+ }
367
+ },
368
+ });
369
+ }
370
+ };
371
+ const unsubPublicChatMessage = events.on(
372
+ EventNames.PUBLIC_CHAT_MESSAGE,
373
+ data => {
374
+ const forceStop =
375
+ $config.ENABLE_WAITING_ROOM &&
376
+ !isHostRef.current.isHost &&
377
+ !callActiveRef.current.callActive;
378
+ //if call is not active don't store the message in the state
379
+ if (forceStop) {
380
+ return;
381
+ }
382
+ const payload = JSON.parse(data.payload);
383
+ const messageAction = payload.action;
384
+ const messageData = payload.value;
385
+ switch (messageAction) {
386
+ case ChatMessageActionEnum.Create:
387
+ showMessageNotification(
388
+ messageData.msg,
389
+ `${data.sender}`,
390
+ false,
391
+ forceStop,
392
+ );
393
+ addMessageToStore(data.sender, {
394
+ msg: messageData.msg,
395
+ createdTimestamp: messageData.createdTimestamp,
396
+ isDeleted: messageData.isDeleted,
397
+ msgId: messageData.msgId,
398
+ });
399
+ /**
400
+ * if chat group window is not active.
401
+ * then we will increment the unread count
402
+ */
403
+ if (!groupActiveRef.current) {
404
+ setUnreadGroupMessageCount(prevState => {
405
+ return prevState + 1;
406
+ });
407
+ }
408
+ break;
409
+ case ChatMessageActionEnum.Update:
410
+ setMessageStore(prevState => {
411
+ const newState = prevState.map(item => {
412
+ if (
413
+ item.msgId === messageData.msgId &&
414
+ item.uid === data.sender
415
+ ) {
416
+ return {
417
+ ...item,
418
+ msg: messageData.msg,
419
+ updatedTimestamp: messageData.updatedTimestamp,
420
+ };
421
+ } else {
422
+ return item;
423
+ }
424
+ });
425
+ return newState;
426
+ });
427
+ break;
428
+ case ChatMessageActionEnum.Delete:
429
+ setMessageStore(prevState => {
430
+ const newState = prevState.map(item => {
431
+ if (
432
+ item.msgId === messageData.msgId &&
433
+ item.uid === data.sender
434
+ ) {
435
+ return {
436
+ ...item,
437
+ isDeleted: true,
438
+ updatedTimestamp: messageData.updatedTimestamp,
439
+ };
440
+ } else {
441
+ return item;
442
+ }
443
+ });
444
+ return newState;
445
+ });
446
+ break;
447
+ default:
448
+ break;
449
+ }
450
+ },
451
+ );
452
+
453
+ const unsubPrivateChatMessage = events.on(
454
+ EventNames.PRIVATE_CHAT_MESSAGE,
455
+ data => {
456
+ const payload = JSON.parse(data.payload);
457
+ const messageAction = payload.action;
458
+ const messageData = payload.value;
459
+ switch (messageAction) {
460
+ case ChatMessageActionEnum.Create:
461
+ //To order chat participant based on recent message
462
+ try {
463
+ updateRenderListState(data.sender, {
464
+ lastMessageTimeStamp: new Date().getTime(),
465
+ });
466
+ } catch (error) {
467
+ logger.error(
468
+ LogSource.Internals,
469
+ 'CHAT',
470
+ 'ERROR : couldnt update the last message timestamp',
471
+ error,
472
+ );
473
+ }
474
+ showMessageNotification(messageData.msg, `${data.sender}`, true);
475
+ addMessageToPrivateStore(
476
+ data.sender,
477
+ {
478
+ msg: messageData.msg,
479
+ createdTimestamp: messageData.createdTimestamp,
480
+ msgId: messageData.msgId,
481
+ isDeleted: messageData.isDeleted,
482
+ },
483
+ false,
484
+ );
485
+ /**
486
+ * if user's private window is active.
487
+ * then we will not increment the unread count
488
+ */
489
+
490
+ if (!(individualActiveRef.current === data.sender)) {
491
+ setUnreadIndividualMessageCount(prevState => {
492
+ const prevCount =
493
+ prevState && prevState[data.sender]
494
+ ? prevState[data.sender]
495
+ : 0;
496
+ return {
497
+ ...prevState,
498
+ [data.sender]: prevCount + 1,
499
+ };
500
+ });
501
+ }
502
+ break;
503
+ case ChatMessageActionEnum.Update:
504
+ setPrivateMessageStore(prevState => {
505
+ const privateChatOfUid = prevState[data.sender];
506
+ const updatedData = privateChatOfUid.map(item => {
507
+ if (
508
+ item.msgId === messageData.msgId &&
509
+ item.uid === data.sender
510
+ ) {
511
+ return {
512
+ ...item,
513
+ msg: messageData.msg,
514
+ updatedTimestamp: messageData.updatedTimestamp,
515
+ };
516
+ } else {
517
+ return item;
518
+ }
519
+ });
520
+ const newState = {
521
+ ...prevState,
522
+ [data.sender]: updatedData,
523
+ };
524
+ return newState;
525
+ });
526
+ break;
527
+ case ChatMessageActionEnum.Delete:
528
+ setPrivateMessageStore(prevState => {
529
+ const privateChatOfUid = prevState[data.sender];
530
+ const updatedData = privateChatOfUid.map(item => {
531
+ if (
532
+ item.msgId === messageData.msgId &&
533
+ item.uid === data.sender
534
+ ) {
535
+ return {
536
+ ...item,
537
+ isDeleted: true,
538
+ updatedTimestamp: messageData.updatedTimestamp,
539
+ };
540
+ } else {
541
+ return item;
542
+ }
543
+ });
544
+ const newState = {
545
+ ...prevState,
546
+ [data.sender]: updatedData,
547
+ };
548
+ return newState;
549
+ });
550
+ break;
551
+ default:
552
+ break;
553
+ }
554
+ },
555
+ );
556
+
557
+ return () => {
558
+ unsubPublicChatMessage();
559
+ unsubPrivateChatMessage();
560
+ };
561
+ }, []);
562
+
314
563
  const addMessageToStore = (uid: UidType, body: messageInterface) => {
315
564
  setMessageStore((m: messageStoreInterface[]) => {
316
565
  return [
@@ -321,11 +570,6 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
321
570
  msg: body.msg,
322
571
  msgId: body.msgId,
323
572
  isDeleted: body.isDeleted,
324
- type: body.type,
325
- thumb: body?.thumb,
326
- url: body?.url,
327
- ext: body?.ext,
328
- fileName: body?.fileName,
329
573
  },
330
574
  ];
331
575
  });
@@ -347,11 +591,6 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
347
591
  msg: body.msg,
348
592
  msgId: body.msgId,
349
593
  isDeleted: body.isDeleted,
350
- type: body.type,
351
- thumb: body?.thumb,
352
- url: body?.url,
353
- ext: body?.ext,
354
- fileName: body?.fileName,
355
594
  },
356
595
  ])
357
596
  : (newState = {
@@ -363,11 +602,6 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
363
602
  msg: body.msg,
364
603
  msgId: body.msgId,
365
604
  isDeleted: body.isDeleted,
366
- type: body.type,
367
- thumb: body.thumb,
368
- url: body.url,
369
- ext: body?.ext,
370
- fileName: body?.fileName,
371
605
  },
372
606
  ],
373
607
  });
@@ -375,257 +609,221 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
375
609
  });
376
610
  };
377
611
 
378
- const removeMessageFromStore = (msgID, isMsgRecalled) => {
379
- console.warn('msg delete native', msgID);
380
- setMessageStore(prev => {
381
- if (isMsgRecalled) {
382
- const recalledMsgIndex = prev.findIndex(msg => msg.msgId === msgID);
383
- if (recalledMsgIndex !== -1) {
384
- const updatedMessages = [...prev];
385
- updatedMessages[recalledMsgIndex].isDeleted = true;
386
- return updatedMessages;
387
- } else {
388
- return prev;
389
- }
390
- } else {
391
- return prev.filter(msg => msg.msgId !== msgID);
392
- }
393
- });
612
+ const sendChatMessage = (msg: string, toUid?: UidType) => {
613
+ if (typeof msg == 'string' && msg.trim() === '') return;
614
+ logger.log(
615
+ LogSource.Internals,
616
+ 'CHAT',
617
+ `sending ${toUid ? 'private' : 'public'} chat message -> ${msg} ${
618
+ toUid ? toUid : ''
619
+ }`,
620
+ );
621
+ if (toUid) {
622
+ const messageData = {
623
+ msg,
624
+ createdTimestamp: timeNow(),
625
+ msgId: getUniqueID(),
626
+ isDeleted: false,
627
+ };
628
+ events.send(
629
+ EventNames.PRIVATE_CHAT_MESSAGE,
630
+ JSON.stringify({
631
+ value: messageData,
632
+ action: ChatMessageActionEnum.Create,
633
+ }),
634
+ PersistanceLevel.None,
635
+ toUid,
636
+ );
637
+ addMessageToPrivateStore(toUid, messageData, true);
638
+ } else {
639
+ const messageData = {
640
+ msg,
641
+ msgId: getUniqueID(),
642
+ isDeleted: false,
643
+ createdTimestamp: timeNow(),
644
+ };
645
+ events.send(
646
+ EventNames.PUBLIC_CHAT_MESSAGE,
647
+ JSON.stringify({
648
+ value: messageData,
649
+ action: ChatMessageActionEnum.Create,
650
+ }),
651
+ PersistanceLevel.None,
652
+ );
653
+ addMessageToStore(localUid, messageData);
654
+ }
394
655
  };
395
656
 
396
- // const removeMessageFromPrivateStore = (msgID, isMsgRecalled) => {
397
- // setPrivateMessageStore(prev => {
398
- // const state = {...prev};
399
- // const filteredData = prev[localUid].filter(msg => msg.msgId !== msgID);
400
- // const newState = {...state, [localUid]: filteredData};
401
- // return {...newState};
402
- // });
403
- // };
404
-
405
- const removeMessageFromPrivateStore = (msgID, isMsgRecalled) => {
406
- setPrivateMessageStore(state => {
407
- const newState = {...state};
408
-
409
- if (isMsgRecalled) {
410
- Object.keys(newState).forEach(uid => {
411
- const messages = newState[uid];
412
- if (messages) {
413
- const recalledMsg = messages.find(msg => msg.msgId === msgID);
414
- if (recalledMsg) {
415
- recalledMsg.isDeleted = true;
657
+ const editChatMessage = (msgId: string, msg: string, toUid?: UidType) => {
658
+ if (typeof msg == 'string' && msg.trim() === '') return;
659
+ logger.log(
660
+ LogSource.Internals,
661
+ 'CHAT',
662
+ `editing ${toUid ? 'private' : 'public'} chat message..`,
663
+ {
664
+ msgId,
665
+ msg,
666
+ },
667
+ );
668
+ if (toUid) {
669
+ const checkData = privateMessageStore[toUid].filter(
670
+ item => item.msgId === msgId && item.uid === localUid,
671
+ );
672
+ if (checkData && checkData.length) {
673
+ const editMsgData = {msg, updatedTimestamp: timeNow()};
674
+ events.send(
675
+ EventNames.PRIVATE_CHAT_MESSAGE,
676
+ JSON.stringify({
677
+ value: {msgId, ...editMsgData},
678
+ action: ChatMessageActionEnum.Update,
679
+ }),
680
+ PersistanceLevel.None,
681
+ toUid,
682
+ );
683
+ setPrivateMessageStore(prevState => {
684
+ const privateChatOfUid = prevState[toUid];
685
+ const updatedData = privateChatOfUid.map(item => {
686
+ if (item.msgId === msgId) {
687
+ return {...item, ...editMsgData};
688
+ } else {
689
+ return item;
416
690
  }
417
- }
691
+ });
692
+ const newState = {...prevState, [toUid]: updatedData};
693
+ return newState;
418
694
  });
419
695
  } else {
420
- Object.keys(newState).forEach(uid => {
421
- const messages = newState[uid];
422
- if (messages) {
423
- newState[uid] = messages.filter(msg => msg.msgId !== msgID);
424
- }
696
+ logger.debug(
697
+ LogSource.Internals,
698
+ 'CHAT',
699
+ "You don't have permission to edit",
700
+ {
701
+ msgId,
702
+ msg,
703
+ },
704
+ );
705
+ }
706
+ } else {
707
+ //check if user has permission to edit
708
+ const checkData = messageStore.filter(
709
+ item => item.msgId === msgId && item.uid === localUid,
710
+ );
711
+ if (checkData && checkData.length) {
712
+ const editMsgData = {msg, updatedTimestamp: timeNow()};
713
+ events.send(
714
+ EventNames.PUBLIC_CHAT_MESSAGE,
715
+ JSON.stringify({
716
+ value: {msgId, ...editMsgData},
717
+ action: ChatMessageActionEnum.Update,
718
+ }),
719
+ PersistanceLevel.None,
720
+ );
721
+ setMessageStore(prevState => {
722
+ const newState = prevState.map(item => {
723
+ if (item.msgId === msgId) {
724
+ return {...item, ...editMsgData};
725
+ } else {
726
+ return item;
727
+ }
728
+ });
729
+ return newState;
425
730
  });
731
+ } else {
732
+ logger.debug(
733
+ LogSource.Internals,
734
+ 'CHAT',
735
+ "You don't have permission to edit",
736
+ {
737
+ msgId,
738
+ msg,
739
+ },
740
+ );
426
741
  }
427
-
428
- return {...newState};
429
- });
742
+ }
430
743
  };
431
744
 
432
- const showMessageNotification = (
433
- msg: string,
434
- uid: string,
435
- isPrivateMessage: boolean = false,
436
- msgType: ChatMessageType,
437
- forceStop: boolean = false,
438
- ) => {
439
- if (isPrivateMessage) {
440
- // update notification count
441
- if (!(individualActiveRef.current === Number(uid))) {
442
- setUnreadIndividualMessageCount(prevState => {
443
- const prevCount = prevState && prevState[uid] ? prevState[uid] : 0;
444
- return {
445
- ...prevState,
446
- [uid]: prevCount + 1,
447
- };
745
+ const deleteChatMessage = (msgId: string, toUid?: UidType) => {
746
+ logger.log(
747
+ LogSource.Internals,
748
+ 'CHAT',
749
+ `deleting ${toUid ? 'private' : 'public'} chat message..`,
750
+ {
751
+ msgId,
752
+ },
753
+ );
754
+ if (toUid) {
755
+ const checkData = privateMessageStore[toUid].filter(
756
+ item => item.msgId === msgId && item.uid === localUid,
757
+ );
758
+ if (checkData && checkData.length) {
759
+ const deleteMsgData = {updatedTimestamp: timeNow()};
760
+ events.send(
761
+ EventNames.PRIVATE_CHAT_MESSAGE,
762
+ JSON.stringify({
763
+ value: {msgId, ...deleteMsgData},
764
+ action: ChatMessageActionEnum.Delete,
765
+ }),
766
+ PersistanceLevel.None,
767
+ toUid,
768
+ );
769
+ setPrivateMessageStore(prevState => {
770
+ const privateChatOfUid = prevState[toUid];
771
+ const updatedData = privateChatOfUid.map(item => {
772
+ if (item.msgId === msgId) {
773
+ return {...item, isDeleted: true, ...deleteMsgData};
774
+ } else {
775
+ return item;
776
+ }
777
+ });
778
+ const newState = {...prevState, [toUid]: updatedData};
779
+ return newState;
448
780
  });
781
+ } else {
782
+ logger.debug(
783
+ LogSource.Internals,
784
+ 'CHAT',
785
+ "You don't have permission to delete",
786
+ {
787
+ msgId,
788
+ },
789
+ );
449
790
  }
450
791
  } else {
451
- if (!groupActiveRef.current) {
452
- setUnreadGroupMessageCount(prevState => {
453
- return prevState + 1;
792
+ //check if user has permission to delete
793
+ const checkData = messageStore.filter(
794
+ item => item.msgId === msgId && item.uid === localUid,
795
+ );
796
+ if (checkData && checkData.length) {
797
+ const deleteMsgData = {updatedTimestamp: timeNow()};
798
+ events.send(
799
+ EventNames.PUBLIC_CHAT_MESSAGE,
800
+ JSON.stringify({
801
+ value: {msgId, ...deleteMsgData},
802
+ action: ChatMessageActionEnum.Delete,
803
+ }),
804
+ PersistanceLevel.None,
805
+ );
806
+ setMessageStore(prevState => {
807
+ const newState = prevState.map(item => {
808
+ if (item.msgId === msgId) {
809
+ return {...item, isDeleted: true, ...deleteMsgData};
810
+ } else {
811
+ return item;
812
+ }
813
+ });
814
+ return newState;
454
815
  });
816
+ } else {
817
+ logger.debug(
818
+ LogSource.Internals,
819
+ 'CHAT',
820
+ "You don't have permission to delete",
821
+ {
822
+ msgId,
823
+ },
824
+ );
455
825
  }
456
826
  }
457
-
458
- //don't show group message notification if group chat is open
459
- if (!isPrivateMessage && groupActiveRef.current) {
460
- return;
461
- }
462
- const uidAsNumber = parseInt(uid);
463
- //don't show private message notification if private chat is open
464
- if (isPrivateMessage && uidAsNumber === individualActiveRef.current) {
465
- return;
466
- }
467
- if (forceStop) {
468
- return;
469
- }
470
- clearTimeout(timeoutRef.current);
471
- isToastVisibleRef.current = true;
472
- timeoutRef.current = setTimeout(() => {
473
- isToastVisibleRef.current = false;
474
- previousNotificationRef.current = [];
475
- }, 3000);
476
-
477
- previousNotificationRef.current.push({
478
- isPrivateMessage: isPrivateMessage,
479
- fromUid: isPrivateMessage ? uidAsNumber : 0,
480
- from:
481
- !isPrivateMessage &&
482
- //@ts-ignore
483
- defaultContentRef.current.defaultContent[uidAsNumber]?.name
484
- ? trimText(
485
- //@ts-ignore
486
- defaultContentRef.current.defaultContent[uidAsNumber]?.name,
487
- )
488
- : '',
489
- });
490
-
491
- const privateMessages = previousNotificationRef.current.filter(
492
- i => i.isPrivateMessage,
493
- );
494
- const publicMessages = previousNotificationRef.current.filter(
495
- i => !i.isPrivateMessage,
496
- );
497
-
498
- //if 1 or more public and private messages
499
- if (publicMessages && publicMessages.length > 1) {
500
- const fromNamesArray = publicMessages
501
- .filter(i => i.from !== undefined && i.from !== null && i.from !== '')
502
- .map(i => i.from);
503
- //removing the duplicate names
504
- const fromNamesArrayUnique = [...new Set(fromNamesArray)];
505
- //public chat with two name will seperated by "and"
506
- //public chat with two or more name will have "and more" at the end
507
- const fromNamesArrayUpdated =
508
- fromNamesArrayUnique.length > 2
509
- ? fromNamesArrayUnique
510
- .slice(0, 2)
511
- .map((i, index) => (index === 0 ? i + ', ' : i))
512
- .concat(privateMessages?.length ? ', more' : ' and more')
513
- : fromNamesArrayUnique.length == 2
514
- ? fromNamesArrayUnique.map((i, index) =>
515
- index === 0 ? i + ' and ' : i,
516
- )
517
- : fromNamesArrayUnique;
518
- //converting the names array to string
519
- const fromNames = fromNamesArrayUpdated.join('');
520
- Toast.show({
521
- //@ts-ignore
522
- update: isToastVisibleRef.current ? true : false,
523
- primaryBtn: null,
524
- secondaryBtn: null,
525
- type: 'info',
526
- leadingIconName: 'chat-nav',
527
- text1:
528
- privateMessages && privateMessages.length
529
- ? multiplePublicAndPrivateChatToastHeadingTT?.current()
530
- : multiplePublicChatToastHeadingTT?.current(),
531
- text2:
532
- privateMessages && privateMessages.length
533
- ? //@ts-ignore
534
- multiplePublicAndPrivateChatToastSubHeadingTT?.current({
535
- publicChatCount: publicMessages.length,
536
- privateChatCount: privateMessages.length,
537
- from: fromNames,
538
- })
539
- : //@ts-ignore
540
- multiplePublicChatToastSubHeadingTT?.current({
541
- count: publicMessages.length,
542
- from: fromNames,
543
- }),
544
- visibilityTime: 3000,
545
- onPress: () => {
546
- if (isPrivateMessage) {
547
- openPrivateChat(uidAsNumber);
548
- } else {
549
- //move this logic into ChatContainer
550
- // setUnreadGroupMessageCount(0);
551
- setPrivateChatUser(0);
552
- setChatType(ChatType.Group);
553
- setSidePanel(SidePanelType.Chat);
554
- }
555
- },
556
- });
557
- }
558
- //if one or more private message and no public messages
559
- else if (privateMessages && privateMessages.length > 1) {
560
- Toast.show({
561
- //@ts-ignore
562
- update: isToastVisibleRef.current ? true : false,
563
- primaryBtn: null,
564
- secondaryBtn: null,
565
- type: 'info',
566
- leadingIconName: 'chat-nav',
567
- //@ts-ignore
568
- text1: multiplePrivateChatToastHeadingTT?.current({
569
- count: privateMessages.length,
570
- }),
571
- text2: ``,
572
- visibilityTime: 3000,
573
- onPress: () => {
574
- const openPrivateChatDetails = allEqual(
575
- privateMessages.map(i => i.fromUid),
576
- );
577
- //if all private message comes from the single user then open details private chat
578
- if (openPrivateChatDetails) {
579
- openPrivateChat(privateMessages[0].fromUid);
580
- }
581
- //if private message comes from different user then open private tab not the private chatting window
582
- else {
583
- //open private tab (not the detail of private chat user)
584
- setPrivateChatUser(0);
585
- setChatType(ChatType.Group);
586
- setSidePanel(SidePanelType.Chat);
587
- }
588
- },
589
- });
590
- }
591
- //either 1 public or 1 private message
592
- else {
593
- Toast.show({
594
- //@ts-ignore
595
- update: isToastVisibleRef.current ? true : false,
596
- primaryBtn: null,
597
- secondaryBtn: null,
598
- type: 'info',
599
- leadingIconName: 'chat-nav',
600
- text1: isPrivateMessage
601
- ? privateMessageLabel?.current()
602
- : //@ts-ignore
603
- defaultContentRef.current.defaultContent[uidAsNumber]?.name
604
- ? fromText(
605
- trimText(
606
- //@ts-ignore
607
- defaultContentRef.current.defaultContent[uidAsNumber]?.name,
608
- ),
609
- msgType,
610
- )
611
- : '',
612
- text2: isPrivateMessage
613
- ? ''
614
- : msg.length > 30
615
- ? msg.slice(0, 30) + '...'
616
- : msg,
617
- visibilityTime: 3000,
618
- onPress: () => {
619
- if (isPrivateMessage) {
620
- openPrivateChat(uidAsNumber);
621
- } else {
622
- setPrivateChatUser(0);
623
- setChatType(ChatType.Group);
624
- setSidePanel(SidePanelType.Chat);
625
- }
626
- },
627
- });
628
- }
629
827
  };
630
828
 
631
829
  return (
@@ -633,11 +831,9 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
633
831
  value={{
634
832
  messageStore,
635
833
  privateMessageStore,
636
- addMessageToStore,
637
- addMessageToPrivateStore,
638
- removeMessageFromStore,
639
- removeMessageFromPrivateStore,
640
- showMessageNotification,
834
+ sendChatMessage,
835
+ editChatMessage,
836
+ deleteChatMessage,
641
837
  openPrivateChat,
642
838
  }}>
643
839
  {props.children}