import React, { useState, useEffect } from "react"; import type { SessionEntry } from "../lib/types"; interface Props { sessions: SessionEntry[]; loading: boolean; selectedId?: string; onSelect: (id: string) => void; } export function SessionList({ sessions, loading, selectedId, onSelect }: Props) { const [selectedProject, setSelectedProject] = useState(null); // Group by project const grouped = new Map(); for (const session of sessions) { const group = grouped.get(session.project) || []; group.push(session); grouped.set(session.project, group); } // Auto-select project when selectedId changes useEffect(() => { if (selectedId) { const match = sessions.find((s) => s.id === selectedId); if (match) { setSelectedProject(match.project); } } }, [selectedId, sessions]); if (loading) { return (
{[...Array(5)].map((_, i) => (
))}
); } if (sessions.length === 0) { return (

No sessions found

Sessions will appear here once created

); } // Session list for selected project if (selectedProject !== null) { const projectSessions = grouped.get(selectedProject) || []; return (
{formatProjectName(selectedProject)}
{projectSessions.map((session, idx) => { const isSelected = selectedId === session.id; return ( ); })}
); } // Project list return (
{[...grouped.entries()].map(([project, projectSessions]) => { const latest = projectSessions.reduce((a, b) => (a.modified || a.created) > (b.modified || b.created) ? a : b ); const count = projectSessions.length; return ( ); })}
); } /** * Best-effort decode of Claude Code's project directory name back to a path. * Claude encodes project paths by replacing '/' with '-', but this is lossy: * a path like /home/user/my-cool-app encodes as -home-user-my-cool-app and * decodes as /home/user/my/cool/app (hyphens in the original name are lost). * There is no way to distinguish path separators from literal hyphens. */ function formatProjectName(project: string): string { if (project.startsWith("-")) { return project.replace(/^-/, "/").replace(/-/g, "/"); } return project; } function formatSessionDuration(ms: number): string { const minutes = Math.floor(ms / 60000); if (minutes < 1) return "<1m"; if (minutes < 60) return `${minutes}m`; const hours = Math.floor(minutes / 60); const rem = minutes % 60; if (rem === 0) return `${hours}h`; return `${hours}h ${rem}m`; } function formatDate(dateStr: string): string { if (!dateStr) return ""; const d = new Date(dateStr); if (isNaN(d.getTime())) return dateStr; return d.toLocaleDateString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); }