← back to Norma
components/email-analyzer/OriginalEmailCard.tsx
270 lines
'use client';
import { useRef } from 'react';
import {
ClipboardPaste,
ChevronDown,
BarChart3,
Loader2,
X,
} from 'lucide-react';
/* ─── Helpers ────────────────────────────────────────────────────────────── */
function countWords(text: string): number {
const plain = text.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim();
return plain.split(/\s+/).filter(Boolean).length;
}
/* ─── Types ──────────────────────────────────────────────────────────────── */
interface OriginalEmailCardProps {
pastedEmail: string;
onPastedEmailChange: (value: string) => void;
showOriginal: boolean;
onToggleOriginal: () => void;
hasVersions: boolean;
isAnalyzing: boolean;
onAnalyze: () => void;
/** Ref forwarded to the textarea for external focus management */
pasteRef?: React.RefObject<HTMLTextAreaElement | null>;
}
interface AddOriginalSectionProps {
show: boolean;
onShow: () => void;
onHide: () => void;
originalCount: number;
newOriginalText: string;
onNewOriginalTextChange: (value: string) => void;
onSave: () => void;
}
/* ─── Original Email Card ────────────────────────────────────────────────── */
export default function OriginalEmailCard({
pastedEmail,
onPastedEmailChange,
showOriginal,
onToggleOriginal,
hasVersions,
isAnalyzing,
onAnalyze,
pasteRef,
}: OriginalEmailCardProps) {
const localRef = useRef<HTMLTextAreaElement>(null);
const textareaRef = pasteRef ?? localRef;
return (
<div
className="card"
style={{ padding: 0, overflow: 'hidden' }}
>
<div
style={{
padding: '12px 16px',
borderBottom: '1px solid var(--color-border)',
display: 'flex',
alignItems: 'center',
gap: 8,
cursor: hasVersions ? 'pointer' : 'default',
}}
onClick={() => hasVersions && onToggleOriginal()}
>
<ClipboardPaste
size={16}
style={{ color: 'var(--color-primary)' }}
/>
<span
style={{
fontSize: 13,
fontWeight: 600,
color: 'var(--color-text)',
flex: 1,
}}
>
Original Email
</span>
{pastedEmail.trim() && (
<span style={{ fontSize: 12, color: 'var(--color-text-muted)' }}>
{countWords(pastedEmail)} words
</span>
)}
{hasVersions && (
<ChevronDown
size={14}
style={{
color: 'var(--color-text-muted)',
transform: showOriginal ? 'rotate(0deg)' : 'rotate(-90deg)',
transition: 'transform 0.15s',
}}
/>
)}
</div>
{(showOriginal || !hasVersions) && (
<>
<textarea
ref={textareaRef}
className="input"
style={{
width: '100%',
minHeight: hasVersions ? 100 : 200,
maxHeight: hasVersions ? 150 : 400,
fontSize: 14,
lineHeight: 1.7,
resize: 'vertical',
border: 'none',
borderRadius: 0,
padding: 16,
backgroundColor: 'var(--color-surface)',
}}
placeholder={
'Paste an email here to analyze and rewrite...\n\nYou can paste plain text or HTML email content. The AI will help you refine the tone, length, and messaging.'
}
value={pastedEmail}
onChange={(e) => onPastedEmailChange(e.target.value)}
readOnly={hasVersions}
/>
{!hasVersions && (
<div
style={{
padding: '10px 16px',
borderTop: '1px solid var(--color-border)',
display: 'flex',
alignItems: 'center',
gap: 8,
}}
>
<button
type="button"
className="btn btn-primary btn-sm"
disabled={!pastedEmail.trim() || isAnalyzing}
onClick={onAnalyze}
style={{ display: 'flex', alignItems: 'center', gap: 6 }}
>
{isAnalyzing ? (
<>
<Loader2 size={14} className="spinner" /> Analyzing...
</>
) : (
<>
<BarChart3 size={14} /> Analyze
</>
)}
</button>
</div>
)}
</>
)}
</div>
);
}
/* ─── Add Another Original Section ───────────────────────────────────────── */
export function AddOriginalSection({
show,
onShow,
onHide,
originalCount,
newOriginalText,
onNewOriginalTextChange,
onSave,
}: AddOriginalSectionProps) {
if (!show) {
return (
<button
type="button"
className="btn btn-ghost btn-sm"
style={{ fontSize: 12, gap: 4, color: 'var(--color-text-muted)' }}
onClick={onShow}
>
<ClipboardPaste size={12} /> Add another original (v0.{originalCount + 1})
</button>
);
}
return (
<div
className="card"
style={{ padding: 0, overflow: 'hidden' }}
>
<div
style={{
padding: '10px 16px',
borderBottom: '1px solid var(--color-border)',
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
}}
>
<span
style={{
fontSize: 13,
fontWeight: 600,
color: 'var(--color-text)',
}}
>
Paste another version (v0.{originalCount + 1})
</span>
<button
type="button"
onClick={onHide}
style={{
background: 'none',
border: 'none',
cursor: 'pointer',
color: 'var(--color-text-muted)',
padding: 2,
display: 'flex',
}}
>
<X size={14} />
</button>
</div>
<textarea
className="input"
style={{
width: '100%',
minHeight: 120,
fontSize: 14,
lineHeight: 1.7,
resize: 'vertical',
border: 'none',
borderRadius: 0,
padding: 16,
backgroundColor: 'var(--color-surface)',
}}
placeholder="Paste a different version of this email..."
value={newOriginalText}
onChange={(e) => onNewOriginalTextChange(e.target.value)}
autoFocus
/>
<div
style={{
padding: '8px 16px',
borderTop: '1px solid var(--color-border)',
display: 'flex',
alignItems: 'center',
gap: 8,
}}
>
<button
type="button"
className="btn btn-primary btn-sm"
disabled={!newOriginalText.trim()}
onClick={onSave}
style={{ fontSize: 12 }}
>
Save as v0.{originalCount + 1}
</button>
{newOriginalText.trim() && (
<span style={{ fontSize: 11, color: 'var(--color-text-muted)' }}>
{countWords(newOriginalText)} words
</span>
)}
</div>
</div>
);
}