import React from "react"; import type { PiiSpan } from "@/lib/tauriCommands"; import { Badge } from "@/components/ui"; interface PiiDiffViewerProps { originalText: string; redactedText: string; spans: PiiSpan[]; approvedSpans: PiiSpan[]; onToggleSpan: (span: PiiSpan, approved: boolean) => void; } export function PiiDiffViewer({ originalText, redactedText, spans, approvedSpans, onToggleSpan, }: PiiDiffViewerProps) { const isApproved = (span: PiiSpan) => approvedSpans.some((s) => s.start === span.start && s.end === span.end); return (
{/* Side-by-side diff */}

Original

{highlightSpans(originalText, spans, "original")}

Redacted

{redactedText || No redactions applied}
{/* PII span list */} {spans.length > 0 && (

Detected PII ({spans.length} items)

{spans.map((span, idx) => (
{span.pii_type} {span.original} -> {span.replacement}
))}
)}
); } function highlightSpans(text: string, spans: PiiSpan[], _mode: "original" | "redacted") { if (spans.length === 0) return text; const sorted = [...spans].sort((a, b) => a.start - b.start); const parts: React.ReactNode[] = []; let lastEnd = 0; sorted.forEach((span, idx) => { if (span.start > lastEnd) { parts.push(text.slice(lastEnd, span.start)); } parts.push( {text.slice(span.start, span.end)} ); lastEnd = span.end; }); if (lastEnd < text.length) { parts.push(text.slice(lastEnd)); } return <>{parts}; } function piiTypeBadgeVariant(piiType: string): "default" | "secondary" | "destructive" | "outline" { switch (piiType.toLowerCase()) { case "email": case "phone": return "default"; case "ip_address": case "hostname": return "secondary"; case "ssn": case "credit_card": case "password": return "destructive"; default: return "outline"; } }