// Tracker — list of all requests with status, deadline countdown, drill-in function Tracker({ go }) { const [filter, setFilter] = React.useState("all"); const [sel, setSel] = React.useState(null); const reqs = window.REQUESTS; const filtered = reqs.filter((r) => { if (filter === "all") return true; if (filter === "active") return !["fulfilled","refused","draft"].includes(r.status); if (filter === "closed") return ["fulfilled","refused"].includes(r.status); return r.status === filter; }); if (sel) { return setSel(null)} />; } const tabs = [ { id: "all", label: "All", count: reqs.length }, { id: "active", label: "Active", count: reqs.filter((r) => !["fulfilled","refused","draft"].includes(r.status)).length }, { id: "overdue", label: "Overdue", count: reqs.filter((r) => r.status === "overdue").length }, { id: "internal-review", label: "Review", count: reqs.filter((r) => r.status === "internal-review").length }, { id: "closed", label: "Closed", count: reqs.filter((r) => ["fulfilled","refused"].includes(r.status)).length } ]; return (
go("compose")} icon={}>New request }>Tracker
{tabs.map((t) => ( ))}
{filtered.map((r) => { const pct = r.workingDaysElapsed ? (r.workingDaysElapsed / 20) * 100 : 0; const tone = r.status === "overdue" ? "danger" : pct > 70 ? "warn" : "info"; const daysLeft = 20 - r.workingDaysElapsed; return ( setSel(r)} style={{ cursor: "pointer", borderBottom: "1px solid var(--rule)" }} onMouseEnter={(e) => e.currentTarget.style.background = "var(--surface-2)"} onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}> ); })}
Ref Title Recipient Status Deadline Replies Owner
{r.id}
{r.title}
{r.tags.map((t) => ( {t} ))}
{r.recipientName}
{r.channel}
{r.sentOn ? ( <>
{daysLeft >= 0 ? `${daysLeft} day${daysLeft === 1 ? "" : "s"} left` : `${Math.abs(daysLeft)} day${Math.abs(daysLeft) === 1 ? "" : "s"} overdue`}
) : }
{r.replies} {r.owner}
); } function RequestDetail({ r, back }) { const replies = window.INBOX.filter((m) => m.requestId === r.id); const pct = r.workingDaysElapsed ? (r.workingDaysElapsed / 20) * 100 : 0; const tone = r.status === "overdue" ? "danger" : pct > 70 ? "warn" : "info"; const daysLeft = 20 - r.workingDaysElapsed; const timeline = [ { date: r.sentOn, label: "Dispatched", desc: `Sent via ${r.channel} to ${r.recipientName}`, ok: true }, { date: r.sentOn, label: "Acknowledgement received", desc: "Recipient confirmed receipt", ok: r.workingDaysElapsed >= 2 }, { date: r.deadline, label: "Substantive response due", desc: "20 working days from dispatch", ok: r.status === "fulfilled" || r.status === "partial" }, { date: null, label: "Internal review window opens", desc: "If refused or partial", ok: r.status === "internal-review" || r.status === "fulfilled" } ]; return (
{r.id}

{r.title}

{r.summary}
{r.status === "refused" && }
{r.sentOn && (
20-working-day clock
FOIA s.10(1) statutory deadline
{daysLeft >= 0 ? `${daysLeft}` : `+${Math.abs(daysLeft)}`}
{daysLeft >= 0 ? "days left" : "days overdue"}
Sent {r.sentOn} Due {r.deadline}
)}
Timeline
{timeline.map((step, i) => (
{step.ok && }
{step.label}
{step.desc}
{step.date || "—"}
))}
{replies.length > 0 && (
Replies on this thread
{replies.length} message{replies.length === 1 ? "" : "s"}
{replies.map((m) => (
{m.fromName}
{m.receivedAt}
{m.subject}
{m.extracted.responseClassification}
))}
)}
Details
Status Recipient{r.recipientName} Channel{r.channel} Sent{r.sentOn || "—"} Owner{r.owner} Replies{r.replies}
Compliance checks
  • Within s.12 cost limit
  • No vexatious-history flags
  • {r.status === "overdue" ? "!" : "✓"} {r.status === "overdue" ? "Past 20-working-day deadline" : "Within 20-working-day window"}
  • Redaction pass complete
); } Object.assign(window, { Tracker, RequestDetail });