153 lines
4.7 KiB
TypeScript
153 lines
4.7 KiB
TypeScript
'use client';
|
|
|
|
import React, { useMemo } from 'react';
|
|
import { EmailContent } from '@/types/email';
|
|
import { detectTextDirection, applyTextDirection } from '@/lib/utils/text-direction';
|
|
import DOMPurify from 'isomorphic-dompurify';
|
|
|
|
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, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.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, '&')
|
|
.replace(/</g, '<')
|
|
.replace(/>/g, '>')
|
|
.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 = DOMPurify.sanitize(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%;
|
|
}
|
|
|
|
.email-content-inner img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
}
|
|
|
|
.email-content-inner blockquote {
|
|
margin: 10px 0;
|
|
padding-left: 15px;
|
|
border-left: 2px solid #ddd;
|
|
color: #666;
|
|
background-color: #f9f9f9;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
/* RTL blockquote styling will be handled by the direction attribute now */
|
|
[dir="rtl"] blockquote {
|
|
padding-left: 0;
|
|
padding-right: 15px;
|
|
border-left: none;
|
|
border-right: 2px solid #ddd;
|
|
}
|
|
`}</style>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default EmailContentDisplay;
|