import { useCallback, useEffect, useState } from "react"; import { Plus, ShieldCheck, Trash, Warning } from "@phosphor-icons/react"; import type { BudgetPolicyRecord, BudgetStatusSummary } from "@shared/types"; import { ActionButton, EmptyState, ListFrame, ListRow } from "../ui"; import { PolicyFormModal } from "./PolicyFormModal"; interface PolicyListProps { companyId: string; agents: Array<{ id: string; name: string }>; projects: Array<{ id: string; name: string }>; } export function PolicyList({ companyId, agents, projects }: PolicyListProps) { const [policies, setPolicies] = useState([]); const [budgetStatus, setBudgetStatus] = useState(null); const [showForm, setShowForm] = useState(false); const [editingPolicy, setEditingPolicy] = useState(null); const loadData = useCallback(async () => { const [polRes, statusRes] = await Promise.all([ window.agentCompany.listBudgetPolicies(companyId), window.agentCompany.getBudgetStatus(companyId), ]); if (polRes.ok) setPolicies(polRes.data); if (statusRes.ok) setBudgetStatus(statusRes.data); }, [companyId]); useEffect(() => { void loadData(); }, [loadData]); function getScopeName(policy: BudgetPolicyRecord): string { if (policy.scopeType === "company") return "Company"; if (policy.scopeType === "agent") { const agent = agents.find((a) => a.id === policy.scopeId); return agent ? agent.name : policy.scopeId.slice(0, 8); } if (policy.scopeType === "project") { const project = projects.find((p) => p.id === policy.scopeId); return project ? project.name : policy.scopeId.slice(0, 8); } return policy.scopeId.slice(0, 8); } function getUtilization(policyId: string): { spent: number; amount: number; pct: number; hasIncident: boolean } | null { if (!budgetStatus) return null; const entry = budgetStatus.policies.find((p) => p.policyId === policyId); if (!entry) return null; const pct = entry.amount > 0 ? (entry.spent / entry.amount) * 100 : 0; return { spent: entry.spent, amount: entry.amount, pct, hasIncident: entry.hasOpenIncident }; } async function handleDelete(policyId: string) { const result = await window.agentCompany.deleteBudgetPolicy({ companyId, policyId }); if (result.ok) void loadData(); } function handleEdit(policy: BudgetPolicyRecord) { setEditingPolicy(policy); setShowForm(true); } function handleAdd() { setEditingPolicy(null); setShowForm(true); } function handleSaved() { void loadData(); } if (policies.length === 0 && !showForm) { return (
} /> setShowForm(false)} onSaved={handleSaved} companyId={companyId} editingPolicy={editingPolicy} agents={agents} projects={projects} />
); } return (

Budget Policies

{policies.map((policy) => { const util = getUtilization(policy.id); const pct = util?.pct ?? 0; const barColor = pct > 100 ? "bg-destructive" : pct > 80 ? "bg-yellow-600 dark:bg-yellow-400" : "bg-green-600 dark:bg-green-400"; return ( handleEdit(policy)}>
{policy.scopeType} {getScopeName(policy)} {policy.hardStopEnabled ? : null} {util?.hasIncident ? : null}
${(policy.amount / 100).toFixed(2)}/mo Warn at {policy.warnPercent}%
{util ? (
{Math.round(pct)}%
) : null}
); })}
{ setShowForm(false); setEditingPolicy(null); }} onSaved={handleSaved} companyId={companyId} editingPolicy={editingPolicy} agents={agents} projects={projects} />
); }