courrier clean 2$

This commit is contained in:
alma 2025-04-26 18:46:21 +02:00
parent e3b946f7e9
commit 3e6b8cae1f

View File

@ -109,19 +109,13 @@ function isLegacyProps(props: ComposeEmailAllProps): props is LegacyComposeEmail
return 'showCompose' in props && 'setShowCompose' in props;
}
// Create a utility function to preprocess email content
function preprocessEmailContent(content: string): string {
if (!content) return '';
// Sanitize HTML content
const sanitized = DOMPurify.sanitize(content);
// Fix common RTL/LTR issues by ensuring consistent direction
// Wrap content in a div with explicit direction if needed
const processed = sanitized.replace(/<div dir=(["'])rtl\1/g, '<div dir="ltr"');
return processed;
}
// Configure DOMPurify to preserve certain attributes
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
// Preserve direction attributes
if (node.hasAttribute('dir')) {
node.setAttribute('dir', node.getAttribute('dir') || 'ltr');
}
});
export default function ComposeEmail(props: ComposeEmailAllProps) {
// Handle legacy props by adapting them to new component
@ -137,10 +131,7 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
const [cc, setCc] = useState<string>('');
const [bcc, setBcc] = useState<string>('');
const [subject, setSubject] = useState<string>('');
const [body, setBody] = useState<string>('');
const [userMessage, setUserMessage] = useState<string>('');
const [originalContent, setOriginalContent] = useState<string>('');
const [editingOriginalContent, setEditingOriginalContent] = useState<boolean>(false);
const [emailContent, setEmailContent] = useState<string>('');
const [showCc, setShowCc] = useState<boolean>(false);
const [showBcc, setShowBcc] = useState<boolean>(false);
const [sending, setSending] = useState<boolean>(false);
@ -153,7 +144,6 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
// Refs
const editorRef = useRef<HTMLDivElement>(null);
const originalContentRef = useRef<HTMLDivElement>(null);
const attachmentInputRef = useRef<HTMLInputElement>(null);
// Initialize the form when replying to or forwarding an email
@ -179,8 +169,8 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
// For forwarding, use the dedicated formatter
const { subject, content } = formatForwardedEmail(formatterEmail);
setSubject(subject);
setBody(content);
setUserMessage(content);
// Apply the formatted content directly without additional sanitization
setEmailContent(content);
} else {
// For reply/reply-all, use the reply formatter
const { to, cc, subject, content } = formatReplyEmail(formatterEmail, type as 'reply' | 'reply-all');
@ -190,8 +180,8 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
setShowCc(true);
}
setSubject(subject);
setBody(content);
setUserMessage(content);
// Apply the formatted content directly without additional sanitization
setEmailContent(content);
}
// Focus editor after initializing
@ -199,10 +189,10 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
if (editorRef.current) {
editorRef.current.focus();
// Place cursor at the beginning
const selection = window.getSelection();
if (selection) {
try {
try {
// Place cursor at the beginning
const selection = window.getSelection();
if (selection) {
const range = document.createRange();
if (editorRef.current.firstChild) {
@ -212,9 +202,9 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
selection.removeAllRanges();
selection.addRange(range);
}
} catch (e) {
console.error('Error positioning cursor:', e);
}
} catch (e) {
console.error('Error positioning cursor:', e);
}
}
}, 100);
@ -224,43 +214,6 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
}
}, [initialEmail, type]);
// Format date for the forwarded message header
const formatDate = (date: Date | null): string => {
if (!date) return '';
try {
return date.toLocaleString('en-US', {
weekday: 'short',
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
} catch (e) {
return date.toString();
}
};
// Format sender address in a readable format
const formatSender = (from: Array<{name?: string, address: string}> | undefined): string => {
if (!from || from.length === 0) return 'Unknown';
return from.map(sender =>
sender.name && sender.name !== sender.address
? `${sender.name} <${sender.address}>`
: sender.address
).join(', ');
};
// Format recipient addresses in a readable format
const formatRecipients = (recipients: Array<{name?: string, address: string}> | undefined): string => {
if (!recipients || recipients.length === 0) return '';
return recipients.map(recipient =>
recipient.name && recipient.name !== recipient.address
? `${recipient.name} <${recipient.address}>`
: recipient.address
).join(', ');
};
// Handle attachment selection
const handleAttachmentClick = () => {
attachmentInputRef.current?.click();
@ -271,12 +224,6 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
const files = e.target.files;
if (!files || files.length === 0) return;
// Convert selected files to attachments
const newAttachments = Array.from(files).map(file => ({
file,
uploading: true
}));
// Read files as data URLs
for (const file of files) {
const reader = new FileReader();
@ -308,50 +255,20 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
setAttachments(current => current.filter((_, i) => i !== index));
};
// Handle editing of original content
const handleOriginalContentInput = (e: React.FormEvent<HTMLDivElement>) => {
if (originalContentRef.current) {
const content = originalContentRef.current.innerHTML;
setOriginalContent(content);
// Handle editor input without re-sanitizing content
const handleEditorInput = () => {
if (editorRef.current) {
// Capture innerHTML directly without reapplying DOMPurify
setEmailContent(editorRef.current.innerHTML);
}
};
// Toggle original content editing
const toggleEditOriginalContent = () => {
setEditingOriginalContent(!editingOriginalContent);
// If we're starting to edit, make sure the content is ready and focused
if (!editingOriginalContent) {
setTimeout(() => {
if (originalContentRef.current) {
originalContentRef.current.focus();
// Place cursor at the beginning
const selection = window.getSelection();
const range = document.createRange();
if (originalContentRef.current.firstChild) {
range.setStart(originalContentRef.current.firstChild, 0);
} else {
range.setStart(originalContentRef.current, 0);
}
range.collapse(true);
selection?.removeAllRanges();
selection?.addRange(range);
}
}, 100);
}
};
// Handling click on original content even when not in edit mode
const handleOriginalContentClick = () => {
if (!editingOriginalContent) {
toggleEditOriginalContent();
}
// Toggle text direction for the entire editor
const toggleTextDirection = () => {
setIsRTL(!isRTL);
};
// Modified send handler to use the entire body content
// Send email without modifying pre-formatted content
const handleSend = async () => {
if (!to) {
alert('Please specify at least one recipient');
@ -361,13 +278,12 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
try {
setSending(true);
// Use the complete edited content as is
await onSend({
to,
cc: cc || undefined,
bcc: bcc || undefined,
subject,
body: userMessage, // Use the full edited message
body: emailContent, // Use the raw edited content
attachments
});
@ -380,23 +296,6 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
}
};
// Handle editor input for the entire content
const handleEditorInput = (e: React.FormEvent<HTMLDivElement>) => {
if (editorRef.current) {
const content = editorRef.current.innerHTML;
setUserMessage(content);
setBody(content);
}
};
// Toggle text direction
const toggleTextDirection = () => {
setIsRTL(!isRTL);
if (editorRef.current) {
editorRef.current.dir = !isRTL ? 'rtl' : 'ltr';
}
};
return (
<Card className="w-full max-w-4xl mx-auto">
<CardHeader>
@ -509,14 +408,15 @@ export default function ComposeEmail(props: ComposeEmailAllProps) {
</Button>
</div>
{/* Email editor with a single editable area for the entire message */}
{/* Email editor with a single editable area */}
<div className="border rounded-md overflow-hidden">
<div
ref={editorRef}
contentEditable={!sending}
className="w-full p-4 min-h-[300px] focus:outline-none"
onInput={handleEditorInput}
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(body) }}
// Use dangerouslySetInnerHTML without sanitizing again
dangerouslySetInnerHTML={{ __html: emailContent }}
dir={isRTL ? 'rtl' : 'ltr'}
style={{
textAlign: isRTL ? 'right' : 'left'