chore: Perform codebase cleanup and refactor App state management

This commit is contained in:
Yunxiao Xu
2026-02-17 02:34:47 -08:00
parent ec6760b5a7
commit a94cbc7f6d
9 changed files with 90 additions and 46 deletions

View File

@@ -1,4 +1,4 @@
import { useState, useEffect } from "react"
import { useState, useEffect, createContext, useContext } from "react"
import { Routes, Route } from "react-router-dom"
import { MainLayout } from "./components/layout/MainLayout"
import { LoginForm } from "./components/auth/LoginForm"
@@ -9,12 +9,42 @@ import { ChatService, type MessageResponse } from "./services/chat"
import { type Conversation } from "./components/layout/HistorySidebar"
import { registerUnauthorizedCallback } from "./services/api"
import { Button } from "./components/ui/button"
import { useTheme } from "./components/theme-provider"
import { ThemeProvider, useTheme } from "./components/theme-provider"
function App() {
const { setThemeLocal } = useTheme()
// --- Auth Context ---
interface AuthContextType {
isAuthenticated: boolean
setIsAuthenticated: (val: boolean) => void
user: UserResponse | null
setUser: (user: UserResponse | null) => void
}
const AuthContext = createContext<AuthContextType | undefined>(undefined)
function AuthProvider({ children }: { children: React.ReactNode }) {
const [isAuthenticated, setIsAuthenticated] = useState(false)
const [user, setUser] = useState<UserResponse | null>(null)
return (
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated, user, setUser }}>
{children}
</AuthContext.Provider>
)
}
function useAuth() {
const context = useContext(AuthContext)
if (context === undefined) {
throw new Error("useAuth must be used within an AuthProvider")
}
return context
}
// --- App Content ---
function AppContent() {
const { setThemeLocal } = useTheme()
const { isAuthenticated, setIsAuthenticated, user, setUser } = useAuth()
const [authMode, setAuthMode] = useState<"login" | "register">("login")
const [isLoading, setIsLoading] = useState(true)
const [selectedThreadId, setSelectedThreadId] = useState<string | null>(null)
@@ -22,13 +52,13 @@ function App() {
const [threadMessages, setThreadMessages] = useState<Record<string, MessageResponse[]>>({})
useEffect(() => {
// Register callback to handle session expiration from anywhere in the app
registerUnauthorizedCallback(() => {
setIsAuthenticated(false)
setUser(null)
setConversations([])
setSelectedThreadId(null)
setThreadMessages({})
setThemeLocal("light")
})
const initAuth = async () => {
@@ -39,7 +69,6 @@ function App() {
if (userData.theme_preference) {
setThemeLocal(userData.theme_preference)
}
// Load history after successful auth
loadHistory()
} catch (err: unknown) {
console.log("No active session found", err)
@@ -50,7 +79,7 @@ function App() {
}
initAuth()
}, [])
}, [setIsAuthenticated, setThemeLocal, setUser])
const loadHistory = async () => {
try {
@@ -86,13 +115,12 @@ function App() {
setSelectedThreadId(null)
setConversations([])
setThreadMessages({})
setThemeLocal("light")
}
}
const handleSelectConversation = async (id: string) => {
setSelectedThreadId(id)
// Always fetch messages to avoid stale cache issues when switching back
// or if the session was updated from elsewhere
try {
const msgs = await ChatService.getMessages(id)
setThreadMessages(prev => ({ ...prev, [id]: msgs }))
@@ -125,7 +153,6 @@ function App() {
try {
await ChatService.deleteConversation(id)
setConversations(prev => prev.filter(c => c.id !== id))
// Also clear from cache
setThreadMessages(prev => {
const next = { ...prev }
delete next[id]
@@ -202,7 +229,7 @@ function App() {
<div className="flex-1 min-h-0">
{selectedThreadId ? (
<ChatInterface
key={selectedThreadId} // Force remount on thread change
key={selectedThreadId}
threadId={selectedThreadId}
initialMessages={threadMessages[selectedThreadId] || []}
onMessagesFinal={(msgs) => handleMessagesFinal(selectedThreadId, msgs)}
@@ -249,4 +276,23 @@ function App() {
)
}
function ThemeWrapper({ children }: { children: React.ReactNode }) {
const { isAuthenticated } = useAuth()
return (
<ThemeProvider isAuthenticated={isAuthenticated}>
{children}
</ThemeProvider>
)
}
function App() {
return (
<AuthProvider>
<ThemeWrapper>
<AppContent />
</ThemeWrapper>
</AuthProvider>
)
}
export default App