// DocumentHeader — cabecera estándar (benchmark §5.2): serie/folio, badges de // cada máquina de estado, cliente enlazable, métricas (total, saldo, fechas) y // un identificador copiable (UUID). import { useState, type ReactNode } from 'react' import { useTranslation } from 'react-i18next' import { Check, Copy } from 'lucide-react' import { Button } from '@asteby/metacore-ui/primitives' import { cn } from '@asteby/metacore-ui/lib' import { StatusBadge } from './status-badge' import { formatFieldValue, type FieldFormatOptions } from './format' import type { StatusDef } from './types' export interface HeaderBadge { id: string label?: string status: StatusDef } export interface HeaderMetric { label: string value: string tone?: 'default' | 'critical' mono?: boolean } export interface DocumentHeaderProps { title: string /** Texto bajo el título; si `subtitleHref` viene, es un enlace (ficha del cliente). */ subtitle?: string subtitleHref?: string badges: HeaderBadge[] metrics?: HeaderMetric[] copyable?: { label: string; value: string } /** Zona de acciones (normalmente ``). */ actions?: ReactNode /** Slot antes del título (botón «Volver»). */ leading?: ReactNode /** Renderiza el subtítulo como enlace del router del host. */ renderLink?: (props: { href: string; children: ReactNode; className?: string }) => ReactNode className?: string } export function DocumentHeader({ title, subtitle, subtitleHref, badges, metrics, copyable, actions, leading, renderLink, className, }: DocumentHeaderProps) { const { t } = useTranslation() const [copied, setCopied] = useState(false) const copy = async () => { if (!copyable?.value) return try { await navigator.clipboard.writeText(copyable.value) setCopied(true) setTimeout(() => setCopied(false), 1500) } catch { /* sin portapapeles (contexto inseguro): el valor sigue seleccionable */ } } const subtitleNode = subtitle ? ( subtitleHref ? ( renderLink ? ( renderLink({ href: subtitleHref, children: subtitle, className: 'text-sm text-primary hover:underline' }) ) : ( {subtitle} ) ) : ( {subtitle} ) ) : null return (
{leading}

{title}

{badges.map((b) => ( ))}
{subtitleNode}
{actions}
{metrics && metrics.length > 0 ? (
{metrics.map((m) => (
{m.label}
{m.value}
))}
) : null} {copyable?.value ? (
{copyable.label} {copyable.value}
) : null}
) } export { formatFieldValue } export type { FieldFormatOptions }