fix infinite rendering

This commit is contained in:
bluemoehre
2026-07-01 01:04:06 +02:00
parent 387cd14e77
commit 3fe5af4a31
2 changed files with 21 additions and 30 deletions
+5
View File
@@ -12,8 +12,12 @@ import { HomeView } from '@/views/HomeView'
import { JobsView } from '@/views/JobsView' import { JobsView } from '@/views/JobsView'
import { NotificationsView } from '@/views/NotificationsView' import { NotificationsView } from '@/views/NotificationsView'
import { SettingsView } from '@/views/SettingsView' import { SettingsView } from '@/views/SettingsView'
import { useSession } from '@livekit/components-react'
import { TokenSource } from 'livekit-client'
export function App() { export function App() {
const session = useSession(TokenSource.sandboxTokenServer('your-sandbox-id'))
const [showSettings, setShowSettings] = useState(false) const [showSettings, setShowSettings] = useState(false)
const [showJobs, setShowJobs] = useState(false) const [showJobs, setShowJobs] = useState(false)
const [showNotifications, setShowNotifications] = useState(false) const [showNotifications, setShowNotifications] = useState(false)
@@ -21,6 +25,7 @@ export function App() {
return ( return (
<> <>
<HomeView <HomeView
session={session}
onSettingsClick={() => setShowSettings(true)} onSettingsClick={() => setShowSettings(true)}
onJobsClick={() => setShowJobs(true)} onJobsClick={() => setShowJobs(true)}
onNotificationsClick={() => setShowNotifications(true)} onNotificationsClick={() => setShowNotifications(true)}
+16 -30
View File
@@ -1,7 +1,6 @@
import { useRef, useState, useEffect } from 'react' import { useRef, useState, useEffect } from 'react'
import { useSession, useAgent, useChat, useSessionMessages } from '@livekit/components-react' import { useAgent, useChat, useSessionMessages, type UseSessionReturn } from '@livekit/components-react'
import { Keyboard, Loader, SendHorizontal } from 'lucide-react' import { Keyboard, Loader, SendHorizontal } from 'lucide-react'
import { TokenSource } from 'livekit-client'
import { AgentAudioVisualizerAura } from '@/components/agents-ui/agent-audio-visualizer-aura' import { AgentAudioVisualizerAura } from '@/components/agents-ui/agent-audio-visualizer-aura'
import { AgentChatTranscript } from '@/components/agents-ui/agent-chat-transcript' import { AgentChatTranscript } from '@/components/agents-ui/agent-chat-transcript'
@@ -10,34 +9,34 @@ import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from
import { AppBar } from '@/components/AppBar' import { AppBar } from '@/components/AppBar'
interface HomeViewProps { interface HomeViewProps {
session: UseSessionReturn
onSettingsClick: () => void onSettingsClick: () => void
onJobsClick: () => void onJobsClick: () => void
onNotificationsClick: () => void onNotificationsClick: () => void
} }
export function HomeView({ onSettingsClick, onJobsClick, onNotificationsClick }: HomeViewProps) { export function HomeView({ session, onSettingsClick, onJobsClick, onNotificationsClick }: HomeViewProps) {
const session = useSession(TokenSource.sandboxTokenServer('your-sandbox-id'))
const { microphoneTrack, state: agentState } = useAgent(session) const { microphoneTrack, state: agentState } = useAgent(session)
const { messages } = useSessionMessages(session) const { messages } = useSessionMessages(session)
const { send } = useChat({ room: session.room }) // const { send } = useChat({ room: session.room })
const [isOpen, setIsOpen] = useState(false) const [isChatOpen, setChatOpen] = useState(false)
const [message, setMessage] = useState('') const [message, setMessage] = useState('')
const [isSending, setIsSending] = useState(false) const [isFormSubmitting, setFormSubmitting] = useState(false)
const inputRef = useRef<HTMLTextAreaElement>(null) const inputRef = useRef<HTMLTextAreaElement>(null)
const isDisabled = isSending || message.trim().length === 0 const isDisabled = isFormSubmitting || message.trim().length === 0
const handleSend = async () => { const handleSend = async () => {
if (isDisabled) return if (isDisabled) return
try { try {
setIsSending(true) setFormSubmitting(true)
await send(message.trim()) await send(message.trim())
setMessage('') setMessage('')
} catch (error) { } catch (error) {
console.error(error) console.error(error)
} finally { } finally {
setIsSending(false) setFormSubmitting(false)
} }
} }
@@ -49,19 +48,10 @@ export function HomeView({ onSettingsClick, onJobsClick, onNotificationsClick }:
} }
useEffect(() => { useEffect(() => {
if (isOpen && inputRef.current) { if (isChatOpen && inputRef.current) {
inputRef.current.focus() inputRef.current.focus()
} }
}, [isOpen]) }, [isChatOpen])
// Auto-open when first message arrives
const hasAutoOpened = useRef(false)
useEffect(() => {
if (messages.length > 0 && !hasAutoOpened.current) {
hasAutoOpened.current = true
setIsOpen(true)
}
}, [messages.length])
return ( return (
<div className="flex min-h-svh flex-col"> <div className="flex min-h-svh flex-col">
@@ -76,8 +66,7 @@ export function HomeView({ onSettingsClick, onJobsClick, onNotificationsClick }:
</div> </div>
</div> </div>
</div> </div>
<Drawer open={isChatOpen} onOpenChange={setChatOpen}>
<Drawer open={isOpen} onOpenChange={setIsOpen}>
<DrawerTrigger asChild> <DrawerTrigger asChild>
<Button variant="outline" size="lg" className="fixed bottom-4 left-1/2 z-50 size-12 -translate-x-1/2"> <Button variant="outline" size="lg" className="fixed bottom-4 left-1/2 z-50 size-12 -translate-x-1/2">
<Keyboard className="size-6" /> <Keyboard className="size-6" />
@@ -93,8 +82,6 @@ export function HomeView({ onSettingsClick, onJobsClick, onNotificationsClick }:
<DrawerHeader> <DrawerHeader>
<DrawerTitle>Chat</DrawerTitle> <DrawerTitle>Chat</DrawerTitle>
</DrawerHeader> </DrawerHeader>
{/* Messages area */}
<div className="flex-1 overflow-hidden"> <div className="flex-1 overflow-hidden">
{messages.length === 0 ? ( {messages.length === 0 ? (
<div className="flex h-full items-center justify-center text-sm text-muted-foreground"> <div className="flex h-full items-center justify-center text-sm text-muted-foreground">
@@ -104,14 +91,12 @@ export function HomeView({ onSettingsClick, onJobsClick, onNotificationsClick }:
<AgentChatTranscript agentState={agentState} messages={messages} className="h-full" /> <AgentChatTranscript agentState={agentState} messages={messages} className="h-full" />
)} )}
</div> </div>
{/* Input area */}
<div className="border-t border-border p-4"> <div className="border-t border-border p-4">
<div className="flex items-end gap-2"> <div className="flex items-end gap-2">
<textarea <textarea
ref={inputRef} ref={inputRef}
value={message} value={message}
disabled={isSending} disabled={isFormSubmitting}
placeholder="Type a message..." placeholder="Type a message..."
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
onChange={(e) => setMessage(e.target.value)} onChange={(e) => setMessage(e.target.value)}
@@ -122,11 +107,11 @@ export function HomeView({ onSettingsClick, onJobsClick, onNotificationsClick }:
type="button" type="button"
disabled={isDisabled} disabled={isDisabled}
variant={isDisabled ? 'secondary' : 'default'} variant={isDisabled ? 'secondary' : 'default'}
title={isSending ? 'Sending...' : 'Send'} title={isFormSubmitting ? 'Sending...' : 'Send'}
onClick={handleSend} onClick={handleSend}
className="shrink-0" className="shrink-0"
> >
{isSending ? <Loader className="animate-spin" /> : <SendHorizontal />} {isFormSubmitting ? <Loader className="animate-spin" /> : <SendHorizontal />}
</Button> </Button>
</div> </div>
</div> </div>
@@ -136,3 +121,4 @@ export function HomeView({ onSettingsClick, onJobsClick, onNotificationsClick }:
</div> </div>
) )
} }