← back to Norma
components/email-analyzer/GeneratedVersionCard.tsx
106 lines
'use client';
import { Mail } from 'lucide-react';
import type { VersionEntry } from './VersionTimeline';
import { sanitizeHtml } from './sanitize';
/* ─── Helpers ────────────────────────────────────────────────────────────── */
function countWords(html: string): number {
const plain = html.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
return plain.split(/\s+/).filter(Boolean).length;
}
/* ─── Types ──────────────────────────────────────────────────────────────── */
interface GeneratedVersionCardProps {
currentVersion: string;
activeVersionId: string | null;
versions: VersionEntry[];
}
/* ─── Component ──────────────────────────────────────────────────────────── */
/**
* Renders the current email version preview with sanitized HTML content.
* Content is sanitized via sanitizeHtml() which strips script tags,
* event handlers, iframes, and other dangerous elements before rendering.
*/
export default function GeneratedVersionCard({
currentVersion,
activeVersionId,
versions,
}: GeneratedVersionCardProps) {
const activeVersion = versions.find((v) => v.id === activeVersionId);
const sanitized = sanitizeHtml(currentVersion);
return (
<div
className="card"
style={{
padding: 0,
display: 'flex',
flexDirection: 'column',
overflow: 'hidden',
}}
>
<div
style={{
padding: '10px 16px',
borderBottom: '1px solid var(--color-border)',
display: 'flex',
alignItems: 'center',
gap: 8,
}}
>
<Mail size={14} style={{ color: 'var(--color-primary)' }} />
<span
style={{
fontSize: 13,
fontWeight: 600,
color: 'var(--color-text)',
}}
>
Generated Version
</span>
{activeVersionId && (
<span
className="badge"
style={{
fontSize: 10,
padding: '1px 6px',
backgroundColor: 'var(--color-primary-dim)',
color: 'var(--color-primary)',
border: '1px solid rgba(10,124,89,0.2)',
}}
>
v{activeVersion?.versionNumber || '?'}
</span>
)}
<span
style={{
fontSize: 12,
color: 'var(--color-text-muted)',
marginLeft: 'auto',
}}
>
{countWords(currentVersion)} words
</span>
</div>
<div
style={{
flex: 1,
padding: 20,
overflowY: 'auto',
fontSize: 14,
lineHeight: 1.8,
color: 'var(--color-text)',
maxHeight: 450,
}}
className="email-preview-content"
dangerouslySetInnerHTML={{ __html: sanitized }}
/>
</div>
);
}