"use client"; import { usePathname, useRouter } from "next/navigation"; import Link from "next/link"; import { useEffect, useState, useCallback } from "react"; import { HugeiconsIcon } from "@hugeicons/react"; import { Delete02Icon, Search01Icon, Notification02Icon, FileImportIcon } from "@hugeicons/core-free-icons"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { ScrollArea } from "@/components/ui/scroll-area"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; import { usePanel } from "@/hooks/usePanel"; import { ConnectionStatus } from "./ConnectionStatus"; import { ImportSessionDialog } from "./ImportSessionDialog"; import type { ChatSession } from "@/types"; interface ChatListPanelProps { open: boolean; width?: number; } function formatRelativeTime(dateStr: string): string { const date = new Date(dateStr.includes("T") ? dateStr : dateStr + "Z"); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMin = Math.floor(diffMs / 60000); const diffHr = Math.floor(diffMin / 60); const diffDay = Math.floor(diffHr / 24); if (diffMin < 1) return "just now"; if (diffMin < 60) return `${diffMin}m ago`; if (diffHr < 24) return `${diffHr}h ago`; if (diffDay < 7) return `${diffDay}d ago`; return date.toLocaleDateString(); } const DATE_GROUP_ORDER = ["Today", "Yesterday", "Last 7 Days", "Older"]; function groupSessionsByDate( sessions: ChatSession[] ): Record { const groups: Record = {}; const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); const yesterday = new Date(today.getTime() - 86400000); const lastWeek = new Date(today.getTime() - 7 * 86400000); for (const session of sessions) { const date = new Date(session.updated_at); let group: string; if (date >= today) group = "Today"; else if (date >= yesterday) group = "Yesterday"; else if (date >= lastWeek) group = "Last 7 Days"; else group = "Older"; if (!groups[group]) groups[group] = []; groups[group].push(session); } return groups; } const MODE_BADGE_CONFIG = { code: { label: "Code", className: "bg-blue-500/10 text-blue-500" }, plan: { label: "Plan", className: "bg-sky-500/10 text-sky-500" }, ask: { label: "Ask", className: "bg-green-500/10 text-green-500" }, } as const; export function ChatListPanel({ open, width }: ChatListPanelProps) { const pathname = usePathname(); const router = useRouter(); const { streamingSessionId, pendingApprovalSessionId } = usePanel(); const [sessions, setSessions] = useState([]); const [hoveredSession, setHoveredSession] = useState(null); const [deletingSession, setDeletingSession] = useState(null); const [searchQuery, setSearchQuery] = useState(""); const [importDialogOpen, setImportDialogOpen] = useState(false); const fetchSessions = useCallback(async () => { try { const res = await fetch("/api/chat/sessions"); if (res.ok) { const data = await res.json(); setSessions(data.sessions || []); } } catch { // API may not be available yet } }, []); useEffect(() => { fetchSessions(); }, [fetchSessions]); // Refresh session list when navigating useEffect(() => { fetchSessions(); }, [pathname, fetchSessions]); // Refresh session list when a session is created or updated useEffect(() => { const handler = () => fetchSessions(); window.addEventListener('session-created', handler); window.addEventListener('session-updated', handler); return () => { window.removeEventListener('session-created', handler); window.removeEventListener('session-updated', handler); }; }, [fetchSessions]); const handleDeleteSession = async ( e: React.MouseEvent, sessionId: string ) => { e.preventDefault(); e.stopPropagation(); if (!confirm('Delete this conversation?')) return; setDeletingSession(sessionId); try { const res = await fetch(`/api/chat/sessions/${sessionId}`, { method: "DELETE", }); if (res.ok) { setSessions((prev) => prev.filter((s) => s.id !== sessionId)); if (pathname === `/chat/${sessionId}`) { router.push("/chat"); } } } catch { // Silently fail } finally { setDeletingSession(null); } }; const filteredSessions = searchQuery ? sessions.filter( (s) => s.title.toLowerCase().includes(searchQuery.toLowerCase()) || (s.project_name && s.project_name.toLowerCase().includes(searchQuery.toLowerCase())) ) : sessions; const groupedSessions = groupSessionsByDate(filteredSessions); if (!open) return null; return ( ); }