import React, { useState } from 'react'; import SessionModal from './SessionModal'; import { useContextMenu } from '../hooks/useContextMenu'; import { renameSession, deleteSession } from '../api/orchestration'; export default function SessionList({ sessions, activeSession, onSelectSession, onNewChat, isOpen, onToggle, onSessionsChange }) { const [modalSession, setModalSession] = useState(null); const [hoveredId, setHoveredId] = useState(null); const { menu, open: openMenu, close: closeMenu } = useContextMenu(); const [modalMode, setModalMode] = useState('settings'); function formatDate(ts) { if (!ts) return ''; const date = new Date(ts * 1000); const now = new Date(); const diffDays = Math.floor((now - date) / (1000 * 60 * 60 * 24)); if (diffDays === 0) return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); if (diffDays === 1) return 'Yesterday'; if (diffDays < 7) return date.toLocaleDateString([], { weekday: 'long' }); return date.toLocaleDateString([], { month: 'short', day: 'numeric' }); } function getPreview(session) { if (session.isNew) return 'New conversation'; return session.name || session.external_id; } async function handleRename(session, name) { try { await renameSession(session.external_id, name); onSessionsChange(); } catch (err) { console.error('[SessionList] Rename failed:', err.message); } } async function handleDelete(session) { try { await deleteSession(session.external_id); onSessionsChange(); } catch (err) { console.error('[SessionList] Delete failed:', err.message); } } return ( <>
{/* Header */}
{isOpen && Conversations}
{/* New chat button */}
{/* Session list */}
{isOpen && sessions.map(session => { const isActive = activeSession?.external_id === session.external_id; const isHovered = hoveredId === session.external_id; return (
setHoveredId(session.external_id)} onMouseLeave={() => setHoveredId(null)} onContextMenu={e => !session.isNew && openMenu(e, session)} style={{ position: 'relative', display: 'flex', alignItems: 'stretch', background: isActive ? 'var(--bg-elevated)' : isHovered ? 'var(--bg-elevated)' : 'transparent', borderLeft: isActive ? '2px solid var(--accent)' : '2px solid transparent', transition: 'background 0.1s', }} > {/* Session select button — no action icons inside */} {/* Action icons — outside the button, alongside it */} {isHovered && !session.isNew && (
)}
); })} {isOpen && sessions.length === 0 && (
No conversations yet
)}
{/* Context menu */} {menu && (
e.stopPropagation()} style={{ position: 'fixed', top: menu.y, left: menu.x, background: 'var(--bg-elevated)', border: '1px solid var(--border)', borderRadius: 'var(--radius-md)', padding: '4px', zIndex: 50, minWidth: '140px', }} >
)} {/* Rename modal */} {modalSession && ( setModalSession(null)} /> )} ); }