import React, { useState, useEffect } from 'react'; import { ChatPanel } from './components/ChatPanel'; import { VoiceControls } from './components/VoiceControls'; import { AvatarView } from './components/AvatarView'; import { Captions } from './components/Captions'; import { Settings } from './components/Settings'; import { useSession } from './hooks/useSession'; import { useConversation } from './hooks/useConversation'; import { useWebRTC } from './hooks/useWebRTC'; import { PostMessageAPI } from './services/postMessage'; import { WidgetConfig } from './types'; import './App.css'; // Default config - can be overridden via postMessage or data attributes const getConfig = (): WidgetConfig => { const script = document.querySelector('script[data-tenant-id]'); if (script) { return { tenantId: script.getAttribute('data-tenant-id') || 'default', userId: script.getAttribute('data-user-id') || undefined, authToken: script.getAttribute('data-auth-token') || undefined, apiUrl: script.getAttribute('data-api-url') || undefined, avatarEnabled: script.getAttribute('data-avatar-enabled') !== 'false', }; } return { tenantId: 'default', avatarEnabled: true, }; }; export const App: React.FC = () => { const [config] = useState(getConfig()); const [showSettings, setShowSettings] = useState(false); const [showCaptions, setShowCaptions] = useState(true); const [avatarEnabled, setAvatarEnabled] = useState(config.avatarEnabled ?? true); const [volume, setVolume] = useState(100); const [isMuted, setIsMuted] = useState(false); const [captionText, setCaptionText] = useState(''); const postMessage = new PostMessageAPI(); const { session, loading, error, createSession, endSession } = useSession(config); const { messages, isListening, isSpeaking, setIsListening, setIsSpeaking, sendMessage, receiveMessage, } = useConversation(); const { isConnected, remoteStream, initializeWebRTC, closeWebRTC } = useWebRTC(); // Initialize session on mount useEffect(() => { createSession(); }, []); // Initialize WebRTC when session is ready useEffect(() => { if (session && !isConnected) { initializeWebRTC(); } }, [session, isConnected]); // Cleanup on unmount useEffect(() => { return () => { endSession(); closeWebRTC(); }; }, []); // Send ready event useEffect(() => { if (session) { postMessage.ready(); postMessage.sessionStarted(session.sessionId); } }, [session]); // Listen for messages from host useEffect(() => { const unsubscribe = postMessage.on('open', () => { // Widget opened }); return unsubscribe; }, []); const handleSendMessage = (message: string) => { sendMessage(message); // TODO: Send to backend via WebRTC or WebSocket }; const handlePushToTalk = () => { setIsListening(true); // TODO: Start audio capture }; const handleHandsFree = () => { setIsListening(true); // TODO: Enable continuous listening }; const handleToggleMute = () => { setIsMuted(!isMuted); // TODO: Mute/unmute audio }; if (loading) { return (
Loading...
); } if (error) { return (
Error: {error}
); } return (

Virtual Banker

{avatarEnabled && (
setAvatarEnabled(false)} />
)}
setShowCaptions(!showCaptions)} />
{showSettings && ( setShowCaptions(!showCaptions)} avatarEnabled={avatarEnabled} onToggleAvatar={() => setAvatarEnabled(!avatarEnabled)} onClose={() => setShowSettings(false)} /> )}
); };