import { useCallback, useRef, useEffect, useState } from 'react'; import { Box, Drawer, IconButton, Avatar, Menu, MenuItem, Typography, CircularProgress, } from '@mui/material'; import MenuIcon from '@mui/icons-material/Menu'; import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; import DragIndicatorIcon from '@mui/icons-material/DragIndicator'; import AccountCircleIcon from '@mui/icons-material/AccountCircle'; import SettingsIcon from '@mui/icons-material/Settings'; import LogoutIcon from '@mui/icons-material/Logout'; import { useSessionStore } from '@/store/sessionStore'; import { useAgentStore } from '@/store/agentStore'; import { useLayoutStore } from '@/store/layoutStore'; import { useAuthStore } from '@/store/authStore'; import { useAgentEvents } from '@/hooks/useAgentEvents'; import SessionSidebar from '@/components/SessionSidebar/SessionSidebar'; import CodePanel from '@/components/CodePanel/CodePanel'; import ChatInput from '@/components/Chat/ChatInput'; import MessageList from '@/components/Chat/MessageList'; import { WelcomeScreen } from '@/components/Welcome'; import { SetupPrompt } from '@/components/Onboarding'; import { SettingsModal } from '@/components/Settings'; import type { Message } from '@/types/agent'; const API_BASE = import.meta.env.DEV ? 'http://127.0.0.1:7860' : ''; const DRAWER_WIDTH = 260; export default function AppLayout() { const { activeSessionId, sessions, isLoading: sessionsLoading, isLoaded: sessionsLoaded, loadSessions, createSession } = useSessionStore(); const { isConnected, isProcessing, messages, addMessage, clearMessages, setPlan, setPanelContent } = useAgentStore(); const { isLeftSidebarOpen, isRightPanelOpen, rightPanelWidth, setRightPanelWidth, toggleLeftSidebar, toggleRightPanel } = useLayoutStore(); const { user, isLoading: authLoading, getAuthHeaders, isAuthenticated, logout } = useAuthStore(); const [userMenuAnchor, setUserMenuAnchor] = useState(null); const [showSettings, setShowSettings] = useState(false); const [isCreatingSession, setIsCreatingSession] = useState(false); const isResizing = useRef(false); const startResizing = useCallback((e: React.MouseEvent) => { e.preventDefault(); isResizing.current = true; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', stopResizing); document.body.style.cursor = 'col-resize'; }, []); const stopResizing = useCallback(() => { isResizing.current = false; document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', stopResizing); document.body.style.cursor = 'default'; }, []); const handleMouseMove = useCallback((e: MouseEvent) => { if (!isResizing.current) return; const newWidth = window.innerWidth - e.clientX; const maxWidth = window.innerWidth * 0.8; const minWidth = 300; if (newWidth > minWidth && newWidth < maxWidth) { setRightPanelWidth(newWidth); } }, [setRightPanelWidth]); useEffect(() => { return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', stopResizing); }; }, [handleMouseMove, stopResizing]); // Load sessions when authenticated (only once) // Note: user is in deps to re-run when auth state changes (isAuthenticated is a stable function ref) useEffect(() => { if (isAuthenticated() && !sessionsLoading && !sessionsLoaded) { loadSessions(); } }, [user, sessionsLoading, sessionsLoaded, loadSessions, isAuthenticated]); useAgentEvents({ sessionId: activeSessionId, onReady: () => console.log('Agent ready'), onError: (error) => console.error('Agent error:', error), }); const handleSendMessage = useCallback( async (text: string) => { if (!activeSessionId || !text.trim()) return; // Bypass Anthropic key check as we use HF token const userMsg: Message = { id: `user_${Date.now()}`, role: 'user', content: text.trim(), timestamp: new Date().toISOString(), }; addMessage(userMsg); try { await fetch(`${API_BASE}/api/submit`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...getAuthHeaders(), }, body: JSON.stringify({ session_id: activeSessionId, text: text.trim(), }), }); } catch (e) { console.error('Send failed:', e); } }, [activeSessionId, addMessage, getAuthHeaders] ); const handleLogout = async () => { setUserMenuAnchor(null); await logout(); }; const handleOpenSettings = () => { setUserMenuAnchor(null); setShowSettings(true); }; const handleStartSession = useCallback(async () => { setIsCreatingSession(true); try { const sessionId = await createSession(); if (sessionId) { clearMessages(); setPlan([]); setPanelContent(null); } } catch (e) { console.error('Failed to create session:', e); } finally { setIsCreatingSession(false); } }, [createSession, clearMessages, setPlan, setPanelContent]); // Auto-create session when authenticated but no sessions (only after sessions have been loaded) const noSessionsAtAll = sessions.length === 0 && !activeSessionId; useEffect(() => { if (isAuthenticated() && sessionsLoaded && noSessionsAtAll && !isCreatingSession) { handleStartSession(); } }, [isAuthenticated, sessionsLoaded, noSessionsAtAll, isCreatingSession, handleStartSession]); // Show loading spinner while auth is loading if (authLoading) { return ( ); } // Show welcome screen for unauthenticated users if (!isAuthenticated()) { return ; } // Show loading while sessions are being fetched if (sessionsLoading) { return ( ); } // Bypassed setup prompt logic as we use HF token const needsApiKey = false; if (needsApiKey) { return ( {/* Minimal header for setup screens */} Hugging Face setUserMenuAnchor(e.currentTarget)} size="small" > {user?.picture ? ( ) : ( )} setUserMenuAnchor(null)} > {user?.name || user?.username} Settings Logout {/* Setup content */} setShowSettings(false)} /> ); } // Show loading while auto-creating first session if (isCreatingSession) { return ( ); } // Full app layout for authenticated users with active session return ( {/* Left Sidebar Drawer */} {/* Main Content Area */} {/* Top Header Bar */} {isLeftSidebarOpen ? : } Hugging Face {/* User Section */} setUserMenuAnchor(e.currentTarget)} size="small" > {user?.picture ? ( ) : ( )} setUserMenuAnchor(null)} > {user?.name || user?.username} Settings Logout {/* Chat Area */} {/* Resize Handle */} {isRightPanelOpen && ( )} {/* Right Panel Drawer */} {/* Settings Modal */} setShowSettings(false)} /> ); }