2025-11-14 20:01:04 -07:00

134 lines
4.0 KiB
TypeScript

"use client"
import { useState, useEffect } from "react"
import { motion } from "framer-motion"
import { ChatInterface } from "@/components/chat-interface"
import type { Agent } from "@/lib/types"
export default function Home() {
const [selectedAgent, setSelectedAgent] = useState<Agent | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [agents, setAgents] = useState<Agent[]>([])
const [agentsError, setAgentsError] = useState<string | null>(null)
const [isAgentsLoading, setIsAgentsLoading] = useState(true)
useEffect(() => {
// Try to load previously selected agent from localStorage
const savedAgent = localStorage.getItem("selected-agent")
if (savedAgent) {
try {
const agent = JSON.parse(savedAgent)
setSelectedAgent(agent)
} catch (err) {
console.error("[home] Failed to load saved agent:", err)
}
}
setIsLoading(false)
}, [])
useEffect(() => {
const fetchAgents = async () => {
try {
setIsAgentsLoading(true)
setAgentsError(null)
const response = await fetch("/api/agents")
const data = (await response.json()) as { agents?: unknown; error?: string }
if (!response.ok || !data.agents) {
throw new Error(data.error || "Failed to load agents")
}
setAgents(data.agents as typeof agents)
} catch (err) {
setAgents([])
setAgentsError(err instanceof Error ? err.message : "Failed to load agents")
} finally {
setIsAgentsLoading(false)
}
}
fetchAgents()
}, [])
useEffect(() => {
if (!selectedAgent || agents.length === 0) return
const match = agents.find((agent) => agent.id === selectedAgent.id)
if (!match) {
setSelectedAgent(null)
localStorage.removeItem("selected-agent")
localStorage.removeItem("selected-agent-id")
return
}
if (
match.name !== selectedAgent.name ||
match.description !== selectedAgent.description
) {
setSelectedAgent(match)
localStorage.setItem("selected-agent-id", match.id)
localStorage.setItem("selected-agent", JSON.stringify(match))
}
}, [agents, selectedAgent])
const handleAgentSelected = (agent: Agent) => {
setSelectedAgent(agent)
localStorage.setItem("selected-agent-id", agent.id)
localStorage.setItem("selected-agent", JSON.stringify(agent))
}
if (isLoading) {
return null // Avoid hydration mismatch
}
// If no agent is selected but we have agents loaded, select the first one
// This ensures we always show the ChatInterface with its beautiful selection UI
const activeAgent = selectedAgent || (agents.length > 0 ? agents[0] : null)
if (!activeAgent) {
return (
<motion.div
className="gallery-shell h-screen"
initial={{ opacity: 0, y: 25 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.9, ease: "easeOut" }}
>
<div className="flex h-full flex-col items-center justify-center gap-4 px-6 text-center">
{agentsError ? (
<p className="text-xs text-destructive">{agentsError}</p>
) : (
<p className="text-sm uppercase tracking-[0.2em] text-muted-foreground">
Loading agents...
</p>
)}
</div>
</motion.div>
)
}
return (
<motion.div
className="gallery-shell mobile-shell h-screen"
initial={{ opacity: 0, y: 25 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.9, ease: "easeOut" }}
>
<div className="flex h-full flex-col">
<main className="flex-1 overflow-hidden px-3 py-4 sm:px-6 sm:py-6">
<div className="mx-auto flex h-full max-w-5xl justify-center">
<div className="h-full w-full">
<ChatInterface
agent={activeAgent}
agents={agents}
onAgentSelected={handleAgentSelected}
isAgentsLoading={isAgentsLoading}
/>
</div>
</div>
</main>
</div>
</motion.div>
)
}