MCPcopy Create free account
hub / github.com/TanStack/ai / ThreadsRoute

Function ThreadsRoute

examples/ts-react-chat/src/routes/threads.tsx:233–341  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

231// ---------------------------------------------------------------------------
232
233function ThreadsRoute() {
234 const { threads, loaded, createThread, deleteThread, touchThread } =
235 useThreadIndex()
236 const [activeId, setActiveId] = useState<string | null>(null)
237
238 // Ensure there's always an active thread: keep the current one if it still
239 // exists, otherwise fall back to the most recent, otherwise create one.
240 useEffect(() => {
241 if (!loaded) return
242 if (activeId && threads.some((t) => t.id === activeId)) return
243 if (threads.length > 0) {
244 setActiveId(threads[0].id)
245 return
246 }
247 setActiveId(createThread().id)
248 // `threads`/`createThread` are derived from the same state; depending on
249 // `activeId` + `loaded` is enough to re-run when the active thread vanishes.
250 }, [loaded, activeId, threads.length])
251
252 const handleNewChat = () => {
253 // Don't pile up empty chats — if an untouched "New chat" exists, focus it.
254 const empty = threads.find((t) => t.title === NEW_CHAT_TITLE)
255 setActiveId(empty ? empty.id : createThread().id)
256 }
257
258 const handleDelete = (id: string) => {
259 deleteThread(id)
260 if (id === activeId) {
261 const next = threads.find((t) => t.id !== id)
262 // If nothing remains the bootstrap effect creates a fresh thread.
263 setActiveId(next ? next.id : null)
264 }
265 }
266
267 return (
268 <div className="flex h-[calc(100vh-72px)] bg-gray-900 text-white">
269 <aside className="flex w-72 flex-col border-r border-gray-800 bg-gray-950">
270 <div className="p-3">
271 <button
272 type="button"
273 onClick={handleNewChat}
274 className="flex w-full items-center justify-center gap-2 rounded-lg border border-orange-500/30 bg-orange-500/10 px-3 py-2 text-sm font-medium text-orange-300 transition-colors hover:bg-orange-500/20"
275 >
276 <Plus size={16} />
277 New chat
278 </button>
279 </div>
280 <nav className="flex-1 overflow-y-auto px-2 pb-3">
281 {threads.length === 0 && (
282 <p className="px-3 py-4 text-sm text-gray-500">No chats yet.</p>
283 )}
284 {threads.map((thread) => {
285 const isActive = thread.id === activeId
286 return (
287 <div
288 key={thread.id}
289 className={`group mb-1 flex items-center gap-2 rounded-lg px-3 py-2 text-sm transition-colors ${
290 isActive

Callers

nothing calls this directly

Calls 5

useThreadIndexFunction · 0.85
createThreadFunction · 0.85
relativeTimeFunction · 0.85
handleDeleteFunction · 0.85
touchThreadFunction · 0.85

Tested by

no test coverage detected