- Replace all rgba(6,182,212,...) cyan focus borders and accents with rgba(249,115,22,...) ember orange across 21+ component files - Remove all var(--glass-border) references (undefined variable) with var(--color-border-default) across 24 files - Remove deprecated blur orbs and glass-morphism effects from SurveyPage, SurveyThankYouPage, and LoginPage - Migrate landing.css from hardcoded hex to CSS custom properties (~97 replacements for single-source theming) - Fix off-palette grays in FlowPilotAnalyticsPage chart styling (#8891a0 → #848b9b, #18191f → var(--color-bg-card)) - Update stale comments: "cyan brand" → "accent brand" in GlowEdge, "gradient cyan square" → "gradient orange square" in BrandLogo - Rename glow-cyan SVG filter ID to glow-accent - Fix category color comment: "cyan" → "deep orange" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
import { useNavigate } from 'react-router-dom'
|
|
import { getTreeNavigatePath } from '@/lib/routing'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
interface ActivityItemProps {
|
|
sessionId: string
|
|
treeName: string
|
|
treeId: string
|
|
treeType: 'troubleshooting' | 'procedural' | 'maintenance'
|
|
status: 'active' | 'paused' | 'recent'
|
|
ticketNumber?: string | null
|
|
timestamp?: string | null
|
|
}
|
|
|
|
function formatRelativeTime(dateString: string): string {
|
|
const now = Date.now()
|
|
const then = new Date(dateString).getTime()
|
|
const diffMinutes = Math.floor((now - then) / 60000)
|
|
|
|
if (diffMinutes < 1) return 'just now'
|
|
if (diffMinutes < 60) return `${diffMinutes}m ago`
|
|
const diffHours = Math.floor(diffMinutes / 60)
|
|
if (diffHours < 24) return `${diffHours}h ago`
|
|
return 'yesterday'
|
|
}
|
|
|
|
export function ActivityItem({
|
|
sessionId,
|
|
treeName,
|
|
treeId,
|
|
treeType,
|
|
status,
|
|
ticketNumber,
|
|
timestamp,
|
|
}: ActivityItemProps) {
|
|
const navigate = useNavigate()
|
|
|
|
const handleClick = () => {
|
|
navigate(getTreeNavigatePath(treeId, treeType), {
|
|
state: { sessionId },
|
|
})
|
|
}
|
|
|
|
const isRecent = status === 'recent'
|
|
|
|
return (
|
|
<button
|
|
onClick={handleClick}
|
|
className={cn(
|
|
'flex w-full items-center gap-2 rounded-lg px-2.5 py-1.5 text-left transition-colors',
|
|
'hover:bg-[rgba(255,255,255,0.03)]',
|
|
isRecent ? 'text-text-rail-label text-[0.72rem]' : 'text-text-primary text-[0.8rem]'
|
|
)}
|
|
title={`${treeName}${ticketNumber ? ` (${ticketNumber})` : ''} — click to resume`}
|
|
aria-label={
|
|
status === 'active'
|
|
? `Active session: ${treeName}`
|
|
: status === 'paused'
|
|
? `Paused session: ${treeName}`
|
|
: `Recent session: ${treeName}`
|
|
}
|
|
>
|
|
{/* Status dot */}
|
|
{status === 'active' && (
|
|
<span
|
|
className="h-[7px] w-[7px] shrink-0 rounded-full"
|
|
style={{
|
|
background: '#34d399',
|
|
boxShadow: '0 0 6px rgba(52,211,153,0.5)',
|
|
animation: 'pulse-dot 2s ease-in-out infinite',
|
|
}}
|
|
aria-label="Active session"
|
|
/>
|
|
)}
|
|
{status === 'paused' && (
|
|
<span
|
|
className="h-[7px] w-[7px] shrink-0 rounded-full"
|
|
style={{
|
|
background: '#f59e0b',
|
|
boxShadow: '0 0 4px rgba(245,158,11,0.3)',
|
|
}}
|
|
aria-label="Paused session"
|
|
/>
|
|
)}
|
|
{status === 'recent' && (
|
|
<span className="h-1 w-1 shrink-0 rounded-full bg-muted-foreground" />
|
|
)}
|
|
|
|
{/* Flow name */}
|
|
<span className="flex-1 truncate">{treeName}</span>
|
|
|
|
{/* Ticket number or timestamp */}
|
|
{ticketNumber && !isRecent && (
|
|
<span className="shrink-0 font-mono text-[0.5625rem] text-[#60a5fa]">
|
|
{ticketNumber}
|
|
</span>
|
|
)}
|
|
{isRecent && timestamp && (
|
|
<span className="shrink-0 font-mono text-[0.5625rem] text-text-muted">
|
|
{formatRelativeTime(timestamp)}
|
|
</span>
|
|
)}
|
|
</button>
|
|
)
|
|
}
|