'use client'; import { useState, useEffect } from 'react'; import { flushSync } from 'react-dom'; import Header from '@/components/Header'; import ChatInterface from '@/components/ChatInterface'; import CodeEditor from '@/components/CodeEditor'; import ControlPanel from '@/components/ControlPanel'; import { apiClient } from '@/lib/api'; import { isAuthenticated as checkIsAuthenticated, getStoredToken } from '@/lib/auth'; import type { Message, Language, CodeGenerationRequest } from '@/types'; export default function Home() { const [messages, setMessages] = useState([]); const [generatedCode, setGeneratedCode] = useState(''); const [selectedLanguage, setSelectedLanguage] = useState('html'); const [selectedModel, setSelectedModel] = useState('gemini-3.0-pro'); const [isGenerating, setIsGenerating] = useState(false); const [isAuthenticated, setIsAuthenticated] = useState(false); // Mobile view state: 'chat', 'editor', or 'settings' const [mobileView, setMobileView] = useState<'chat' | 'editor' | 'settings'>('editor'); useEffect(() => { checkAuth(); // Check auth status every second to catch OAuth redirects const interval = setInterval(checkAuth, 1000); return () => clearInterval(interval); }, []); const checkAuth = () => { const authenticated = checkIsAuthenticated(); setIsAuthenticated(authenticated); // Make sure API client has the token if (authenticated) { const token = getStoredToken(); if (token) { apiClient.setToken(token); } } }; const handleSendMessage = async (message: string) => { if (!isAuthenticated) { alert('Please sign in with HuggingFace first! Click the "Sign in with Hugging Face" button in the header.'); return; } // If there's existing code, include it in the message context for modifications let enhancedMessage = message; const hasRealCode = generatedCode && generatedCode.length > 50 && !generatedCode.includes('Your generated code will appear here'); if (hasRealCode) { enhancedMessage = `I have existing code in the editor. Please modify it based on my request.\n\nCurrent code:\n\`\`\`${selectedLanguage}\n${generatedCode}\n\`\`\`\n\nMy request: ${message}`; } // Add user message (show original message to user, but send enhanced to API) const userMessage: Message = { role: 'user', content: message, timestamp: new Date().toISOString(), }; setMessages((prev) => [...prev, userMessage]); setIsGenerating(true); // Clear previous code to show streaming from start setGeneratedCode(''); // Prepare request with enhanced query that includes current code const request: CodeGenerationRequest = { query: enhancedMessage, language: selectedLanguage, model_id: selectedModel, provider: 'auto', history: messages.map((m) => [m.role, m.content]), agent_mode: false, }; const assistantMessage: Message = { role: 'assistant', content: '⏳ Generating code...', timestamp: new Date().toISOString(), }; // Add placeholder for assistant message setMessages((prev) => [...prev, assistantMessage]); // Stream the response try { apiClient.generateCodeStream( request, // onChunk - Update code editor in real-time with immediate flush (chunk: string) => { console.log('[Stream] Received chunk:', chunk.substring(0, 50), '... (length:', chunk.length, ')'); // Use flushSync to force immediate DOM update without React batching flushSync(() => { setGeneratedCode((prevCode) => { const newCode = prevCode + chunk; console.log('[Stream] Total code length:', newCode.length); return newCode; }); }); }, // onComplete (code: string) => { setGeneratedCode(code); setIsGenerating(false); // Update final message - just show success, not the code setMessages((prev) => { const newMessages = [...prev]; newMessages[newMessages.length - 1] = { ...assistantMessage, content: '✅ Code generated successfully! Check the editor →', }; return newMessages; }); }, // onError (error: string) => { setIsGenerating(false); setMessages((prev) => { const newMessages = [...prev]; newMessages[newMessages.length - 1] = { ...assistantMessage, content: `❌ Error: ${error}`, }; return newMessages; }); } ); } catch (error) { setIsGenerating(false); setMessages((prev) => { const newMessages = [...prev]; newMessages[newMessages.length - 1] = { ...assistantMessage, content: `❌ Error: ${error instanceof Error ? error.message : 'Unknown error'}`, }; return newMessages; }); } }; const handleDeploy = async () => { if (!generatedCode) { alert('No code to deploy! Generate some code first.'); return; } const spaceName = prompt('Enter HuggingFace Space name (or leave empty for auto-generated):'); if (spaceName === null) return; // User cancelled try { const response = await apiClient.deploy({ code: generatedCode, space_name: spaceName || undefined, language: selectedLanguage, }); if (response.success) { // Open the space URL in a new tab window.open(response.space_url, '_blank'); // Show success message const isDev = response.dev_mode; const message = isDev ? '🚀 Opening HuggingFace Spaces creation page...\nPlease complete the space setup in the new tab.' : `✅ Deployed successfully!\n\nOpening: ${response.space_url}`; alert(message); } else { alert(`Deployment failed: ${response.message}`); } } catch (error) { alert(`Deployment error: ${error instanceof Error ? error.message : 'Unknown error'}`); } }; const handleClear = () => { if (confirm('Clear all messages and code?')) { setMessages([]); setGeneratedCode(''); } }; const handleImport = (code: string, language: Language) => { setGeneratedCode(code); setSelectedLanguage(language); // Add messages that include the imported code so LLM can see it const userMessage: Message = { role: 'user', content: `I imported a ${language} project. Here's the code that was imported.`, timestamp: new Date().toISOString(), }; const assistantMessage: Message = { role: 'assistant', content: `✅ I've loaded your ${language} project. The code is now in the editor. You can ask me to:\n\n• Modify existing features\n• Add new functionality\n• Fix bugs or improve code\n• Explain how it works\n• Deploy it to HuggingFace Spaces\n\nWhat would you like me to help you with?`, timestamp: new Date().toISOString(), }; setMessages((prev) => [...prev, userMessage, assistantMessage]); // Switch to editor view on mobile setMobileView('editor'); }; return (
{/* VS Code layout with Apple styling - Responsive */}
{/* Left Sidebar - Chat Panel (Hidden on mobile, shown when mobileView='chat') */}
{/* Panel Header */}
Chat
{/* Chat Panel */}
{/* Center - Editor Group (Always visible on mobile when mobileView='editor', always visible on desktop) */}
{/* Tab Bar */}
{selectedLanguage}.{ selectedLanguage === 'html' ? 'html' : selectedLanguage === 'gradio' || selectedLanguage === 'streamlit' ? 'py' : selectedLanguage === 'transformers.js' ? 'js' : selectedLanguage === 'comfyui' ? 'json' : 'jsx' }
{isGenerating && (
Generating...
)} {selectedLanguage.toUpperCase()}
{/* Editor */}
{/* Right Sidebar - Configuration Panel (Hidden on mobile, shown when mobileView='settings') */}
{/* Mobile Bottom Navigation (visible only on mobile) */} {/* Status Bar - Apple style (hidden on mobile) */}
); }