import { useCallback, useMemo } from 'react'; import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip'; import { useStore } from '@renderer/store'; import { resolveProjectIdByPath } from '@renderer/utils/projectLookup'; import { formatDistanceToNowStrict } from 'date-fns'; import { AlertCircle, Crown, ExternalLink, Filter, FilterX, Loader2, MessageSquare, Monitor, } from 'lucide-react'; import { useShallow } from 'zustand/react/shallow'; import type { Session } from '@renderer/types/data'; interface TeamSessionsSectionProps { sessions: Session[]; sessionsLoading: boolean; sessionsError: string | null; leadSessionId?: string; selectedSessionId: string | null; onSelectSession: (sessionId: string | null) => void; projectPath?: string; } export const TeamSessionsSection = ({ sessions, sessionsLoading, sessionsError, leadSessionId, selectedSessionId, onSelectSession, projectPath, }: TeamSessionsSectionProps): React.JSX.Element => { const { openTab, selectSession, projects, repositoryGroups } = useStore( useShallow((s) => ({ openTab: s.openTab, selectSession: s.selectSession, projects: s.projects, repositoryGroups: s.repositoryGroups, })) ); const projectId = useMemo( () => resolveProjectIdByPath(projectPath, projects, repositoryGroups), [projects, repositoryGroups, projectPath] ); // Sort: lead session first, then by most recent const sortedSessions = useMemo(() => { if (!leadSessionId) return sessions; return [...sessions].sort((a, b) => { if (a.id === leadSessionId) return -1; if (b.id === leadSessionId) return 1; return b.createdAt - a.createdAt; }); }, [sessions, leadSessionId]); const handleSessionClick = useCallback( (session: Session) => { if (!projectId) return; openTab( { type: 'session', sessionId: session.id, projectId, label: session.firstMessage?.slice(0, 50) ?? 'Session', }, { forceNewTab: true } ); selectSession(session.id); }, [projectId, openTab, selectSession] ); if (!projectPath) { return (
No project path linked

Sessions will appear after team provisioning

); } if (!projectId) { return (
Project not found

{projectPath}

); } if (sessionsLoading) { return (
Loading sessions...
); } if (sessionsError) { return (
{sessionsError}
); } if (sortedSessions.length === 0) { return (
No sessions found
); } return (
{selectedSessionId !== null && ( )} {sortedSessions.map((session) => ( handleSessionClick(session)} onToggleFilter={() => onSelectSession(session.id === selectedSessionId ? null : session.id) } /> ))}
); }; // --------------------------------------------------------------------------- // Session row // --------------------------------------------------------------------------- interface SessionRowProps { session: Session; isLead: boolean; isSelected: boolean; onClick: () => void; onToggleFilter: () => void; } const SessionRow = ({ session, isLead, isSelected, onClick, onToggleFilter, }: SessionRowProps): React.JSX.Element => { const timeAgo = formatShortTime(new Date(session.createdAt)); const label = session.firstMessage ?? 'Untitled session'; return (
{isLead && }
{isSelected ? 'Remove filter' : 'Filter by this session'} Open session
); }; // --------------------------------------------------------------------------- // Helpers // --------------------------------------------------------------------------- function formatShortTime(date: Date): string { const distance = formatDistanceToNowStrict(date, { addSuffix: false }); return distance .replace(' seconds', 's') .replace(' second', 's') .replace(' minutes', 'm') .replace(' minute', 'm') .replace(' hours', 'h') .replace(' hour', 'h') .replace(' days', 'd') .replace(' day', 'd') .replace(' weeks', 'w') .replace(' week', 'w') .replace(' months', 'mo') .replace(' month', 'mo') .replace(' years', 'y') .replace(' year', 'y'); }