From d88fc133d2d4b988b157fbfdbedaef86303aa4ff Mon Sep 17 00:00:00 2001 From: alma Date: Thu, 1 May 2025 09:43:25 +0200 Subject: [PATCH] courrier preview --- components/email/ComposeEmail.tsx | 8 +- components/email/EmailContentDisplay.tsx | 20 ++-- lib/utils/email-adapters.ts | 13 +-- lib/utils/email-formatter.ts | 127 ++++++++--------------- lib/utils/email-utils.ts | 119 +++++++++++---------- 5 files changed, 130 insertions(+), 157 deletions(-) diff --git a/components/email/ComposeEmail.tsx b/components/email/ComposeEmail.tsx index c127fe52..41aaf28e 100644 --- a/components/email/ComposeEmail.tsx +++ b/components/email/ComposeEmail.tsx @@ -352,7 +352,13 @@ export default function ComposeEmail(props: ComposeEmailProps) { ref={editorRef} initialContent={emailContent} initialDirection={detectTextDirection(emailContent)} - onChange={setEmailContent} + onChange={(html) => { + // Store the content + setEmailContent(html); + + // But don't update direction on every keystroke + // The RichTextEditor will handle direction changes internally + }} className="min-h-[320px] border rounded-md bg-white text-gray-800 flex-1" placeholder="Write your message here..." /> diff --git a/components/email/EmailContentDisplay.tsx b/components/email/EmailContentDisplay.tsx index af326c6c..3c23aa89 100644 --- a/components/email/EmailContentDisplay.tsx +++ b/components/email/EmailContentDisplay.tsx @@ -2,7 +2,7 @@ import React, { useMemo } from 'react'; import { EmailContent } from '@/types/email'; -import { detectTextDirection } from '@/lib/utils/text-direction'; +import { detectTextDirection, applyTextDirection } from '@/lib/utils/text-direction'; import DOMPurify from 'isomorphic-dompurify'; interface EmailContentDisplayProps { @@ -94,13 +94,16 @@ const EmailContentDisplay: React.FC = ({ return htmlToDisplay; }, [htmlToDisplay, showQuotedText]); - // Sanitize HTML content before rendering + // Sanitize HTML content and apply proper direction const sanitizedHTML = useMemo(() => { - return DOMPurify.sanitize(processedHTML); - }, [processedHTML]); + const clean = DOMPurify.sanitize(processedHTML); + + // Apply text direction consistently using our utility + return applyTextDirection(clean, safeContent.text); + }, [processedHTML, safeContent.text]); return ( -
+
= ({ width: 100%; } - .email-content-display[dir="rtl"] { - text-align: right; - } - .email-content-inner img { max-width: 100%; height: auto; @@ -139,7 +138,8 @@ const EmailContentDisplay: React.FC = ({ border-radius: 4px; } - .email-content-display[dir="rtl"] .email-content-inner blockquote { + /* RTL blockquote styling will be handled by the direction attribute now */ + [dir="rtl"] blockquote { padding-left: 0; padding-right: 15px; border-left: none; diff --git a/lib/utils/email-adapters.ts b/lib/utils/email-adapters.ts index 6ae7ecfa..6bdbf96e 100644 --- a/lib/utils/email-adapters.ts +++ b/lib/utils/email-adapters.ts @@ -1,5 +1,6 @@ import { EmailMessage, EmailContent, EmailAddress, LegacyEmailMessage } from '@/types/email'; import { sanitizeHtml } from './email-utils'; +import { detectTextDirection } from './text-direction'; /** * Adapts a legacy email format to the standardized EmailMessage format @@ -224,17 +225,7 @@ function normalizeContent(email: LegacyEmailMessage): EmailContent { } /** - * Detects the text direction (LTR or RTL) based on the content - */ -function detectTextDirection(text: string): 'ltr' | 'rtl' { - // Simple RTL detection for common RTL languages - // This is a basic implementation and can be enhanced - const rtlChars = /[\u0591-\u07FF\u200F\u202B\u202E\uFB1D-\uFDFD\uFE70-\uFEFC]/; - return rtlChars.test(text) ? 'rtl' : 'ltr'; -} - -/** - * Normalizes email addresses to the EmailAddress format + * Normalizes addresses to EmailAddress objects */ function normalizeAddresses(addresses: string | EmailAddress[] | undefined): EmailAddress[] { if (!addresses) { diff --git a/lib/utils/email-formatter.ts b/lib/utils/email-formatter.ts index 58e716e1..10cddddf 100644 --- a/lib/utils/email-formatter.ts +++ b/lib/utils/email-formatter.ts @@ -9,6 +9,8 @@ */ import DOMPurify from 'isomorphic-dompurify'; +import { sanitizeHtml } from './email-utils'; +import { applyTextDirection } from './text-direction'; // Instead of importing, implement the formatDateRelative function directly // import { formatDateRelative } from './date-formatter'; @@ -133,59 +135,6 @@ export function formatEmailDate(date: Date | string | undefined): string { } } -/** - * Sanitize HTML content before processing or displaying - * Implements email industry standards for proper, consistent, and secure rendering - * - * @param html HTML content to sanitize - * @returns Sanitized HTML with preserved styling and structure - */ -export function sanitizeHtml(html: string): string { - if (!html) return ''; - - try { - // Use DOMPurify with comprehensive email HTML standards - const clean = DOMPurify.sanitize(html, { - ADD_TAGS: [ - 'html', 'head', 'body', 'style', 'link', 'meta', 'title', - 'table', 'caption', 'col', 'colgroup', 'thead', 'tbody', 'tfoot', 'tr', 'td', 'th', - 'div', 'span', 'img', 'br', 'hr', 'section', 'article', 'header', 'footer', - 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'blockquote', 'pre', 'code', - 'ul', 'ol', 'li', 'dl', 'dt', 'dd', 'a', 'b', 'i', 'u', 'em', - 'strong', 'del', 'ins', 'mark', 'small', 'sub', 'sup', 'q', 'abbr' - ], - ADD_ATTR: [ - 'style', 'class', 'id', 'name', 'href', 'src', 'alt', 'title', 'width', 'height', - 'border', 'cellspacing', 'cellpadding', 'bgcolor', 'background', 'color', - 'align', 'valign', 'dir', 'lang', 'target', 'rel', 'charset', 'media', - 'colspan', 'rowspan', 'scope', 'span', 'size', 'face', 'hspace', 'vspace', - 'data-*' - ], - KEEP_CONTENT: true, - WHOLE_DOCUMENT: false, - ALLOW_DATA_ATTR: true, - ALLOW_UNKNOWN_PROTOCOLS: true, // Needed for some email clients - FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form', 'input', 'button', 'select', 'textarea'], - FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onmouseout'], - FORCE_BODY: false - }); - - // Fix common email rendering issues - return clean - // Fix for Outlook WebVML content - .replace(/