agora-appbuilder-core 4.0.35 → 4.1.0-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.
Files changed (75) hide show
  1. package/package.json +2 -2
  2. package/template/agora-rn-uikit/README.md +1 -40
  3. package/template/agora-rn-uikit/src/Contexts/PropsContext.tsx +1 -0
  4. package/template/agora-rn-uikit/src/Contexts/RtcContext.tsx +1 -0
  5. package/template/agora-rn-uikit/src/Reducer/Spotlight.ts +11 -0
  6. package/template/agora-rn-uikit/src/Reducer/index.ts +1 -0
  7. package/template/agora-rn-uikit/src/RtcConfigure.tsx +7 -0
  8. package/template/bridge/rtc/webNg/RtcEngine.ts +4 -1
  9. package/template/customization-api/app-state.ts +11 -7
  10. package/template/customization-api/{customize.ts → customize.tsx} +116 -11
  11. package/template/customization-api/sub-components.ts +4 -0
  12. package/template/customization-api/temp.ts +2 -0
  13. package/template/customization-api/typeDefinition.ts +2 -1
  14. package/template/customization-api/utils.ts +6 -1
  15. package/template/defaultConfig.js +4 -2
  16. package/template/global.d.ts +2 -0
  17. package/template/src/AppRoutes.tsx +15 -5
  18. package/template/src/ai-agent/components/AgentControls/AgentContext.tsx +163 -0
  19. package/template/src/ai-agent/components/AgentControls/LeaveCall.png +0 -0
  20. package/template/src/ai-agent/components/AgentControls/Vector.svg +3 -0
  21. package/template/src/ai-agent/components/AgentControls/const.ts +58 -0
  22. package/template/src/ai-agent/components/AgentControls/index.tsx +293 -0
  23. package/template/src/ai-agent/components/AudioVisualizer.tsx +91 -0
  24. package/template/src/ai-agent/components/Bottombar.tsx +91 -0
  25. package/template/src/ai-agent/components/CustomCreate.tsx +279 -0
  26. package/template/src/ai-agent/components/CustomCreateNative.tsx +265 -0
  27. package/template/src/ai-agent/components/CustomSidePanel.tsx +135 -0
  28. package/template/src/ai-agent/components/FallbackLogo.tsx +80 -0
  29. package/template/src/ai-agent/components/LocalAudioWave.tsx +171 -0
  30. package/template/src/ai-agent/components/agent-chat-panel/agent-chat-ui.tsx +82 -0
  31. package/template/src/ai-agent/components/icons.tsx +227 -0
  32. package/template/src/ai-agent/components/mobile/Bottombar.tsx +47 -0
  33. package/template/src/ai-agent/components/mobile/MobileLayoutComponent.tsx +106 -0
  34. package/template/src/ai-agent/components/mobile/Topbar.tsx +62 -0
  35. package/template/src/ai-agent/components/react-audio-visualize/LiveAudioVisualizer/LiveAudioVisualizer.tsx +173 -0
  36. package/template/src/ai-agent/components/react-audio-visualize/LiveAudioVisualizer/index.ts +1 -0
  37. package/template/src/ai-agent/components/react-audio-visualize/LiveAudioVisualizer/utils.ts +102 -0
  38. package/template/src/ai-agent/components/react-audio-visualize/index.ts +1 -0
  39. package/template/src/ai-agent/components/utils.ts +15 -0
  40. package/template/src/ai-agent/index.tsx +301 -0
  41. package/template/src/ai-agent/routes/CustomLoginRoute.tsx +25 -0
  42. package/template/src/ai-agent/routes/CustomValidateRoute.tsx +25 -0
  43. package/template/src/ai-agent/utils.ts +78 -0
  44. package/template/src/assets/font-styles.css +4 -0
  45. package/template/src/assets/fonts/icomoon.ttf +0 -0
  46. package/template/src/assets/selection.json +1 -1
  47. package/template/src/atoms/CustomIcon.tsx +1 -0
  48. package/template/src/atoms/ImageIcon.tsx +3 -0
  49. package/template/src/atoms/ToolbarItem.tsx +0 -2
  50. package/template/src/components/ChatContext.ts +7 -0
  51. package/template/src/components/Controls.tsx +6 -1
  52. package/template/src/components/ErrorBoundary.tsx +37 -0
  53. package/template/src/components/ErrorBoundaryFallback.tsx +44 -0
  54. package/template/src/components/RTMConfigure.tsx +25 -20
  55. package/template/src/components/participants/Participant.tsx +4 -0
  56. package/template/src/components/participants/UserActionMenuOptions.tsx +34 -1
  57. package/template/src/components/precall/PermissionHelper.tsx +11 -8
  58. package/template/src/language/default-labels/videoCallScreenLabels.ts +8 -0
  59. package/template/src/logger/AppBuilderLogger.tsx +4 -1
  60. package/template/src/pages/Create.tsx +11 -12
  61. package/template/src/pages/VideoCall.tsx +1 -0
  62. package/template/src/pages/video-call/ActionSheet.tsx +33 -29
  63. package/template/src/pages/video-call/SidePanelHeader.tsx +8 -3
  64. package/template/src/pages/video-call/SpotlightHighlighter.tsx +91 -0
  65. package/template/src/pages/video-call/VideoCallMobileView.tsx +17 -6
  66. package/template/src/pages/video-call/VideoCallScreen.tsx +0 -1
  67. package/template/src/pages/video-call/VideoRenderer.tsx +32 -4
  68. package/template/src/rtm-events/constants.ts +2 -0
  69. package/template/src/subComponents/ChatBubble.tsx +34 -15
  70. package/template/src/subComponents/FallbackLogo.tsx +3 -1
  71. package/template/src/subComponents/LocalAudioMute.tsx +20 -2
  72. package/template/src/utils/index.tsx +3 -4
  73. package/template/src/utils/useJoinRoom.ts +14 -0
  74. package/template/src/utils/useSpotlight.ts +31 -0
  75. package/template/tsconfig.json +23 -18
