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";
}
}