agora-appbuilder-core 2.3.0-beta.12 → 2.3.0-beta.15

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agora-appbuilder-core",
3
- "version": "2.3.0-beta.12",
3
+ "version": "2.3.0-beta.15",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -23,12 +23,14 @@
23
23
  "electron-updater": "4.3.9",
24
24
  "exponential-backoff": "3.1.0",
25
25
  "graphql": "15.5.0",
26
+ "nanoid": "4.0.0",
26
27
  "nosleep.js": "0.12.0",
27
28
  "react": "16.13.1",
28
29
  "react-dom": "16.13.1",
29
30
  "react-is": "18.0.0",
30
31
  "react-native": "0.63.3",
31
32
  "react-native-agora": "3.4.2",
33
+ "react-native-get-random-values": "1.8.0",
32
34
  "react-native-hyperlink": "0.0.19",
33
35
  "react-native-inappbrowser-reborn": "3.5.1",
34
36
  "react-native-keep-awake": "4.0.0",
@@ -12940,6 +12942,11 @@
12940
12942
  "node": ">= 0.10"
12941
12943
  }
12942
12944
  },
12945
+ "node_modules/fast-base64-decode": {
12946
+ "version": "1.0.0",
12947
+ "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz",
12948
+ "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="
12949
+ },
12943
12950
  "node_modules/fast-deep-equal": {
12944
12951
  "version": "3.1.3",
12945
12952
  "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -22140,6 +22147,17 @@
22140
22147
  "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
22141
22148
  "optional": true
22142
22149
  },
22150
+ "node_modules/nanoid": {
22151
+ "version": "4.0.0",
22152
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
22153
+ "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
22154
+ "bin": {
22155
+ "nanoid": "bin/nanoid.js"
22156
+ },
22157
+ "engines": {
22158
+ "node": "^14 || ^16 || >=18"
22159
+ }
22160
+ },
22143
22161
  "node_modules/nanomatch": {
22144
22162
  "version": "1.2.13",
22145
22163
  "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -23984,6 +24002,17 @@
23984
24002
  "react-native": "*"
23985
24003
  }
23986
24004
  },
24005
+ "node_modules/react-native-get-random-values": {
24006
+ "version": "1.8.0",
24007
+ "resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.8.0.tgz",
24008
+ "integrity": "sha512-H/zghhun0T+UIJLmig3+ZuBCvF66rdbiWUfRSNS6kv5oDSpa1ZiVyvRWtuPesQpT8dXj+Bv7WJRQOUP+5TB1sA==",
24009
+ "dependencies": {
24010
+ "fast-base64-decode": "^1.0.0"
24011
+ },
24012
+ "peerDependencies": {
24013
+ "react-native": ">=0.56"
24014
+ }
24015
+ },
23987
24016
  "node_modules/react-native-hyperlink": {
23988
24017
  "version": "0.0.19",
23989
24018
  "resolved": "https://registry.npmjs.org/react-native-hyperlink/-/react-native-hyperlink-0.0.19.tgz",
@@ -39247,6 +39276,11 @@
39247
39276
  "time-stamp": "^1.0.0"
39248
39277
  }
39249
39278
  },
39279
+ "fast-base64-decode": {
39280
+ "version": "1.0.0",
39281
+ "resolved": "https://registry.npmjs.org/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz",
39282
+ "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q=="
39283
+ },
39250
39284
  "fast-deep-equal": {
39251
39285
  "version": "3.1.3",
39252
39286
  "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -46424,6 +46458,11 @@
46424
46458
  "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==",
46425
46459
  "optional": true
46426
46460
  },
46461
+ "nanoid": {
46462
+ "version": "4.0.0",
46463
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
46464
+ "integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg=="
46465
+ },
46427
46466
  "nanomatch": {
46428
46467
  "version": "1.2.13",
46429
46468
  "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
@@ -48158,6 +48197,14 @@
48158
48197
  "integrity": "sha512-zY2BIDCG9vEGQMW9oggsom9XHZJqETG/nafLsZx4z52TzHw9bipNypL/jXpE50Ofg+bS9YKYJaSZGy8M9dgKSA==",
48159
48198
  "requires": {}
48160
48199
  },
48200
+ "react-native-get-random-values": {
48201
+ "version": "1.8.0",
48202
+ "resolved": "https://registry.npmjs.org/react-native-get-random-values/-/react-native-get-random-values-1.8.0.tgz",
48203
+ "integrity": "sha512-H/zghhun0T+UIJLmig3+ZuBCvF66rdbiWUfRSNS6kv5oDSpa1ZiVyvRWtuPesQpT8dXj+Bv7WJRQOUP+5TB1sA==",
48204
+ "requires": {
48205
+ "fast-base64-decode": "^1.0.0"
48206
+ }
48207
+ },
48161
48208
  "react-native-hyperlink": {
48162
48209
  "version": "0.0.19",
48163
48210
  "resolved": "https://registry.npmjs.org/react-native-hyperlink/-/react-native-hyperlink-0.0.19.tgz",
@@ -32,7 +32,9 @@ export default function UserJoined(
32
32
  ...typeData,
33
33
  },
34
34
  };
35
- let renderPosition = [...state.renderPosition, newUid];
35
+ let renderPosition = state.renderPosition.filter((i) => i === newUid).length
36
+ ? [...state.renderPosition]
37
+ : [...state.renderPosition, newUid];
36
38
  const [maxUid] = renderPosition;
