import { useNavigate, useParams } from "@tanstack/react-router"; import { motion, type Variants } from "framer-motion"; import { ChevronRight, CircleDot, Clock, MessageSquare } from "lucide-react"; import { useMemo, useState } from "react"; import { useSessions } from "@/api/queries"; import type { components } from "@/api/schema.d.ts"; import { Breadcrumb } from "@/components/layout/Breadcrumb"; import { EmptyState } from "@/components/shared/EmptyState"; import { ErrorAlert } from "@/components/shared/ErrorAlert"; import { Pagination } from "@/components/shared/Pagination"; import { Skeleton } from "@/components/shared/Skeleton"; import { SortControl, type SortDir } from "@/components/shared/SortControl"; import { MonoCaption, PageTitle } from "@/components/ui/typography"; import { useDemo } from "@/hooks/useDemo"; import { COLOR } from "@/lib/constants"; type Session = components["schemas"]["Session"]; const SORT_OPTIONS = [ { value: "created_at", label: "Newest" }, { value: "active", label: "Active" }, { value: "id", label: "ID" }, ]; const container: Variants = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.05 } }, }; const item: Variants = { hidden: { opacity: 0, y: 10 }, show: { opacity: 1, y: 0, transition: { type: "spring", stiffness: 280, damping: 24 } }, }; export function SessionList() { const { mask } = useDemo(); const { workspaceId } = useParams({ strict: false }) as { workspaceId: string }; const [page, setPage] = useState(1); const [sortField, setSortField] = useState("created_at"); const [sortDir, setSortDir] = useState("desc"); const navigate = useNavigate(); const { data, isLoading, error } = useSessions(workspaceId, page); const sessions: Session[] = (data as { items?: Session[] } | undefined)?.items ?? []; const totalPages = (data as { pages?: number } | undefined)?.pages ?? 1; const total = (data as { total?: number } | undefined)?.total ?? 0; const sorted = useMemo(() => { return [...sessions].sort((a, b) => { let cmp = 0; if (sortField === "created_at") { cmp = new Date(a.created_at).getTime() - new Date(b.created_at).getTime(); } else if (sortField === "active") { // active sessions first (true > false) cmp = Number(a.is_active) - Number(b.is_active); } else if (sortField === "id") { cmp = a.id.localeCompare(b.id); } return sortDir === "asc" ? cmp : -cmp; }); }, [sessions, sortField, sortDir]); function handleSort(field: string, dir: SortDir) { setSortField(field); setSortDir(dir); } return (
Sessions {total > 0 && ( {total} )}
{mask(workspaceId)}
{isLoading && } {!isLoading && sessions.length === 0 && ( )} {!isLoading && sorted.length > 0 && ( <> {sorted.map((session) => ( navigate({ to: "/workspaces/$workspaceId/sessions/$sessionId", params: { workspaceId, sessionId: session.id } as never, }) } className="w-full text-left rounded-xl px-5 py-4 group" style={{ background: COLOR.cardBaseBg, border: `1px solid ${COLOR.cardBaseBorder}`, }} whileHover={{ background: COLOR.accentDimHover, borderColor: COLOR.accentBorder, x: 2, }} >
{mask(session.id)}
{session.is_active && (
Active
)}
{session.created_at && (
{new Date(session.created_at).toLocaleString()}
)} {(session.metadata as Record | null)?.source && ( {mask((session.metadata as Record).source)} )}
))}
)}
); } function SessionListSkeleton() { return ( ); }