agora-appbuilder-core 4.1.6 → 4.1.7-beta.2

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.1.6",
3
+ "version": "4.1.7-beta.2",
4
4
  "description": "React Native template for RTE app builder",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -77,8 +77,8 @@ const DefaultConfig = {
77
77
  CHAT_ORG_NAME: '',
78
78
  CHAT_APP_NAME: '',
79
79
  CHAT_URL: '',
80
- CLI_VERSION: '3.1.6',
81
- CORE_VERSION: '4.1.6',
80
+ CLI_VERSION: '3.1.7-beta.2',
81
+ CORE_VERSION: '4.1.7-beta.2',
82
82
  DISABLE_LANDSCAPE_MODE: false,
83
83
  STT_AUTO_START: false,
84
84
  CLOUD_RECORDING_AUTO_START: false,
@@ -88,6 +88,8 @@ const DefaultConfig = {
88
88
  CUSTOMIZE_AGENT: true,
89
89
  AI_LAYOUT: 'LAYOUT_TYPE_1',
90
90
  SDK_CODEC: 'vp8',
91
+ ENABLE_WAITING_ROOM_AUTO_APPROVAL: false,
92
+ ENABLE_WAITING_ROOM_AUTO_REQUEST: false
91
93
  };
92
94
 
93
95
  module.exports = DefaultConfig;
@@ -175,6 +175,8 @@ interface ConfigInterface {
175
175
  CUSTOMIZE_AGENT: boolean;
176
176
  AI_LAYOUT: string;
177
177
  SDK_CODEC: string;
178
+ ENABLE_WAITING_ROOM_AUTO_APPROVAL: boolean;
179
+ ENABLE_WAITING_ROOM_AUTO_REQUEST: boolean;
178
180
  }
179
181
  declare var $config: ConfigInterface;
180
182
  declare module 'customization' {
@@ -9,7 +9,7 @@
9
9
  information visit https://appbuilder.agora.io.
10
10
  *********************************************
11
11
  */
12
- import React, {useState, useLayoutEffect} from 'react';
12
+ import React, {useState, useLayoutEffect, useEffect} from 'react';
13
13
  import {Platform} from 'react-native';
14
14
  import KeyboardManager from 'react-native-keyboard-manager';
15
15
  import AppWrapper from './AppWrapper';
@@ -22,6 +22,7 @@ import {SetRoomInfoProvider} from './components/room-info/useSetRoomInfo';
22
22
  import {ShareLinkProvider} from './components/useShareLink';
23
23
  import AppRoutes from './AppRoutes';
24
24
  import {isWebInternal} from './utils/common';
25
+ import LocalEventEmitter, {LocalEventsEnum} from './rtm-events-api/LocalEvents';
25
26
 
26
27
  // hook can't be used in the outside react function calls. so directly checking the platform.
27
28
  if (Platform.OS === 'ios') {
@@ -103,6 +104,22 @@ const App: React.FC = () => {
103
104
  };
104
105
  }, []);
105
106
 
107
+ const updateToken = token => {
108
+ setRoomInfo(prevState => {
109
+ return {
110
+ ...prevState,
111
+ loginToken: token,
112
+ };
113
+ });
114
+ };
115
+
116
+ useEffect(() => {
117
+ LocalEventEmitter.on(LocalEventsEnum.SDK_TOKEN_CHANGED, updateToken);
118
+ return () => {
119
+ LocalEventEmitter.off(LocalEventsEnum.SDK_TOKEN_CHANGED, updateToken);
120
+ };
121
+ }, []);
122
+
106
123
  const [roomInfo, setRoomInfo] =
107
124
  useState<RoomInfoContextInterface>(RoomInfoDefaultValue);
108
125
 
@@ -330,6 +330,18 @@ export const AgentProvider: React.FC<{children: React.ReactNode}> = ({
330
330
  secondaryBtn: null,
331
331
  leadingIcon: null,
332
332
  });
333
+ } else if (agentConnectError.toString().indexOf('403') !== -1) {
334
+ Toast.show({
335
+ leadingIconName: 'alert',
336
+ type: 'error',
337
+ text1: 'Uh oh! Agent failed to connect',
338
+ text2:
339
+ "Verify if you've enabled conversational AI on agora console or if they have configured correct customerId & customer certificate for your project on appbuilder console",
340
+ visibilityTime: 5000,
341
+ primaryBtn: null,
342
+ secondaryBtn: null,
343
+ leadingIcon: null,
344
+ });
333
345
  } else {
334
346
  Toast.show({
335
347
  leadingIconName: 'alert',
@@ -73,7 +73,11 @@ export const AgentControl: React.FC = () => {
73
73
  ) : (
74
74
  <Image style={{width: 24, height: 24}} source={LeaveCallIcon} />
75
75
  )}
76
- {!isMobileUA() && !(agentConnectionState === 'AGENT_CONNECTED') ? (
76
+ {!isMobileUA() &&
77
+ !(
78
+ agentConnectionState === 'AGENT_CONNECTED' ||
79
+ agentConnectionState === 'AGENT_DISCONNECT_FAILED'
80
+ ) ? (
77
81
  <Text
78
82
  style={{
79
83
  fontFamily: ThemeConfig.FontFamily.sansPro,
@@ -66,7 +66,12 @@ const CustomCreate = () => {
66
66
  ) => {
67
67
  if (roomTitle !== '') {
68
68
  try {
69
- setRoomInfo(RoomInfoDefaultValue);
69
+ setRoomInfo(prevState => {
70
+ return {
71
+ ...RoomInfoDefaultValue,
72
+ loginToken: prevState?.loginToken,
73
+ };
74
+ });
70
75
  //@ts-ignore
71
76
  //isSeparateHostLink will be for internal usage since backend integration is not there
72
77
  await createRoomFun(roomTitle, enablePSTN, isSeparateHostLink);
@@ -84,7 +84,9 @@ export default function ConversationalAI() {
84
84
  )}
85
85
  </View>
86
86
  <View style={styles.btnContainer}>
87
- {!isLoading && agentConnectionState === 'AGENT_CONNECTED' ? (
87
+ {!isLoading &&
88
+ (agentConnectionState === 'AGENT_CONNECTED' ||
89
+ agentConnectionState === 'AGENT_DISCONNECT_FAILED') ? (
88
90
  <View style={styles.controlsContainer}>
89
91
  <MicButton />
90
92
  <TranscriptButton />
@@ -51,7 +51,9 @@ export default function NewAnimation() {
51
51
  <AiAgentCustomView connectionState={agentConnectionState} />
52
52
  </View>
53
53
  <View style={styles.btnContainer}>
54
- {!isLoading && agentConnectionState === 'AGENT_CONNECTED' ? (
54
+ {!isLoading &&
55
+ (agentConnectionState === 'AGENT_CONNECTED' ||
56
+ agentConnectionState === 'AGENT_DISCONNECT_FAILED') ? (
55
57
  <View style={styles.controlsContainer}>
56
58
  <MicButton />
57
59
  <TranscriptButton />
@@ -40,6 +40,10 @@ import {
40
40
  import {LogSource, logger} from '../logger/AppBuilderLogger';
41
41
  import getUniqueID from '../utils/getUniqueID';
42
42
  import {useIsRecordingBot} from '../subComponents/recording/useIsRecordingBot';
43
+ import SDKEvents from '../utils/SdkEvents';
44
+ import LocalEventEmitter, {
45
+ LocalEventsEnum,
46
+ } from '../rtm-events-api/LocalEvents';
43
47
 
44
48
  export const GET_USER = gql`
45
49
  query getUser {
@@ -258,7 +262,7 @@ const AuthProvider = (props: AuthProviderProps) => {
258
262
  text2: 'Please try again later.',
259
263
  visibilityTime: 1000 * 60,
260
264
  });
261
- rej('SDK Login failed' + JSON.stringify(error));
265
+ rej('SDK Login failed ' + JSON.stringify(error));
262
266
  });
263
267
  });
264
268
  } catch (error) {
@@ -270,7 +274,7 @@ const AuthProvider = (props: AuthProviderProps) => {
270
274
  text2: 'Please try again later.',
271
275
  visibilityTime: 1000 * 60,
272
276
  });
273
- rej('SDK Login failed' + JSON.stringify(error));
277
+ rej('SDK Login failed ' + JSON.stringify(error));
274
278
  }
275
279
  });
276
280
  SDKMethodEventsManager.on('logout', async (res, rej) => {
@@ -727,6 +731,17 @@ const AuthProvider = (props: AuthProviderProps) => {
727
731
  }
728
732
  };
729
733
 
734
+ useEffect(() => {
735
+ LocalEventEmitter.on(LocalEventsEnum.SDK_TOKEN_CHANGED, token => {
736
+ if (!token) {
737
+ setLoading(true);
738
+ }
739
+ });
740
+ SDKEvents.on('unauthorized', () => {
741
+ setLoading(true);
742
+ });
743
+ }, []);
744
+
730
745
  return (
731
746
  <AuthContext.Provider
732
747
  value={{
@@ -6,6 +6,9 @@ import isSDK from '../utils/isSDK';
6
6
  import {getPlatformId} from './config';
7
7
  import {LogSource, logger} from '../logger/AppBuilderLogger';
8
8
  import getUniqueID from '../utils/getUniqueID';
9
+ import LocalEventEmitter, {
10
+ LocalEventsEnum,
11
+ } from '../rtm-events-api/LocalEvents';
9
12
  const REFRESH_TOKEN_DURATION_IN_SEC = 59;
10
13
 
11
14
  const useTokenAuth = () => {
@@ -165,6 +168,10 @@ const useTokenAuth = () => {
165
168
  try {
166
169
  if (validateToken(token)) {
167
170
  if (updateTokenInStore) {
171
+ LocalEventEmitter.emit(
172
+ LocalEventsEnum.SDK_TOKEN_CHANGED,
173
+ token,
174
+ );
168
175
  updateToken(token);
169
176
  }
170
177
  setTimeout(() => {
@@ -234,6 +241,7 @@ const useTokenAuth = () => {
234
241
  },
235
242
  );
236
243
  resolve(true);
244
+ LocalEventEmitter.emit(LocalEventsEnum.SDK_TOKEN_CHANGED, null);
237
245
  updateToken(null);
238
246
  })
239
247
  .catch(error => {
@@ -668,6 +668,36 @@ const EventsConfigure: React.FC<Props> = ({
668
668
  waitingRoomRef.current[attendee_uid] = 'PENDING';
669
669
  // check if any other host has approved then dont show permission to join the room
670
670
 
671
+ const approveWaitingRoomRequest = () => {
672
+ // user approving waiting room request
673
+ const res = approval({
674
+ host_uid: localUid,
675
+ attendee_uid: attendee_uid,
676
+ attendee_screenshare_uid: attendee_screenshare_uid,
677
+ approved: true,
678
+ });
679
+ dispatch({
680
+ type: 'UpdateRenderList',
681
+ value: [attendee_uid, {isInWaitingRoom: false}],
682
+ });
683
+
684
+ waitingRoomRef.current[attendee_uid] = 'APPROVED';
685
+
686
+ console.log('waitingRoomRef on APPROVAL', waitingRoomRef.current);
687
+ // inform other that hosts as well
688
+ events.send(
689
+ EventNames.WAITING_ROOM_STATUS_UPDATE,
690
+ JSON.stringify({attendee_uid, approved: true}),
691
+ PersistanceLevel.None,
692
+ );
693
+ // server will send the RTM message with approved status and RTC token to the approved attendee.
694
+ };
695
+
696
+ if ($config.ENABLE_WAITING_ROOM_AUTO_APPROVAL) {
697
+ approveWaitingRoomRequest();
698
+ return;
699
+ }
700
+
671
701
  let btns: any = {};
672
702
  btns.toastId = attendee_uid;
673
703
  btns.primaryBtn = (
@@ -676,28 +706,7 @@ const EventsConfigure: React.FC<Props> = ({
676
706
  textStyle={style.textStyle}
677
707
  text={waitingRoomApprovalPrimaryBtnRef.current}
678
708
  onPress={() => {
679
- // user approving waiting room request
680
- const res = approval({
681
- host_uid: localUid,
682
- attendee_uid: attendee_uid,
683
- attendee_screenshare_uid: attendee_screenshare_uid,
684
- approved: true,
685
- });
686
- dispatch({
687
- type: 'UpdateRenderList',
688
- value: [attendee_uid, {isInWaitingRoom: false}],
689
- });
690
-
691
- waitingRoomRef.current[attendee_uid] = 'APPROVED';
692
-
693
- console.log('waitingRoomRef on APPROVAL', waitingRoomRef.current);
694
- // inform other that hosts as well
695
- events.send(
696
- EventNames.WAITING_ROOM_STATUS_UPDATE,
697
- JSON.stringify({attendee_uid, approved: true}),
698
- PersistanceLevel.None,
699
- );
700
- // server will send the RTM message with approved status and RTC token to the approved attendee.
709
+ approveWaitingRoomRequest();
701
710
  Toast.hide();
702
711
  }}
703
712
  />
@@ -341,6 +341,7 @@ const RtmConfigure = (props: any) => {
341
341
  type: uid === parseInt(RECORDING_BOT_UID) ? 'bot' : 'rtc',
342
342
  uid,
343
343
  offline: false,
344
+ isHost: attr?.attributes?.isHost,
344
345
  lastMessageTimeStamp: 0,
345
346
  };
346
347
  updateRenderListState(uid, userData);
@@ -510,6 +511,7 @@ const RtmConfigure = (props: any) => {
510
511
  uid,
511
512
  offline: false,
512
513
  lastMessageTimeStamp: 0,
514
+ isHost: attr?.attributes?.isHost,
513
515
  };
514
516
  updateRenderListState(uid, userData);
515
517
  //end- updating user data in rtc
@@ -22,6 +22,7 @@ import TertiaryButton from '../../atoms/TertiaryButton';
22
22
  import ThemeConfig from '../../theme';
23
23
  import {CopyMeetingInfo} from '../../components/Share';
24
24
  import {
25
+ AuthErrorCodes,
25
26
  isMobileUA,
26
27
  isValidReactComponent,
27
28
  useIsDesktop,
@@ -38,6 +39,8 @@ import {
38
39
  } from '../../language/default-labels/videoCallScreenLabels';
39
40
  import {cancelText} from '../../language/default-labels/commonLabels';
40
41
  import {logger, LogSource} from '../../logger/AppBuilderLogger';
42
+ import isSDK from '../../utils/isSDK';
43
+ import SDKEvents from '../../utils/SdkEvents';
41
44
 
42
45
  const InvitePopup = () => {
43
46
  const {setShowInvitePopup, showInvitePopup} = useVideoCall();
@@ -48,6 +51,10 @@ const InvitePopup = () => {
48
51
  const getMeeting = useGetMeetingPhrase();
49
52
  useEffect(() => {
50
53
  getMeeting(phrase).catch(error => {
54
+ const errorCode = error?.networkError?.result?.error?.code;
55
+ if (AuthErrorCodes.indexOf(errorCode) !== -1 && isSDK()) {
56
+ SDKEvents.emit('unauthorized', error?.networkError?.result?.error);
57
+ }
51
58
  logger.error(
52
59
  LogSource.Internals,
53
60
  'GET_MEETING_PHRASE',
@@ -10,19 +10,18 @@
10
10
  *********************************************
11
11
  */
12
12
 
13
- import React, {useContext, useEffect} from 'react';
13
+ import React, {useContext, useEffect, useState} from 'react';
14
14
  import PrimaryButton from '../../atoms/PrimaryButton';
15
15
  import {usePreCall} from './usePreCall';
16
16
  import {useString, useStringRef} from '../../utils/useString';
17
17
  import {
18
- ChannelProfile,
19
18
  DispatchContext,
20
19
  PropsContext,
21
20
  useLocalUid,
22
21
  } from '../../../agora-rn-uikit';
23
22
  import {
24
- PrecallJoinBtnTextInterface,
25
- precallJoinBtnText,
23
+ PrecallWaitingRoomJoinBtnTextInterface,
24
+ precallWaitingRoomJoinBtnText,
26
25
  } from '../../language/default-labels/precallScreenLabels';
27
26
  import {WaitingRoomStatus, useRoomInfo} from '../room-info/useRoomInfo';
28
27
  import useGetName from '../../utils/useGetName';
@@ -37,6 +36,8 @@ import EventsConfigure from '../EventsConfigure';
37
36
  import {
38
37
  waitingRoomApprovalRejectionToastHeading,
39
38
  waitingRoomApprovalRejectionToastSubHeading,
39
+ waitingRoomHostNotJoined,
40
+ waitingRoomUsersInCall,
40
41
  } from '../../language/default-labels/videoCallScreenLabels';
41
42
 
42
43
  export interface PreCallJoinWaitingRoomBtnProps {
@@ -53,19 +54,24 @@ const JoinWaitingRoomBtn = (props: PreCallJoinWaitingRoomBtnProps) => {
53
54
  const subheadinglabel = useStringRef(
54
55
  waitingRoomApprovalRejectionToastSubHeading,
55
56
  );
57
+ const waitingRoomUserNotJoinedText = useString(waitingRoomHostNotJoined);
58
+ const waitingRoomUsersInCallText = useString(waitingRoomUsersInCall);
56
59
  let pollingTimeout = React.useRef(null);
57
60
  const {rtcProps} = useContext(PropsContext);
58
61
  const {setCallActive, callActive} = usePreCall();
59
62
  const username = useGetName();
60
63
  const {isJoinDataFetched, isInWaitingRoom} = useRoomInfo();
61
64
  const {setRoomInfo} = useSetRoomInfo();
65
+ const [hasHostJoined, setHasHostJoined] = useState(false);
66
+ const {defaultContent} = useContent();
62
67
 
63
- const waitingRoomButton =
64
- useString<PrecallJoinBtnTextInterface>(precallJoinBtnText);
68
+ const waitingRoomButton = useString<PrecallWaitingRoomJoinBtnTextInterface>(
69
+ precallWaitingRoomJoinBtnText,
70
+ );
65
71
  const [buttonText, setButtonText] = React.useState(
66
72
  waitingRoomButton({
67
- waitingRoom: true,
68
73
  ready: isInWaitingRoom,
74
+ isAutoRequest: $config.ENABLE_WAITING_ROOM_AUTO_REQUEST,
69
75
  }),
70
76
  );
71
77
  const {request: requestToJoin} = useWaitingRoomAPI();
@@ -78,6 +84,28 @@ const JoinWaitingRoomBtn = (props: PreCallJoinWaitingRoomBtnProps) => {
78
84
  activeUidsRef.current = activeUids;
79
85
  }, [activeUids]);
80
86
 
87
+ React.useEffect(() => {
88
+ if ($config.ENABLE_WAITING_ROOM_AUTO_REQUEST) {
89
+ const hostUsersInCall = Object.keys(defaultContent).filter(
90
+ key =>
91
+ defaultContent[key].type === 'rtc' &&
92
+ defaultContent[key].offline === false &&
93
+ Number(key) !== localUid &&
94
+ defaultContent[key].isHost === 'true',
95
+ );
96
+
97
+ //console.log('host users in call ->', hostUsersInCall);
98
+
99
+ setHasHostJoined(hostUsersInCall.length > 0);
100
+
101
+ setButtonText(
102
+ hostUsersInCall.length > 0
103
+ ? waitingRoomUsersInCallText()
104
+ : waitingRoomUserNotJoinedText(),
105
+ );
106
+ }
107
+ }, [defaultContent]);
108
+
81
109
  const {
82
110
  data: {token, isHost},
83
111
  } = useRoomInfo();
@@ -91,8 +119,8 @@ const JoinWaitingRoomBtn = (props: PreCallJoinWaitingRoomBtnProps) => {
91
119
  useEffect(() => {
92
120
  setButtonText(
93
121
  waitingRoomButton({
94
- waitingRoom: true,
95
122
  ready: !isInWaitingRoom,
123
+ isAutoRequest: $config.ENABLE_WAITING_ROOM_AUTO_REQUEST,
96
124
  }),
97
125
  );
98
126
  }, [isInWaitingRoom]);
@@ -201,7 +229,9 @@ const JoinWaitingRoomBtn = (props: PreCallJoinWaitingRoomBtnProps) => {
201
229
 
202
230
  const title = buttonText;
203
231
  const onPress = () => onSubmit();
204
- const disabled = isInWaitingRoom || username === '';
232
+ const disabled = $config.ENABLE_WAITING_ROOM_AUTO_REQUEST
233
+ ? !hasHostJoined
234
+ : isInWaitingRoom || username?.trim() === '';
205
235
  return props?.render ? (
206
236
  props.render(onPress, title, disabled)
207
237
  ) : (
@@ -10,19 +10,18 @@
10
10
  *********************************************
11
11
  */
12
12
 
13
- import React, {useContext, useEffect} from 'react';
13
+ import React, {useContext, useEffect, useState} from 'react';
14
14
  import PrimaryButton from '../../atoms/PrimaryButton';
15
15
  import {usePreCall} from './usePreCall';
16
16
  import {useString, useStringRef} from '../../utils/useString';
17
17
  import {
18
- ChannelProfile,
19
18
  DispatchContext,
20
19
  PropsContext,
21
20
  useLocalUid,
22
21
  } from '../../../agora-rn-uikit';
23
22
  import {
24
- PrecallJoinBtnTextInterface,
25
- precallJoinBtnText,
23
+ PrecallWaitingRoomJoinBtnTextInterface,
24
+ precallWaitingRoomJoinBtnText,
26
25
  } from '../../language/default-labels/precallScreenLabels';
27
26
 
28
27
  import useGetName from '../../utils/useGetName';
@@ -39,10 +38,12 @@ import Toast from '../../../react-native-toast-message';
39
38
  import events from '../../rtm-events-api';
40
39
  import useWaitingRoomAPI from '../../subComponents/waiting-rooms/useWaitingRoomAPI';
41
40
  import {UserType} from '../RTMConfigure';
42
- import {useContent} from 'customization-api';
41
+ import {useContent, useIsHost} from 'customization-api';
43
42
  import {
44
43
  waitingRoomApprovalRejectionToastHeading,
45
44
  waitingRoomApprovalRejectionToastSubHeading,
45
+ waitingRoomHostNotJoined,
46
+ waitingRoomUsersInCall,
46
47
  } from '../../language/default-labels/videoCallScreenLabels';
47
48
 
48
49
  const audio = new Audio(
@@ -63,6 +64,9 @@ const JoinWaitingRoomBtn = (props: PreCallJoinWaitingRoomBtnProps) => {
63
64
  const subheadinglabel = useStringRef(
64
65
  waitingRoomApprovalRejectionToastSubHeading,
65
66
  );
67
+
68
+ const waitingRoomUserNotJoinedText = useString(waitingRoomHostNotJoined);
69
+ const waitingRoomUsersInCallText = useString(waitingRoomUsersInCall);
66
70
  let pollingTimeout = React.useRef(null);
67
71
  const {rtcProps} = useContext(PropsContext);
68
72
  const {setCallActive, callActive} = usePreCall();
@@ -70,27 +74,51 @@ const JoinWaitingRoomBtn = (props: PreCallJoinWaitingRoomBtnProps) => {
70
74
  const setUsername = useSetName();
71
75
  const {isJoinDataFetched, isInWaitingRoom} = useRoomInfo();
72
76
  const {awake, request} = useWakeLock();
73
- const waitingRoomButton =
74
- useString<PrecallJoinBtnTextInterface>(precallJoinBtnText);
77
+ const waitingRoomButton = useString<PrecallWaitingRoomJoinBtnTextInterface>(
78
+ precallWaitingRoomJoinBtnText,
79
+ );
75
80
  const {setRoomInfo} = useSetRoomInfo();
76
81
  const {request: requestToJoin} = useWaitingRoomAPI();
82
+ const [hasHostJoined, setHasHostJoined] = useState(false);
83
+ const {defaultContent} = useContent();
77
84
 
78
- const {activeUids} = useContent();
79
- const activeUidsRef = React.useRef(activeUids);
80
-
81
- React.useEffect(() => {
82
- activeUidsRef.current = activeUids;
83
- }, [activeUids]);
85
+ const localUid = useLocalUid();
86
+ const {dispatch} = useContext(DispatchContext);
84
87
 
85
88
  const [buttonText, setButtonText] = React.useState(
86
89
  waitingRoomButton({
87
- waitingRoom: true,
88
90
  ready: isInWaitingRoom,
91
+ isAutoRequest: $config.ENABLE_WAITING_ROOM_AUTO_REQUEST,
89
92
  }),
90
93
  );
91
94
 
92
- const {dispatch} = useContext(DispatchContext);
93
- const localUid = useLocalUid();
95
+ React.useEffect(() => {
96
+ if ($config.ENABLE_WAITING_ROOM_AUTO_REQUEST) {
97
+ const usersInCall = Object.keys(defaultContent).filter(
98
+ key =>
99
+ defaultContent[key].type === 'rtc' &&
100
+ defaultContent[key].offline === false &&
101
+ Number(key) !== localUid,
102
+ );
103
+ const hostUsersInCall = Object.keys(defaultContent).filter(
104
+ key =>
105
+ defaultContent[key].type === 'rtc' &&
106
+ defaultContent[key].offline === false &&
107
+ Number(key) !== localUid &&
108
+ defaultContent[key].isHost === 'true',
109
+ );
110
+
111
+ //console.log('host users in call ->', hostUsersInCall);
112
+
113
+ setHasHostJoined(hostUsersInCall.length > 0);
114
+
115
+ setButtonText(
116
+ hostUsersInCall.length > 0
117
+ ? waitingRoomUsersInCallText()
118
+ : waitingRoomUserNotJoinedText(),
119
+ );
120
+ }
121
+ }, [defaultContent]);
94
122
 
95
123
  const {
96
124
  data: {token, isHost},
@@ -242,15 +270,17 @@ const JoinWaitingRoomBtn = (props: PreCallJoinWaitingRoomBtnProps) => {
242
270
  useEffect(() => {
243
271
  setButtonText(
244
272
  waitingRoomButton({
245
- waitingRoom: true,
246
273
  ready: !isInWaitingRoom,
274
+ isAutoRequest: $config.ENABLE_WAITING_ROOM_AUTO_REQUEST,
247
275
  }),
248
276
  );
249
277
  }, [isInWaitingRoom]);
250
278
 
251
279
  const title = buttonText;
252
280
  const onPress = () => onSubmit();
253
- const disabled = isInWaitingRoom || username?.trim() === '';
281
+ const disabled = $config.ENABLE_WAITING_ROOM_AUTO_REQUEST
282
+ ? !hasHostJoined
283
+ : isInWaitingRoom || username?.trim() === '';
254
284
  return props?.render ? (
255
285
  props.render(onPress, title, disabled)
256
286
  ) : (
@@ -109,6 +109,7 @@ export interface RoomInfoContextInterface {
109
109
  };
110
110
  isSTTActive?: boolean;
111
111
  roomPreference?: joinRoomPreference;
112
+ loginToken?: string;
112
113
  }
113
114
 
114
115
  export const validateMeetingInfoData = (
@@ -161,6 +162,7 @@ export const RoomInfoDefaultValue: RoomInfoContextInterface = {
161
162
  disableParticipants: false,
162
163
  userRemovalTimeout: 5000,
163
164
  },
165
+ loginToken: '',
164
166
  };
165
167
 
166
168
  const RoomInfoContext = createContext(RoomInfoDefaultValue);
@@ -7,6 +7,10 @@ export interface PrecallJoinBtnTextInterface {
7
7
  role?: ClientRoleType;
8
8
  waitingRoom?: boolean;
9
9
  }
10
+ export interface PrecallWaitingRoomJoinBtnTextInterface {
11
+ ready: boolean;
12
+ isAutoRequest: boolean;
13
+ }
10
14
 
11
15
  export const permissionPopupHeading = `permissionPopupHeading`;
12
16
  export const permissionPopupSubHeading = `permissionPopupSubHeading`;
@@ -42,6 +46,7 @@ export const precallYouAreJoiningAsHeading = 'precallYouAreJoiningAsHeading';
42
46
  export const precallNameInputPlaceholderText =
43
47
  'precallNameInputPlaceholderText';
44
48
  export const precallJoinBtnText = 'precallJoinBtnText';
49
+ export const precallWaitingRoomJoinBtnText = 'precallWaitingRoomJoinBtnText';
45
50
  export const precallInputGettingName = 'precallInputGettingName';
46
51
 
47
52
  export const vbPanelHeading = 'vbPanelHeading';
@@ -78,6 +83,7 @@ export interface I18nPrecallScreenLabelsInterface {
78
83
  [precallYouAreJoiningAsHeading]?: I18nBaseType;
79
84
  [precallNameInputPlaceholderText]?: I18nBaseType;
80
85
  [precallJoinBtnText]?: I18nBaseType<PrecallJoinBtnTextInterface>;
86
+ [precallWaitingRoomJoinBtnText]?: I18nBaseType<PrecallWaitingRoomJoinBtnTextInterface>;
81
87
 
82
88
  [vbPanelHeading]?: I18nBaseType;
83
89
  [vbPanelInfo]?: I18nConditionalType;
@@ -129,6 +135,14 @@ export const PrecallScreenLabels: I18nPrecallScreenLabelsInterface = {
129
135
  [precallYouAreJoiningAsHeading]: 'You are joining',
130
136
  [precallNameInputPlaceholderText]: 'Enter Your Name',
131
137
  [precallInputGettingName]: 'Getting name...',
138
+ [precallWaitingRoomJoinBtnText]: ({ready, isAutoRequest}) => {
139
+ return isAutoRequest
140
+ ? 'Joining...'
141
+ : ready
142
+ ? 'Ask To Join'
143
+ : `Waiting for approval...`;
144
+ },
145
+
132
146
  [precallJoinBtnText]: ({waitingRoom, ready, role}) => {
133
147
  if (waitingRoom) {
134
148
  return ready ? 'Ask To Join' : `Waiting for approval...`;
@@ -245,7 +245,7 @@ export const chatUploadStatusInProgress = 'chatUploadStatusInProgress';
245
245
  export const chatUploadStatusFailure = 'chatUploadStatusFailure';
246
246
  export const chatUploadMaxLimit = 'chatUploadMaxLimit';
247
247
  export const chatErrorNoToken = 'chatErrorNoToken';
248
- export const chatErrorNotConnected = 'chatErrorNotConnected'
248
+ export const chatErrorNotConnected = 'chatErrorNotConnected';
249
249
 
250
250
  export const peoplePanelTurnoffAllCameraBtnText =
251
251
  'peoplePanelTurnoffAllCameraBtnText';
@@ -479,6 +479,8 @@ export const waitingRoomApprovalRejectionToastHeading =
479
479
  'waitingRoomApprovalRejectionToastHeading';
480
480
  export const waitingRoomApprovalRejectionToastSubHeading =
481
481
  'waitingRoomApprovalRejectionToastSubHeading';
482
+ export const waitingRoomHostNotJoined = 'waitingRoomHostNotJoined';
483
+ export const waitingRoomUsersInCall = 'waitingRoomUsersInCall';
482
484
 
483
485
  export const videoRoomRecordingText = `video${room}RecordingText` as const;
484
486
  export const videoRoomGoToActiveSpeakerText =
@@ -820,7 +822,9 @@ export interface I18nVideoCallScreenLabelsInterface {
820
822
  [waitingRoomApprovalRequiredSecondaryBtnText]?: I18nBaseType;
821
823
 
822
824
  [waitingRoomApprovalRejectionToastHeading]?: I18nBaseType;
825
+ [waitingRoomUsersInCall]?: I18nBaseType;
823
826
  [waitingRoomApprovalRejectionToastSubHeading]?: I18nBaseType;
827
+ [waitingRoomHostNotJoined]?: I18nBaseType;
824
828
 
825
829
  [videoRoomRecordingText]?: I18nBaseType;
826
830
  [videoRoomGoToActiveSpeakerText]?: I18nBaseType;
@@ -1067,8 +1071,10 @@ export const VideoCallScreenLabels: I18nVideoCallScreenLabelsInterface = {
1067
1071
  [chatPublicMessageDeletePopupText]: `Are you sure you want to delete this message for everyone in the public chat? `,
1068
1072
  [chatPrivateMessageDeletePopupText]: (name: string) =>
1069
1073
  `Are you sure you want to delete this message for ${name}`,
1070
- [chatErrorNoToken]:'Chat is currently unavailable. Please try rejoining the session or contact support',
1071
- [chatErrorNotConnected]:'Unable to connect to chat. Please try rejoining the session or contact support',
1074
+ [chatErrorNoToken]:
1075
+ 'Chat is currently unavailable. Please try rejoining the session or contact support',
1076
+ [chatErrorNotConnected]:
1077
+ 'Unable to connect to chat. Please try rejoining the session or contact support',
1072
1078
 
1073
1079
  [peoplePanelTurnoffAllCameraBtnText]: 'Turn off all cameras',
1074
1080
  [peoplePanelMuteAllMicBtnText]: 'Mute Everyone',
@@ -1284,6 +1290,8 @@ export const VideoCallScreenLabels: I18nVideoCallScreenLabelsInterface = {
1284
1290
  [waitingRoomApprovalRejectionToastHeading]: 'Approval Required',
1285
1291
  [waitingRoomApprovalRejectionToastSubHeading]:
1286
1292
  'Permission to enter the meeting was denied by the host',
1293
+ [waitingRoomHostNotJoined]: 'Waiting for Host, Please wait...',
1294
+ [waitingRoomUsersInCall]: `Meeting Started, Join Now !`,
1287
1295
 
1288
1296
  [videoRoomRecordingText]: 'REC',
1289
1297
 
@@ -23,6 +23,7 @@ import {
23
23
  isMobileUA,
24
24
  trimText,
25
25
  isValidReactComponent,
26
+ AuthErrorCodes,
26
27
  } from '../utils/common';
27
28
  import {useCustomization} from 'customization-implementation';
28
29
  import {useString} from '../utils/useString';
@@ -63,6 +64,7 @@ import {
63
64
  createRoomSuccessToastSubHeading,
64
65
  } from '../language/default-labels/createScreenLabels';
65
66
  import {LogSource, logger} from '../logger/AppBuilderLogger';
67
+ import SDKEvents from '../utils/SdkEvents';
66
68
 
67
69
  const Create = () => {
68
70
  const {CreateComponent} = useCustomization(data => {
@@ -212,7 +214,12 @@ const Create = () => {
212
214
  );
213
215
  setLoading(true);
214
216
  try {
215
- setRoomInfo(RoomInfoDefaultValue);
217
+ setRoomInfo(prevState => {
218
+ return {
219
+ ...RoomInfoDefaultValue,
220
+ loginToken: prevState?.loginToken,
221
+ };
222
+ });
216
223
  //@ts-ignore
217
224
  //isSeparateHostLink will be for internal usage since backend integration is not there
218
225
  await createRoomFun(roomTitle, enablePSTN, isSeparateHostLink);
@@ -230,6 +237,10 @@ const Create = () => {
230
237
  });
231
238
  showShareScreen();
232
239
  } catch (error) {
240
+ const errorCode = error?.networkError?.result?.error?.code;
241
+ if (AuthErrorCodes.indexOf(errorCode) !== -1 && isSDK()) {
242
+ SDKEvents.emit('unauthorized', error?.networkError?.result?.error);
243
+ }
233
244
  setLoading(false);
234
245
  logger.error(
235
246
  LogSource.Internals,
@@ -16,6 +16,7 @@ import {useHistory} from '../components/Router';
16
16
  import Logo from '../components/common/Logo';
17
17
  import Spacer from '../atoms/Spacer';
18
18
  import {
19
+ AuthErrorCodes,
19
20
  isMobileUA,
20
21
  isValidReactComponent,
21
22
  shouldAuthenticate,
@@ -49,6 +50,8 @@ import {
49
50
  joinRoomInputPlaceHolderText,
50
51
  } from '../language/default-labels/joinScreenLabels';
51
52
  import {LogSource, logger} from '../logger/AppBuilderLogger';
53
+ import isSDK from '../utils/isSDK';
54
+ import SDKEvents from '../utils/SdkEvents';
52
55
 
53
56
  const mobileOrTablet = isMobileOrTablet();
54
57
 
@@ -120,7 +123,12 @@ const Join = () => {
120
123
  );
121
124
  apiJoinCall(phrase)
122
125
  .then(() => {
123
- setRoomInfo(RoomInfoDefaultValue);
126
+ setRoomInfo(prevState => {
127
+ return {
128
+ ...RoomInfoDefaultValue,
129
+ loginToken: prevState?.loginToken,
130
+ };
131
+ });
124
132
  logger.log(
125
133
  LogSource.Internals,
126
134
  'JOIN_MEETING',
@@ -130,6 +138,10 @@ const Join = () => {
130
138
  history.push(phrase);
131
139
  })
132
140
  .catch(error => {
141
+ const errorCode = error?.networkError?.result?.error?.code;
142
+ if (AuthErrorCodes.indexOf(errorCode) !== -1 && isSDK()) {
143
+ SDKEvents.emit('unauthorized', error?.networkError?.result?.error);
144
+ }
133
145
  logger.error(
134
146
  LogSource.Internals,
135
147
  'JOIN_MEETING',
@@ -81,6 +81,7 @@ import {useCustomization} from 'customization-implementation';
81
81
  import {BeautyEffectProvider} from '../components/beauty-effect/useBeautyEffects';
82
82
  import {UserActionMenuProvider} from '../components/useUserActionMenu';
83
83
  import Toast from '../../react-native-toast-message';
84
+ import {AuthErrorCodes} from '../utils/common';
84
85
 
85
86
  enum RnEncryptionEnum {
86
87
  /**
@@ -245,7 +246,12 @@ const VideoCall: React.FC = () => {
245
246
  'VIDEO_CALL_ROOM',
246
247
  'Videocall unmounted',
247
248
  );
248
- setRoomInfo(RoomInfoDefaultValue);
249
+ setRoomInfo(prevState => {
250
+ return {
251
+ ...RoomInfoDefaultValue,
252
+ loginToken: prevState?.loginToken,
253
+ };
254
+ });
249
255
  if (awake) {
250
256
  release();
251
257
  }
@@ -263,6 +269,10 @@ const VideoCall: React.FC = () => {
263
269
  );
264
270
  })
265
271
  .catch(error => {
272
+ const errorCode = error?.networkError?.result?.error?.code;
273
+ if (AuthErrorCodes.indexOf(errorCode) !== -1 && isSDK()) {
274
+ SDKEvents.emit('unauthorized', error?.networkError?.result?.error);
275
+ }
266
276
  logger.error(
267
277
  LogSource.Internals,
268
278
  'JOIN_MEETING',
@@ -295,6 +305,7 @@ const VideoCall: React.FC = () => {
295
305
  setQueryComplete(false);
296
306
  setRoomInfo(roomInfo => {
297
307
  return {
308
+ ...roomInfo,
298
309
  isJoinDataFetched: true,
299
310
  data: {
300
311
  ...roomInfo.data,
@@ -315,6 +326,10 @@ const VideoCall: React.FC = () => {
315
326
  );
316
327
  })
317
328
  .catch(error => {
329
+ const errorCode = error?.networkError?.result?.error?.code;
330
+ if (AuthErrorCodes.indexOf(errorCode) !== -1 && isSDK()) {
331
+ SDKEvents.emit('unauthorized', error?.networkError?.result?.error);
332
+ }
318
333
  logger.error(
319
334
  LogSource.Internals,
320
335
  'JOIN_MEETING',
@@ -399,7 +414,7 @@ const VideoCall: React.FC = () => {
399
414
  // SdkJoinState.promise?.res();
400
415
  // }
401
416
  // },
402
- EndCall: () => {
417
+ EndCall: () => {
403
418
  clearState('join');
404
419
  setTimeout(() => {
405
420
  // TODO: These callbacks are being called twice
@@ -11,6 +11,7 @@ export enum LocalEventsEnum {
11
11
  CLEAR_WHITEBOARD = 'CLEAR_WHITEBOARD',
12
12
  USER_KICKED_OFF_BY_REMOTE_HOST = 'USER_KICKED_OFF_BY_REMOTE_HOST',
13
13
  AGENT_TRANSCRIPT_CHANGE = 'AGENT_TRANSCRIPT_CHANGE',
14
+ SDK_TOKEN_CHANGED = 'SDK_TOKEN_CHANGED',
14
15
  }
15
16
  const LocalEventEmitter = new EventEmitter();
16
17
  export default LocalEventEmitter;
@@ -50,6 +50,7 @@ export interface userEventsMapInterface {
50
50
  'did-token-expire': () => void;
51
51
  'token-refreshed': () => void;
52
52
  'rtc-user-removed': (uid: UidType, channel: string) => void;
53
+ unauthorized: (errorMessage) => void;
53
54
  }
54
55
 
55
56
  const SDKEvents = createNanoEvents<userEventsMapInterface>();
@@ -17,6 +17,8 @@ import {
17
17
  import Platform from '../subComponents/Platform';
18
18
  import * as ReactIs from 'react-is';
19
19
 
20
+ const AuthErrorCodes = [602, 603, 604];
21
+
20
22
  const trimText = (text: string, length: number = 25) => {
21
23
  if (!text) {
22
24
  return '';
@@ -412,4 +414,5 @@ export {
412
414
  CustomToolbarSorting,
413
415
  CustomToolbarMerge,
414
416
  MergeMoreButtonFields,
417
+ AuthErrorCodes,
415
418
  };
@@ -142,14 +142,17 @@ export default function useCreateRoom(): createRoomFun {
142
142
  roomId: roomInfo?.roomId,
143
143
  pstn: roomInfo?.pstn,
144
144
  });
145
- setRoomInfo({
146
- data: {
147
- isHost: true,
148
- isSeparateHostLink: isSeparateHostLink ? true : false,
149
- meetingTitle: roomTitle,
150
- roomId: roomInfo?.roomId,
151
- pstn: roomInfo?.pstn,
152
- },
145
+ setRoomInfo(prev => {
146
+ return {
147
+ ...prev,
148
+ data: {
149
+ isHost: true,
150
+ isSeparateHostLink: isSeparateHostLink ? true : false,
151
+ meetingTitle: roomTitle,
152
+ roomId: roomInfo?.roomId,
153
+ pstn: roomInfo?.pstn,
154
+ },
155
+ };
153
156
  });
154
157
  SDKEvents.emit(
155
158
  'create',