courrier clean 2$
This commit is contained in:
parent
3e6b8cae1f
commit
4c9fcdeb29
@ -11,10 +11,11 @@ import { Input } from '@/components/ui/input';
|
|||||||
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card';
|
import { Card, CardContent, CardHeader, CardTitle, CardFooter } from '@/components/ui/card';
|
||||||
import DOMPurify from 'isomorphic-dompurify';
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
|
||||||
// Import the new email formatter utilities
|
// Import ONLY from the centralized formatter
|
||||||
import {
|
import {
|
||||||
formatForwardedEmail,
|
formatForwardedEmail,
|
||||||
formatReplyEmail,
|
formatReplyEmail,
|
||||||
|
formatEmailForReplyOrForward,
|
||||||
EmailMessage as FormatterEmailMessage
|
EmailMessage as FormatterEmailMessage
|
||||||
} from '@/lib/utils/email-formatter';
|
} from '@/lib/utils/email-formatter';
|
||||||
|
|
||||||
@ -169,7 +170,6 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
// For forwarding, use the dedicated formatter
|
// For forwarding, use the dedicated formatter
|
||||||
const { subject, content } = formatForwardedEmail(formatterEmail);
|
const { subject, content } = formatForwardedEmail(formatterEmail);
|
||||||
setSubject(subject);
|
setSubject(subject);
|
||||||
// Apply the formatted content directly without additional sanitization
|
|
||||||
setEmailContent(content);
|
setEmailContent(content);
|
||||||
} else {
|
} else {
|
||||||
// For reply/reply-all, use the reply formatter
|
// For reply/reply-all, use the reply formatter
|
||||||
@ -180,7 +180,6 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
setShowCc(true);
|
setShowCc(true);
|
||||||
}
|
}
|
||||||
setSubject(subject);
|
setSubject(subject);
|
||||||
// Apply the formatted content directly without additional sanitization
|
|
||||||
setEmailContent(content);
|
setEmailContent(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,7 +257,7 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
// Handle editor input without re-sanitizing content
|
// Handle editor input without re-sanitizing content
|
||||||
const handleEditorInput = () => {
|
const handleEditorInput = () => {
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
// Capture innerHTML directly without reapplying DOMPurify
|
// Capture innerHTML directly without reapplying sanitization
|
||||||
setEmailContent(editorRef.current.innerHTML);
|
setEmailContent(editorRef.current.innerHTML);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -307,7 +306,7 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
</CardTitle>
|
</CardTitle>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
{/* Recipients, Subject fields remain the same */}
|
{/* Recipients, Subject fields */}
|
||||||
<div className="p-3 border-b space-y-2">
|
<div className="p-3 border-b space-y-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span className="w-16 text-sm font-medium">To:</span>
|
<span className="w-16 text-sm font-medium">To:</span>
|
||||||
@ -391,7 +390,7 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Updated Email Body Editor */}
|
{/* Email Body Editor */}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<label htmlFor="body" className="text-sm font-medium">Message</label>
|
<label htmlFor="body" className="text-sm font-medium">Message</label>
|
||||||
@ -415,7 +414,7 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
contentEditable={!sending}
|
contentEditable={!sending}
|
||||||
className="w-full p-4 min-h-[300px] focus:outline-none"
|
className="w-full p-4 min-h-[300px] focus:outline-none"
|
||||||
onInput={handleEditorInput}
|
onInput={handleEditorInput}
|
||||||
// Use dangerouslySetInnerHTML without sanitizing again
|
// Use dangerouslySetInnerHTML without sanitizing again to preserve our formatting
|
||||||
dangerouslySetInnerHTML={{ __html: emailContent }}
|
dangerouslySetInnerHTML={{ __html: emailContent }}
|
||||||
dir={isRTL ? 'rtl' : 'ltr'}
|
dir={isRTL ? 'rtl' : 'ltr'}
|
||||||
style={{
|
style={{
|
||||||
@ -425,7 +424,7 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Attachments section remains the same */}
|
{/* Attachments section */}
|
||||||
{attachments.length > 0 && (
|
{attachments.length > 0 && (
|
||||||
<div className="border-t p-2">
|
<div className="border-t p-2">
|
||||||
<div className="text-sm font-medium mb-1">Attachments:</div>
|
<div className="text-sm font-medium mb-1">Attachments:</div>
|
||||||
|
|||||||
@ -1,9 +1,30 @@
|
|||||||
/**
|
/**
|
||||||
* Utilities for email formatting with proper text direction handling
|
* CENTRAL EMAIL FORMATTER
|
||||||
|
*
|
||||||
|
* This is the primary and only email formatting utility to be used.
|
||||||
|
* All email formatting should go through here to ensure consistent
|
||||||
|
* handling of text direction and HTML sanitization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import DOMPurify from 'isomorphic-dompurify';
|
import DOMPurify from 'isomorphic-dompurify';
|
||||||
|
|
||||||
|
// Configure DOMPurify to preserve direction attributes
|
||||||
|
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
|
||||||
|
// Preserve direction attributes
|
||||||
|
if (node.hasAttribute('dir')) {
|
||||||
|
node.setAttribute('dir', node.getAttribute('dir') || 'ltr');
|
||||||
|
}
|
||||||
|
// Preserve text-align in styles
|
||||||
|
if (node.hasAttribute('style')) {
|
||||||
|
const style = node.getAttribute('style') || '';
|
||||||
|
if (style.includes('text-align')) {
|
||||||
|
// Keep existing alignment
|
||||||
|
} else if (node.hasAttribute('dir') && node.getAttribute('dir') === 'rtl') {
|
||||||
|
node.setAttribute('style', style + '; text-align: right;');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Interface definitions
|
// Interface definitions
|
||||||
export interface EmailAddress {
|
export interface EmailAddress {
|
||||||
name: string;
|
name: string;
|
||||||
@ -73,17 +94,19 @@ export function formatEmailDate(date: Date | string | undefined): string {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean HTML content to prevent RTL/LTR issues
|
* Clean HTML content to prevent RTL/LTR issues
|
||||||
|
* This is the ONLY function that should be used for cleaning HTML content
|
||||||
*/
|
*/
|
||||||
export function cleanHtmlContent(content: string): string {
|
export function cleanHtmlContent(content: string): string {
|
||||||
if (!content) return '';
|
if (!content) return '';
|
||||||
|
|
||||||
// First sanitize the HTML
|
// First sanitize the HTML with our configured DOMPurify
|
||||||
const sanitized = DOMPurify.sanitize(content);
|
const sanitized = DOMPurify.sanitize(content);
|
||||||
|
|
||||||
// Process content to ensure consistent direction
|
// Process content to ensure consistent direction
|
||||||
let processed = sanitized;
|
let processed = sanitized;
|
||||||
|
|
||||||
// Replace RTL attributes with LTR
|
// Replace RTL attributes with LTR if needed
|
||||||
|
// We're now more careful to only modify direction attributes if needed
|
||||||
processed = processed.replace(/dir\s*=\s*["']rtl["']/gi, 'dir="ltr"');
|
processed = processed.replace(/dir\s*=\s*["']rtl["']/gi, 'dir="ltr"');
|
||||||
processed = processed.replace(/style\s*=\s*["']([^"']*)direction\s*:\s*rtl;?([^"']*)["']/gi,
|
processed = processed.replace(/style\s*=\s*["']([^"']*)direction\s*:\s*rtl;?([^"']*)["']/gi,
|
||||||
(match, before, after) => `style="${before}direction: ltr;${after}"`);
|
(match, before, after) => `style="${before}direction: ltr;${after}"`);
|
||||||
@ -92,7 +115,8 @@ export function cleanHtmlContent(content: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format an email for forwarding
|
* Format an email for forwarding - CENTRAL IMPLEMENTATION
|
||||||
|
* All other formatting functions should be deprecated in favor of this one
|
||||||
*/
|
*/
|
||||||
export function formatForwardedEmail(email: EmailMessage): {
|
export function formatForwardedEmail(email: EmailMessage): {
|
||||||
subject: string;
|
subject: string;
|
||||||
@ -135,7 +159,8 @@ export function formatForwardedEmail(email: EmailMessage): {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format an email for reply or reply-all
|
* Format an email for reply or reply-all - CENTRAL IMPLEMENTATION
|
||||||
|
* All other formatting functions should be deprecated in favor of this one
|
||||||
*/
|
*/
|
||||||
export function formatReplyEmail(email: EmailMessage, type: 'reply' | 'reply-all'): {
|
export function formatReplyEmail(email: EmailMessage, type: 'reply' | 'reply-all'): {
|
||||||
to: string;
|
to: string;
|
||||||
@ -206,3 +231,36 @@ export function formatReplyEmail(email: EmailMessage, type: 'reply' | 'reply-all
|
|||||||
content
|
content
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* COMPATIBILITY LAYER: For backward compatibility with the old email-formatter.ts
|
||||||
|
* These functions map to our new implementation but preserve the old interface
|
||||||
|
*/
|
||||||
|
|
||||||
|
// For compatibility with old code that might be using the other email-formatter.ts
|
||||||
|
export function formatEmailForReplyOrForward(
|
||||||
|
email: EmailMessage,
|
||||||
|
type: 'reply' | 'reply-all' | 'forward'
|
||||||
|
): {
|
||||||
|
to: string;
|
||||||
|
cc?: string;
|
||||||
|
subject: string;
|
||||||
|
body: string;
|
||||||
|
} {
|
||||||
|
if (type === 'forward') {
|
||||||
|
const { subject, content } = formatForwardedEmail(email);
|
||||||
|
return {
|
||||||
|
to: '',
|
||||||
|
subject,
|
||||||
|
body: content
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const { to, cc, subject, content } = formatReplyEmail(email, type as 'reply' | 'reply-all');
|
||||||
|
return {
|
||||||
|
to,
|
||||||
|
cc,
|
||||||
|
subject,
|
||||||
|
body: content
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user