feat(chat): Implement real-time SSE streaming with reasoning steps and improved UI indicators.
This commit is contained in:
@@ -4,7 +4,9 @@ import { MainLayout } from "./components/layout/MainLayout"
|
||||
import { LoginForm } from "./components/auth/LoginForm"
|
||||
import { RegisterForm } from "./components/auth/RegisterForm"
|
||||
import { AuthCallback } from "./components/auth/AuthCallback"
|
||||
import { ChatInterface } from "./components/chat/ChatInterface"
|
||||
import { AuthService, type UserResponse } from "./services/auth"
|
||||
import { ChatService } from "./services/chat"
|
||||
import { registerUnauthorizedCallback } from "./services/api"
|
||||
|
||||
function App() {
|
||||
@@ -12,6 +14,7 @@ function App() {
|
||||
const [user, setUser] = useState<UserResponse | null>(null)
|
||||
const [authMode, setAuthMode] = useState<"login" | "register">("login")
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [selectedThreadId, setSelectedThreadId] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
// Register callback to handle session expiration from anywhere in the app
|
||||
@@ -55,6 +58,17 @@ function App() {
|
||||
} finally {
|
||||
setIsAuthenticated(false)
|
||||
setUser(null)
|
||||
setSelectedThreadId(null)
|
||||
}
|
||||
}
|
||||
|
||||
const handleCreateTempChat = async () => {
|
||||
try {
|
||||
const conv = await ChatService.createConversation("Temporary Chat")
|
||||
setSelectedThreadId(conv.id)
|
||||
} catch (err) {
|
||||
console.error("Failed to create conversation:", err)
|
||||
alert("Failed to start chat session. Please try again.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,13 +102,12 @@ function App() {
|
||||
</div>
|
||||
) : (
|
||||
<MainLayout>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex flex-col h-full gap-4">
|
||||
<div className="flex justify-between items-center shrink-0">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold">
|
||||
<h1 className="text-xl font-bold">
|
||||
Welcome, {user?.display_name || user?.email || "User"}!
|
||||
</h1>
|
||||
<p className="text-sm text-muted-foreground">{user?.email}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
@@ -103,9 +116,43 @@ function App() {
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-muted-foreground mt-4">
|
||||
Select a conversation from the sidebar or start a new one to begin your analysis.
|
||||
</p>
|
||||
|
||||
<div className="flex-1 min-h-0">
|
||||
{selectedThreadId ? (
|
||||
<ChatInterface threadId={selectedThreadId} />
|
||||
) : (
|
||||
<div className="flex flex-col items-center justify-center h-full text-center space-y-4 bg-muted/30 rounded-xl border border-dashed p-12">
|
||||
<div className="p-4 bg-background rounded-full shadow-sm">
|
||||
<svg
|
||||
className="w-12 h-12 text-primary"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M8 10h.01M12 10h.01M16 10h.01M9 16H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-5l-5 5v-5z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="max-w-xs space-y-2">
|
||||
<h2 className="text-lg font-semibold">Ready to analyze election data?</h2>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Create a new conversation in the sidebar to start asking questions.
|
||||
</p>
|
||||
<button
|
||||
onClick={handleCreateTempChat}
|
||||
className="mt-4 px-4 py-2 bg-primary text-primary-foreground rounded-md text-sm font-medium hover:bg-primary/90"
|
||||
>
|
||||
Start Temporary Chat
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</MainLayout>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user