@@ -0,0 +1,58 @@
1
+ import {isMobileUA} from '../../../utils/common';
2
+
3
+ export const AI_AGENT_STATE = {
4
+ NOT_CONNECTED: 'Start Call',
5
+ REQUEST_SENT: isMobileUA() ? 'Start Call' : 'Requesting agent join..', // loading - reg
6
+ AWAITING_JOIN: isMobileUA() ? 'Start Call' : 'Agent will join shortly..', // loading
7
+ AGENT_CONNECTED: 'End Call',
8
+ AGENT_REQUEST_FAILED: 'Start Call',
9
+ AGENT_DISCONNECT_REQUEST: isMobileUA()
10
+ ? 'End Call'
11
+ : 'Disconnecting agent...', // loading - req
12
+ AGENT_DISCONNECT_FAILED: 'End Call',
13
+ AWAITING_LEAVE: 'Start Call', // loading
14
+ } as const;
15
+
16
+ export type AIAgentState = keyof typeof AI_AGENT_STATE;
17
+
18
+ export const AGENT_STATE_TO_API_ACTION = {
19
+ NOT_CONNECTED: 'start_agent',
20
+ AGENT_CONNECTED: 'stop_agent',
21
+ } as const;
22
+
23
+ export type AgentStateToApiAction = keyof typeof AGENT_STATE_TO_API_ACTION;
24
+
25
+ export const enum AgentState {
26
+ NOT_CONNECTED = 'NOT_CONNECTED',
27
+ REQUEST_SENT = 'REQUEST_SENT',
28
+ AWAITING_JOIN = 'AWAITING_JOIN',
29
+ AGENT_CONNECTED = 'AGENT_CONNECTED',
30
+ AGENT_REQUEST_FAILED = 'AGENT_REQUEST_FAILED',
31
+ AGENT_DISCONNECT_REQUEST = 'AGENT_DISCONNECT_REQUEST',
32
+ AGENT_DISCONNECT_FAILED = 'AGENT_DISCONNECT_FAILED',
33
+ AWAITING_LEAVE = 'AWAITING_LEAVE',
34
+ }
35
+
36
+ export const AI_AGENT_UID = 123456;
37
+
38
+ // export const AGENT_PROXY_URL = "http://localhost:3000/api/proxy"
39
+ // export const AGENT_PROXY_URL = "https://conversational-ai-agent-git-testing-cors-agoraio.vercel.app/api/proxy"
40
+ // export const AGENT_PROXY_URL = "https://nodejs-serverless-function-express-alpha-smoky.vercel.app/api/hello"
41
+ // export const AGENT_PROXY_URL = "https://conversational-ai-agent-git-setmute-agoraio.vercel.app/api/proxy"
42
+
43
+ // production router
44
+ export const AGENT_PROXY_URL =
45
+ 'https://agora-realtime-proxy-590d34bfeb04.herokuapp.com';
46
+ // production sso
47
+ export const AGORA_SSO_BASE = 'https://sso2.agora.io';
48
+
49
+ // staging router
50
+ // export const AGENT_PROXY_URL = "https://agora-realtime-proxy-dev-0af5192e12dd.herokuapp.com"
51
+ // staging sso
52
+ // export const AGORA_SSO_BASE = 'https://staging-sso.agora.io';
53
+
54
+ export const AGORA_SSO_LOGIN_PATH = '/api/v0/oauth/authorize';
55
+
56
+ export const AGORA_SSO_LOGOUT_PATH = '/api/v0/logout';
57
+
58
+ export const AGORA_SSO_CLIENT_ID = 'openai_agora';
@@ -0,0 +1,293 @@
1
+ import React, {useContext, useEffect} from 'react';
2
+ import {AI_AGENT_STATE, AgentState} from './const';
3
+ import {TouchableOpacity, Text, ActivityIndicator} from 'react-native';
4
+ import {AgentContext} from './AgentContext';
5
+ import {
6
+ ThemeConfig,
7
+ UidType,
8
+ useContent,
9
+ useEndCall,
10
+ useLocalUid,
11
+ useHistory,
12
+ useStorageContext,
13
+ Toast,
14
+ } from 'customization-api';
15
+ import {isMobileUA} from '../../../utils/common';
16
+ import {CallIcon, EndCall} from '../icons';
17
+
18
+ const connectToAIAgent = async (
19
+ agentAction: 'start' | 'stop',
20
+ channel_name: string,
21
+ localUid: UidType,
22
+ agentAuthToken: string,
23
+ ): Promise<{}> => {
24
+ // const apiUrl = '/api/proxy';
25
+ const apiUrl = $config.BACKEND_ENDPOINT + '/v1/convoai';
26
+ const requestBody = {
27
+ channel_name: channel_name,
28
+ uid: localUid, // user uid // localUid or 0
29
+ };
30
+ console.log({requestBody});
31
+ const headers: HeadersInit = {
32
+ 'Content-Type': 'application/json',
33
+ Authorization: `Bearer ${agentAuthToken}`,
34
+ };
35
+
36
+ try {
37
+ const response = await fetch(`${apiUrl}/${agentAction}`, {
38
+ method: 'POST',
39
+ headers: headers,
40
+ body: JSON.stringify(requestBody),
41
+ });
42
+
43
+ if (!response.ok) {
44
+ throw new Error(`HTTP error! status: ${response.status}`);
45
+ }
46
+
47
+ const data = await response.json();
48
+
49
+ // console.log({data}, "X-Client-ID start stop")
50
+ console.log(
51
+ `AI agent ${agentAction === 'start' ? 'connected' : 'disconnected'}`,
52
+ data,
53
+ );
54
+ if (agentAction === 'start') {
55
+ return data;
56
+ }
57
+ } catch (error) {
58
+ console.error(`Failed to ${agentAction} AI agent connection:`, error);
59
+ throw error;
60
+ }
61
+ };
62
+
63
+ export const AgentControl: React.FC<{channel_name: string}> = ({
64
+ channel_name,
65
+ }) => {
66
+ const {
67
+ agentConnectionState,
68
+ setAgentConnectionState,
69
+ agentAuthToken,
70
+ setAgentAuthToken,
71
+ agentUID,
72
+ setAgentUID,
73
+ } = useContext(AgentContext);
74
+ // console.log("X-Client-ID state", clientId)
75
+ // const { users } = useContext(UserContext)
76
+ const {activeUids: users} = useContent();
77
+ const endcall = useEndCall();
78
+ const history = useHistory();
79
+ const {store} = useStorageContext();
80
+ const localUid = useLocalUid();
81
+
82
+ // stop_agent API is successful, but agent has not yet left the RTC channel
83
+ const isAwaitingLeave = agentConnectionState === AgentState.AWAITING_LEAVE;
84
+
85
+ console.log(
86
+ 'Agent Control--',
87
+ {agentConnectionState},
88
+ {bth: AI_AGENT_STATE[agentConnectionState]},
89
+ );
90
+
91
+ const handleConnectionToggle = async () => {
92
+ try {
93
+ // connect to agent when agent is in not connected state or when earlier connect failed
94
+ if (
95
+ agentConnectionState === AgentState.NOT_CONNECTED ||
96
+ agentConnectionState === AgentState.AGENT_REQUEST_FAILED ||
97
+ isAwaitingLeave
98
+ ) {
99
+ try {
100
+ setAgentConnectionState(AgentState.REQUEST_SENT);
101
+ const data = await connectToAIAgent(
102
+ 'start',
103
+ channel_name,
104
+ localUid,
105
+ store.token,
106
+ );
107
+ // console.log("response X-Client-ID", newClientId, typeof newClientId)
108
+ // @ts-ignore
109
+ const {agent_uid = null} = data;
110
+
111
+ //setClientId(agent_id);
112
+ setAgentUID(agent_uid);
113
+
114
+ setAgentConnectionState(AgentState.AWAITING_JOIN);
115
+
116
+ Toast.show({
117
+ leadingIconName: 'tick-fill',
118
+ type: 'success',
119
+ text1: 'Agent requested to join',
120
+ text2: null,
121
+ visibilityTime: 3000,
122
+ primaryBtn: null,
123
+ secondaryBtn: null,
124
+ leadingIcon: null,
125
+ });
126
+ } catch (agentConnectError) {
127
+ setAgentConnectionState(AgentState.AGENT_REQUEST_FAILED);
128
+
129
+ if (agentConnectError.toString().indexOf('401') !== -1) {
130
+ Toast.show({
131
+ leadingIconName: 'alert',
132
+ type: 'error',
133
+ text1: 'Your session is expired. Please sign in to join call.',
134
+ text2: null,
135
+ visibilityTime: 5000,
136
+ primaryBtn: null,
137
+ secondaryBtn: null,
138
+ leadingIcon: null,
139
+ });
140
+ // window.location.href = '/create'
141
+ await endcall();
142
+ setAgentAuthToken(null);
143
+ return;
144
+ } else {
145
+ Toast.show({
146
+ leadingIconName: 'alert',
147
+ type: 'error',
148
+ text1: 'Uh oh! Agent failed to connect',
149
+ text2: null,
150
+ visibilityTime: 5000,
151
+ primaryBtn: null,
152
+ secondaryBtn: null,
153
+ leadingIcon: null,
154
+ });
155
+ }
156
+
157
+ throw agentConnectError;
158
+ }
159
+ }
160
+ // disconnect agent with agent is already connected or when earlier disconnect failed
161
+ if (
162
+ agentConnectionState === AgentState.AGENT_CONNECTED ||
163
+ agentConnectionState === AgentState.AGENT_DISCONNECT_FAILED
164
+ ) {
165
+ if (isMobileUA()) {
166
+ await endcall();
167
+ setAgentConnectionState(AgentState.NOT_CONNECTED);
168
+ setAgentAuthToken(null);
169
+ return; // check later
170
+ }
171
+ try {
172
+ setAgentConnectionState(AgentState.AGENT_DISCONNECT_REQUEST);
173
+ await connectToAIAgent('stop', channel_name, localUid, store.token);
174
+ setAgentConnectionState(AgentState.AWAITING_LEAVE);
175
+
176
+ Toast.show({
177
+ leadingIconName: 'tick-fill',
178
+ type: 'success',
179
+ text1: 'Agent disconnected',
180
+ text2: null,
181
+ visibilityTime: 3000,
182
+ primaryBtn: null,
183
+ secondaryBtn: null,
184
+ leadingIcon: null,
185
+ });
186
+ } catch (agentDisconnectError) {
187
+ setAgentConnectionState(AgentState.AGENT_DISCONNECT_FAILED);
188
+
189
+ Toast.show({
190
+ leadingIconName: 'alert',
191
+ type: 'error',
192
+ text1: 'Uh oh! Agent failed to disconnect',
193
+ text2: null,
194
+ visibilityTime: 5000,
195
+ primaryBtn: null,
196
+ secondaryBtn: null,
197
+ leadingIcon: null,
198
+ });
199
+
200
+ throw agentDisconnectError;
201
+ }
202
+ }
203
+ } catch (error) {
204
+ console.log(`Agent failed to connect/disconnect - ${error}`);
205
+ }
206
+ };
207
+
208
+ useEffect(() => {
209
+ console.log('agent contrl', {users});
210
+ // welcome agent
211
+ const aiAgentUID = users.filter(item => item === agentUID);
212
+ if (
213
+ aiAgentUID.length &&
214
+ agentConnectionState === AgentState.AWAITING_JOIN
215
+ ) {
216
+ setAgentConnectionState(AgentState.AGENT_CONNECTED);
217
+
218
+ Toast.show({
219
+ leadingIconName: 'tick-fill',
220
+ type: 'success',
221
+ text1: 'Say Hi!!',
222
+ text2: null,
223
+ visibilityTime: 3000,
224
+ primaryBtn: null,
225
+ secondaryBtn: null,
226
+ leadingIcon: null,
227
+ });
228
+ }
229
+ // when agent leaves, show left toast, and set agent to not connected state
230
+ if (
231
+ !aiAgentUID.length &&
232
+ agentConnectionState === AgentState.AWAITING_LEAVE
233
+ ) {
234
+ setAgentConnectionState(AgentState.NOT_CONNECTED);
235
+ }
236
+ }, [users]);
237
+
238
+ const isLoading =
239
+ agentConnectionState === AgentState.REQUEST_SENT ||
240
+ agentConnectionState === AgentState.AGENT_DISCONNECT_REQUEST ||
241
+ // || agentConnectionState === AgentState.AWAITING_LEAVE
242
+ agentConnectionState === AgentState.AWAITING_JOIN;
243
+
244
+ const isStartAgent =
245
+ agentConnectionState === AgentState.NOT_CONNECTED ||
246
+ agentConnectionState === AgentState.AGENT_REQUEST_FAILED ||
247
+ isAwaitingLeave;
248
+ const isEndAgent =
249
+ agentConnectionState === AgentState.AGENT_CONNECTED ||
250
+ agentConnectionState === AgentState.AGENT_DISCONNECT_FAILED;
251
+
252
+ const backgroundColorStyle = isMobileUA()
253
+ ? {backgroundColor: isEndAgent ? '#FF414D' : '#00C2FF', height: 72}
254
+ : {};
255
+ const fontcolorStyle = isMobileUA()
256
+ ? {color: '#FFF'}
257
+ : {color: isEndAgent ? '#FF414D' : '#00C2FF'};
258
+ return (
259
+ <TouchableOpacity
260
+ style={{
261
+ display: 'flex',
262
+ height: 48,
263
+ padding: 20,
264
+ justifyContent: 'space-between',
265
+ alignItems: 'center',
266
+ gap: 8,
267
+ borderRadius: 40,
268
+ borderWidth: isMobileUA() ? 0 : 1,
269
+ borderColor: isEndAgent ? '#FF414D' : '#00C2FF',
270
+ flexDirection: 'row',
271
+ ...backgroundColorStyle,
272
+ }}
273
+ onPress={handleConnectionToggle}
274
+ disabled={isLoading}>
275
+ {isLoading ? (
276
+ <ActivityIndicator
277
+ size="small"
278
+ color={isMobileUA() ? '#FFFFFF' : '#00C2FF'}
279
+ />
280
+ ) : isStartAgent ? (
281
+ <CallIcon fill={isMobileUA() ? '#FFFFFF' : '#00C2FF'} />
282
+ ) : (
283
+ <EndCall fill={isMobileUA() ? '#FFFFFF' : '#FF414D'} />
284
+ )}
285
+
286
+ <Text
287
+ style={{
288
+ fontFamily: ThemeConfig.FontFamily.sansPro,
289
+ ...fontcolorStyle,
290
+ }}>{`${AI_AGENT_STATE[agentConnectionState]}`}</Text>
291
+ </TouchableOpacity>
292
+ );
293
+ };
@@ -0,0 +1,91 @@
1
+ import React from 'react';
2
+ import {Text, View} from 'react-native';
3
+ import {LiveAudioVisualizer} from './react-audio-visualize';
4
+ import {DisconnectedIconDesktop, DisconnectedIconMobile} from './icons';
5
+ import {isMobileUA} from '../../utils/common';
6
+
7
+ export const DisconnectedView = ({isConnected}) => {
8
+ return (
9
+ <View
10
+ style={{
11
+ flex: 1,
12
+ backgroundColor: '#222',
13
+ display: 'flex',
14
+ alignItems: 'center',
15
+ justifyContent: 'center',
16
+ }}>
17
+ {/* big circle that covers the parent view */}
18
+ {isMobileUA() ? <DisconnectedIconMobile /> : <DisconnectedIconDesktop />}
19
+ <Text
20
+ style={{
21
+ color: '#B3B3B3',
22
+ fontSize: 20,
23
+ fontWeight: '400',
24
+ marginTop: 20,
25
+ }}>
26
+ {isConnected ? '' : 'Not Joined'}
27
+ </Text>
28
+ </View>
29
+ );
30
+ };
31
+
32
+ function createSilentAudioTrack(): MediaStreamTrack {
33
+ const audioContext = new (window.AudioContext ||
34
+ (window as any).webkitAudioContext)();
35
+ const oscillator = audioContext.createOscillator();
36
+ const dst = audioContext.createMediaStreamDestination();
37
+ oscillator.connect(dst);
38
+ oscillator.start();
39
+ const track = dst.stream.getAudioTracks()[0];
40
+ return Object.assign(track, {enabled: false});
41
+ }
42
+
43
+ const emptyAudioTrack = {
44
+ getMediaStreamTrack: () => createSilentAudioTrack(),
45
+ getVolumeLevel: () => 0,
46
+ setVolume: () => {},
47
+ setEnabled: () => {},
48
+ play: () => {},
49
+ stop: () => {},
50
+ setPlaybackDevice: () => Promise.resolve(),
51
+ getStats: () => ({
52
+ receiveBytes: 0,
53
+ receivePackets: 0,
54
+ receivePacketsLost: 0,
55
+ state: 'stopped',
56
+ }),
57
+ isPlaying: false,
58
+ processTrack: {
59
+ on: () => {},
60
+ off: () => {},
61
+ },
62
+ };
63
+
64
+ const AudioVisualizer = ({audioTrack}) => {
65
+ return (
66
+ <View
67
+ style={{
68
+ flex: 1,
69
+ backgroundColor: '#222',
70
+ display: 'flex',
71
+ alignItems: 'center',
72
+ justifyContent: 'center',
73
+ }}>
74
+ <LiveAudioVisualizer
75
+ audioTrack={audioTrack || emptyAudioTrack}
76
+ width={300}
77
+ height={400}
78
+ fftSize={32}
79
+ barWidth={10}
80
+ minDecibels={-60}
81
+ maxDecibels={-10}
82
+ gap={2}
83
+ backgroundColor="transparent"
84
+ barColor="#00C2FF"
85
+ smoothingTimeConstant={0.9}
86
+ />
87
+ </View>
88
+ );
89
+ };
90
+
91
+ export default AudioVisualizer;
@@ -0,0 +1,91 @@
1
+ import {
2
+ ToolbarPreset,
3
+ ToolbarComponents,
4
+ useSidePanel,
5
+ useRoomInfo,
6
+ } from 'customization-api';
7
+ import ThemeConfig from '../../theme';
8
+ import {isMobileUA} from '../../utils/common';
9
+ import React, {useEffect, useState} from 'react';
10
+ import {Text, View} from 'react-native';
11
+ import {AgentControl} from './AgentControls';
12
+ import {LogoIcon} from './icons';
13
+
14
+ export const LogoComponent = () => {
15
+ return (
16
+ <View
17
+ style={{
18
+ flexDirection: 'row',
19
+ alignItems: 'center',
20
+ justifyContent: 'center',
21
+ gap: 8,
22
+ marginRight: 20,
23
+ }}>
24
+ <LogoIcon />
25
+ <Text
26
+ style={{
27
+ color: '#C3C3C3',
28
+ textAlign: 'center',
29
+ fontSize: 18,
30
+ fontStyle: 'normal',
31
+ fontWeight: '600',
32
+ lineHeight: 18,
33
+ fontFamily: ThemeConfig.FontFamily.sansPro,
34
+ }}>
35
+ AI Builder Demo
36
+ </Text>
37
+ </View>
38
+ );
39
+ };
40
+
41
+ const Bottombar = () => {
42
+ const {MeetingTitleToolbarItem, ParticipantCountToolbarItem} =
43
+ ToolbarComponents;
44
+ const {setSidePanel} = useSidePanel();
45
+ const {data} = useRoomInfo();
46
+ const [clientId, setClientId] = useState<string | null>(null);
47
+ useEffect(() => {
48
+ !isMobileUA() && setSidePanel('agent-transcript-panel');
49
+ }, []);
50
+ return (
51
+ <ToolbarPreset
52
+ align="bottom"
53
+ items={{
54
+ layout: {hide: true},
55
+ invite: {hide: true},
56
+ more: {hide: true},
57
+ logo: {
58
+ align: 'start',
59
+ order: 0,
60
+ component: () => <LogoComponent />,
61
+ },
62
+ 'meeting-title': {
63
+ align: 'start',
64
+ component: MeetingTitleToolbarItem,
65
+ order: 1,
66
+ hide: true,
67
+ },
68
+ 'participant-count': {
69
+ align: 'start',
70
+ component: ParticipantCountToolbarItem,
71
+ order: 2,
72
+ hide: true,
73
+ },
74
+
75
+ 'connect-agent': {
76
+ align: 'end',
77
+ label: 'Agent',
78
+ component: () => <AgentControl channel_name={data.channel} />,
79
+ order: 3,
80
+ },
81
+ 'local-video': {hide: true},
82
+ screenshare: {hide: true},
83
+ recording: {hide: true},
84
+ 'local-audio': {align: 'end', order: 1},
85
+ 'end-call': {align: 'end', order: 2, hide: true},
86
+ }}
87
+ />
88
+ );
89
+ };
90
+
91
+ export default Bottombar;