agora-appbuilder-core 4.0.0-beta.11 → 4.0.0-beta.13

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": "4.0.0-beta.11",
3
+ "version": "4.0.0-beta.13",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -9,25 +9,43 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React, { useContext } from 'react';
12
+ import React, {useContext} from 'react';
13
13
  /**
14
- *
14
+ *
15
15
  * @param context - any context data which we want to extract the data.
16
16
  * @returns useContextWithSelector in which we can pass selector function to extract data from the context that we passed.
17
17
  */
18
18
  function createHook<T>(context: React.Context<T>) {
19
-
20
19
  function useContextWithSelector<U>(contextSelector: (data: T) => U): U;
21
20
  function useContextWithSelector(): T;
22
21
  /**
23
- *
22
+ *
24
23
  * @param contextSelector is used to pass callback function used to select data from the context data
25
24
  * @returns the data selected from the context
26
25
  */
27
26
  function useContextWithSelector<U>(contextSelector?: (data: T) => U): U | T {
28
27
  const data = useContext(context);
29
- return contextSelector ? contextSelector(data) : data
28
+ return contextSelector ? contextSelector(data) : data;
30
29
  }
31
30
  return useContextWithSelector;
32
31
  }
33
- export default createHook;
32
+
33
+ export function createConcealedHook<T, V>(
34
+ context: React.Context<T>,
35
+ preselect: (data: T) => V,
36
+ ) {
37
+ function useContextWithSelector<U>(contextSelector: (data: V) => U): U;
38
+ function useContextWithSelector(): V;
39
+ /**
40
+ *
41
+ * @param contextSelector is used to pass callback function used to select data from the context data
42
+ * @returns the data selected from the context
43
+ */
44
+ function useContextWithSelector<U>(contextSelector?: (data: V) => U): U | V {
45
+ const data = useContext(context);
46
+ return contextSelector ? contextSelector(preselect(data)) : preselect(data);
47
+ }
48
+ return useContextWithSelector;
49
+ }
50
+
51
+ export default createHook;
@@ -1,4 +1,4 @@
1
- export {default as createHook} from './createHook';
1
+ export {default as createHook, createConcealedHook} from './createHook';
2
2
  export {CustomizationProvider, useCustomization} from './useCustomization';
3
3
  export type {CustomizationProviderProps} from './useCustomization';
4
4
  export {default as customizationConfig} from 'customization';
@@ -9,22 +9,20 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React from 'react';
12
+ import React, {useContext} from 'react';
13
13
  import {CustomizationApiInterface} from 'customization-api';
14
14
  import customizationConfig from 'customization';
15
15
  import createHook from './createHook';
16
+ import {SdkApiContext} from '../src/components/SdkApiContext';
16
17
 
17
18
  const CustomizationContext: React.Context<CustomizationApiInterface> =
18
19
  React.createContext(customizationConfig);
19
20
 
