@revrag-ai/embed-react-native 1.0.26 → 1.0.28
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/README.md +5 -0
- package/android/build.gradle +1 -0
- package/dist/commonjs/api/api.js.map +1 -1
- package/dist/commonjs/assets/fonts/PlaywriteNZBasic-ExtraLight.ttf +0 -0
- package/dist/commonjs/assets/fonts/PlaywriteNZBasic-Light.ttf +0 -0
- package/dist/commonjs/assets/fonts/PlaywriteNZBasic-Regular.ttf +0 -0
- package/dist/commonjs/assets/fonts/PlaywriteNZBasic-Thin.ttf +0 -0
- package/dist/commonjs/components/DynamicComponent/Typewriter.js +124 -0
- package/dist/commonjs/components/DynamicComponent/Typewriter.js.map +1 -0
- package/dist/commonjs/components/Embed/EmbedButton.js +362 -113
- package/dist/commonjs/components/Embed/EmbedButton.js.map +1 -1
- package/dist/commonjs/components/styles/EmbedButton.style.js +112 -158
- package/dist/commonjs/components/styles/EmbedButton.style.js.map +1 -1
- package/dist/commonjs/context/EmbedProvider.js +187 -14
- package/dist/commonjs/context/EmbedProvider.js.map +1 -1
- package/dist/commonjs/events/clickEventTracker.js +210 -0
- package/dist/commonjs/events/clickEventTracker.js.map +1 -0
- package/dist/commonjs/events/embed.event.js +11 -3
- package/dist/commonjs/events/embed.event.js.map +1 -1
- package/dist/commonjs/hooks/EmbedButton.animations.js +115 -15
- package/dist/commonjs/hooks/EmbedButton.animations.js.map +1 -1
- package/dist/commonjs/hooks/EmbedButton.helpers.js +11 -3
- package/dist/commonjs/hooks/EmbedButton.helpers.js.map +1 -1
- package/dist/commonjs/hooks/EmbedButton.hooks.js +17 -11
- package/dist/commonjs/hooks/EmbedButton.hooks.js.map +1 -1
- package/dist/commonjs/hooks/voiceagent.js +34 -12
- package/dist/commonjs/hooks/voiceagent.js.map +1 -1
- package/dist/commonjs/index.js +6 -2
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/utils/constant.js +6 -1
- package/dist/commonjs/utils/constant.js.map +1 -1
- package/dist/commonjs/utils/permision.js +42 -1
- package/dist/commonjs/utils/permision.js.map +1 -1
- package/dist/commonjs/utils/reanimated.helper.js +4 -0
- package/dist/commonjs/utils/reanimated.helper.js.map +1 -1
- package/dist/module/api/api.js.map +1 -1
- package/dist/module/assets/fonts/PlaywriteNZBasic-ExtraLight.ttf +0 -0
- package/dist/module/assets/fonts/PlaywriteNZBasic-Light.ttf +0 -0
- package/dist/module/assets/fonts/PlaywriteNZBasic-Regular.ttf +0 -0
- package/dist/module/assets/fonts/PlaywriteNZBasic-Thin.ttf +0 -0
- package/dist/module/components/DynamicComponent/Typewriter.js +122 -0
- package/dist/module/components/DynamicComponent/Typewriter.js.map +1 -0
- package/dist/module/components/Embed/EmbedButton.js +367 -118
- package/dist/module/components/Embed/EmbedButton.js.map +1 -1
- package/dist/module/components/styles/EmbedButton.style.js +111 -157
- package/dist/module/components/styles/EmbedButton.style.js.map +1 -1
- package/dist/module/context/EmbedProvider.js +187 -14
- package/dist/module/context/EmbedProvider.js.map +1 -1
- package/dist/module/events/clickEventTracker.js +199 -0
- package/dist/module/events/clickEventTracker.js.map +1 -0
- package/dist/module/events/embed.event.js +11 -3
- package/dist/module/events/embed.event.js.map +1 -1
- package/dist/module/hooks/EmbedButton.animations.js +109 -13
- package/dist/module/hooks/EmbedButton.animations.js.map +1 -1
- package/dist/module/hooks/EmbedButton.helpers.js +10 -2
- package/dist/module/hooks/EmbedButton.helpers.js.map +1 -1
- package/dist/module/hooks/EmbedButton.hooks.js +17 -11
- package/dist/module/hooks/EmbedButton.hooks.js.map +1 -1
- package/dist/module/hooks/voiceagent.js +34 -12
- package/dist/module/hooks/voiceagent.js.map +1 -1
- package/dist/module/index.js +8 -3
- package/dist/module/index.js.map +1 -1
- package/dist/module/utils/constant.js +6 -1
- package/dist/module/utils/constant.js.map +1 -1
- package/dist/module/utils/permision.js +42 -1
- package/dist/module/utils/permision.js.map +1 -1
- package/dist/module/utils/reanimated.helper.js +4 -0
- package/dist/module/utils/reanimated.helper.js.map +1 -1
- package/dist/typescript/src/api/api.d.ts.map +1 -1
- package/dist/typescript/src/components/DynamicComponent/Typewriter.d.ts +15 -0
- package/dist/typescript/src/components/DynamicComponent/Typewriter.d.ts.map +1 -0
- package/dist/typescript/src/components/Embed/EmbedButton.d.ts +7 -1
- package/dist/typescript/src/components/Embed/EmbedButton.d.ts.map +1 -1
- package/dist/typescript/src/components/styles/EmbedButton.style.d.ts +22 -114
- package/dist/typescript/src/components/styles/EmbedButton.style.d.ts.map +1 -1
- package/dist/typescript/src/context/EmbedProvider.d.ts +30 -0
- package/dist/typescript/src/context/EmbedProvider.d.ts.map +1 -1
- package/dist/typescript/src/events/__tests__/agent-event-emitter.test.d.ts +5 -0
- package/dist/typescript/src/events/__tests__/agent-event-emitter.test.d.ts.map +1 -0
- package/dist/typescript/src/events/__tests__/clickEventTracker.test.d.ts +5 -0
- package/dist/typescript/src/events/__tests__/clickEventTracker.test.d.ts.map +1 -0
- package/dist/typescript/src/events/__tests__/embed.event.test.d.ts +5 -0
- package/dist/typescript/src/events/__tests__/embed.event.test.d.ts.map +1 -0
- package/dist/typescript/src/events/__tests__/embed.validators.test.d.ts +5 -0
- package/dist/typescript/src/events/__tests__/embed.validators.test.d.ts.map +1 -0
- package/dist/typescript/src/events/clickEventTracker.d.ts +70 -0
- package/dist/typescript/src/events/clickEventTracker.d.ts.map +1 -0
- package/dist/typescript/src/events/embed.event.d.ts.map +1 -1
- package/dist/typescript/src/hooks/EmbedButton.animations.d.ts +29 -6
- package/dist/typescript/src/hooks/EmbedButton.animations.d.ts.map +1 -1
- package/dist/typescript/src/hooks/EmbedButton.helpers.d.ts +60 -8
- package/dist/typescript/src/hooks/EmbedButton.helpers.d.ts.map +1 -1
- package/dist/typescript/src/hooks/EmbedButton.hooks.d.ts +4 -2
- package/dist/typescript/src/hooks/EmbedButton.hooks.d.ts.map +1 -1
- package/dist/typescript/src/hooks/types/voiceAgent.types.d.ts +2 -0
- package/dist/typescript/src/hooks/types/voiceAgent.types.d.ts.map +1 -1
- package/dist/typescript/src/hooks/voiceagent.d.ts.map +1 -1
- package/dist/typescript/src/index.d.ts +8 -9
- package/dist/typescript/src/index.d.ts.map +1 -1
- package/dist/typescript/src/utils/constant.d.ts +1 -1
- package/dist/typescript/src/utils/constant.d.ts.map +1 -1
- package/dist/typescript/src/utils/permision.d.ts.map +1 -1
- package/dist/typescript/src/utils/reanimated.helper.d.ts +2 -0
- package/dist/typescript/src/utils/reanimated.helper.d.ts.map +1 -1
- package/package.json +3 -8
- package/react-native.config.js +1 -0
- package/revrag-ai-embed-react-native.podspec +1 -0
- package/src/assets/fonts/PlaywriteNZBasic-ExtraLight.ttf +0 -0
- package/src/assets/fonts/PlaywriteNZBasic-Light.ttf +0 -0
- package/src/assets/fonts/PlaywriteNZBasic-Regular.ttf +0 -0
- package/src/assets/fonts/PlaywriteNZBasic-Thin.ttf +0 -0
|
@@ -6,28 +6,30 @@
|
|
|
6
6
|
* Features: draggable, expandable, animated, with call controls and auto-trigger support.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { ConnectionState } from 'livekit-client';
|
|
9
10
|
import LottieView from 'lottie-react-native';
|
|
10
|
-
import { useEffect, useMemo, useRef, useState } from 'react';
|
|
11
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
11
12
|
import { Image, Text, TouchableOpacity, View } from 'react-native';
|
|
12
|
-
import { GestureDetector } from 'react-native-gesture-handler';
|
|
13
|
+
import { GestureDetector, ScrollView } from 'react-native-gesture-handler';
|
|
13
14
|
import LinearGradient from 'react-native-linear-gradient';
|
|
15
|
+
import Embed, { AgentEvent, EventKeys } from "../../events/embed.event.js";
|
|
14
16
|
import { useVoiceAgent } from "../../hooks/voiceagent.js";
|
|
15
17
|
import { createEmbedButtonStyles } from "../styles/EmbedButton.style.js";
|
|
16
18
|
import { WaveformVisualizer } from "./EmbedAudioWave.js";
|
|
17
19
|
import Voice from "./EmbedVoice.js";
|
|
18
|
-
import Embed, { AgentEvent } from "../../events/embed.event.js";
|
|
19
20
|
|
|
20
21
|
// Helpers and constants
|
|
21
|
-
import { BUTTON_DIMENSIONS, DEFAULT_GRADIENT_COLORS, formatDuration, ICON_URLS } from "../../hooks/EmbedButton.helpers.js";
|
|
22
|
+
import { BUTTON_DIMENSIONS, DEFAULT_GRADIENT_COLORS, FOOTER_SAFE_INSET, formatDuration, ICON_URLS } from "../../hooks/EmbedButton.helpers.js";
|
|
23
|
+
import Typewriter from "../DynamicComponent/Typewriter.js";
|
|
22
24
|
|
|
23
25
|
// Custom hooks
|
|
24
26
|
import { useCallDuration, useCallManagement, useConfigData, useInactivityBehavior } from "../../hooks/EmbedButton.hooks.js";
|
|
25
27
|
|
|
26
28
|
// Animation hooks
|
|
27
|
-
import { Animated, createPanGesture, useAnimationValues, useBreathingAnimation, useButtonAnimatedStyles, useButtonAnimations, usePopupAnimatedStyles } from "../../hooks/EmbedButton.animations.js";
|
|
29
|
+
import { Animated, createPanGesture, useAnimationValues, useBreathingAnimation, useButtonAnimatedStyles, useButtonAnimations, useExpandedContentAnimatedStyles, useInputSectionAnimations, usePopupAnimatedStyles } from "../../hooks/EmbedButton.animations.js";
|
|
28
30
|
|
|
29
31
|
// ==================== STYLES CONFIG ====================
|
|
30
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
32
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
31
33
|
const defaultStyles = {
|
|
32
34
|
buttonWidth: BUTTON_DIMENSIONS.WIDTH,
|
|
33
35
|
buttonHeight: BUTTON_DIMENSIONS.HEIGHT,
|
|
@@ -44,35 +46,57 @@ const defaultStyles = {
|
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
// ==================== MAIN COMPONENT ====================
|
|
49
|
+
|
|
47
50
|
/**
|
|
48
51
|
* EmbedButton - Main voice agent floating action button
|
|
49
52
|
*
|
|
50
53
|
* @example
|
|
51
54
|
* ```tsx
|
|
52
55
|
* <EmbedButton />
|
|
56
|
+
* <EmbedButton containerInset={{ right: 16, bottom: 24 }} />
|
|
53
57
|
* ```
|
|
54
58
|
*/
|
|
55
|
-
export function EmbedButton(
|
|
59
|
+
export function EmbedButton({
|
|
60
|
+
containerInset
|
|
61
|
+
} = {}) {
|
|
56
62
|
// ==================== VOICE AGENT STATE ====================
|
|
57
63
|
const {
|
|
58
|
-
initializeVoiceAgent,
|
|
59
64
|
tokenDetails,
|
|
60
|
-
endCall,
|
|
61
65
|
isLoading,
|
|
62
66
|
isMicMuted,
|
|
67
|
+
connectionState,
|
|
68
|
+
roomRef,
|
|
63
69
|
muteMic,
|
|
70
|
+
endCall,
|
|
64
71
|
unmuteMic,
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
clearDataReceived,
|
|
73
|
+
dataTranscription: livekitData,
|
|
74
|
+
initializeVoiceAgent
|
|
67
75
|
} = useVoiceAgent();
|
|
68
76
|
|
|
69
77
|
// ==================== LOCAL STATE ====================
|
|
70
78
|
const [isOpen, setIsOpen] = useState(false);
|
|
79
|
+
const [expandDirection, setExpandDirection] = useState('right');
|
|
71
80
|
const lottieRef = useRef(null);
|
|
72
|
-
const
|
|
81
|
+
const calculationScrollRef = useRef(null);
|
|
82
|
+
const userScrolledUpRef = useRef(false);
|
|
83
|
+
const SCROLL_END_THRESHOLD = 20;
|
|
84
|
+
|
|
85
|
+
// Reset "user scrolled up" when calculation content changes so new content auto-scrolls to bottom
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (livekitData?.type === 'calculation') {
|
|
88
|
+
userScrolledUpRef.current = false;
|
|
89
|
+
}
|
|
90
|
+
}, [livekitData?.list, livekitData?.type]);
|
|
73
91
|
|
|
74
92
|
// ==================== CUSTOM HOOKS ====================
|
|
75
93
|
const configData = useConfigData();
|
|
94
|
+
const styles = useMemo(() => createEmbedButtonStyles({
|
|
95
|
+
...defaultStyles,
|
|
96
|
+
...(containerInset != null && {
|
|
97
|
+
containerInset
|
|
98
|
+
})
|
|
99
|
+
}, configData), [configData, containerInset]);
|
|
76
100
|
const {
|
|
77
101
|
callDuration,
|
|
78
102
|
resetDuration
|
|
@@ -82,13 +106,14 @@ export function EmbedButton() {
|
|
|
82
106
|
handleEndCall,
|
|
83
107
|
handleMicToggle
|
|
84
108
|
} = useCallManagement({
|
|
85
|
-
|
|
109
|
+
isOpen,
|
|
110
|
+
isMicMuted,
|
|
86
111
|
endCall,
|
|
87
112
|
muteMic,
|
|
113
|
+
setIsOpen,
|
|
88
114
|
unmuteMic,
|
|
89
|
-
isMicMuted,
|
|
90
115
|
resetDuration,
|
|
91
|
-
|
|
116
|
+
initializeVoiceAgent
|
|
92
117
|
});
|
|
93
118
|
const {
|
|
94
119
|
isAutoOpen,
|
|
@@ -109,86 +134,175 @@ export function EmbedButton() {
|
|
|
109
134
|
start,
|
|
110
135
|
menuAnimation,
|
|
111
136
|
buttonWidth,
|
|
112
|
-
buttonScale
|
|
137
|
+
buttonScale,
|
|
138
|
+
buttonHeight,
|
|
139
|
+
inputSectionProgress
|
|
113
140
|
} = animationValues;
|
|
114
|
-
useButtonAnimations(isOpen, menuAnimation, buttonWidth);
|
|
141
|
+
useButtonAnimations(isOpen || livekitData && Object.keys(livekitData).length > 0, menuAnimation, buttonWidth, offset, start, expandDirection);
|
|
142
|
+
useInputSectionAnimations(livekitData && Object.keys(livekitData).length > 0, inputSectionProgress, buttonHeight);
|
|
115
143
|
useBreathingAnimation(isOpen, isAutoOpen, buttonScale);
|
|
116
|
-
const buttonAnimatedStyles = useButtonAnimatedStyles(isOpen, offset, buttonWidth, isPressed, buttonScale);
|
|
117
|
-
const
|
|
118
|
-
const
|
|
144
|
+
const buttonAnimatedStyles = useButtonAnimatedStyles(isOpen, offset, buttonWidth, isPressed, buttonScale, buttonHeight);
|
|
145
|
+
const expandedContentAnimatedStyles = useExpandedContentAnimatedStyles(menuAnimation);
|
|
146
|
+
const popupAnimatedStyles = usePopupAnimatedStyles(offset, isPressed, expandDirection);
|
|
147
|
+
const panGesture = useMemo(() => createPanGesture(isPressed, offset, start, isOpen, setIsAutoOpen, setExpandDirection), [isPressed, offset, start, isOpen, setIsAutoOpen]);
|
|
119
148
|
|
|
120
149
|
// ==================== AGENT EVENT EMISSIONS ====================
|
|
121
150
|
// Emit agent connected/disconnected events based on connection state
|
|
151
|
+
// Track previous connection state to properly detect disconnection
|
|
152
|
+
const prevConnectionStateRef = useRef(connectionState);
|
|
153
|
+
const lastEmittedEventRef = useRef(null);
|
|
122
154
|
useEffect(() => {
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
});
|
|
131
|
-
} else if (connectionState === 'disconnected' && callDuration > 0) {
|
|
132
|
-
// Only emit disconnected if we were previously connected
|
|
133
|
-
await Embed.event.emit(AgentEvent.AGENT_DISCONNECTED, {
|
|
134
|
-
timestamp: new Date().toISOString(),
|
|
135
|
-
metadata: {
|
|
136
|
-
callDuration
|
|
137
|
-
}
|
|
138
|
-
});
|
|
155
|
+
const prevState = prevConnectionStateRef.current;
|
|
156
|
+
|
|
157
|
+
// Check if we should emit connected event
|
|
158
|
+
if (connectionState === ConnectionState.Connected && prevState !== ConnectionState.Connected) {
|
|
159
|
+
// Prevent duplicate connected events
|
|
160
|
+
if (lastEmittedEventRef.current?.type === 'connected' && lastEmittedEventRef.current?.state === connectionState) {
|
|
161
|
+
return;
|
|
139
162
|
}
|
|
140
|
-
};
|
|
141
|
-
emitConnectionEvent().catch(error => {
|
|
142
|
-
console.error('Error emitting connection event:', error);
|
|
143
|
-
});
|
|
144
|
-
}, [connectionState]);
|
|
145
163
|
|
|
146
|
-
|
|
164
|
+
// Update refs IMMEDIATELY (synchronously) before async emit
|
|
165
|
+
prevConnectionStateRef.current = connectionState;
|
|
166
|
+
lastEmittedEventRef.current = {
|
|
167
|
+
type: 'connected',
|
|
168
|
+
state: connectionState
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Emit connected when entering Connected state
|
|
172
|
+
Embed.event.emit(AgentEvent.AGENT_CONNECTED, {
|
|
173
|
+
timestamp: new Date().toISOString(),
|
|
174
|
+
metadata: {
|
|
175
|
+
callDuration: 0
|
|
176
|
+
}
|
|
177
|
+
}).catch(error => {
|
|
178
|
+
console.error('Error emitting connected event:', error);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// Send analytics to backend when agent conversation has started (connected)
|
|
182
|
+
Embed.Event(EventKeys.ANALYTICS_DATA, {
|
|
183
|
+
event_name: 'agent_conversation_started'
|
|
184
|
+
}).catch(error => {
|
|
185
|
+
console.error('Error sending agent_conversation_started analytics:', error);
|
|
186
|
+
});
|
|
187
|
+
} else if (prevState === ConnectionState.Connected && connectionState !== ConnectionState.Connected) {
|
|
188
|
+
// Prevent duplicate disconnected events
|
|
189
|
+
if (lastEmittedEventRef.current?.type === 'disconnected') {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Update refs IMMEDIATELY (synchronously) before async emit
|
|
194
|
+
prevConnectionStateRef.current = connectionState;
|
|
195
|
+
lastEmittedEventRef.current = {
|
|
196
|
+
type: 'disconnected',
|
|
197
|
+
state: connectionState
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
// Emit disconnected when LEAVING Connected state (to Connecting or Disconnected)
|
|
201
|
+
// This catches the transition: Connected -> Connecting -> Disconnected
|
|
202
|
+
Embed.event.emit(AgentEvent.AGENT_DISCONNECTED, {
|
|
203
|
+
timestamp: new Date().toISOString(),
|
|
204
|
+
metadata: {
|
|
205
|
+
callDuration
|
|
206
|
+
}
|
|
207
|
+
}).catch(error => {
|
|
208
|
+
console.error('Error emitting disconnected event:', error);
|
|
209
|
+
});
|
|
210
|
+
} else {
|
|
211
|
+
// Update previous state for other transitions
|
|
212
|
+
prevConnectionStateRef.current = connectionState;
|
|
213
|
+
}
|
|
214
|
+
}, [connectionState, callDuration]); // Include callDuration to get fresh value
|
|
215
|
+
|
|
216
|
+
// Emit popup_message_visible when the popup is actually shown (isAutoOpen && !isOpen)
|
|
147
217
|
useEffect(() => {
|
|
218
|
+
const popupVisible = isAutoOpen && !isOpen;
|
|
219
|
+
if (!popupVisible) return;
|
|
148
220
|
const emitPopupEvent = async () => {
|
|
149
|
-
await Embed.
|
|
150
|
-
|
|
221
|
+
await Embed.Event(EventKeys.ANALYTICS_DATA, {
|
|
222
|
+
event_name: 'popup_message_visible',
|
|
151
223
|
metadata: {
|
|
152
|
-
|
|
224
|
+
value: true,
|
|
225
|
+
trigger: 'auto_inactivity'
|
|
153
226
|
}
|
|
154
227
|
});
|
|
155
228
|
};
|
|
156
229
|
emitPopupEvent().catch(error => {
|
|
157
230
|
console.error('Error emitting popup visibility event:', error);
|
|
158
231
|
});
|
|
159
|
-
}, [isAutoOpen]);
|
|
232
|
+
}, [isAutoOpen, isOpen]);
|
|
233
|
+
|
|
234
|
+
// Emit gen_tool_triggered analytics when livekit data is first received
|
|
235
|
+
const prevLivekitDataRef = useRef(false);
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
const isLivekitData = livekitData && Object.keys(livekitData).length > 0;
|
|
238
|
+
if (isLivekitData && !prevLivekitDataRef.current) {
|
|
239
|
+
prevLivekitDataRef.current = true;
|
|
240
|
+
Embed.Event(EventKeys.ANALYTICS_DATA, {
|
|
241
|
+
event_name: 'gen_tool_triggered',
|
|
242
|
+
metadata: {
|
|
243
|
+
source: 'livekit_data'
|
|
244
|
+
}
|
|
245
|
+
}).catch(error => {
|
|
246
|
+
console.error('Error sending gen_tool_triggered analytics:', error);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (!isLivekitData) {
|
|
250
|
+
prevLivekitDataRef.current = false;
|
|
251
|
+
}
|
|
252
|
+
}, [livekitData]);
|
|
160
253
|
|
|
161
254
|
// ==================== HANDLERS ====================
|
|
162
|
-
const handleButtonPress = () => {
|
|
163
|
-
|
|
255
|
+
const handleButtonPress = useCallback(async () => {
|
|
256
|
+
const eventName = isOpen ? 'agent_tap_to_close' : 'agent_tap_to_open';
|
|
257
|
+
try {
|
|
258
|
+
await Embed.Event(EventKeys.ANALYTICS_DATA, {
|
|
259
|
+
event_name: eventName,
|
|
260
|
+
metadata: {
|
|
261
|
+
button_pressed: 'button_pressed'
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
} catch (error) {
|
|
265
|
+
console.error('Error sending button_pressed analytics:', error);
|
|
266
|
+
}
|
|
267
|
+
setIsOpen(prev => !prev);
|
|
164
268
|
setIsAutoOpen(false);
|
|
165
|
-
};
|
|
166
|
-
const handleConnected = () => {
|
|
167
|
-
//
|
|
168
|
-
};
|
|
269
|
+
}, [isOpen, setIsAutoOpen]);
|
|
270
|
+
const handleConnected = useCallback(() => {
|
|
271
|
+
// Reserved for connection success side effects (e.g. analytics)
|
|
272
|
+
}, []);
|
|
169
273
|
|
|
170
274
|
// ==================== COMPUTED VALUES ====================
|
|
171
275
|
const lottieSource = useMemo(() => ({
|
|
172
|
-
uri: configData?.
|
|
173
|
-
}), [configData?.
|
|
276
|
+
uri: configData?.agentAvatar?.avatarUrl || ICON_URLS.AMPLIFY_ANIMATION
|
|
277
|
+
}), [configData?.agentAvatar?.avatarUrl]);
|
|
278
|
+
const micIconSource = useMemo(() => ({
|
|
279
|
+
uri: isMicMuted ? ICON_URLS.MIC_OFF : ICON_URLS.MIC_ON
|
|
280
|
+
}), [isMicMuted]);
|
|
174
281
|
const statusText = useMemo(() => {
|
|
175
282
|
if (isLoading) return 'Connecting...';
|
|
176
283
|
if (tokenDetails?.token) return formatDuration(callDuration);
|
|
177
|
-
return configData?.
|
|
178
|
-
}, [isLoading, tokenDetails?.token, callDuration, configData?.
|
|
179
|
-
const gradientColors = configData?.
|
|
180
|
-
const agentName = configData?.
|
|
181
|
-
const popupText = configData?.
|
|
182
|
-
const connectButtonText = configData?.
|
|
284
|
+
return configData?.agentTextContent?.agentType ?? 'Onboarding Agent';
|
|
285
|
+
}, [isLoading, tokenDetails?.token, callDuration, configData?.agentTextContent?.agentType]);
|
|
286
|
+
const gradientColors = configData?.colorPalette?.grad1 != null && configData?.colorPalette?.grad2 != null ? [configData.colorPalette.grad1, configData.colorPalette.grad2] : configData?.colorPalette?.grad1 != null && configData?.colorPalette?.grad2 != null ? [configData.colorPalette.grad1, configData.colorPalette.grad2] : DEFAULT_GRADIENT_COLORS;
|
|
287
|
+
const agentName = configData?.agentTextContent?.agentName ?? 'Your AI Agent';
|
|
288
|
+
const popupText = configData?.collapsedView?.tooltipMessage ?? 'Any doubts? Ask agent now';
|
|
289
|
+
const connectButtonText = configData?.agentTextContent?.buttonText ?? 'Start Call';
|
|
290
|
+
const isLivekitData = livekitData && Object.keys(livekitData).length > 0;
|
|
291
|
+
const gradientStyle = useMemo(() => [styles.linearGradient, isLivekitData ? styles.linearGradientColumn : isOpen ? styles.expandedLinearGradient : styles.collapsedLinearGradient], [isOpen, isLivekitData, styles]);
|
|
292
|
+
const isConnected = !!tokenDetails?.token;
|
|
183
293
|
|
|
184
294
|
// ==================== EARLY RETURNS ====================
|
|
185
295
|
if (!configData) return null;
|
|
186
296
|
|
|
187
297
|
// ==================== RENDER ====================
|
|
188
298
|
return /*#__PURE__*/_jsxs(View, {
|
|
189
|
-
style: styles.container,
|
|
299
|
+
style: [styles.container, isLivekitData && {
|
|
300
|
+
bottom: FOOTER_SAFE_INSET
|
|
301
|
+
}],
|
|
190
302
|
children: [isAutoOpen && !isOpen && /*#__PURE__*/_jsx(Animated.View, {
|
|
191
303
|
style: [popupAnimatedStyles, styles.popupContainer],
|
|
304
|
+
accessibilityLabel: popupText,
|
|
305
|
+
accessibilityLiveRegion: "polite",
|
|
192
306
|
children: /*#__PURE__*/_jsx(Text, {
|
|
193
307
|
style: styles.popupText,
|
|
194
308
|
children: popupText
|
|
@@ -197,7 +311,7 @@ export function EmbedButton() {
|
|
|
197
311
|
gesture: panGesture,
|
|
198
312
|
children: /*#__PURE__*/_jsx(Animated.View, {
|
|
199
313
|
pointerEvents: "auto",
|
|
200
|
-
style: [styles.button, buttonAnimatedStyles, styles.buttonContent],
|
|
314
|
+
style: [styles.button, buttonAnimatedStyles, isLivekitData ? styles.expandedButtonWhite : styles.buttonContent],
|
|
201
315
|
children: /*#__PURE__*/_jsxs(LinearGradient, {
|
|
202
316
|
colors: gradientColors,
|
|
203
317
|
start: {
|
|
@@ -208,7 +322,7 @@ export function EmbedButton() {
|
|
|
208
322
|
x: 1,
|
|
209
323
|
y: 0
|
|
210
324
|
},
|
|
211
|
-
style:
|
|
325
|
+
style: gradientStyle,
|
|
212
326
|
angle: 0,
|
|
213
327
|
angleCenter: {
|
|
214
328
|
x: 0.5,
|
|
@@ -220,67 +334,202 @@ export function EmbedButton() {
|
|
|
220
334
|
onDisconnected: handleEndCall,
|
|
221
335
|
roomRef: roomRef,
|
|
222
336
|
onConnected: handleConnected
|
|
223
|
-
}), /*#__PURE__*/
|
|
224
|
-
|
|
225
|
-
style: styles.pressable,
|
|
226
|
-
children: /*#__PURE__*/_jsx(LottieView, {
|
|
227
|
-
ref: lottieRef,
|
|
228
|
-
source: lottieSource,
|
|
229
|
-
autoPlay: true,
|
|
230
|
-
loop: true,
|
|
231
|
-
style: styles.iconImage,
|
|
232
|
-
enableMergePathsAndroidForKitKatAndAbove: true,
|
|
233
|
-
enableSafeModeAndroid: true
|
|
234
|
-
})
|
|
235
|
-
}), isOpen && /*#__PURE__*/_jsxs(View, {
|
|
236
|
-
style: styles.expandedContentContainer,
|
|
337
|
+
}), isLivekitData ? /*#__PURE__*/_jsxs(View, {
|
|
338
|
+
style: styles.expandedCallViewWrapper,
|
|
237
339
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
238
|
-
style: styles.
|
|
239
|
-
children: [/*#__PURE__*/_jsx(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
children:
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
roomRef: roomRef
|
|
250
|
-
})
|
|
251
|
-
}), /*#__PURE__*/_jsxs(View, {
|
|
252
|
-
style: styles.rightContentSection,
|
|
253
|
-
children: [!tokenDetails?.token && /*#__PURE__*/_jsx(View, {
|
|
254
|
-
style: styles.buttonContainer,
|
|
255
|
-
children: /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
256
|
-
onPress: handleStartCall,
|
|
257
|
-
style: styles.startCallButton,
|
|
258
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
259
|
-
style: styles.startCallText,
|
|
260
|
-
children: connectButtonText
|
|
261
|
-
})
|
|
340
|
+
style: styles.callContentArea,
|
|
341
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
342
|
+
onPress: () => clearDataReceived(),
|
|
343
|
+
style: styles.closeButton,
|
|
344
|
+
accessibilityLabel: "Close",
|
|
345
|
+
accessibilityRole: "button",
|
|
346
|
+
children: /*#__PURE__*/_jsx(Image, {
|
|
347
|
+
source: {
|
|
348
|
+
uri: ICON_URLS.CLOSE_ICON
|
|
349
|
+
},
|
|
350
|
+
style: styles.popupCloseIcon
|
|
262
351
|
})
|
|
263
|
-
}),
|
|
264
|
-
style: styles.
|
|
265
|
-
children:
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
352
|
+
}), livekitData.type === 'calculation' && /*#__PURE__*/_jsx(View, {
|
|
353
|
+
style: styles.callContentTextContainer,
|
|
354
|
+
children: /*#__PURE__*/_jsx(ScrollView, {
|
|
355
|
+
ref: calculationScrollRef,
|
|
356
|
+
style: styles.callContentScrollView,
|
|
357
|
+
contentContainerStyle: styles.callContentScrollViewContent,
|
|
358
|
+
showsVerticalScrollIndicator: true,
|
|
359
|
+
bounces: false,
|
|
360
|
+
nestedScrollEnabled: true,
|
|
361
|
+
onScroll: e => {
|
|
362
|
+
const {
|
|
363
|
+
contentOffset,
|
|
364
|
+
contentSize,
|
|
365
|
+
layoutMeasurement
|
|
366
|
+
} = e.nativeEvent;
|
|
367
|
+
const isAtBottom = contentOffset.y + layoutMeasurement.height >= contentSize.height - SCROLL_END_THRESHOLD;
|
|
368
|
+
userScrolledUpRef.current = !isAtBottom;
|
|
369
|
+
},
|
|
370
|
+
onContentSizeChange: () => {
|
|
371
|
+
if (!userScrolledUpRef.current) {
|
|
372
|
+
calculationScrollRef.current?.scrollToEnd({
|
|
373
|
+
animated: true
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
children: /*#__PURE__*/_jsx(Typewriter, {
|
|
378
|
+
lines: Array.isArray(livekitData.list) ? livekitData.list : [],
|
|
379
|
+
typingSpeed: 50,
|
|
380
|
+
textStyle: styles.callContentText,
|
|
381
|
+
showCursor: false,
|
|
382
|
+
onViewClose: flag => {
|
|
383
|
+
if (flag) {
|
|
384
|
+
clearDataReceived();
|
|
385
|
+
}
|
|
271
386
|
},
|
|
272
|
-
|
|
387
|
+
viewCloseDelay: livekitData.delay || 15000
|
|
273
388
|
})
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
389
|
+
})
|
|
390
|
+
})]
|
|
391
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
392
|
+
style: styles.expandedContentContainer,
|
|
393
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
394
|
+
onPress: handleButtonPress,
|
|
395
|
+
style: styles.pressable,
|
|
396
|
+
children: configData?.agentAvatar?.avatarType === 'image' ? /*#__PURE__*/_jsx(Image, {
|
|
397
|
+
source: {
|
|
398
|
+
uri: configData?.agentAvatar?.avatarUrl
|
|
399
|
+
},
|
|
400
|
+
style: styles.iconImage
|
|
401
|
+
}) : /*#__PURE__*/_jsx(LottieView, {
|
|
402
|
+
ref: lottieRef,
|
|
403
|
+
source: lottieSource,
|
|
404
|
+
autoPlay: true,
|
|
405
|
+
loop: true,
|
|
406
|
+
style: styles.iconImage,
|
|
407
|
+
enableMergePathsAndroidForKitKatAndAbove: true,
|
|
408
|
+
enableSafeModeAndroid: true
|
|
409
|
+
})
|
|
410
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
411
|
+
style: styles.leftContentSection,
|
|
412
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
413
|
+
style: [styles.agentNameText, styles.leftAlignedText],
|
|
414
|
+
numberOfLines: 1,
|
|
415
|
+
ellipsizeMode: "tail",
|
|
416
|
+
children: agentName
|
|
417
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
418
|
+
style: [styles.leftAlignedText, styles.statusText],
|
|
419
|
+
numberOfLines: 1,
|
|
420
|
+
ellipsizeMode: "tail",
|
|
421
|
+
children: statusText
|
|
422
|
+
})]
|
|
423
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
424
|
+
style: styles.middleContentSection,
|
|
425
|
+
children: /*#__PURE__*/_jsx(WaveformVisualizer, {
|
|
426
|
+
roomRef: roomRef
|
|
427
|
+
})
|
|
428
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
429
|
+
style: [styles.rightContentSection, styles.rightContentSectionPadded],
|
|
430
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
431
|
+
style: styles.buttonContainer,
|
|
432
|
+
children: !isConnected ? /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
433
|
+
onPress: handleStartCall,
|
|
434
|
+
style: styles.startCallButton,
|
|
435
|
+
accessibilityLabel: `Start call - ${connectButtonText}`,
|
|
436
|
+
accessibilityRole: "button",
|
|
437
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
438
|
+
style: styles.startCallText,
|
|
439
|
+
children: connectButtonText
|
|
440
|
+
})
|
|
441
|
+
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
442
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
443
|
+
style: styles.muteButton,
|
|
444
|
+
onPress: handleMicToggle,
|
|
445
|
+
accessibilityLabel: isMicMuted ? 'Unmute microphone' : 'Mute microphone',
|
|
446
|
+
accessibilityRole: "button",
|
|
447
|
+
children: /*#__PURE__*/_jsx(Image, {
|
|
448
|
+
source: micIconSource,
|
|
449
|
+
style: styles.buttonImage
|
|
450
|
+
})
|
|
451
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
452
|
+
onPress: handleEndCall,
|
|
453
|
+
style: styles.endCallButton,
|
|
454
|
+
accessibilityLabel: "End call",
|
|
455
|
+
accessibilityRole: "button",
|
|
456
|
+
children: /*#__PURE__*/_jsx(Image, {
|
|
457
|
+
source: {
|
|
458
|
+
uri: ICON_URLS.END_CALL
|
|
459
|
+
},
|
|
460
|
+
style: styles.buttonImage
|
|
461
|
+
})
|
|
462
|
+
})]
|
|
282
463
|
})
|
|
464
|
+
})
|
|
465
|
+
})]
|
|
466
|
+
})]
|
|
467
|
+
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
468
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
469
|
+
onPress: handleButtonPress,
|
|
470
|
+
style: styles.pressable,
|
|
471
|
+
children: /*#__PURE__*/_jsx(LottieView, {
|
|
472
|
+
ref: lottieRef,
|
|
473
|
+
source: lottieSource,
|
|
474
|
+
autoPlay: true,
|
|
475
|
+
loop: true,
|
|
476
|
+
style: styles.iconImage,
|
|
477
|
+
enableMergePathsAndroidForKitKatAndAbove: true,
|
|
478
|
+
enableSafeModeAndroid: true
|
|
479
|
+
})
|
|
480
|
+
}), isOpen && /*#__PURE__*/_jsxs(Animated.View, {
|
|
481
|
+
style: [styles.expandedContentContainer, expandedContentAnimatedStyles],
|
|
482
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
483
|
+
style: styles.leftContentSection,
|
|
484
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
485
|
+
style: [styles.agentNameText, styles.leftAlignedText],
|
|
486
|
+
children: agentName
|
|
487
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
488
|
+
style: [styles.leftAlignedText, styles.statusText],
|
|
489
|
+
children: statusText
|
|
283
490
|
})]
|
|
491
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
492
|
+
style: styles.middleContentSection,
|
|
493
|
+
children: /*#__PURE__*/_jsx(WaveformVisualizer, {
|
|
494
|
+
roomRef: roomRef
|
|
495
|
+
})
|
|
496
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
497
|
+
style: styles.rightContentSection,
|
|
498
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
499
|
+
style: styles.buttonContainer,
|
|
500
|
+
children: !isConnected ? /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
501
|
+
onPress: handleStartCall,
|
|
502
|
+
style: styles.startCallButton,
|
|
503
|
+
accessibilityLabel: `Start call - ${connectButtonText}`,
|
|
504
|
+
accessibilityRole: "button",
|
|
505
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
506
|
+
style: styles.startCallText,
|
|
507
|
+
children: connectButtonText
|
|
508
|
+
})
|
|
509
|
+
}) : /*#__PURE__*/_jsxs(_Fragment, {
|
|
510
|
+
children: [/*#__PURE__*/_jsx(TouchableOpacity, {
|
|
511
|
+
style: styles.muteButton,
|
|
512
|
+
onPress: handleMicToggle,
|
|
513
|
+
accessibilityLabel: isMicMuted ? 'Unmute microphone' : 'Mute microphone',
|
|
514
|
+
accessibilityRole: "button",
|
|
515
|
+
children: /*#__PURE__*/_jsx(Image, {
|
|
516
|
+
source: micIconSource,
|
|
517
|
+
style: styles.buttonImage
|
|
518
|
+
})
|
|
519
|
+
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
520
|
+
onPress: handleEndCall,
|
|
521
|
+
style: styles.endCallButton,
|
|
522
|
+
accessibilityLabel: "End call",
|
|
523
|
+
accessibilityRole: "button",
|
|
524
|
+
children: /*#__PURE__*/_jsx(Image, {
|
|
525
|
+
source: {
|
|
526
|
+
uri: ICON_URLS.END_CALL
|
|
527
|
+
},
|
|
528
|
+
style: styles.buttonImage
|
|
529
|
+
})
|
|
530
|
+
})]
|
|
531
|
+
})
|
|
532
|
+
})
|
|
284
533
|
})]
|
|
285
534
|
})]
|
|
286
535
|
})]
|