'use client' import * as React from 'react' import { formatDistanceToNow } from 'date-fns' import { Eye, TerminalSquare } from 'lucide-react' import { cn } from '../../lib/utils' import { SessionStatusBadge } from './SessionStatusBadge' import type { SessionSummary } from './types' export interface SessionCardProps { session: SessionSummary /** Inject routing: return an href for the session detail. Renders the title as a link. */ href?: (id: string) => string /** Called when the card / Details is activated (used when `href` is absent). */ onOpen?: (id: string) => void /** Called when the Terminal action is activated. */ onOpenTerminal?: (id: string) => void className?: string } /** Relative "created …" label, tolerant of string | number timestamps. */ export function formatRelative(value: string | number): string { const date = typeof value === 'number' ? new Date(value) : new Date(value) if (Number.isNaN(date.getTime())) return String(value) return formatDistanceToNow(date, { addSuffix: true }) } function SessionCardComponent({ session, href, onOpen, onOpenTerminal, className }: SessionCardProps) { const open = React.useCallback(() => onOpen?.(session.id), [onOpen, session.id]) const handleKeyDown = React.useCallback( (e: React.KeyboardEvent) => { if (href) return // native link handles keyboard if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() open() } }, [href, open], ) const titleNode = href ? ( {session.name} ) : (

{session.name}

) const clickable = !href && !!onOpen return (
{session.hasUnread && ( )}
{session.number != null && (
{String(session.number).padStart(3, '0')}
)}
{titleNode}
{session.agentName && (
Agent: {session.agentName}
)} {session.projectName && (
Project: {session.projectName}
)} {session.branch && (
Branch: {session.branch}
)}
Created {formatRelative(session.createdAt)}
{(onOpen || href || onOpenTerminal) && (
{href ? ( e.stopPropagation()} className="inline-flex flex-1 items-center justify-center gap-1 rounded-md border border-border px-3 py-1.5 text-sm text-foreground transition-colors hover:bg-accent" > ) : ( onOpen && ( ) )} {onOpenTerminal && ( )}
)}
) } /** Memoised — cheap re-renders in long lists. */ export const SessionCard = React.memo(SessionCardComponent) /** Skeleton loader matching the card layout. */ export function SessionCardSkeleton({ className }: { className?: string }) { return (
) }