courrier clean 2$
This commit is contained in:
parent
e3b946f7e9
commit
3e6b8cae1f
@ -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'
|
||||
|
||||
Loading…
Reference in New Issue
Block a user