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 +1 -1
- package/template/_package-lock.json +47 -0
- package/template/agora-rn-uikit/src/Reducer/UserJoined.ts +3 -1
- package/template/agora-rn-uikit/src/RtcConfigure.tsx +19 -4
- package/template/fpe-api/utils.ts +2 -0
- package/template/package.json +2 -0
- package/template/src/components/ChatContext.ts +10 -3
- package/template/src/components/RTMConfigure.tsx +12 -24
- package/template/src/components/chat-messages/useChatMessages.tsx +367 -68
- package/template/src/pages/VideoCall.tsx +8 -8
- package/template/src/pages/video-call/VideoCallScreen.tsx +7 -8
- package/template/src/rtm/RTMEngine.ts +13 -0
- package/template/src/rtm-events/EventUtils.ts +3 -0
- package/template/src/rtm-events/EventsQueue.ts +9 -3
- package/template/src/subComponents/ChatBubble.tsx +20 -4
- package/template/src/subComponents/ChatContainer.tsx +8 -2
- package/template/src/subComponents/recording/useRecording.tsx +9 -4
- package/template/src/subComponents/recording/useRecordingLayoutQuery.tsx +3 -4
- package/template/src/subComponents/screenshare/ScreenshareConfigure.tsx +17 -4
- package/template/src/utils/getUniqueID.native.ts +6 -0
- package/template/src/utils/getUniqueID.ts +5 -0
- package/template/src/utils/useDeleteMessage.ts +36 -0
- package/template/src/utils/useEditMessage.ts +41 -0
- package/template/src/utils/useSendMessage.ts +4 -5
package/package.json
CHANGED
|
@@ -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 =
|
|
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,
|
package/template/package.json
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
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
|
-
? (
|
|
558
|
-
|
|
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
|
-
|
|
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
|
|
38
|
-
privateMessageStore:
|
|
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 {
|
|
53
|
-
|
|
54
|
-
|
|
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 = (
|
|
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[
|
|
83
|
-
? fromText(renderListRef.current.renderList[
|
|
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
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
msg
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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 [
|
|
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
|
|
314
|
+
setPrivateMessageStore((state) => {
|
|
151
315
|
let newState = {...state};
|
|
152
316
|
newState[uid] !== undefined
|
|
153
317
|
? (newState[uid] = [
|
|
154
318
|
...newState[uid],
|
|
155
|
-
{
|
|
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]: [
|
|
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:
|
|
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:
|
|
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
|
-
<
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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
|
-
</
|
|
264
|
-
</
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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;
|
|
@@ -27,10 +27,16 @@ const EventsQueue = (function () {
|
|
|
27
27
|
},
|
|
28
28
|
dequeue() {
|
|
29
29
|
if (_eventsQueue.length == 0) return;
|
|
30
|
-
_eventsQueue.
|
|
30
|
+
return _eventsQueue.pop();
|
|
31
31
|
},
|
|
32
|
-
|
|
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 {
|
|
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(
|
|
34
|
+
new Date(parseInt(createdTimestamp)).getHours() +
|
|
27
35
|
':' +
|
|
28
|
-
new Date(parseInt(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import {useParams} from '../../components/Router';
|
|
3
3
|
|
|
4
4
|
import {gql, useMutation} from '@apollo/client';
|
|
5
|
-
import {
|
|
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 (
|
|
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("
|
|
159
|
+
console.error("can't start the screen share", e);
|
|
147
160
|
executeNormalQuery();
|
|
148
161
|
}
|
|
149
162
|
};
|
|
@@ -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 {
|
|
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
|
-
|
|
24
|
+
sendChatMessage(message);
|
|
26
25
|
break;
|
|
27
26
|
case MESSAGE_TYPE.private:
|
|
28
27
|
if (uid) {
|
|
29
|
-
|
|
28
|
+
sendChatMessage(message, uid);
|
|
30
29
|
} else {
|
|
31
30
|
console.error('To send the private message, UID should be passed');
|
|
32
31
|
}
|