Spaces:
Running
Running
import React, { useState } from 'react'; | |
import { useLocation } from 'wouter'; | |
import { Settings, MessageSquare, Menu, Video, Image, AlertCircle } from 'lucide-react'; | |
import { Link } from 'wouter'; | |
import { Button } from '@/components/ui/button'; | |
import { Alert, AlertDescription } from '@/components/ui/alert'; | |
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '@/components/ui/tooltip'; | |
import ChatHistory from '@/components/ChatHistory'; | |
import ChatInputForm from '@/components/ChatInputForm'; | |
import ConversationSidebar from '@/components/ConversationSidebar'; | |
import ConnectionStatus from '@/components/ConnectionStatus'; | |
import UserSettingsModal from '@/components/UserSettingsModal'; | |
import { useAuth } from '@/hooks/use-auth'; | |
import { useChat } from '@/lib/hooks'; | |
// Main home page component | |
const Home: React.FC = () => { | |
const { user, logoutMutation } = useAuth(); | |
const [, navigate] = useLocation(); | |
const [sidebarOpen, setSidebarOpen] = useState(false); | |
const [errorVisible, setErrorVisible] = useState(true); | |
const [settingsOpen, setSettingsOpen] = useState(false); | |
const { | |
messages, | |
isLoading, | |
error, | |
isConnected, | |
currentModel, | |
sendMessage, | |
conversationId, | |
setConversationId | |
} = useChat("default"); | |
// Handle creating a new conversation | |
const handleNewConversation = async () => { | |
try { | |
// Create a new conversation on the server | |
const response = await fetch('/api/conversations', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
title: '' // Let the server generate a title | |
}), | |
}); | |
if (!response.ok) { | |
throw new Error('Failed to create new conversation'); | |
} | |
const newConversation = await response.json(); | |
setConversationId(newConversation.id); | |
// The useEffect in useChat will automatically load messages | |
setSidebarOpen(false); | |
} catch (error) { | |
console.error('Error creating new conversation:', error); | |
} | |
}; | |
// Handle selecting a conversation | |
const handleSelectConversation = (id: string) => { | |
if (id === conversationId) { | |
// Already selected, just close the sidebar | |
setSidebarOpen(false); | |
return; | |
} | |
// Set the conversation ID, which will trigger loading the messages | |
setConversationId(id); | |
// Close sidebar on mobile after selection | |
setSidebarOpen(false); | |
}; | |
// Handle sign in button click | |
const handleSignIn = () => { | |
navigate('/auth'); | |
}; | |
return ( | |
<div className="flex flex-col h-screen"> | |
{/* Conversation Sidebar */} | |
<ConversationSidebar | |
isOpen={sidebarOpen} | |
onClose={() => setSidebarOpen(false)} | |
selectedConversationId={conversationId} | |
onSelectConversation={handleSelectConversation} | |
onNewConversation={handleNewConversation} | |
/> | |
{/* Header */} | |
<header className="bg-white border-b border-gray-200 py-4 px-6 shadow-sm"> | |
<div className="max-w-5xl mx-auto flex items-center justify-between"> | |
<div className="flex items-center"> | |
<Button | |
variant="ghost" | |
size="icon" | |
onClick={() => setSidebarOpen(true)} | |
className="mr-2 md:hidden" | |
> | |
<Menu className="h-5 w-5" /> | |
</Button> | |
<Button | |
variant="outline" | |
size="sm" | |
onClick={() => setSidebarOpen(true)} | |
className="mr-4 hidden md:flex" | |
> | |
<MessageSquare className="h-4 w-4 mr-2" /> | |
<span>Conversations</span> | |
</Button> | |
<h1 className="font-bold text-2xl text-primary">AI Chat Assistant</h1> | |
</div> | |
<div className="flex items-center space-x-3"> | |
<ConnectionStatus isConnected={isConnected} currentModel={currentModel} /> | |
<TooltipProvider> | |
<Tooltip> | |
<TooltipTrigger asChild> | |
<Link href="/image-generator"> | |
<Button variant="outline" size="sm" className="flex items-center"> | |
<Image className="h-4 w-4 mr-2" /> | |
<span>Image Generator</span> | |
</Button> | |
</Link> | |
</TooltipTrigger> | |
<TooltipContent> | |
<p>Create AI-generated images</p> | |
</TooltipContent> | |
</Tooltip> | |
</TooltipProvider> | |
<TooltipProvider> | |
<Tooltip> | |
<TooltipTrigger asChild> | |
<Link href="/video-generator"> | |
<Button variant="outline" size="sm" className="flex items-center"> | |
<Video className="h-4 w-4 mr-2" /> | |
<span>Video Generator</span> | |
</Button> | |
</Link> | |
</TooltipTrigger> | |
<TooltipContent> | |
<p>Create AI-generated videos</p> | |
</TooltipContent> | |
</Tooltip> | |
</TooltipProvider> | |
<TooltipProvider> | |
<Tooltip> | |
<TooltipTrigger asChild> | |
<button | |
className="p-2 rounded-full hover:bg-gray-100 text-gray-600" | |
aria-label="Settings" | |
onClick={() => setSettingsOpen(true)} | |
> | |
<Settings className="h-5 w-5" /> | |
</button> | |
</TooltipTrigger> | |
<TooltipContent> | |
<p>Settings</p> | |
</TooltipContent> | |
</Tooltip> | |
</TooltipProvider> | |
</div> | |
</div> | |
</header> | |
{/* Main chat container */} | |
<main className="flex-1 overflow-hidden max-w-5xl w-full mx-auto px-4 sm:px-6 py-4"> | |
{/* Error message */} | |
{error && errorVisible && ( | |
<Alert variant="destructive" className="mb-4 shadow-lg border-l-4 border-red-600"> | |
<AlertCircle className="h-4 w-4 mr-2" /> | |
<AlertDescription className="flex justify-between items-center"> | |
<div className="flex-1"> | |
<p className="font-medium text-red-800">{error}</p> | |
{error.includes('API quota') && ( | |
<p className="text-sm mt-1 text-gray-700"> | |
This usually means the OpenAI API key has reached its limit or doesn't have a payment method associated with it. | |
The system will attempt to use the Qwen fallback model. | |
</p> | |
)} | |
</div> | |
<button | |
onClick={() => setErrorVisible(false)} | |
className="ml-2 text-foreground hover:text-foreground/80 p-1 flex-shrink-0" | |
aria-label="Dismiss" | |
> | |
<svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> | |
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /> | |
</svg> | |
</button> | |
</AlertDescription> | |
</Alert> | |
)} | |
{/* Chat history */} | |
<ChatHistory | |
messages={messages} | |
isLoading={isLoading} | |
currentModel={currentModel} | |
/> | |
</main> | |
{/* Input area */} | |
<footer className="bg-white border-t border-gray-200 py-4 px-4 sm:px-6 shadow-inner"> | |
<div className="max-w-5xl mx-auto"> | |
<ChatInputForm | |
onSendMessage={sendMessage} | |
isLoading={isLoading} | |
/> | |
</div> | |
</footer> | |
{/* User Settings Modal */} | |
{user && ( | |
<UserSettingsModal | |
isOpen={settingsOpen} | |
onClose={() => setSettingsOpen(false)} | |
/> | |
)} | |
</div> | |
); | |
}; | |
export default Home; |