20
- export interface CustomizationProviderProps {
21
- children: React.ReactNode;
22
- value: CustomizationApiInterface;
23
- }
21
+ const CustomizationProvider: React.FC = (props) => {
22
+ const {customize: userCustomization} = useContext(SdkApiContext);
24
23
 
25
- const CustomizationProvider = (props: CustomizationProviderProps) => {
26
24
  return (
27
- <CustomizationContext.Provider value={props.value}>
25
+ <CustomizationContext.Provider value={userCustomization.customization}>
28
26
  {props.children}
29
27
  </CustomizationContext.Provider>
30
28
  );
@@ -12,12 +12,19 @@ export * from 'customization-implementation';
12
12
 
13
13
  interface AppBuilderWebSdkInterface extends AppBuilderSdkApiInterface {}
14
14
 
15
+ const clearEvent = {
16
+ clear: () => {},
17
+ };
18
+
15
19
  const AppBuilderWebSdkApi: AppBuilderWebSdkInterface = {
16
20
  ...AppBuilderSdkApi,
17
21
  // Override customize function for web-sdk
18
22
  customize: (customization) => {
19
- SDKEvents.on('addFpeInit', () => {
23
+ SDKEvents.emit('addFpe', customization);
24
+ clearEvent.clear = SDKEvents.on('addFpeInit', () => {
25
+ console.log('addFpeInit called');
20
26
  SDKEvents.emit('addFpe', customization);
27
+ clearEvent.clear();
21
28
  });
22
29
  },
23
30
  };
@@ -9,7 +9,7 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React, {useState} from 'react';
12
+ import React, {useState, useContext} from 'react';
13
13
  import {Platform} from 'react-native';
14
14
  import Join from './pages/Join';
15
15
  import VideoCall from './pages/VideoCall';
@@ -9,7 +9,7 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React from 'react';
12
+ import React, {useContext} from 'react';
13
13
  import {Router} from './components/Router';
14
14
  import Navigation from './components/Navigation';
15
15
  import {StorageProvider} from './components/StorageContext';
@@ -32,6 +32,8 @@ import {LanguageProvider} from './language/useLanguage';
32
32
  import {PropsConsumer} from 'agora-rn-uikit';
33
33
  import ToastComponent from './components/ToastComponent';
34
34
  import {ToastContext, ToastProvider} from './components/useToast';
35
+ import {SdkApiContext} from './components/SdkApiContext';
36
+ import isSDK from './utils/isSDK';
35
37
 
36
38
  interface AppWrapperProps {
37
39
  children: React.ReactNode;
@@ -73,6 +75,8 @@ const AppWrapper = (props: AppWrapperProps) => {
73
75
  return React.Fragment;
74
76
  });
75
77
 
78
+ const {join: SdkJoinState} = useContext(SdkApiContext);
79
+
76
80
  return (
77
81
  <AppRoot>
78
82
  <ImageBackgroundComp bg={$config.BG} color={$config.BACKGROUND_COLOR}>
@@ -88,7 +92,13 @@ const AppWrapper = (props: AppWrapperProps) => {
88
92
  </ToastContext.Consumer>
89
93
  <StorageProvider>
90
94
  <GraphQLProvider>
91
- <Router>
95
+ <Router
96
+ /*@ts-ignore Router will be memory Router in sdk*/
97
+ initialEntries={[
98
+ isSDK && SdkJoinState.phrase
99
+ ? `/${SdkJoinState.phrase}`
100
+ : '',
101
+ ]}>
92
102
  <SessionProvider>
93
103
  <ColorConfigure>
94
104
  <DimensionProvider>
@@ -1,86 +1,82 @@
1
- import React, {useEffect, useState} from 'react';
2
- import {CustomizationApiInterface, customize} from 'customization-api';
1
+ import React from 'react';
3
2
  import {
4
- customizationConfig,
5
- CustomizationProvider,
6
- } from 'customization-implementation';
7
- import SDKEvents from './utils/SdkEvents';
8
- import {Unsubscribe} from 'nanoevents';
3
+ CustomizationApiInterface,
4
+ customize,
5
+ MeetingInfoContextInterface,
6
+ customEvents,
7
+ } from 'customization-api';
8
+ import {CustomizationProvider} from 'customization-implementation';
9
+ import SDKEvents, {userEventsMapInterface} from './utils/SdkEvents';
10
+ import SDKMethodEventsManager from './utils/SdkMethodEvents';
9
11
  import App from './App';
12
+ import SdkApiContextProvider from './components/SdkApiContext';
13
+ import {Unsubscribe} from 'nanoevents';
10
14
 
11
- export interface userEventsMapInterface {
12
- leave: () => void;
13
- create: (
14
- hostPhrase: string,
15
- attendeePhrase?: string,
16
- pstnNumer?: {
17
- number: string;
18
- pin: string;
19
- },
20
- ) => void;
21
- 'ready-to-join': (meetingTitle: string, devices: MediaDeviceInfo[]) => void;
22
- join: (
23
- meetingTitle: string,
24
- devices: MediaDeviceInfo[],
25
- isHost: boolean,
26
- ) => void;
27
- }
15
+ // type makeAsync<T extends (...p: any) => void> = (
16
+ // ...p: Parameters<T>
17
+ // ) => PromiseLike<ReturnType<T>>;
18
+ //
19
+ // type takeOnlyFirstParam<T extends (...p: any) => void> = (
20
+ // p: Parameters<T>[0],
21
+ // ) => ReturnType<T>;
28
22
 
29
- export interface AppBuilderSdkApiInterface {
23
+ export interface SdkMethodEvents {
30
24
  customize: (customization: CustomizationApiInterface) => void;
31
- createCustomization: (
32
- customization: CustomizationApiInterface,
33
- ) => CustomizationApiInterface;
34
- join: (roomid: string) => Promise<void>;
35
- on: <T extends keyof userEventsMapInterface>(
36
- userEventName: T,
37
- callBack: userEventsMapInterface[T],
38
- ) => Unsubscribe;
25
+ join(
26
+ roomid: string | Partial<MeetingInfoContextInterface['data']>,
27
+ skipPrecall?: boolean,
28
+ ): MeetingInfoContextInterface['data'];
39
29
  }
40
30
 
41
- let joinInit = false;
31
+ // interface AppBuilderSdkApiInterface {
32
+ // customize: makeAsync<SdkMethodEvents['customize']>;
33
+ // joinRoom: makeAsync<takeOnlyFirstParam<SdkMethodEvents['join']>>;
34
+ // joinPrecall: makeAsync<takeOnlyFirstParam<SdkMethodEvents['join']>>;
35
+ // createCustomization: (
36
+ // customization: CustomizationApiInterface,
37
+ // ) => CustomizationApiInterface;
38
+ // on: <T extends keyof userEventsMapInterface>(
39
+ // userEventName: T,
40
+ // callBack: userEventsMapInterface[T],
41
+ // ) => Unsubscribe;
42
+ // }
42
43
 
43
- export const AppBuilderSdkApi: AppBuilderSdkApiInterface = {
44
- customize: (customization: CustomizationApiInterface) => {
45
- SDKEvents.emit('addFpe', customization);
44
+ export const AppBuilderSdkApi = {
45
+ customize: async (customization: CustomizationApiInterface) => {
46
+ return await SDKMethodEventsManager.emit('customize', customization);
47
+ },
48
+ customEvents: customEvents,
49
+ join: async (roomDetails: string) => {
50
+ await SDKMethodEventsManager.emit('join', roomDetails, false);
51
+ },
52
+ joinRoom: async (
53
+ roomDetails: string | Partial<MeetingInfoContextInterface['data']>,
54
+ ) => {
55
+ return await SDKMethodEventsManager.emit('join', roomDetails, true);
56
+ },
57
+ joinPrecall: async (
58
+ roomDetails: string | Partial<MeetingInfoContextInterface['data']>,
59
+ ) => {
60
+ const t = await SDKMethodEventsManager.emit('join', roomDetails);
61
+ return t as unknown as [MeetingInfoContextInterface['data'], () => {}];
46
62
  },
47
- join: (roomid: string) =>
48
- new Promise((resolve, reject) => {
49
- if (joinInit) {
50
- console.log('[SDKEvents] Join listener emitted preemptive');
51
- SDKEvents.emit('joinMeetingWithPhrase', roomid, resolve, reject);
52
- }
53
- SDKEvents.on('joinInit', () => {
54
- if (!joinInit) {
55
- console.log('[SDKEvents] Join listener emitted');
56
- SDKEvents.emit('joinMeetingWithPhrase', roomid, resolve, reject);
57
- joinInit = true;
58
- }
59
- });
60
- }),
61
63
  createCustomization: customize,
62
- on: (userEventName, cb) => {
64
+ on: <T extends keyof userEventsMapInterface>(
65
+ userEventName: T,
66
+ cb: userEventsMapInterface[T],
67
+ ): Unsubscribe => {
63
68
  console.log('SDKEvents: Event Registered', userEventName);
64
69
  return SDKEvents.on(userEventName, cb);
65
70
  },
66
71
  };
67
72
 
68
73
  const SDKAppWrapper = () => {
69
- const [fpe, setFpe] = useState(customizationConfig);
70
- useEffect(() => {
71
- SDKEvents.on('addFpe', (sdkFpeConfig) => {
72
- console.log('SDKEvents: addFpe event called');
73
- setFpe(sdkFpeConfig);
74
- });
75
- SDKEvents.emit('addFpeInit');
76
- // Join event consumed in Create.tsx
77
- }, []);
78
74
  return (
79
- <>
80
- <CustomizationProvider value={fpe}>
75
+ <SdkApiContextProvider>
76
+ <CustomizationProvider>
81
77
  <App />
82
78
  </CustomizationProvider>
83
- </>
79
+ </SdkApiContextProvider>
84
80
  );
85
81
  };
86
82
 
@@ -45,11 +45,15 @@ type deviceKind = deviceInfo['kind'];
45
45
 
46
46
  const DeviceConfigure: React.FC<Props> = (props: any) => {
47
47
  const rtc = useRtc();
48
- const [selectedCam, setUiSelectedCam] = useState('');
49
- const [selectedMic, setUiSelectedMic] = useState('');
50
- const [selectedSpeaker, setUiSelectedSpeaker] = useState('');
48
+ const [uiSelectedCam, setUiSelectedCam] = useState('');
49
+ const [uiSelectedMic, setUiSelectedMic] = useState('');
50
+ const [uiSelectedSpeaker, setUiSelectedSpeaker] = useState('');
51
51
  const [deviceList, setDeviceList] = useState<deviceInfo[]>([]);
52
52
 
53
+ const micSelectInProgress = useRef(false);
54
+ const camSelectInProgress = useRef(false);
55
+ const speakerSelectInProgress = useRef(false);
56
+
53
57
  const {primaryColor} = useContext(ColorContext);
54
58
  const {store, setStore} = useContext(StorageContext);
55
59
  const {rememberedDevicesList, activeDeviceId} = store;
@@ -241,7 +245,7 @@ const DeviceConfigure: React.FC<Props> = (props: any) => {
241
245
 
242
246
  if (activeDeviceId && deviceList.length > 0) {
243
247
  // If stream exists and selected devices are empty, check for devices again
244
- if (!selectedCam || selectedCam.trim().length == 0) {
248
+ if (!uiSelectedCam || uiSelectedCam.trim().length == 0) {
245
249
  log(logTag, 'cam: Device list populated but No selected cam');
246
250
  const currentVideoDevice = getAgoraTrackDeviceId('video');
247
251
  const {videoinput: storedVideoInput} = activeDeviceId;
@@ -259,7 +263,7 @@ const DeviceConfigure: React.FC<Props> = (props: any) => {
259
263
  }
260
264
  }
261
265
 
262
- if (!selectedMic || selectedMic.trim().length == 0) {
266
+ if (!uiSelectedMic || uiSelectedMic.trim().length == 0) {
263
267
  log(logTag, 'mic: Device list populated but No selected mic');
264
268
  const currentAudioDevice = getAgoraTrackDeviceId('audio');
265
269
  const {audioinput: storedAudioInput} = activeDeviceId;
@@ -277,7 +281,7 @@ const DeviceConfigure: React.FC<Props> = (props: any) => {
277
281
  }
278
282
  }
279
283
 
280
- if (!selectedSpeaker || selectedSpeaker.trim().length == 0) {
284
+ if (!uiSelectedSpeaker || uiSelectedSpeaker.trim().length == 0) {
281
285
  log(logTag, 'speaker: Device list populated but No selected speaker');
282
286
  const {audiooutput: storedAudioOutput} = activeDeviceId;
283
287
  const defaultSpeaker = deviceList.find(
@@ -323,17 +327,17 @@ const DeviceConfigure: React.FC<Props> = (props: any) => {
323
327
  const {logTag, currentDevice, setCurrentDevice} = {
324
328
  audioinput: {
325
329
  logTag: 'mic: on-microphone-changed',
326
- currentDevice: selectedMic,
330
+ currentDevice: uiSelectedMic,
327
331
  setCurrentDevice: setSelectedMic,
328
332
  },
329
333
  audiooutput: {
330
334
  logTag: 'speaker: on-speaker-changed',
331
- currentDevice: selectedSpeaker,
335
+ currentDevice: uiSelectedSpeaker,
332
336
  setCurrentDevice: setSelectedSpeaker,
333
337
  },
334
338
  videoinput: {
335
339
  logTag: 'cam: on-camera-changed',
336
- currentDevice: selectedCam,
340
+ currentDevice: uiSelectedCam,
337
341
  setCurrentDevice: setSelectedCam,
338
342
  },
339
343
  }[changedDevice.kind];
@@ -398,27 +402,45 @@ const DeviceConfigure: React.FC<Props> = (props: any) => {
398
402
  useEffect(() => {
399
403
  log('previous devicelist updated', deviceList);
400
404
  AgoraRTC.onMicrophoneChanged = commonOnChangedEvent;
401
- }, [selectedMic, deviceList]);
405
+ return () => {
406
+ AgoraRTC.onMicrophoneChanged = null;
407
+ };
408
+ }, [uiSelectedMic, deviceList]);
402
409
 
403
410
  useEffect(() => {
404
411
  AgoraRTC.onPlaybackDeviceChanged = commonOnChangedEvent;
405
- }, [selectedSpeaker, deviceList]);
412
+ return () => {
413
+ AgoraRTC.onPlaybackDeviceChanged = null;
414
+ };
415
+ }, [uiSelectedSpeaker, deviceList]);
406
416
 
407
417
  useEffect(() => {
408
418
  AgoraRTC.onCameraChanged = commonOnChangedEvent;
409
- }, [selectedCam, deviceList]);
419
+ return () => {
420
+ AgoraRTC.onCameraChanged = null;
421
+ };
422
+ }, [uiSelectedCam, deviceList]);
410
423
 
411
424
  const setSelectedMic = (deviceId: deviceId) => {
412
425
  log('mic: setting to', deviceId);
413
426
  return new Promise((res, rej) => {
427
+ if (micSelectInProgress.current) {
428
+ const e = new Error('Change already in progress');
429
+ console.error('DeviceConfigure: Error setting mic', e);
430
+ rej(e);
431
+ return;
432
+ }
433
+ micSelectInProgress.current = true;
414
434
  RtcEngine.changeMic(
415
435
  deviceId,
416
436
  () => {
417
437
  syncSelectedDeviceUi('audioinput');
418
438
  updateActiveDeviceId('audioinput', deviceId);
439
+ micSelectInProgress.current = false;
419
440
  res(null);
420
441
  },
421
442
  (e: any) => {
443
+ micSelectInProgress.current = false;
422
444
  console.error('DeviceConfigure: Error setting mic', e);
423
445
  rej(e);
424
446
  },
@@ -429,14 +451,23 @@ const DeviceConfigure: React.FC<Props> = (props: any) => {
429
451
  const setSelectedCam = (deviceId: deviceId) => {
430
452
  log('cam: setting to', deviceId);
431
453
  return new Promise((res, rej) => {
454
+ if (camSelectInProgress.current) {
455
+ const e = new Error('Change already in progress');
456
+ console.error('DeviceConfigure: Error setting webcam', e);
457
+ rej(e);
458
+ return;
459
+ }
460
+ camSelectInProgress.current = true;
432
461
  RtcEngine.changeCamera(
433
462
  deviceId,
434
463
  () => {
435
464
  syncSelectedDeviceUi('videoinput');
436
465
  updateActiveDeviceId('videoinput', deviceId);
466
+ camSelectInProgress.current = false;
437
467
  res(null);
438
468
  },
439
469
  (e: any) => {
470
+ camSelectInProgress.current = false;
440
471
  console.error('Device Configure: Error setting webcam', e);
441
472
  rej(e);
442
473
  },
@@ -447,16 +478,25 @@ const DeviceConfigure: React.FC<Props> = (props: any) => {
447
478
  const setSelectedSpeaker = (deviceId: deviceId) => {
448
479
  log('speaker: setting to', deviceId);
449
480
  return new Promise((res, rej) => {
481
+ if (speakerSelectInProgress.current) {
482
+ const e = new Error('Change already in progress');
483
+ console.error('DeviceConfigure: Error setting speaker', e);
484
+ rej(e);
485
+ return;
486
+ }
487
+ speakerSelectInProgress.current = true;
450
488
  RtcEngine.changeSpeaker(
451
489
  deviceId,
452
490
  () => {
453
491
  setUiSelectedSpeaker(deviceId);
454
492
  updateActiveDeviceId('audiooutput', deviceId);
493
+ speakerSelectInProgress.current = false;
455
494
  res(null);
456
495
  },
457
496
  (e: any) => {
497
+ speakerSelectInProgress.current = false;
458
498
  console.error('Device Configure: Error setting speaker', e);
459
- rej(selectedSpeaker);
499
+ rej(uiSelectedSpeaker);
460
500
  },
461
501
  );
462
502
  });
@@ -517,11 +557,11 @@ const DeviceConfigure: React.FC<Props> = (props: any) => {
517
557
  return (
518
558
  <DeviceContext.Provider
519
559
  value={{
520
- selectedCam,
560
+ selectedCam: uiSelectedCam,
521
561
  setSelectedCam,
522
- selectedMic,
562
+ selectedMic: uiSelectedMic,
523
563
  setSelectedMic,
524
- selectedSpeaker,
564
+ selectedSpeaker: uiSelectedSpeaker,
525
565
  setSelectedSpeaker,
526
566
  deviceList,
527
567
  setDeviceList,
@@ -9,9 +9,23 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React from 'react';
12
+ import React, {useEffect, useContext} from 'react';
13
+ import {SdkApiContext} from './SdkApiContext';
14
+ import {useHistory} from './Router';
15
+ import isSDK from '../utils/isSDK';
13
16
 
14
17
  const Navigation = () => {
18
+ const {join: SdkJoinState} = useContext(SdkApiContext);
19
+
20
+ const history = useHistory();
21
+
22
+ useEffect(() => {
23
+ if (isSDK() && SdkJoinState.initialized) {
24
+ if (SdkJoinState.phrase) {
25
+ history.push(`/${SdkJoinState.phrase}`);
26
+ }
27
+ }
28
+ }, [SdkJoinState]);
15
29
  return <></>;
16
30
  };
17
31
 
@@ -114,6 +114,7 @@ const RtmConfigure = (props: any) => {
114
114
  uid: localUid.toString(),
115
115
  token: rtcProps.rtm,
116
116
  });
117
+ RTMEngine.getInstance().setLocalUID(localUid.toString());
117
118
  timerValueRef.current = 5;
118
119
  setAttribute();
119
120
  } catch (error) {
@@ -144,7 +145,12 @@ const RtmConfigure = (props: any) => {
144
145
 
145
146
  const joinChannel = async () => {
146
147
  try {
147
- await engine.current.joinChannel(rtcProps.channel);
148
+ if (RTMEngine.getInstance().channelUid !== rtcProps.channel) {
149
+ await engine.current.joinChannel(rtcProps.channel);
150
+ RTMEngine.getInstance().setChannelId(rtcProps.channel);
151
+ } else {
152
+ console.log('RTM already joined channel skipping');
153
+ }
148
154
  timerValueRef.current = 5;
149
155
  await getMembers();
150
156
  } catch (error) {
@@ -260,7 +266,7 @@ const RtmConfigure = (props: any) => {
260
266
 
261
267
  const init = async () => {
262
268
  engine.current = RTMEngine.getInstance().engine;
263
- RTMEngine.getInstance().setLoginInfo(localUid.toString(), rtcProps.channel);
269
+ RTMEngine.getInstance();
264
270
 
265
271
  engine.current.on('connectionStateChanged', (evt: any) => {
266
272
  //console.log(evt);
@@ -414,6 +420,17 @@ const RtmConfigure = (props: any) => {
414
420
  const {payload, persistLevel, source} = JSON.parse(value);
415
421
  console.log('CUSTOM_EVENT_API: emiting event..: ');
416
422
  EventUtils.emitEvent(evt, source, {payload, persistLevel, sender, ts});
423
+ // Because async gets evaluated in a different order when in an sdk
424
+ if (evt === 'name') {
425
+ setTimeout(() => {
426
+ EventUtils.emitEvent(evt, source, {
427
+ payload,
428
+ persistLevel,
429
+ sender,
430
+ ts,
431
+ });
432
+ }, 200);
433
+ }
417
434
  } catch (error) {
418
435
  console.log('CUSTOM_EVENT_API: error while emiting event: ', error);
419
436
  }
@@ -0,0 +1,161 @@
1
+ import React, {createContext, useState, useEffect} from 'react';
2
+ import SDKMethodEventsManager, {
3
+ _InternalSDKMethodEventsMap,
4
+ } from '../utils/SdkMethodEvents';
5
+ import {
6
+ validateMeetingInfoData,
7
+ MeetingInfoContextInterface,
8
+ } from './meeting-info/useMeetingInfo';
9
+ import {CustomizationApiInterface} from 'customization-api';
10
+ import {Unsubscribe} from 'nanoevents';
11
+
12
+ type SdkApiContextInterface = {
13
+ join:
14
+ | {
15
+ initialized: true;
16
+ phrase: string;
17
+ meetingDetails?: Partial<MeetingInfoContextInterface['data']>;
18
+ skipPrecall: boolean;
19
+ promise: {
20
+ res: Parameters<_InternalSDKMethodEventsMap['join']>[0];
21
+ rej: Parameters<_InternalSDKMethodEventsMap['join']>[1];
22
+ };
23
+ }
24
+ | {
25
+ initialized: false;
26
+ };
27
+ customize: {
28
+ customization?: CustomizationApiInterface;
29
+ promise?: {
30
+ res: Parameters<_InternalSDKMethodEventsMap['customize']>[0];
31
+ rej: Parameters<_InternalSDKMethodEventsMap['customize']>[1];
32
+ };
33
+ };
34
+ clearState: (key: keyof _InternalSDKMethodEventsMap) => void;
35
+ };
36
+
37
+ const SdkApiInitState: SdkApiContextInterface = {
38
+ join: {
39
+ initialized: false,
40
+ },
41
+ customize: {},
42
+ clearState: () => {},
43
+ };
44
+
45
+ export const SDK_MEETING_TAG = 'sdk-initiated-meeting';
46
+
47
+ export const SdkApiContext = createContext(SdkApiInitState);
48
+
49
+ let moduleEventsUnsub: any[] = [];
50
+
51
+ type commonEventHandlers = {
52
+ [K in keyof _InternalSDKMethodEventsMap]?: (
53
+ setter: (p: SdkApiContextInterface[K]) => void,
54
+ ) => Unsubscribe;
55
+ };
56
+
57
+ const commonEventHandlers: commonEventHandlers = {
58
+ join: (setter) => {
59
+ return SDKMethodEventsManager.on(
60
+ 'join',
61
+ (res, rej, roomDetail, skipPrecall) => {
62
+ if (typeof roomDetail === 'object') {
63
+ if (!validateMeetingInfoData(roomDetail)) {
64
+ rej(new Error('Invalid meeting details'));
65
+ return;
66
+ }
67
+ setter({
68
+ initialized: true,
69
+ phrase: SDK_MEETING_TAG,
70
+ meetingDetails: roomDetail,
71
+ skipPrecall,
72
+ promise: {res, rej},
73
+ });
74
+ } else if (
75
+ typeof roomDetail === 'string' &&
76
+ roomDetail.trim().length > 0
77
+ ) {
78
+ setter({
79
+ initialized: true,
80
+ phrase: roomDetail,
81
+ skipPrecall,
82
+ promise: {res, rej},
83
+ });
84
+ } else {
85
+ rej(new Error('Invalid room detail'));
86
+ }
87
+ },
88
+ );
89
+ },
90
+ customize: (setter) => {
91
+ return SDKMethodEventsManager.on('customize', (res, rej, customization) => {
92
+ setter({
93
+ customization: customization,
94
+ });
95
+ res();
96
+ });
97
+ },
98
+ };
99
+
100
+ const registerListener = () => {
101
+ moduleEventsUnsub = [
102
+ commonEventHandlers.customize((state) => {
103
+ SdkApiInitState.customize = state;
104
+ }),
105
+ commonEventHandlers.join((state) => {
106
+ SdkApiInitState.join = state;
107
+ }),
108
+ ];
109
+ };
110
+
111
+ const deRegisterListener = () => {
112
+ moduleEventsUnsub.forEach((v) => v());
113
+ };
114
+
115
+ const SdkApiContextProvider: React.FC = (props) => {
116
+ const [joinState, setJoinState] = useState(SdkApiInitState.join);
117
+ const [userCustomization, setUserCustomization] = useState(
118
+ SdkApiInitState.customize,
119
+ );
120
+
121
+ const clearState: SdkApiContextInterface['clearState'] = (key) => {
122
+ switch (key) {
123
+ case 'join':
124
+ setJoinState(SdkApiInitState.join);
125
+ return;
126
+ case 'customize':
127
+ setUserCustomization(SdkApiInitState.customize);
128
+ }
129
+ };
130
+
131
+ useEffect(() => {
132
+ deRegisterListener();
133
+ console.log('[SDKContext] join state is ', joinState);
134
+ const unsub = [
135
+ commonEventHandlers.customize((state) => {
136
+ setUserCustomization(state);
137
+ }),
138
+ commonEventHandlers.join((state) => {
139
+ setJoinState(state);
140
+ }),
141
+ ];
142
+
143
+ return () => {
144
+ unsub.forEach((v) => v());
145
+ registerListener();
146
+ };
147
+ }, []);
148
+
149
+ return (
150
+ <SdkApiContext.Provider
151
+ value={{
152
+ join: joinState,
153
+ customize: userCustomization,
154
+ clearState,
155
+ }}>
156
+ {props.children}
157
+ </SdkApiContext.Provider>
158
+ );
159
+ };
160
+
161
+ export default SdkApiContextProvider;
@@ -36,6 +36,30 @@ export interface MeetingInfoContextInterface {
36
36
  };
37
37
  }
38
38
 
39
+ export const validateMeetingInfoData = (
40
+ meetingInfo: Partial<MeetingInfoContextInterface['data']>,
41
+ ) => {
42
+ const {
43
+ channel,
44
+ encryptionSecret,
45
+ rtmToken,
46
+ screenShareToken,
47
+ screenShareUid,
48
+ token,
49
+ uid,
50
+ } = meetingInfo;
51
+ if ($config.ENCRYPTION_ENABLED && !encryptionSecret) {
52
+ return false;
53
+ }
54
+ if ($config.SCREEN_SHARING && (!screenShareToken || !screenShareUid)) {
55
+ return false;
56
+ }
57
+ if (!channel || !rtmToken || !token || !uid) {
58
+ return false;
59
+ }
60
+ return true;
61
+ };
62
+
39
63
  export const MeetingInfoDefaultValue: MeetingInfoContextInterface = {
40
64
  isJoinDataFetched: false,
41
65
  data: {
@@ -9,9 +9,15 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React, {createContext} from 'react';
12
+ import React, {createContext, useContext, useEffect} from 'react';
13
13
  import {createHook} from 'customization-implementation';
14
14
  import {ApolloError} from '@apollo/client';
15
+ import {SdkApiContext} from '../SdkApiContext';
16
+ import {
17
+ useMeetingInfo,
18
+ } from '../meeting-info/useMeetingInfo';
19
+ import SDKEvents from '../../utils/SdkEvents';
20
+ import DeviceContext from '../DeviceContext';
15
21
 
16
22
  export interface PreCallContextInterface {
17
23
  callActive: boolean;
@@ -46,6 +52,24 @@ interface PreCallProviderProps {
46
52
  }
47
53
 
48
54
  const PreCallProvider = (props: PreCallProviderProps) => {
55
+ const {join} = useContext(SdkApiContext);
56
+ const meetingInfo = useMeetingInfo();
57
+ const {deviceList} = useContext(DeviceContext);
58
+
59
+ useEffect(() => {
60
+ if (join.phrase) {
61
+ //@ts-ignore
62
+ join?.promise?.res([
63
+ meetingInfo.data,
64
+ () => {
65
+ props.value.setCallActive(true);
66
+ },
67
+ ]);
68
+ }
69
+
70
+ SDKEvents.emit('ready-to-join', meetingInfo.data.meetingTitle, deviceList);
71
+ }, []);
72
+
49
73
  return (
50
74
  <PreCallContext.Provider value={{...props.value}}>
51
75
  {props.children}
@@ -10,10 +10,14 @@
10
10
  *********************************************
11
11
  */
12
12
 
13
- import React, {SetStateAction, useState} from 'react';
13
+ import React, {SetStateAction, useState, useContext, useEffect} from 'react';
14
14
  import {createHook} from 'customization-implementation';
15
15
  import InvitePopup from './popups/InvitePopup';
16
16
  import StopRecordingPopup from './popups/StopRecordingPopup';
17
+ import {SdkApiContext} from './SdkApiContext';
18
+ import {useRtc, useMeetingInfo} from 'customization-api';
19
+ import SDKEvents from '../utils/SdkEvents';
20
+ import DeviceContext from './DeviceContext';
17
21
 
18
22
  export interface VideoCallContextInterface {
19
23
  showInvitePopup: boolean;
@@ -40,6 +44,21 @@ const VideoCallProvider = (props: VideoCallProviderProps) => {
40
44
  const [showLayoutOption, setShowLayoutOption] = useState(false);
41
45
  const [showInvitePopup, setShowInvitePopup] = useState(false);
42
46
  const [showStopRecordingPopup, setShowStopRecordingPopup] = useState(false);
47
+ const {join} = useContext(SdkApiContext);
48
+ const meetingInfo = useMeetingInfo();
49
+ const {deviceList} = useContext(DeviceContext);
50
+
51
+ useEffect(() => {
52
+ if (join.initialized && join.phrase) {
53
+ join.promise.res(meetingInfo.data);
54
+ }
55
+ SDKEvents.emit(
56
+ 'join',
57
+ meetingInfo.data.meetingTitle,
58
+ deviceList,
59
+ meetingInfo.data.isHost,
60
+ );
61
+ }, []);
43
62
  return (
44
63
  <VideoCallContext.Provider
45
64
  value={{
@@ -28,9 +28,7 @@ import {useString} from '../utils/useString';
28
28
  import useCreateMeeting from '../utils/useCreateMeeting';
29
29
  import {CreateProvider} from './create/useCreate';
30
30
  import useJoinMeeting from '../utils/useJoinMeeting';
31
- import SDKEvents from '../utils/SdkEvents';
32
31
  import {MeetingInfoDefaultValue} from '../components/meeting-info/useMeetingInfo';
33
- import {useSetMeetingInfo} from '../components/meeting-info/useSetMeetingInfo';
34
32
  import Input from '../atoms/Input';
35
33
  import Toggle from '../atoms/Toggle';
36
34
  import Card from '../atoms/Card';
@@ -42,6 +40,7 @@ import Tooltip from '../atoms/Tooltip';
42
40
  import ImageIcon from '../atoms/ImageIcon';
43
41
  import hexadecimalTransparency from '../utils/hexadecimalTransparency';
44
42
  import {randomNameGenerator} from '../utils';
43
+ import {useSetMeetingInfo} from '../components/meeting-info/useSetMeetingInfo';
45
44
 
46
45
  const Create = () => {
47
46
  const {CreateComponent} = useCustomization((data) => {
@@ -121,23 +120,7 @@ const Create = () => {
121
120
  document.title = $config.APP_NAME;
122
121
  }
123
122
  console.log('[SDKEvents] Join listener registered');
124
- const unbind = SDKEvents.on(
125
- 'joinMeetingWithPhrase',
126
- (phrase, resolve, reject) => {
127
- console.log('SDKEvents: joinMeetingWithPhrase event called', phrase);
128
- try {
129
- setMeetingInfo(MeetingInfoDefaultValue);
130
- history.push(phrase);
131
- resolve();
132
- } catch (error) {
133
- reject(error);
134
- }
135
- },
136
- );
137
- SDKEvents.emit('joinInit');
138
- return () => {
139
- unbind();
140
- };
123
+ return () => {};
141
124
  }, []);
142
125
 
143
126
  const showShareScreen = () => {
@@ -10,7 +10,7 @@
10
10
  *********************************************
11
11
  */
12
12
  // @ts-nocheck
13
- import React, {useState, useContext, useEffect} from 'react';
13
+ import React, {useState, useContext, useEffect, useRef} from 'react';
14
14
  import {View, StyleSheet, Text, useWindowDimensions} from 'react-native';
15
15
  import {
16
16
  RtcConfigure,
@@ -18,6 +18,9 @@ import {
18
18
  ClientRole,
19
19
  ChannelProfile,
20
20
  LocalUserContext,
21
+ UidType,
22
+ CallbacksInterface,
23
+ ToggleState,
21
24
  } from '../../agora-rn-uikit';
22
25
  import styles from '../components/styles';
23
26
  import {useParams, useHistory} from '../components/Router';
@@ -38,7 +41,11 @@ import {useString} from '../utils/useString';
38
41
  import useLayoutsData from './video-call/useLayoutsData';
39
42
  import {RecordingProvider} from '../subComponents/recording/useRecording';
40
43
  import useJoinMeeting from '../utils/useJoinMeeting';
41
- import {useMeetingInfo} from '../components/meeting-info/useMeetingInfo';
44
+ import {
45
+ useMeetingInfo,
46
+ MeetingInfoDefaultValue,
47
+ validateMeetingInfoData,
48
+ } from '../components/meeting-info/useMeetingInfo';
42
49
  import {SidePanelProvider} from '../utils/useSidePanel';
43
50
  import VideoCallScreen from './video-call/VideoCallScreen';
44
51
  import {NetworkQualityProvider} from '../components/NetworkQualityContext';
@@ -57,6 +64,9 @@ import EventsConfigure from '../components/EventsConfigure';
57
64
  import PermissionHelper from '../components/precall/PermissionHelper';
58
65
  import {currentFocus, FocusProvider} from '../utils/useFocus';
59
66
  import {VideoCallProvider} from '../components/useVideoCall';
67
+ import {SdkApiContext, SDK_MEETING_TAG} from '../components/SdkApiContext';
68
+ import isSDK from '../utils/isSDK';
69
+ import {useSetMeetingInfo} from '../components/meeting-info/useSetMeetingInfo';
60
70
 
61
71
  enum RnEncryptionEnum {
62
72
  /**
@@ -127,11 +137,18 @@ const VideoCall: React.FC = () => {
127
137
  activeSpeaker: $config.ACTIVE_SPEAKER,
128
138
  });
129
139
 
140
+ const {join: SdkJoinState, clearState} = useContext(SdkApiContext);
141
+ const history = useHistory();
142
+ const currentMeetingPhrase = useRef(history.location.pathname);
143
+
130
144
  const useJoin = useJoinMeeting();
145
+ const {setMeetingInfo} = useSetMeetingInfo();
146
+ const {isJoinDataFetched, data} = useMeetingInfo();
131
147
 
132
148
  React.useEffect(() => {
133
149
  return () => {
134
150
  console.log('Videocall unmounted');
151
+ setMeetingInfo(MeetingInfoDefaultValue);
135
152
  if (awake) {
136
153
  release();
137
154
  }
@@ -139,18 +156,56 @@ const VideoCall: React.FC = () => {
139
156
  }, []);
140
157
 
141
158
  useEffect(() => {
142
- useJoin(phrase)
143
- .then(() => {})
144
- .catch((error) => {
159
+ if (!SdkJoinState.phrase) {
160
+ useJoin(phrase)
161
+ .then(() => {})
162
+ .catch((error) => {
163
+ setGlobalErrorMessage(error);
164
+ history.push('/');
165
+ });
166
+ }
167
+ }, []);
168
+
169
+ useEffect(() => {
170
+ if (!isSDK() || !SdkJoinState.initialized) {
171
+ return;
172
+ }
173
+ const {
174
+ phrase: sdkMeetingPhrase,
175
+ meetingDetails: sdkMeetingDetails,
176
+ skipPrecall,
177
+ promise,
178
+ } = SdkJoinState;
179
+
180
+ const sdkMeetingPath = `/${sdkMeetingPhrase}`;
181
+
182
+ setCallActive(skipPrecall);
183
+
184
+ if (sdkMeetingDetails) {
185
+ setQueryComplete(false);
186
+ setMeetingInfo((meetingInfo) => {
187
+ return {
188
+ isJoinDataFetched: true,
189
+ data: {
190
+ ...meetingInfo.data,
191
+ ...sdkMeetingDetails,
192
+ },
193
+ };
194
+ });
195
+ } else if (sdkMeetingPhrase) {
196
+ setQueryComplete(false);
197
+ currentMeetingPhrase.current = sdkMeetingPath;
198
+ useJoin(sdkMeetingPhrase).catch((error) => {
145
199
  setGlobalErrorMessage(error);
146
200
  history.push('/');
201
+ currentMeetingPhrase.current = '';
202
+ promise.rej(error);
147
203
  });
148
- }, []);
149
-
150
- const {isJoinDataFetched, data} = useMeetingInfo();
204
+ }
205
+ }, [SdkJoinState]);
151
206
 
152
207
  React.useEffect(() => {
153
- if (isJoinDataFetched === true) {
208
+ if (isJoinDataFetched === true && !queryComplete) {
154
209
  setRtcProps({
155
210
  appId: $config.APP_ID,
156
211
  channel: data.channel,
@@ -178,17 +233,48 @@ const VideoCall: React.FC = () => {
178
233
  // if (data.username) {
179
234
  // setUsername(data.username);
180
235
  // }
181
- queryComplete ? {} : setQueryComplete(isJoinDataFetched);
236
+ setQueryComplete(true);
182
237
  }
183
- }, [isJoinDataFetched]);
238
+ }, [isJoinDataFetched, data, queryComplete]);
184
239
 
185
- const history = useHistory();
186
- const callbacks = {
187
- EndCall: () =>
240
+ const callbacks: CallbacksInterface = {
241
+ // RtcLeft: () => {},
242
+ // RtcJoined: () => {
243
+ // if (SdkJoinState.phrase && SdkJoinState.skipPrecall) {
244
+ // SdkJoinState.promise?.res();
245
+ // }
246
+ // },
247
+ EndCall: () => {
248
+ clearState('join');
188
249
  setTimeout(() => {
189
250
  SDKEvents.emit('leave');
190
251
  history.push('/');
191
- }, 0),
252
+ }, 0);
253
+ },
254
+ UserJoined: (uid: UidType) => {
255
+ console.log("UIKIT Callback: UserJoined", uid)
256
+ SDKEvents.emit('rtc-user-joined', uid);
257
+ },
258
+ UserOffline: (uid: UidType) => {
259
+ console.log("UIKIT Callback: UserOffline", uid)
260
+ SDKEvents.emit('rtc-user-joined', uid);
261
+ },
262
+ RemoteAudioStateChanged: (uid: UidType, status: 0 | 2) => {
263
+ console.log("UIKIT Callback: RemoteAudioStateChanged", uid, status)
264
+ if (status === 0) {
265
+ SDKEvents.emit('rtc-user-unpublished', uid, 'audio');
266
+ } else {
267
+ SDKEvents.emit('rtc-user-published', uid, 'audio');
268
+ }
269
+ },
270
+ RemoteVideoStateChanged: (uid: UidType, status: 0 | 2) => {
271
+ console.log("UIKIT Callback: RemoteVideoStateChanged", uid, status)
272
+ if (status === 0) {
273
+ SDKEvents.emit('rtc-user-unpublished', uid, 'video');
274
+ } else {
275
+ SDKEvents.emit('rtc-user-published', uid, 'video');
276
+ }
277
+ },
192
278
  };
193
279
  const [isCameraAvailable, setCameraAvailable] = useState(false);
194
280
  const [isMicAvailable, setMicAvailable] = useState(false);
@@ -142,33 +142,6 @@ const VideoCallScreen = () => {
142
142
  return components;
143
143
  });
144
144
 
145
- useEffect(() => {
146
- // setTimeout(() => {
147
- // events.send(
148
- // controlMessageEnum.newUserJoined,
149
- // JSON.stringify({name}),
150
- // EventPersistLevel.LEVEL1,
151
- // );
152
- // }, 1000);
153
-
154
- /**
155
- * OLD: Commenting this code as getDevices API is web only
156
- * The below code fails on native app
157
- * RESPONSE: Added isWebInternal check to restrict execution only on web.
158
- */
159
- if (isWebInternal()) {
160
- new Promise((res) =>
161
- //@ts-ignore
162
- rtc.RtcEngine.getDevices(function (devices: MediaDeviceInfo[]) {
163
- res(devices);
164
- }),
165
- ).then((devices: MediaDeviceInfo[]) => {
166
- SDKEvents.emit('join', meetingTitle, devices, isHost);
167
- console.log('SDKEvents: Event Called join');
168
- });
169
- }
170
- }, []);
171
-
172
145
  const isDesktop = useIsDesktop();
173
146
 
174
147
  return VideocallComponent ? (
@@ -47,6 +47,12 @@ class RTMEngine {
47
47
 
48
48
  return RTMEngine._instance;
49
49
  }
50
+ setLocalUID(localUID: string) {
51
+ this.localUID = localUID;
52
+ }
53
+ setChannelId(channelID: string) {
54
+ this.channelId = channelID;
55
+ }
50
56
 
51
57
  setLoginInfo(localUID: string, channelID: string) {
52
58
  this.localUID = localUID;
@@ -62,6 +68,8 @@ class RTMEngine {
62
68
  try {
63
69
  this.destroyClientInstance();
64
70
  RTMEngine._instance = null;
71
+ this.localUID = '';
72
+ this.channelId = '';
65
73
  } catch (error) {
66
74
  console.log('Error destroying instance error: ', error);
67
75
  }
@@ -165,6 +165,7 @@ class Events {
165
165
  if (!this._validateEvt(eventName) || !this._validateListener(listener))
166
166
  return;
167
167
  EventUtils.addListener(eventName, listener, this.source);
168
+ console.log('CUSTOM_EVENT_API event listener registered', eventName);
168
169
  return () => {
169
170
  EventUtils.removeListener(eventName, listener, this.source);
170
171
  };
@@ -9,24 +9,33 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- /**
13
- * @format
14
- */
15
- type callBackType = (...args: any[]) => void;
16
- import {userEventsMapInterface} from '../SDKAppWrapper';
12
+
17
13
  import {createNanoEvents} from 'nanoevents';
14
+ import {UidType} from 'agora-rn-uikit';
15
+ import {IRemoteTrack} from 'agora-rtc-sdk-ng';
18
16
 
19
- interface eventsMapInterface extends userEventsMapInterface {
20
- addFpe?: callBackType;
21
- addFpeInit?: () => void;
22
- joinInit?: () => void;
23
- joinMeetingWithPhrase?: (
24
- phrase: string,
25
- resolve: () => void,
26
- reject: (e: Error) => void,
17
+ export interface userEventsMapInterface {
18
+ leave: () => void;
19
+ create: (
20
+ hostPhrase: string,
21
+ attendeePhrase?: string,
22
+ pstnNumer?: {
23
+ number: string;
24
+ pin: string;
25
+ },
26
+ ) => void;
27
+ 'ready-to-join': (meetingTitle: string, devices: MediaDeviceInfo[]) => void;
28
+ join: (
29
+ meetingTitle: string,
30
+ devices: MediaDeviceInfo[],
31
+ isHost: boolean,
27
32
  ) => void;
33
+ 'rtc-user-published': (uid: UidType, trackType: 'audio' | 'video') => void;
34
+ 'rtc-user-unpublished': (uid: UidType, trackType: 'audio' | 'video') => void;
35
+ 'rtc-user-joined': (uid: UidType) => void;
36
+ 'rtc-user-left': (uid: UidType) => void;
28
37
  }
29
38
 
30
- const SDKEvents = createNanoEvents<eventsMapInterface>();
39
+ const SDKEvents = createNanoEvents<userEventsMapInterface>();
31
40
 
32
41
  export default SDKEvents;
@@ -0,0 +1,81 @@
1
+ import {SdkMethodEvents} from '../SDKAppWrapper';
2
+ import {createNanoEvents, Emitter} from 'nanoevents';
3
+
4
+ type EventParameterHelper<T extends keyof SdkMethodEvents> = Parameters<
5
+ SdkMethodEvents[T]
6
+ >;
7
+
8
+ type EventReturnTypeHelper<T extends keyof SdkMethodEvents> = ReturnType<
9
+ SdkMethodEvents[T]
10
+ >;
11
+
12
+ type EventKeyNameHelper = keyof SdkMethodEvents;
13
+
14
+ type injectAsync<T extends (...p: any) => any> = (
15
+ res: (result?: ReturnType<T> | PromiseLike<ReturnType<T>>) => void,
16
+ rej: (reason?: any) => void,
17
+ ...params: Parameters<T>
18
+ ) => void;
19
+
20
+ export type _InternalSDKMethodEventsMap = {
21
+ [K in EventKeyNameHelper]: injectAsync<SdkMethodEvents[K]>;
22
+ };
23
+
24
+ type emitCacheType = {
25
+ [K in EventKeyNameHelper]?: Parameters<_InternalSDKMethodEventsMap[K]>;
26
+ };
27
+
28
+ type emitCacheEnabledType = {
29
+ [K in EventKeyNameHelper]?: boolean;
30
+ };
31
+
32
+ class SDKMethodEvents {
33
+ constructor() {
34
+ this.emitter = createNanoEvents();
35
+ }
36
+
37
+ emitter: Emitter;
38
+
39
+ emitCache: emitCacheType = {};
40
+ emitCacheDisabled: emitCacheEnabledType = {};
41
+
42
+ async emit<T extends EventKeyNameHelper>(
43
+ event: T,
44
+ ...params: EventParameterHelper<T>
45
+ ) {
46
+ if (this.emitCache[event]) {
47
+ throw new Error(`Event: ${event} already in callstack`);
48
+ }
49
+
50
+ const result = await new Promise<EventReturnTypeHelper<T>>((res, rej) => {
51
+ this.emitCache[event] = [res, rej, ...params] as any;
52
+ this.emitter.emit(event, res, rej, ...params);
53
+ })
54
+ .then((res) => {
55
+ delete this.emitCache[event];
56
+ return res;
57
+ })
58
+ .catch((e) => {
59
+ delete this.emitCache[event];
60
+ throw e;
61
+ });
62
+
63
+ return result;
64
+ }
65
+
66
+ on<T extends EventKeyNameHelper>(
67
+ event: T,
68
+ callback: _InternalSDKMethodEventsMap[T],
69
+ ) {
70
+ const unsub = this.emitter.on(event, callback);
71
+ if (this.emitCache[event] && !this.emitCacheDisabled[event]) {
72
+ this.emitter.emit(event, ...this.emitCache[event]);
73
+ }
74
+ this.emitCacheDisabled[event] = true;
75
+ return unsub;
76
+ }
77
+ }
78
+
79
+ const SDKMethodEventsManager = new SDKMethodEvents();
80
+
81
+ export default SDKMethodEventsManager;
@@ -111,16 +111,22 @@ export default function useJoinMeeting() {
111
111
  // if (data?.getUser?.name) {
112
112
  // meetingInfo.username = data.getUser.name;
113
113
  // }
114
+ console.log('!!!!!Meetinginfo', {
115
+ meetingInfo,
116
+ response: response.data,
117
+ });
114
118
  setMeetingInfo((prevState) => {
119
+ let compiledMeetingInfo = {
120
+ ...prevState.data,
121
+ ...meetingInfo,
122
+ };
115
123
  return {
116
124
  ...prevState,
117
125
  isJoinDataFetched: true,
118
- data: {
119
- ...prevState.data,
120
- ...meetingInfo,
121
- },
126
+ data: compiledMeetingInfo,
122
127
  };
123
128
  });
129
+ return meetingInfo;
124
130
  } else {
125
131
  throw new Error('An error occurred in parsing the channel data.');
126
132
  }
@@ -17,13 +17,12 @@ module.exports = merge(commons, {
17
17
  'react-router': 'react-router',
18
18
  'react-router-dom': 'react-router-dom',
19
19
  '@apollo/client': '@apollo/client',
20
- nanoid: 'nanoid',
21
20
  },
22
21
  // Main entry point for the web application
23
22
  entry: {
24
23
  main: './index.rsdk.tsx',
25
24
  },
26
- target: 'node',
25
+ target: 'web',
27
26
  output: {
28
27
  path: path.resolve(__dirname, `../Builds/react-sdk`),
29
28
  filename: 'index.js',