"use client" import { forwardRef, useState } from "react" import { cn } from "../../utils/cn" import { Button } from "../ui/button" import { Tag } from "../ui/tag" import { Ban, CheckCircle, XCircle } from "lucide-react" import { ApprovalStatusTag } from "./approval-batch-message" import type { ApprovalRequestMessageProps } from "./types" import type { ApprovalRequestField } from "./types/message.types" /** * Stacked label/value rows for the approval card's structured field * list. Labels are tiny uppercase muted text; values render as primary * text with `whitespace-pre-wrap` so multi-line descriptions * (`content`, `resolution`, etc.) keep their structure. Mirrored across * the pending + resolved branches so an approved ticket reads the same * way it did at decision time. */ function ApprovalFieldList({ fields }: { fields: ApprovalRequestField[] }) { return (
` element from an out-of-sync copy-paste edit).
*/
function ApprovalCardBody({
data,
}: {
data: ApprovalRequestMessageProps['data']
}) {
return (
{data.command}
{data.icon && (
{data.icon}
)}
{data.fields && data.fields.length > 0 ? (
) : (
data.explanation && (
{data.explanation}
)
)}
)
}
const ApprovalRequestMessage = forwardRef(
// `assistantType` is accepted for prop-parity with the batch card (so hosts
// can forward it uniformly); the viewer variant is driven by `variant`.
({ className, data, onApprove, onReject, status = 'pending', assistantType: _assistantType, variant = 'admin', resolvedByName, showFooterActions = true, ...props }, ref) => {
const [isProcessing, setIsProcessing] = useState(false)
const handleApprove = async () => {
setIsProcessing(true)
try {
await onApprove?.(data.requestId)
} finally {
setIsProcessing(false)
}
}
const handleReject = async () => {
setIsProcessing(true)
try {
await onReject?.(data.requestId)
} finally {
setIsProcessing(false)
}
}
// CLIENT (Fae end-user) card — Figma 203-11947 "fae-approval-block".
// Shows ONLY the BE-generated title (`explanation`) plus the actions row
// or the full-text resolved pill; the raw command is never rendered.
if (variant === 'client') {
return (
{data.explanation?.trim() || "Approval required"}
{!showFooterActions ? null : status === 'pending' ? (
) : (
)}
)
}
return (
{!showFooterActions ? null : status === 'pending' ? (
) : (
{status === 'approved' ? (
} />
) : status === 'cancelled' ? (
} />
) : (
} />
)}
)}
)
}
)
ApprovalRequestMessage.displayName = "ApprovalRequestMessage"
export { ApprovalRequestMessage }