import { useMemo, useState } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Bell, ShieldCheck, Warning, XCircle, CurrencyCircleDollar, ArrowRight, CheckCircle, Clock, Eye, Robot, Heartbeat, Target, ChatCircle, Tray, } from "@phosphor-icons/react"; import type { InboxItem, InboxItemType, SectionId, StandupReport, CompanyMetrics } from "@shared/types"; import { formatMoney, timeAgo, getAgentInitials, formatDuration } from "../lib/formatters"; import { useT } from "../i18n"; const typeConfig: Record = { pending_approval: { icon: ShieldCheck, color: "var(--warn)", bg: "var(--warn-soft)", label: "Approval" }, failed_run: { icon: XCircle, color: "var(--danger)", bg: "var(--danger-soft)", label: "Failed Run" }, budget_warning: { icon: CurrencyCircleDollar, color: "var(--warn)", bg: "var(--warn-soft)", label: "Budget" }, blocked_task: { icon: Warning, color: "var(--danger)", bg: "var(--danger-soft)", label: "Blocked" }, review_needed: { icon: Eye, color: "var(--accent)", bg: "var(--accent-soft)", label: "Review" }, agent_message: { icon: ChatCircle, color: "var(--accent)", bg: "var(--accent-soft)", label: "Message" }, }; const severityColors: Record = { critical: "border-l-[color:var(--danger)]", high: "border-l-[color:var(--warn)]", medium: "border-l-[color:var(--accent)]", low: "border-l-[color:var(--line)]", }; interface InboxProps { items: InboxItem[]; onNavigate: (section: SectionId, entityId?: string) => void; } export function Inbox({ items, onNavigate }: InboxProps) { const t = useT(); const [filter, setFilter] = useState("all"); const filteredItems = useMemo(() => { if (filter === "all") return items; return items.filter(i => i.type === filter); }, [items, filter]); const counts = useMemo(() => ({ all: items.length, pending_approval: items.filter(i => i.type === "pending_approval").length, failed_run: items.filter(i => i.type === "failed_run").length, budget_warning: items.filter(i => i.type === "budget_warning").length, blocked_task: items.filter(i => i.type === "blocked_task").length, review_needed: items.filter(i => i.type === "review_needed").length, agent_message: items.filter(i => i.type === "agent_message").length, }), [items]); const handleItemClick = (item: InboxItem) => { const sectionMap: Record = { approval: "approvals", run: "runs", agent: "agents", task: "tasks", message: "communication", }; const section = sectionMap[item.entityType] ?? "overview"; onNavigate(section, item.entityId); }; const filterButtons: Array<{ key: InboxItemType | "all"; label: string; count: number }> = [ { key: "all", label: "All", count: counts.all }, { key: "pending_approval", label: "Approvals", count: counts.pending_approval }, { key: "review_needed", label: "Reviews", count: counts.review_needed }, { key: "failed_run", label: "Failed", count: counts.failed_run }, { key: "blocked_task", label: "Blocked", count: counts.blocked_task }, { key: "budget_warning", label: "Budget", count: counts.budget_warning }, { key: "agent_message", label: "Messages", count: counts.agent_message }, ]; return (

{t("inbox.title")}

{counts.all} item{counts.all !== 1 ? "s" : ""} need{counts.all === 1 ? "s" : ""} your attention

{filterButtons.map(btn => ( ))}
{filteredItems.length === 0 ? (
{t("inbox.allClear")}
{t("inbox.noItemsNow")}
) : (
{filteredItems.map((item) => { const config = typeConfig[item.type]; const Icon = config.icon; return (
); })}
)}
); } interface StandupProps { report: StandupReport | null; onNavigate: (section: SectionId, entityId?: string) => void; } export function StandupView({ report, onNavigate }: StandupProps) { const t = useT(); if (!report) { return (
{t("standup.noData")}
{t("standup.noDataDesc")}
); } return (

{t("standup.dailyStandup")}

Generated {new Date(report.generatedAt).toLocaleString()}

{report.summary}
{report.agentReports.filter(r => r.tasksCompleted24h > 0).length}
{t("standup.productive")}
{report.blockers.length}
{t("standup.blockers")}
{report.pendingApprovals}
{t("standup.pendingApprovals")}
80 ? "text-[color:var(--danger)]" : "text-[color:var(--text)]"}`}> {report.budgetUtilization}%
{t("standup.budgetUsed")}
{report.companyHighlights.length > 0 ? (
{t("standup.highlights")}
{report.companyHighlights.map((h, i) => (
{h}
))}
) : null} {report.blockers.length > 0 ? (
Blockers
{report.blockers.map((b, i) => (
{b}
))}
) : null}
{t("standup.agentStatus")}
{report.agentReports.map((ar) => ( ))}
); } interface PerformanceProps { metrics: CompanyMetrics | null; onNavigate: (section: SectionId, entityId?: string) => void; } export function PerformanceView({ metrics, onNavigate }: PerformanceProps) { const t = useT(); if (!metrics) { return (
{t("perf.noMetrics")}
{t("perf.noMetricsDesc")}
); } return (
= 80 ? "success" : metrics.overallSuccessRate >= 50 ? "warn" : "danger"} />
Run Activity (30d)
{metrics.successfulRuns} succeeded {metrics.failedRuns} failed
Agent Performance
{metrics.agentMetrics .sort((a, b) => b.tasksCompleted - a.tasksCompleted) .map((am) => ( onNavigate("agents", am.agentId)} > ))}
Agent Tasks Done Success % Runs Avg Duration Cost
{getAgentInitials(am.agentName)}
{am.agentName}
{am.tasksCompleted} = 80 ? "text-[color:var(--success)]" : am.successRate >= 50 ? "text-[color:var(--warn)]" : "text-[color:var(--danger)]" }`}> {am.successRate}% {am.runsTotal} {formatDuration(am.avgRunDurationSec)} {formatMoney(am.totalCostUsd)}
); } function CompactMetric({ label, value, tone = "default", subtitle }: { label: string; value: string | number; tone?: "default" | "success" | "warn" | "danger" | "accent"; subtitle?: string; }) { const toneMap = { default: "text-[color:var(--text)]", success: "text-[color:var(--success)]", warn: "text-[color:var(--warn)]", danger: "text-[color:var(--danger)]", accent: "text-[color:var(--accent)]", }; return (
{label}
{value}
{subtitle ?
{subtitle}
: null}
); } function RunProgressBar({ succeeded, failed, total }: { succeeded: number; failed: number; total: number }) { if (total === 0) return
; const successPct = (succeeded / total) * 100; const failPct = (failed / total) * 100; return (
); }