Neah/components/email/EmailContentDisplay.tsx
2025-05-01 09:54:17 +02:00

160 lines
4.9 KiB
TypeScript

'use client';
import React, { useMemo } from 'react';
import { EmailContent } from '@/types/email';
import { detectTextDirection, applyTextDirection } from '@/lib/utils/text-direction';
import { sanitizeHtml } from '@/lib/utils/dom-sanitizer';
interface EmailContentDisplayProps {
content: EmailContent | null | undefined;
className?: string;
showQuotedText?: boolean;
type?: 'html' | 'text' | 'auto';
debug?: boolean;
}
/**
* Unified component for displaying email content in a consistent way
* This handles both HTML and plain text content with proper styling and RTL support
*/
const EmailContentDisplay: React.FC<EmailContentDisplayProps> = ({
content,
className = '',
showQuotedText = true,
type = 'auto',
debug = false
}) => {
// Create a safe content object with fallback values for missing properties
const safeContent = useMemo(() => {
if (!content) {
return {
text: '',
html: undefined,
isHtml: false,
direction: 'ltr' as const
};
}
return {
text: content.text || '',
html: content.html,
isHtml: content.isHtml,
// If direction is missing, detect it from the text content
direction: content.direction || detectTextDirection(content.text)
};
}, [content]);
// Determine what content to display based on type preference and available content
const htmlToDisplay = useMemo(() => {
// If no content is available, show a placeholder
if (!safeContent.text && !safeContent.html) {
return '<div class="text-gray-400">No content available</div>';
}
// If type is explicitly set to text, or we don't have HTML and auto mode
if (type === 'text' || (type === 'auto' && !safeContent.isHtml)) {
// Format plain text with line breaks for HTML display
if (safeContent.text) {
const formattedText = safeContent.text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\n/g, '<br>');
return formattedText;
}
}
// Otherwise use HTML content if available
if (safeContent.isHtml && safeContent.html) {
return safeContent.html;
}
// Fallback to text content if there's no HTML
if (safeContent.text) {
const formattedText = safeContent.text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\n/g, '<br>');
return formattedText;
}
return '<div class="text-gray-400">No content available</div>';
}, [safeContent, type]);
// Handle quoted text display
const processedHTML = useMemo(() => {
if (!showQuotedText) {
// This is simplified - a more robust approach would parse and handle
// quoted sections more intelligently
return htmlToDisplay.replace(/<blockquote[^>]*>[\s\S]*?<\/blockquote>/gi,
'<div class="text-gray-400">[Quoted text hidden]</div>');
}
return htmlToDisplay;
}, [htmlToDisplay, showQuotedText]);
// Sanitize HTML content and apply proper direction
const sanitizedHTML = useMemo(() => {
const clean = sanitizeHtml(processedHTML);
// Apply text direction consistently using our utility
return applyTextDirection(clean, safeContent.text);
}, [processedHTML, safeContent.text]);
return (
<div className={`email-content-display ${className}`}>
<div
className="email-content-inner"
dangerouslySetInnerHTML={{ __html: sanitizedHTML }}
/>
{/* Debug output if enabled */}
{debug && (
<div className="mt-4 p-2 text-xs bg-gray-100 border rounded">
<p><strong>Content Type:</strong> {safeContent.isHtml ? 'HTML' : 'Text'}</p>
<p><strong>Direction:</strong> {safeContent.direction}</p>
<p><strong>HTML Length:</strong> {safeContent.html?.length || 0}</p>
<p><strong>Text Length:</strong> {safeContent.text?.length || 0}</p>
</div>
)}
<style jsx>{`
.email-content-display {
width: 100%;
}
/* Enhanced RTL styling - handle direction at every level */
[dir="rtl"] {
text-align: right;
}
/* Ensure images don't overflow their containers */
.email-content-inner img {
max-width: 100%;
height: auto;
}
/* Blockquote styling for LTR content */
.email-content-inner blockquote {
margin: 10px 0;
padding-left: 15px;
border-left: 2px solid #ddd;
color: #666;
background-color: #f9f9f9;
border-radius: 4px;
}
/* Special styling for RTL blockquotes - handled via attribute selector */
[dir="rtl"] blockquote {
padding-left: 0;
padding-right: 15px;
border-left: none;
border-right: 2px solid #ddd;
}
`}</style>
</div>
);
};
export default EmailContentDisplay;