import type { ApprovalRequest, ApprovalStatus } from "@/types/appops"; export interface ApprovalFollowupLink { label: string; href: string; } export interface ApprovalFollowupView { status: ApprovalStatus; statusLabel: string; expiryLabel: string; auditReference: string | null; jobReference: string | null; executionCopy: string; canDecide: boolean; links: ApprovalFollowupLink[]; } export interface ApprovalEmptyState { title: string; message: string; actions: ApprovalFollowupLink[]; } const statusLabels: Record = { pending: "Pending", approved: "Approved", rejected: "Rejected", expired: "Expired", executed: "Executed", }; const normalizeStatus = (status?: string): ApprovalStatus => ( status === "approved" || status === "rejected" || status === "expired" || status === "executed" ? status : "pending" ); const formatRelativeExpiry = (expiresAt?: string, now = new Date()): { label: string; expired: boolean } => { if (!expiresAt) return { label: "Geen vervaldatum", expired: false }; const timestamp = Date.parse(expiresAt); if (!Number.isFinite(timestamp)) return { label: "Vervaldatum onbekend", expired: false }; const diffMs = timestamp - now.getTime(); const absMinutes = Math.max(1, Math.round(Math.abs(diffMs) / 60_000)); const hours = Math.floor(absMinutes / 60); const minutes = absMinutes % 60; const duration = hours > 0 ? `${hours}u ${minutes}m` : `${absMinutes}m`; return diffMs < 0 ? { label: `Verlopen ${duration} geleden`, expired: true } : { label: `Verloopt over ${duration}`, expired: false }; }; export const buildApprovalFollowupView = (approval: ApprovalRequest, now = new Date()): ApprovalFollowupView => { const status = normalizeStatus(approval.status); const expiry = formatRelativeExpiry(approval.expiresAt, now); const effectiveStatus: ApprovalStatus = status === "pending" && expiry.expired ? "expired" : status; const auditReference = approval.auditId || null; const jobReference = approval.jobId || null; const decided = effectiveStatus !== "pending"; const canDecide = effectiveStatus === "pending"; const links: ApprovalFollowupLink[] = decided ? [ { label: "Open Audit", href: auditReference ? `/audit?query=${encodeURIComponent(auditReference)}` : "/audit" }, { label: "Jobs", href: jobReference ? `/jobs?query=${encodeURIComponent(jobReference)}` : "/jobs" }, ] : [ { label: "Open Audit", href: "/audit" }, { label: "Command Center", href: "/command-center" }, { label: "Jobs", href: "/jobs" }, ]; return { status: effectiveStatus, statusLabel: statusLabels[effectiveStatus], expiryLabel: effectiveStatus === "expired" ? expiry.label : expiry.label, auditReference, jobReference, executionCopy: decided ? effectiveStatus === "expired" ? "Approval is verlopen. Er wordt geen actie uitgevoerd; maak indien nodig een nieuwe expliciete aanvraag." : "Beslissing opgeslagen. Controleer Audit en Jobs voor echte vervolgstatussen wanneer die beschikbaar zijn." : "Nog niet uitgevoerd. Goedkeuren of afwijzen schrijft audit en kan daarna een job opleveren als de actie een executor heeft.", canDecide, links, }; }; export const filterApprovals = (approvals: ApprovalRequest[], query: string): ApprovalRequest[] => { const normalizedQuery = query.trim().toLowerCase(); if (!normalizedQuery) return approvals; return approvals.filter((approval) => [ approval.id, approval.action, approval.target, approval.requester, approval.context, approval.reason || "", approval.auditId || "", approval.jobId || "", ].some((value) => value.toLowerCase().includes(normalizedQuery))); }; export const buildApprovalEmptyState = ( options: { totalApprovals: number; visibleApprovals: number; query: string }, ): ApprovalEmptyState => { const query = options.query.trim(); if (options.totalApprovals === 0) { return { title: "Geen openstaande approvals", message: "Er staan geen approvals klaar. Nieuwe approval-first acties verschijnen hier zodra Command Center, connectors of remediation flows er een aanvragen.", actions: [{ label: "Command Center", href: "/command-center" }], }; } if (query && options.visibleApprovals === 0) { return { title: "Geen approval voor deze handoff", message: `Er is geen approval gevonden voor "${query}". Controleer Audit of Jobs om te zien of de aanvraag al verwerkt, verlopen of als job doorgezet is.`, actions: [ { label: "Toon alle approvals", href: "/approvals" }, { label: "Zoek in Audit", href: `/audit?query=${encodeURIComponent(query)}` }, { label: "Zoek in Jobs", href: `/jobs?query=${encodeURIComponent(query)}` }, { label: "Command Center", href: "/command-center" }, ], }; } return { title: "Geen approvals zichtbaar", message: "De huidige selectie bevat geen approvals. Toon alles of start een nieuwe approval-first actie via Command Center.", actions: [ { label: "Toon alle approvals", href: "/approvals" }, { label: "Command Center", href: "/command-center" }, ], }; };