exec-ops-env / frontend /src /components /TimelinePanel.js
saaheerpurav's picture
first commit
1bb18a0
Raw
History Blame Contribute Delete
3.16 kB
import React, { useEffect, useRef } from 'react';
const ACTION_CONFIG = {
reply: { icon: '↩', color: '#3b82f6', label: 'Reply' },
schedule: { icon: '📅', color: '#8b5cf6', label: 'Schedule' },
delegate: { icon: '→', color: '#f97316', label: 'Delegate' },
ignore: { icon: '✕', color: '#64748b', label: 'Ignore' },
};
const PRIORITY_COLORS = { 5: '#ef4444', 4: '#f59e0b', 3: '#eab308', 2: '#22c55e', 1: '#94a3b8' };
export default function TimelinePanel({ history }) {
const endRef = useRef(null);
useEffect(() => {
endRef.current?.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'end' });
}, [history.length]);
return (
<div className="panel timeline-panel">
<div className="panel-header">
<span className="panel-title">📊 Action Timeline</span>
<span className="panel-badge">{history.length} actions</span>
</div>
<div className="timeline-scroll">
{history.length === 0 ? (
<div className="timeline-empty">
<span className="timeline-empty-icon"></span>
<span>No actions yet — click <strong>Watch AI Play</strong> or select an email above</span>
</div>
) : (
<div className="timeline-track">
{history.map((entry, i) => {
const cfg = ACTION_CONFIG[entry.action] || ACTION_CONFIG.ignore;
const positive = entry.reward >= 0;
const isLast = i === history.length - 1;
return (
<div key={i} className={`timeline-entry ${isLast ? 'latest' : ''}`}>
{/* Connector line */}
{i > 0 && <div className="timeline-line" style={{ background: `${cfg.color}40` }} />}
{/* Step badge */}
<div className="timeline-step" style={{ background: cfg.color }}>
{entry.step + 1}
</div>
{/* Card */}
<div className="timeline-card" style={{ borderColor: `${cfg.color}40` }}>
<div className="timeline-card-top">
<span className="tl-time">{entry.time}</span>
<span className="tl-action" style={{ color: cfg.color }}>
{cfg.icon} {cfg.label}
</span>
<span
className="tl-reward"
style={{ color: positive ? '#22c55e' : '#ef4444' }}
>
{positive ? '+' : ''}{entry.reward.toFixed(3)}
</span>
</div>
<div className="timeline-card-body">
<span
className="tl-dot"
style={{ background: PRIORITY_COLORS[entry.email_priority] || '#94a3b8' }}
/>
<span className="tl-subject">{entry.email_subject}</span>
</div>
</div>
</div>
);
})}
<div ref={endRef} />
</div>
)}
</div>
</div>
);
}