Spaces:
Sleeping
Sleeping
| import React, { useState, useEffect } from 'react'; | |
| import { Toaster } from 'react-hot-toast'; | |
| import ChatInterface from './components/ChatInterface'; | |
| import Sidebar from './components/Sidebar'; | |
| import WelcomeScreen from './components/WelcomeScreen'; | |
| import { SunIcon, MoonIcon, HomeIcon } from '@heroicons/react/24/outline'; | |
| import ConversationStorage from './utils/conversationStorage'; | |
| function App() { | |
| const [darkMode, setDarkMode] = useState(false); | |
| const [sidebarOpen, setSidebarOpen] = useState(false); | |
| const [chatStarted, setChatStarted] = useState(false); | |
| const [conversations, setConversations] = useState([]); | |
| const [activeConversationId, setActiveConversationId] = useState(null); | |
| useEffect(() => { | |
| // Check for saved theme preference or default to light mode | |
| const savedTheme = localStorage.getItem('theme'); | |
| const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; | |
| if (savedTheme === 'dark' || (!savedTheme && prefersDark)) { | |
| setDarkMode(true); | |
| document.documentElement.classList.add('dark'); | |
| } | |
| // Load conversations from localStorage | |
| const savedConversations = ConversationStorage.loadConversations(); | |
| if (savedConversations.length > 0) { | |
| setConversations(savedConversations); | |
| setChatStarted(true); | |
| // Set the most recent conversation as active | |
| setActiveConversationId(savedConversations[0].id); | |
| } | |
| }, []); | |
| const toggleDarkMode = () => { | |
| setDarkMode(!darkMode); | |
| if (darkMode) { | |
| document.documentElement.classList.remove('dark'); | |
| localStorage.setItem('theme', 'light'); | |
| } else { | |
| document.documentElement.classList.add('dark'); | |
| localStorage.setItem('theme', 'dark'); | |
| } | |
| }; | |
| const startNewChat = () => { | |
| const newConversation = { | |
| id: Date.now().toString(), | |
| title: 'New Conversation', | |
| messages: [], | |
| createdAt: new Date(), | |
| updatedAt: new Date(), | |
| }; | |
| // Save to localStorage | |
| ConversationStorage.addConversation(newConversation); | |
| setConversations(prev => [newConversation, ...prev]); | |
| setActiveConversationId(newConversation.id); | |
| setChatStarted(true); | |
| setSidebarOpen(false); | |
| }; | |
| const deleteConversation = (conversationId) => { | |
| // Delete from localStorage | |
| ConversationStorage.deleteConversation(conversationId); | |
| setConversations(prev => prev.filter(conv => conv.id !== conversationId)); | |
| // If the deleted conversation was active, switch to another one | |
| if (activeConversationId === conversationId) { | |
| const remainingConversations = conversations.filter(conv => conv.id !== conversationId); | |
| if (remainingConversations.length > 0) { | |
| setActiveConversationId(remainingConversations[0].id); | |
| } else { | |
| setActiveConversationId(null); | |
| setChatStarted(false); | |
| } | |
| } | |
| }; | |
| const updateConversations = (updatedConversations) => { | |
| setConversations(updatedConversations); | |
| // Save to localStorage | |
| ConversationStorage.saveConversations(updatedConversations); | |
| }; | |
| const handleFirstMessage = (message) => { | |
| if (!chatStarted) { | |
| startNewChat(); | |
| } | |
| }; | |
| const goBackToHome = () => { | |
| setActiveConversationId(null); | |
| setChatStarted(false); | |
| setSidebarOpen(false); | |
| }; | |
| return ( | |
| <div className={`min-h-screen transition-colors duration-200 ${ | |
| darkMode | |
| ? 'bg-gray-900 text-white' | |
| : 'bg-gray-50 text-gray-900' | |
| }`}> | |
| {/* Header */} | |
| <header className={`fixed top-0 left-0 right-0 z-50 ${ | |
| darkMode | |
| ? 'bg-gray-800/95 border-gray-700' | |
| : 'bg-white/95 border-gray-200' | |
| } backdrop-blur-sm border-b`}> | |
| <div className="flex items-center justify-between px-4 py-3"> | |
| <div className="flex items-center space-x-4"> | |
| <button | |
| onClick={() => setSidebarOpen(!sidebarOpen)} | |
| className={`p-2 rounded-lg transition-colors ${ | |
| darkMode | |
| ? 'hover:bg-gray-700 text-gray-300' | |
| : 'hover:bg-gray-100 text-gray-600' | |
| }`} | |
| > | |
| <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" /> | |
| </svg> | |
| </button> | |
| <button | |
| onClick={goBackToHome} | |
| className="text-lg font-semibold gradient-text hover:opacity-80 transition-opacity" | |
| > | |
| CA Study Assistant | |
| </button> | |
| </div> | |
| <div className="flex items-center space-x-2"> | |
| {chatStarted && ( | |
| <button | |
| onClick={goBackToHome} | |
| className={`p-2 rounded-lg transition-colors ${ | |
| darkMode | |
| ? 'hover:bg-gray-700 text-gray-300' | |
| : 'hover:bg-gray-100 text-gray-600' | |
| }`} | |
| title="Back to Home" | |
| > | |
| <HomeIcon className="w-5 h-5" /> | |
| </button> | |
| )} | |
| <button | |
| onClick={toggleDarkMode} | |
| className={`p-2 rounded-lg transition-colors ${ | |
| darkMode | |
| ? 'hover:bg-gray-700 text-gray-300' | |
| : 'hover:bg-gray-100 text-gray-600' | |
| }`} | |
| > | |
| {darkMode ? ( | |
| <SunIcon className="w-5 h-5" /> | |
| ) : ( | |
| <MoonIcon className="w-5 h-5" /> | |
| )} | |
| </button> | |
| </div> | |
| </div> | |
| </header> | |
| {/* Sidebar */} | |
| <Sidebar | |
| open={sidebarOpen} | |
| onClose={() => setSidebarOpen(false)} | |
| conversations={conversations} | |
| activeConversationId={activeConversationId} | |
| onConversationSelect={setActiveConversationId} | |
| onNewChat={startNewChat} | |
| onDeleteConversation={deleteConversation} | |
| onBackToHome={goBackToHome} | |
| darkMode={darkMode} | |
| /> | |
| {/* Main Content */} | |
| <main className={`transition-all duration-200 ${ | |
| sidebarOpen ? 'md:ml-64' : 'ml-0' | |
| } pt-16`}> | |
| {chatStarted ? ( | |
| <ChatInterface | |
| conversationId={activeConversationId} | |
| conversations={conversations} | |
| setConversations={updateConversations} | |
| darkMode={darkMode} | |
| /> | |
| ) : ( | |
| <WelcomeScreen | |
| onStartChat={handleFirstMessage} | |
| onNewChat={startNewChat} | |
| darkMode={darkMode} | |
| /> | |
| )} | |
| </main> | |
| {/* Toast notifications */} | |
| <Toaster | |
| position="top-right" | |
| toastOptions={{ | |
| duration: 4000, | |
| style: { | |
| background: darkMode ? '#374151' : '#ffffff', | |
| color: darkMode ? '#f9fafb' : '#111827', | |
| border: darkMode ? '1px solid #4b5563' : '1px solid #e5e7eb', | |
| }, | |
| }} | |
| /> | |
| </div> | |
| ); | |
| } | |
| export default App; |