37
39
  if (renderPosition.length === 2 && maxUid === localUid) {
38
40
  //Only one remote and local is maximized
@@ -203,16 +203,30 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
203
203
 
204
204
  const swapVideo = useCallback(
205
205
  (state: RenderStateInterface, newMaxUid: UidType) => {
206
+ if (state?.renderPosition?.indexOf(newMaxUid) === -1) {
207
+ //skip the update if new max uid is not joined yet.
208
+ return {};
209
+ }
206
210
  let renderPosition: RenderStateInterface['renderPosition'] = [
207
211
  ...state.renderPosition,
208
212
  ];
209
213
  let renderList: RenderStateInterface['renderList'] = {
210
214
  ...state.renderList,
211
215
  };
216
+
212
217
  // Element which is currently maximized
213
218
  const [currentMaxUid] = renderPosition;
214
219
 
215
220
  if (currentMaxUid === newMaxUid) {
221
+ //skip the update if new max uid is already maximized
222
+ return {};
223
+ }
224
+
225
+ const newMaxUidOldPosition = renderPosition.findIndex(
226
+ (i) => i === newMaxUid,
227
+ );
228
+
229
+ if (!newMaxUidOldPosition) {
216
230
  return {};
217
231
  }
218
232
 
@@ -228,10 +242,6 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
228
242
  * else push newMaxUid at last position
229
243
  */
230
244
 
231
- const newMaxUidOldPosition = renderPosition.findIndex(
232
- (i) => i === newMaxUid,
233
- );
234
-
235
245
  renderPosition[0] = newMaxUid;
236
246
  renderPosition[newMaxUidOldPosition] = currentMaxUid;
237
247
 
@@ -254,10 +264,15 @@ const RtcConfigure = (props: {children: React.ReactNode}) => {
254
264
  let renderList: RenderStateInterface['renderList'] = {
255
265
  ...state.renderList,
256
266
  };
267
+ if (!(newMaxUid in renderList)) {
268
+ //skip the update if new max uid is not joined yet.
269
+ return {};
270
+ }
257
271
  // Element which is currently maximized
258
272
  const [currentMaxUid] = renderPosition;
259
273
 
260
274
  if (currentMaxUid === newMaxUid) {
275
+ //skip the update if new max uid is already maximized
261
276
  return {};
262
277
  }
263
278
 
@@ -38,6 +38,8 @@ export {
38
38
  default as useSendMessage,
39
39
  MESSAGE_TYPE,
40
40
  } from '../src/utils/useSendMessage';
41
+ export {default as useEditMessage} from '../src/utils/useEditMessage';
42
+ export {default as useDeleteMessage} from '../src/utils/useDeleteMessage';
41
43
  export {controlMessageEnum} from '../src/components/ChatContext';
42
44
  export {
43
45
  default as useSendControlMessage,
@@ -62,12 +62,14 @@
62
62
  "electron-updater": "4.3.9",
63
63
  "exponential-backoff": "3.1.0",
64
64
  "graphql": "15.5.0",
65
+ "nanoid": "4.0.0",
65
66
  "nosleep.js": "0.12.0",
66
67
  "react": "16.13.1",
67
68
  "react-dom": "16.13.1",
68
69
  "react-is": "18.0.0",
69
70
  "react-native": "0.63.3",
70
71
  "react-native-agora": "3.4.2",
72
+ "react-native-get-random-values": "1.8.0",
71
73
  "react-native-hyperlink": "0.0.19",
72
74
  "react-native-inappbrowser-reborn": "3.5.1",
73
75
  "react-native-keep-awake": "4.0.0",
@@ -16,18 +16,25 @@ import {createContext, SetStateAction} from 'react';
16
16
  export interface ChatBubbleProps {
17
17
  isLocal: boolean;
18
18
  message: string;
19
- timestamp: string;
19
+ createdTimestamp: string;
20
+ updatedTimestamp?: string;
20
21
  uid: UidType;
22
+ msgId: string;
23
+ isDeleted: boolean;
21
24
  render?: (
22
25
  isLocal: boolean,
23
26
  message: string,
24
- timestamp: string,
27
+ createdTimestamp: string,
25
28
  uid: UidType,
29
+ msgId: string,
30
+ isDeleted: boolean,
31
+ updatedTimestamp?: string,
26
32
  ) => JSX.Element;
27
33
  }
28
34
 
29
35
  export interface messageStoreInterface {
30
- ts: string;
36
+ createdTimestamp: string;
37
+ updatedTimestamp?: string;
31
38
  uid: UidType;
32
39
  msg: string;
33
40
  }
@@ -11,7 +11,7 @@
11
11
  */
12
12
  // @ts-nocheck
13
13
  import React, {useState, useContext, useEffect, useRef} from 'react';
14
- import RtmEngine, {RtmAttribute} from 'agora-react-native-rtm';
14
+ import RtmEngine from 'agora-react-native-rtm';
15
15
  import {PropsContext, useLocalUid} from '../../agora-rn-uikit';
16
16
  import ChatContext, {controlMessageEnum} from './ChatContext';
17
17
  import {RtcContext} from '../../agora-rn-uikit';
@@ -20,7 +20,6 @@ import {Platform} from 'react-native';
20
20
  import {backOff} from 'exponential-backoff';
21
21
  import {useString} from '../utils/useString';
22
22
  import {isAndroid, isWeb} from '../utils/common';
23
- import StorageContext from './StorageContext';
24
23
  import {useRenderContext} from 'fpe-api';
25
24
  import {
26
25
  safeJsonParse,
@@ -33,8 +32,6 @@ import {
33
32
  import {EventUtils, EventsQueue, eventMessageType} from '../rtm-events';
34
33
  import RTMEngine from '../rtm/RTMEngine';
35
34
  import {filterObject} from '../utils';
36
- import CustomEvents, {EventLevel} from '../custom-events';
37
- import {EventNames} from '../rtm-events';
38
35
  import useLocalScreenShareUid from '../utils/useLocalShareScreenUid';
39
36
 
40
37
  export enum UserType {
@@ -139,7 +136,9 @@ const RtmConfigure = (props: any) => {
139
136
  try {
140
137
  await engine.current.setLocalUserAttributes(rtmAttributes);
141
138
  timerValueRef.current = 5;
142
- joinChannel();
139
+ await joinChannel();
140
+ setHasUserJoinedRTM(true);
141
+ await runQueuedCustomEvents();
143
142
  } catch (error) {
144
143
  setTimeout(async () => {
145
144
  timerValueRef.current = timerValueRef.current + timerValueRef.current;
@@ -153,8 +152,6 @@ const RtmConfigure = (props: any) => {
153
152
  await engine.current.joinChannel(rtcProps.channel);
154
153
  timerValueRef.current = 5;
155
154
  await getMembers();
156
- setHasUserJoinedRTM(true);
157
- await runQueuedCustomEvents();
158
155
  } catch (error) {
159
156
  setTimeout(async () => {
160
157
  timerValueRef.current = timerValueRef.current + timerValueRef.current;
@@ -446,22 +443,12 @@ const RtmConfigure = (props: any) => {
446
443
 
447
444
  const runQueuedCustomEvents = async () => {
448
445
  try {
449
- const eventsInQueue = EventsQueue.printQueue();
450
- if (eventsInQueue.length !== 0) {
451
- for (const queuedEvents of eventsInQueue) {
452
- await customEventDispatcher(
453
- queuedEvents.data,
454
- queuedEvents.uid,
455
- queuedEvents.ts,
456
- );
457
- // EventsQueue.dequeue();
458
- }
446
+ while (!EventsQueue.isEmpty()) {
447
+ const currEvt = EventsQueue.dequeue();
448
+ await customEventDispatcher(currEvt.data, currEvt.uid, currEvt.ts);
459
449
  }
460
450
  } catch (error) {
461
- throw Error(
462
- 'CUSTOM_EVENTS_API: error while running queued events ',
463
- error,
464
- );
451
+ console.log('CUSTOM_EVENT_API: error while running queue events', error);
465
452
  }
466
453
  };
467
454
 
@@ -486,7 +473,7 @@ const RtmConfigure = (props: any) => {
486
473
  }
487
474
  // Step 2: Emit the event
488
475
  try {
489
- console.log('CUSTOM_EVENT_API: emiting event: ');
476
+ console.log('CUSTOM_EVENT_API: emiting event..: ');
490
477
  EventUtils.emitEvent(evt, {payload, sender, ts});
491
478
  } catch (error) {
492
479
  console.log('CUSTOM_EVENT_API: error while emiting event: ', error);
@@ -554,8 +541,9 @@ const RtmConfigure = (props: any) => {
554
541
 
555
542
  const end = async () => {
556
543
  callActive
557
- ? (await (engine.current as RtmEngine).logout(),
558
- await (engine.current as RtmEngine).destroyClient(),
544
+ ? (RTMEngine.getInstance().destroy(),
545
+ EventUtils.clear(),
546
+ setHasUserJoinedRTM(false),
559
547
  // setLogin(false),
560
548
  console.log('RTM cleanup done'))
561
549
  : {};
@@ -21,39 +21,66 @@ import {useChatNotification} from '../chat-notification/useChatNotification';
21
21
  import Toast from '../../../react-native-toast-message';
22
22
  import {timeNow} from '../../rtm/utils';
23
23
  import {useSidePanel} from '../../utils/useSidePanel';
24
+ import getUniqueID from '../../utils/getUniqueID';
25
+
26
+ enum ChatMessageActionEnum {
27
+ Create = 'Create_Chat_Message',
28
+ Update = 'Update_Chat_Message',
29
+ Delete = 'Delete_Chat_Message',
30
+ }
24
31
 
25
32
  interface ChatMessagesProviderProps {
26
33
  children: React.ReactNode;
27
34
  }
28
35
  interface messageInterface {
29
- ts: number;
36
+ createdTimestamp: number;
37
+ updatedTimestamp?: number;
30
38
  msg: string;
39
+ msgId: string;
40
+ isDeleted: boolean;
31
41
  }
32
42
  interface messageStoreInterface extends messageInterface {
33
43
  uid: UidType;
34
44
  }
35
45
 
36
46
  interface ChatMessagesInterface {
37
- messageStore: messageStoreInterface | any;
38
- privateMessageStore: any;
47
+ messageStore: messageStoreInterface[];
48
+ privateMessageStore: {[key: string]: messageStoreInterface[]};
39
49
  sendChatMessage: (msg: string, toUid?: UidType) => void;
50
+ editChatMessage: (msgId: string, msg: string, toUid?: UidType) => void;
51
+ deleteChatMessage: (msgId: string, toUid?: UidType) => void;
40
52
  }
41
53
 
42
54
  const ChatMessagesContext = React.createContext<ChatMessagesInterface>({
43
55
  messageStore: [],
44
56
  privateMessageStore: {},
45
57
  sendChatMessage: () => {},
58
+ editChatMessage: () => {},
59
+ deleteChatMessage: () => {},
46
60
  });
47
61
 
48
62
  const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
49
63
  const {renderList} = useRenderContext();
50
64
  const localUid = useLocalUid();
51
65
  const {setSidePanel} = useSidePanel();
52
- const {groupActive, selectedChatUserId, setGroupActive} = useChatUIControl();
53
- const {setUnreadGroupMessageCount, setUnreadIndividualMessageCount} =
54
- useChatNotification();
66
+ const {
67
+ groupActive,
68
+ selectedChatUserId,
69
+ setGroupActive,
70
+ setPrivateActive,
71
+ setSelectedChatUserId,
72
+ } = useChatUIControl();
73
+ const {
74
+ setUnreadGroupMessageCount,
75
+ setUnreadIndividualMessageCount,
76
+ unreadPrivateMessageCount,
77
+ unreadIndividualMessageCount,
78
+ setUnreadPrivateMessageCount,
79
+ } = useChatNotification();
55
80
  const [messageStore, setMessageStore] = useState<messageStoreInterface[]>([]);
56
- const [privateMessageStore, setPrivateMessageStore] = useState({});
81
+ const [privateMessageStore, setPrivateMessageStore] = useState<{
82
+ [key: string]: messageStoreInterface[];
83
+ }>({});
57
84
 
58
85
  const renderListRef = useRef({renderList: renderList});
59
86
  const groupActiveRef = useRef<boolean>();
@@ -75,70 +102,207 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
75
102
  }, [selectedChatUserId]);
76
103
 
77
104
  React.useEffect(() => {
78
- const showMessageNotification = (msg: string, uid: string) => {
105
+ const showMessageNotification = (
106
+ msg: string,
107
+ uid: string,
108
+ isPrivateMessage: boolean = false,
109
+ ) => {
110
+ const uidAsNumber = parseInt(uid);
79
111
  Toast.show({
80
112
  type: 'success',
81
113
  text1: msg.length > 30 ? msg.slice(0, 30) + '...' : msg,
82
- text2: renderListRef.current.renderList[parseInt(uid)]?.name
83
- ? fromText(renderListRef.current.renderList[parseInt(uid)]?.name)
114
+ text2: renderListRef.current.renderList[uidAsNumber]?.name
115
+ ? fromText(renderListRef.current.renderList[uidAsNumber]?.name)
84
116
  : '',
85
117
  visibilityTime: 1000,
86
118
  onPress: () => {
119
+ if (isPrivateMessage) {
120
+ setUnreadPrivateMessageCount(
121
+ unreadPrivateMessageCount -
122
+ (unreadIndividualMessageCount[uidAsNumber] || 0),
123
+ );
124
+ setUnreadIndividualMessageCount((prevState) => {
125
+ return {
126
+ ...prevState,
127
+ [uidAsNumber]: 0,
128
+ };
129
+ });
130
+ setGroupActive(false);
131
+ setSelectedChatUserId(uidAsNumber);
132
+ setPrivateActive(true);
133
+ } else {
134
+ setUnreadGroupMessageCount(0);
135
+ setPrivateActive(false);
136
+ setSelectedChatUserId(0);
137
+ setGroupActive(true);
138
+ }
87
139
  setSidePanel(SidePanelType.Chat);
88
- setUnreadGroupMessageCount(0);
89
- setGroupActive(true);
90
140
  },
91
141
  });
92
142
  };
93
143
  CustomEvents.on(EventNames.PUBLIC_CHAT_MESSAGE, (data) => {
94
- showMessageNotification(data.payload.value, data.sender);
95
- addMessageToStore(parseInt(data.sender), {
96
- msg: data.payload.value,
97
- ts: data.ts,
98
- });
99
- /**
100
- * if chat group window is not active.
101
- * then we will increment the unread count
102
- */
103
- if (!groupActiveRef.current) {
104
- setUnreadGroupMessageCount((prevState) => {
105
- return prevState + 1;
106
- });
144
+ const messageData = JSON.parse(data.payload.value);
145
+ switch (data?.payload?.action) {
146
+ case ChatMessageActionEnum.Create:
147
+ showMessageNotification(messageData.msg, data.sender);
148
+ addMessageToStore(parseInt(data.sender), {
149
+ msg: messageData.msg,
150
+ createdTimestamp: messageData.createdTimestamp,
151
+ isDeleted: messageData.isDeleted,
152
+ msgId: messageData.msgId,
153
+ });
154
+ /**
155
+ * if chat group window is not active.
156
+ * then we will increment the unread count
157
+ */
158
+ if (!groupActiveRef.current) {
159
+ setUnreadGroupMessageCount((prevState) => {
160
+ return prevState + 1;
161
+ });
162
+ }
163
+ break;
164
+ case ChatMessageActionEnum.Update:
165
+ setMessageStore((prevState) => {
166
+ const newState = prevState.map((item) => {
167
+ if (
168
+ item.msgId === messageData.msgId &&
169
+ item.uid === parseInt(data.sender)
170
+ ) {
171
+ return {
172
+ ...item,
173
+ msg: messageData.msg,
174
+ updatedTimestamp: messageData.updatedTimestamp,
175
+ };
176
+ } else {
177
+ return item;
178
+ }
179
+ });
180
+ return newState;
181
+ });
182
+ break;
183
+ case ChatMessageActionEnum.Delete:
184
+ setMessageStore((prevState) => {
185
+ const newState = prevState.map((item) => {
186
+ if (
187
+ item.msgId === messageData.msgId &&
188
+ item.uid === parseInt(data.sender)
189
+ ) {
190
+ return {
191
+ ...item,
192
+ isDeleted: true,
193
+ updatedTimestamp: messageData.updatedTimestamp,
194
+ };
195
+ } else {
196
+ return item;
197
+ }
198
+ });
199
+ return newState;
200
+ });
201
+ break;
202
+ default:
203
+ break;
107
204
  }
108
205
  });
109
206
  CustomEvents.on(EventNames.PRIVATE_CHAT_MESSAGE, (data) => {
110
- showMessageNotification(data.payload.value, data.sender);
111
- addMessageToPrivateStore(
112
- parseInt(data.sender),
113
- {
114
- msg: data.payload.value,
115
- ts: data.ts,
116
- },
117
- false,
118
- );
119
- /**
120
- * if user's private window is active.
121
- * then we will not increment the unread count
122
- */
123
-
124
- if (!(individualActiveRef.current === parseInt(data.sender))) {
125
- setUnreadIndividualMessageCount((prevState) => {
126
- const prevCount =
127
- prevState && prevState[parseInt(data.sender)]
128
- ? prevState[parseInt(data.sender)]
129
- : 0;
130
- return {
131
- ...prevState,
132
- [parseInt(data.sender)]: prevCount + 1,
133
- };
134
- });
207
+ const messageData = JSON.parse(data.payload.value);
208
+
209
+ switch (data?.payload?.action) {
210
+ case ChatMessageActionEnum.Create:
211
+ showMessageNotification(messageData.msg, data.sender, true);
212
+ addMessageToPrivateStore(
213
+ parseInt(data.sender),
214
+ {
215
+ msg: messageData.msg,
216
+ createdTimestamp: messageData.createdTimestamp,
217
+ msgId: messageData.msgId,
218
+ isDeleted: messageData.isDeleted,
219
+ },
220
+ false,
221
+ );
222
+ /**
223
+ * if user's private window is active.
224
+ * then we will not increment the unread count
225
+ */
226
+
227
+ if (!(individualActiveRef.current === parseInt(data.sender))) {
228
+ setUnreadIndividualMessageCount((prevState) => {
229
+ const prevCount =
230
+ prevState && prevState[parseInt(data.sender)]
231
+ ? prevState[parseInt(data.sender)]
232
+ : 0;
233
+ return {
234
+ ...prevState,
235
+ [parseInt(data.sender)]: prevCount + 1,
236
+ };
237
+ });
238
+ }
239
+ break;
240
+ case ChatMessageActionEnum.Update:
241
+ setPrivateMessageStore((prevState) => {
242
+ const privateChatOfUid = prevState[parseInt(data.sender)];
243
+ const updatedData = privateChatOfUid.map((item) => {
244
+ if (
245
+ item.msgId === messageData.msgId &&
246
+ item.uid === parseInt(data.sender)
247
+ ) {
248
+ return {
249
+ ...item,
250
+ msg: messageData.msg,
251
+ updatedTimestamp: messageData.updatedTimestamp,
252
+ };
253
+ } else {
254
+ return item;
255
+ }
256
+ });
257
+ const newState = {
258
+ ...prevState,
259
+ [parseInt(data.sender)]: updatedData,
260
+ };
261
+ return newState;
262
+ });
263
+ break;
264
+ case ChatMessageActionEnum.Delete:
265
+ setPrivateMessageStore((prevState) => {
266
+ const privateChatOfUid = prevState[parseInt(data.sender)];
267
+ const updatedData = privateChatOfUid.map((item) => {
268
+ if (
269
+ item.msgId === messageData.msgId &&
270
+ item.uid === parseInt(data.sender)
271
+ ) {
272
+ return {
273
+ ...item,
274
+ isDeleted: true,
275
+ updatedTimestamp: messageData.updatedTimestamp,
276
+ };
277
+ } else {
278
+ return item;
279
+ }
280
+ });
281
+ const newState = {
282
+ ...prevState,
283
+ [parseInt(data.sender)]: updatedData,
284
+ };
285
+ return newState;
286
+ });
287
+ break;
288
+ default:
289
+ break;
135
290
  }
136
291
  });
137
292
  }, []);
138
293
 
139
294
  const addMessageToStore = (uid: UidType, body: messageInterface) => {
140
295
  setMessageStore((m: messageStoreInterface[]) => {
141
- return [...m, {ts: body.ts, uid, msg: body.msg}];
296
+ return [
297
+ ...m,
298
+ {
299
+ createdTimestamp: body.createdTimestamp,
300
+ uid,
301
+ msg: body.msg,
302
+ msgId: body.msgId,
303
+ isDeleted: body.isDeleted,
304
+ },
305
+ ];
142
306
  });
143
307
  };
144
308
 
@@ -147,16 +311,30 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
147
311
  body: messageInterface,
148
312
  local: boolean,
149
313
  ) => {
150
- setPrivateMessageStore((state: any) => {
314
+ setPrivateMessageStore((state) => {
151
315
  let newState = {...state};
152
316
  newState[uid] !== undefined
153
317
  ? (newState[uid] = [
154
318
  ...newState[uid],
155
- {ts: body.ts, uid: local ? localUid : uid, msg: body.msg},
319
+ {
320
+ createdTimestamp: body.createdTimestamp,
321
+ uid: local ? localUid : uid,
322
+ msg: body.msg,
323
+ msgId: body.msgId,
324
+ isDeleted: body.isDeleted,
325
+ },
156
326
  ])
157
327
  : (newState = {
158
328
  ...newState,
159
- [uid]: [{ts: body.ts, uid: local ? localUid : uid, msg: body.msg}],
329
+ [uid]: [
330
+ {
331
+ createdTimestamp: body.createdTimestamp,
332
+ uid: local ? localUid : uid,
333
+ msg: body.msg,
334
+ msgId: body.msgId,
335
+ isDeleted: body.isDeleted,
336
+ },
337
+ ],
160
338
  });
161
339
  return {...newState};
162
340
  });
@@ -165,29 +343,148 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
165
343
  const sendChatMessage = (msg: string, toUid?: UidType) => {
166
344
  if (typeof msg == 'string' && msg.trim() === '') return;
167
345
  if (toUid) {
346
+ const messageData = {
347
+ msg,
348
+ createdTimestamp: timeNow(),
349
+ msgId: getUniqueID(),
350
+ isDeleted: false,
351
+ };
168
352
  CustomEvents.send(
169
353
  EventNames.PRIVATE_CHAT_MESSAGE,
170
354
  {
171
- value: msg,
355
+ value: JSON.stringify(messageData),
356
+ action: ChatMessageActionEnum.Create,
172
357
  },
173
358
  toUid,
174
359
  );
175
- addMessageToPrivateStore(
176
- toUid,
177
- {
178
- msg: msg,
179
- ts: timeNow(),
180
- },
181
- true,
182
- );
360
+ addMessageToPrivateStore(toUid, messageData, true);
183
361
  } else {
362
+ const messageData = {
363
+ msg,
364
+ msgId: getUniqueID(),
365
+ isDeleted: false,
366
+ createdTimestamp: timeNow(),
367
+ };
184
368
  CustomEvents.send(EventNames.PUBLIC_CHAT_MESSAGE, {
185
- value: msg,
186
- });
187
- addMessageToStore(localUid, {
188
- msg: msg,
189
- ts: timeNow(),
369
+ value: JSON.stringify(messageData),
370
+ action: ChatMessageActionEnum.Create,
190
371
  });
372
+ addMessageToStore(localUid, messageData);
373
+ }
374
+ };
375
+
376
+ const editChatMessage = (msgId: string, msg: string, toUid?: UidType) => {
377
+ if (typeof msg == 'string' && msg.trim() === '') return;
378
+ if (toUid) {
379
+ const checkData = privateMessageStore[toUid].filter(
380
+ (item) => item.msgId === msgId && item.uid === localUid,
381
+ );
382
+ if (checkData && checkData.length) {
383
+ const editMsgData = {msg, updatedTimestamp: timeNow()};
384
+ CustomEvents.send(
385
+ EventNames.PRIVATE_CHAT_MESSAGE,
386
+ {
387
+ value: JSON.stringify({msgId, ...editMsgData}),
388
+ action: ChatMessageActionEnum.Update,
389
+ },
390
+ toUid,
391
+ );
392
+ setPrivateMessageStore((prevState) => {
393
+ const privateChatOfUid = prevState[toUid];
394
+ const updatedData = privateChatOfUid.map((item) => {
395
+ if (item.msgId === msgId) {
396
+ return {...item, ...editMsgData};
397
+ } else {
398
+ return item;
399
+ }
400
+ });
401
+ const newState = {...prevState, [toUid]: updatedData};
402
+ return newState;
403
+ });
404
+ } else {
405
+ console.log("You don't have permission to edit");
406
+ }
407
+ } else {
408
+ //check if user has permission to edit
409
+ const checkData = messageStore.filter(
410
+ (item) => item.msgId === msgId && item.uid === localUid,
411
+ );
412
+ if (checkData && checkData.length) {
413
+ const editMsgData = {msg, updatedTimestamp: timeNow()};
414
+ CustomEvents.send(EventNames.PUBLIC_CHAT_MESSAGE, {
415
+ value: JSON.stringify({msgId, ...editMsgData}),
416
+ action: ChatMessageActionEnum.Update,
417
+ });
418
+ setMessageStore((prevState) => {
419
+ const newState = prevState.map((item) => {
420
+ if (item.msgId === msgId) {
421
+ return {...item, ...editMsgData};
422
+ } else {
423
+ return item;
424
+ }
425
+ });
426
+ return newState;
427
+ });
428
+ } else {
429
+ console.log("You don't have permission to edit");
430
+ }
431
+ }
432
+ };
433
+
434
+ const deleteChatMessage = (msgId: string, toUid?: UidType) => {
435
+ if (toUid) {
436
+ const checkData = privateMessageStore[toUid].filter(
437
+ (item) => item.msgId === msgId && item.uid === localUid,
438
+ );
439
+ if (checkData && checkData.length) {
440
+ const deleteMsgData = {updatedTimestamp: timeNow()};
441
+ CustomEvents.send(
442
+ EventNames.PRIVATE_CHAT_MESSAGE,
443
+ {
444
+ value: JSON.stringify({msgId, ...deleteMsgData}),
445
+ action: ChatMessageActionEnum.Delete,
446
+ },
447
+ toUid,
448
+ );
449
+ setPrivateMessageStore((prevState) => {
450
+ const privateChatOfUid = prevState[toUid];
451
+ const updatedData = privateChatOfUid.map((item) => {
452
+ if (item.msgId === msgId) {
453
+ return {...item, isDeleted: true, ...deleteMsgData};
454
+ } else {
455
+ return item;
456
+ }
457
+ });
458
+ const newState = {...prevState, [toUid]: updatedData};
459
+ return newState;
460
+ });
461
+ } else {
462
+ console.log("You don't have permission to delete");
463
+ }
464
+ } else {
465
+ //check if user has permission to delete
466
+ const checkData = messageStore.filter(
467
+ (item) => item.msgId === msgId && item.uid === localUid,
468
+ );
469
+ if (checkData && checkData.length) {
470
+ const deleteMsgData = {updatedTimestamp: timeNow()};
471
+ CustomEvents.send(EventNames.PUBLIC_CHAT_MESSAGE, {
472
+ value: JSON.stringify({msgId, ...deleteMsgData}),
473
+ action: ChatMessageActionEnum.Delete,
474
+ });
475
+ setMessageStore((prevState) => {
476
+ const newState = prevState.map((item) => {
477
+ if (item.msgId === msgId) {
478
+ return {...item, isDeleted: true, ...deleteMsgData};
479
+ } else {
480
+ return item;
481
+ }
482
+ });
483
+ return newState;
484
+ });
485
+ } else {
486
+ console.log("You don't have permission to delete");
487
+ }
191
488
  }
192
489
  };
193
490
 
@@ -197,6 +494,8 @@ const ChatMessagesProvider = (props: ChatMessagesProviderProps) => {
197
494
  messageStore,
198
495
  privateMessageStore,
199
496
  sendChatMessage,
497
+ editChatMessage,
498
+ deleteChatMessage,
200
499
  }}>
201
500
  {props.children}
202
501
  </ChatMessagesContext.Provider>
@@ -201,12 +201,12 @@ const VideoCall: React.FC = () => {
201
201
  <DeviceConfigure>
202
202
  <ChatUIControlProvider>
203
203
  <ChatNotificationProvider>
204
- <ChatMessagesProvider>
205
- <SidePanelProvider
206
- value={{
207
- sidePanel,
208
- setSidePanel,
209
- }}>
204
+ <SidePanelProvider
205
+ value={{
206
+ sidePanel,
207
+ setSidePanel,
208
+ }}>
209
+ <ChatMessagesProvider>
210
210
  <ScreenShareProvider>
211
211
  <RtmConfigure
212
212
  setRecordingActive={setRecordingActive}
@@ -260,8 +260,8 @@ const VideoCall: React.FC = () => {
260
260
  </UserPreferenceProvider>
261
261
  </RtmConfigure>
262
262
  </ScreenShareProvider>
263
- </SidePanelProvider>
264
- </ChatMessagesProvider>
263
+ </ChatMessagesProvider>
264
+ </SidePanelProvider>
265
265
  </ChatNotificationProvider>
266
266
  </ChatUIControlProvider>
267
267
  </DeviceConfigure>
@@ -95,14 +95,13 @@ const VideoCallScreen = () => {
95
95
  components.BottombarComponent = data?.components?.videoCall.bottomBar;
96
96
  }
97
97
 
98
- // commented for v1 release
99
- // if (
100
- // data?.components?.videoCall.topBar &&
101
- // typeof data?.components?.videoCall.topBar !== 'object' &&
102
- // isValidReactComponent(data?.components?.videoCall.topBar)
103
- // ) {
104
- // components.TopbarComponent = data?.components?.videoCall.topBar;
105
- // }
98
+ if (
99
+ data?.components?.videoCall.topBar &&
100
+ typeof data?.components?.videoCall.topBar !== 'object' &&
101
+ isValidReactComponent(data?.components?.videoCall.topBar)
102
+ ) {
103
+ components.TopbarComponent = data?.components?.videoCall.topBar;
104
+ }
106
105
 
107
106
  if (
108
107
  data?.components?.videoCall.participantsPanel &&
@@ -30,6 +30,11 @@ class RTMEngine {
30
30
  await this.engine.createClient($config.APP_ID);
31
31
  }
32
32
 
33
+ private async destroyClientInstance() {
34
+ await this.engine.logout();
35
+ await this.engine.destroyClient();
36
+ }
37
+
33
38
  private constructor() {
34
39
  if (RTMEngine._instance) {
35
40
  return RTMEngine._instance;
@@ -53,6 +58,14 @@ class RTMEngine {
53
58
  get channelUid() {
54
59
  return this.channelId;
55
60
  }
61
+ destroy() {
62
+ try {
63
+ this.destroyClientInstance();
64
+ RTMEngine._instance = null;
65
+ } catch (error) {
66
+ console.log('Error destroying instance error: ', error);
67
+ }
68
+ }
56
69
  }
57
70
 
58
71
  export default RTMEngine;
@@ -245,6 +245,9 @@ const EventUtils = (function () {
245
245
  }
246
246
  return this;
247
247
  },
248
+ clear() {
249
+ _events = {};
250
+ },
248
251
  // 1. To add multiple listeners
249
252
  // addListeners(evt: string, listeners: any) {
250
253
  // if (Array.isArray(listeners)) {
@@ -27,10 +27,16 @@ const EventsQueue = (function () {
27
27
  },
28
28
  dequeue() {
29
29
  if (_eventsQueue.length == 0) return;
30
- _eventsQueue.shift();
30
+ return _eventsQueue.pop();
31
31
  },
32
- printQueue() {
33
- return _eventsQueue;
32
+ isEmpty() {
33
+ return _eventsQueue.length === 0;
34
+ },
35
+ size() {
36
+ return _eventsQueue.length;
37
+ },
38
+ clear() {
39
+ _eventsQueue = [];
34
40
  },
35
41
  };
36
42
  })();
@@ -21,11 +21,19 @@ import useUserList from '../utils/useUserList';
21
21
  const ChatBubble = (props: ChatBubbleProps) => {
22
22
  const {renderList} = useUserList();
23
23
  const {primaryColor} = useContext(ColorContext);
24
- let {isLocal, message, timestamp, uid} = props;
24
+ let {
25
+ isLocal,
26
+ message,
27
+ createdTimestamp,
28
+ uid,
29
+ isDeleted,
30
+ msgId,
31
+ updatedTimestamp,
32
+ } = props;
25
33
  let time =
26
- new Date(parseInt(timestamp)).getHours() +
34
+ new Date(parseInt(createdTimestamp)).getHours() +
27
35
  ':' +
28
- new Date(parseInt(timestamp)).getMinutes();
36
+ new Date(parseInt(createdTimestamp)).getMinutes();
29
37
  const handleUrl = (url: string) => {
30
38
  if (isWeb) {
31
39
  window.open(url, '_blank');
@@ -37,7 +45,15 @@ const ChatBubble = (props: ChatBubbleProps) => {
37
45
  //const remoteUserDefaultLabel = useString('remoteUserDefaultLabel')();
38
46
  const remoteUserDefaultLabel = 'User';
39
47
  return props?.render ? (
40
- props.render(isLocal, message, timestamp, uid)
48
+ props.render(
49
+ isLocal,
50
+ message,
51
+ createdTimestamp,
52
+ uid,
53
+ msgId,
54
+ isDeleted,
55
+ updatedTimestamp,
56
+ )
41
57
  ) : (
42
58
  <View>
43
59
  <View style={isLocal ? style.chatSenderViewLocal : style.chatSenderView}>
@@ -129,9 +129,12 @@ const ChatContainer = (props?: {
129
129
  <ChatBubbleComponent
130
130
  isLocal={localUid === message.uid}
131
131
  message={message.msg}
132
- timestamp={message.ts}
132
+ createdTimestamp={message.createdTimestamp}
133
+ updatedTimestamp={message.updatedTimestamp}
133
134
  uid={message.uid}
134
135
  key={message.ts}
136
+ msgId={message.msgId}
137
+ isDeleted={message.isDeleted}
135
138
  />
136
139
  </>
137
140
  ))
@@ -140,9 +143,12 @@ const ChatContainer = (props?: {
140
143
  <ChatBubbleComponent
141
144
  isLocal={localUid === message.uid}
142
145
  message={message.msg}
143
- timestamp={message.ts}
146
+ createdTimestamp={message.createdTimestamp}
147
+ updatedTimestamp={message.updatedTimestamp}
144
148
  uid={message.uid}
145
149
  key={message.ts}
150
+ msgId={message.msgId}
151
+ isDeleted={message.isDeleted}
146
152
  />
147
153
  ))
148
154
  ) : (
@@ -91,7 +91,7 @@ const RecordingProvider = (props: RecordingProviderProps) => {
91
91
  //const recordingStartedText = useString<boolean>('recordingNotificationLabel');
92
92
  const recordingStartedText = (active: boolean) =>
93
93
  active ? 'Recording Started' : 'Recording Stopped';
94
- const {executePresenterQuery} = useRecordingLayoutQuery();
94
+ const {executePresenterQuery, executeNormalQuery} = useRecordingLayoutQuery();
95
95
  const {localUid} = useContext(ChatContext);
96
96
  const {screenShareData} = useScreenContext();
97
97
 
@@ -156,9 +156,14 @@ const RecordingProvider = (props: RecordingProviderProps) => {
156
156
  // 2. set the local recording state to true to update the UI
157
157
  setRecordingActive(true);
158
158
  // 3. set the presenter mode if screen share is active
159
- if (Object.values(screenShareData).some((item) => item.isActive)) {
160
- console.log('Executing presenter query');
161
- executePresenterQuery();
159
+ const activeScreenshareUid = Object.keys(screenShareData).find(
160
+ (key) => screenShareData[key]?.isActive,
161
+ );
162
+ if (activeScreenshareUid) {
163
+ console.log('screenshare: Executing presenter query');
164
+ executePresenterQuery(parseInt(activeScreenshareUid));
165
+ } else {
166
+ executeNormalQuery();
162
167
  }
163
168
  }
164
169
  })
@@ -1,8 +1,8 @@
1
- import React, {useContext} from 'react';
1
+ import React from 'react';
2
2
  import {useParams} from '../../components/Router';
3
3
 
4
4
  import {gql, useMutation} from '@apollo/client';
5
- import {PropsContext} from '../../../agora-rn-uikit';
5
+ import {UidType} from '../../../agora-rn-uikit';
6
6
 
7
7
  const SET_PRESENTER = gql`
8
8
  mutation setPresenter($uid: Int!, $passphrase: String!) {
@@ -19,10 +19,9 @@ const SET_NORMAL = gql`
19
19
  function useRecordingLayoutQuery() {
20
20
  const [setPresenterQuery] = useMutation(SET_PRESENTER);
21
21
  const [setNormalQuery] = useMutation(SET_NORMAL);
22
- const {screenShareUid} = useContext(PropsContext).rtcProps;
23
22
  const {phrase} = useParams<any>();
24
23
 
25
- const executePresenterQuery = () => {
24
+ const executePresenterQuery = (screenShareUid: UidType) => {
26
25
  setPresenterQuery({
27
26
  variables: {
28
27
  uid: screenShareUid,
@@ -99,9 +99,10 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
99
99
  }, []);
100
100
 
101
101
  const executeRecordingQuery = (isScreenActive: boolean) => {
102
- if (!isScreenActive) {
102
+ if (isScreenActive) {
103
+ console.log('screenshare: Executing presenter query');
103
104
  // If screen share is not going on, start the screen share by executing the graphql query
104
- executePresenterQuery();
105
+ executePresenterQuery(screenShareUid);
105
106
  } else {
106
107
  // If recording is already going on, stop the recording by executing the graphql query.
107
108
  executeNormalQuery();
@@ -134,16 +135,28 @@ export const ScreenshareConfigure = (props: {children: React.ReactNode}) => {
134
135
  encryption as unknown as any,
135
136
  );
136
137
  isActive && setScreenshareActive(true);
138
+
137
139
  if (isActive) {
140
+ // 1. Set local state
141
+ setScreenShareData((prevState) => {
142
+ return {
143
+ ...prevState,
144
+ [screenShareUid]: {
145
+ name: renderListRef.current.renderList[screenShareUid]?.name,
146
+ isActive: true,
147
+ },
148
+ };
149
+ });
150
+ // 2. Inform everyone in the channel screenshare is actice
138
151
  CustomEvents.send(EventNames.SCREENSHARE_ATTRIBUTE, {
139
152
  value: `${true}`,
140
153
  level: EventLevel.LEVEL2,
141
154
  });
142
- //if local user started the screenshare then change layout to pinned
155
+ //3 . if local user started the screenshare then change layout to pinned
143
156
  triggerChangeLayout(true, screenShareUid);
144
157
  }
145
158
  } catch (e) {
146
- console.error("supriya an't start the screen share", e);
159
+ console.error("can't start the screen share", e);
147
160
  executeNormalQuery();
148
161
  }
149
162
  };
@@ -0,0 +1,6 @@
1
+ import 'react-native-get-random-values';
2
+ import {nanoid} from 'nanoid';
3
+
4
+ export default function getUniqueID() {
5
+ return nanoid();
6
+ }
@@ -0,0 +1,5 @@
1
+ import {nanoid} from 'nanoid';
2
+
3
+ export default function getUniqueID() {
4
+ return nanoid();
5
+ }
@@ -0,0 +1,36 @@
1
+ /*
2
+ ********************************************
3
+ Copyright © 2021 Agora Lab, Inc., all rights reserved.
4
+ AppBuilder and all associated components, source code, APIs, services, and documentation
5
+ (the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
6
+ accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
7
+ Use without a license or in violation of any license terms and conditions (including use for
8
+ any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
9
+ information visit https://appbuilder.agora.io.
10
+ *********************************************
11
+ */
12
+ import {UidType} from '../../agora-rn-uikit';
13
+ import {useChatMessages} from '../components/chat-messages/useChatMessages';
14
+ import {MESSAGE_TYPE} from './useSendMessage';
15
+
16
+ function useDeleteMessage() {
17
+ const {deleteChatMessage} = useChatMessages();
18
+ return (type: MESSAGE_TYPE, msgId: string, uid?: UidType) => {
19
+ switch (type) {
20
+ case MESSAGE_TYPE.group:
21
+ deleteChatMessage(msgId);
22
+ break;
23
+ case MESSAGE_TYPE.private:
24
+ if (uid) {
25
+ deleteChatMessage(msgId, uid);
26
+ } else {
27
+ console.error('To delete the private message, UID should be passed');
28
+ }
29
+ break;
30
+ default:
31
+ break;
32
+ }
33
+ };
34
+ }
35
+
36
+ export default useDeleteMessage;
@@ -0,0 +1,41 @@
1
+ /*
2
+ ********************************************
3
+ Copyright © 2021 Agora Lab, Inc., all rights reserved.
4
+ AppBuilder and all associated components, source code, APIs, services, and documentation
5
+ (the “Materials”) are owned by Agora Lab, Inc. and its licensors. The Materials may not be
6
+ accessed, used, modified, or distributed for any purpose without a license from Agora Lab, Inc.
7
+ Use without a license or in violation of any license terms and conditions (including use for
8
+ any purpose competitive to Agora Lab, Inc.’s business) is strictly prohibited. For more
9
+ information visit https://appbuilder.agora.io.
10
+ *********************************************
11
+ */
12
+ import {UidType} from '../../agora-rn-uikit';
13
+ import {useChatMessages} from '../components/chat-messages/useChatMessages';
14
+ import {MESSAGE_TYPE} from './useSendMessage';
15
+
16
+ function useEditMessage() {
17
+ const {editChatMessage} = useChatMessages();
18
+ return (
19
+ type: MESSAGE_TYPE,
20
+ msgId: string,
21
+ message: string,
22
+ uid?: UidType,
23
+ ) => {
24
+ switch (type) {
25
+ case MESSAGE_TYPE.group:
26
+ editChatMessage(msgId, message);
27
+ break;
28
+ case MESSAGE_TYPE.private:
29
+ if (uid) {
30
+ editChatMessage(msgId, message, uid);
31
+ } else {
32
+ console.error('To edit the private message, UID should be passed');
33
+ }
34
+ break;
35
+ default:
36
+ break;
37
+ }
38
+ };
39
+ }
40
+
41
+ export default useEditMessage;
@@ -9,24 +9,23 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import {useContext} from 'react';
13
- import ChatContext from '../components/ChatContext';
14
12
  import {UidType} from '../../agora-rn-uikit';
13
+ import {useChatMessages} from '../components/chat-messages/useChatMessages';
15
14
 
16
15
  export enum MESSAGE_TYPE {
17
16
  group,
18
17
  private,
19
18
  }
20
19
  function useSendMessage() {
21
- const {sendMessage, sendMessageToUid} = useContext(ChatContext);
20
+ const {sendChatMessage} = useChatMessages();
22
21
  return (type: MESSAGE_TYPE, message: string, uid?: UidType) => {
23
22
  switch (type) {
24
23
  case MESSAGE_TYPE.group:
25
- sendMessage(message);
24
+ sendChatMessage(message);
26
25
  break;
27
26
  case MESSAGE_TYPE.private:
28
27
  if (uid) {
29
- sendMessageToUid(message, uid);
28
+ sendChatMessage(message, uid);
30
29
  } else {
31
30
  console.error('To send the private message, UID should be passed');
32
31
  }