courrier clean 2$

This commit is contained in:
alma 2025-04-26 21:12:18 +02:00
parent 1685946c07
commit fb0ab72675

View File

@ -6,33 +6,21 @@ import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input'; import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea'; import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import DOMPurify from 'isomorphic-dompurify'; import { sanitizeHtml } from '@/lib/utils/email-formatter';
// Add a CSS style block to handle the direction properly // Simple CSS for email styling - leverages our centralized sanitization for text direction
const forceLTRStyles = ` const emailStyles = `
.force-ltr {
direction: ltr !important;
text-align: left !important;
unicode-bidi: isolate !important;
writing-mode: horizontal-tb !important;
}
.force-ltr * {
direction: ltr !important;
text-align: left !important;
unicode-bidi: isolate !important;
}
[dir="rtl"] .force-ltr,
[dir="rtl"] .force-ltr * {
direction: ltr !important;
text-align: left !important;
}
.email-content { .email-content {
direction: ltr !important; font-family: Arial, sans-serif;
text-align: left !important;
} }
.email-content * { .quoted-content {
direction: ltr !important; margin-top: 20px;
text-align: left !important; border-top: 1px solid #e2e2e2;
padding-top: 10px;
color: #555;
}
.user-message {
margin-bottom: 20px;
} }
`; `;
@ -164,17 +152,19 @@ export default function ComposeEmail({
// Handle contentEditable input changes // Handle contentEditable input changes
const handleUserMessageChange = () => { const handleUserMessageChange = () => {
if (contentEditableRef.current) { if (contentEditableRef.current) {
const content = contentEditableRef.current.innerHTML; let content = contentEditableRef.current.innerHTML;
// Check if this is the initial state or if the user has actually typed something // Check if this is the initial state or if the user has actually typed something
if (content && content !== '<p>Write your message here...</p>') { if (content && content !== '<p>Write your message here...</p>') {
setHasStartedTyping(true); setHasStartedTyping(true);
} }
// Sanitize the user's message using our centralized sanitizer
content = sanitizeHtml(content);
setUserMessage(content); setUserMessage(content);
// Combine user message with quoted content for the full email body // Combine user message with quoted content for the full email body
const combined = `${content}${quotedContent ? `<div class="original-content">${quotedContent}</div>` : ''}`; const combined = `${content}${quotedContent ? `<div class="quoted-content">${quotedContent}</div>` : ''}`;
setComposeBody(combined); setComposeBody(combined);
} }
}; };
@ -188,10 +178,12 @@ export default function ComposeEmail({
// For rich editor, combine user message with quoted content // For rich editor, combine user message with quoted content
if (useRichEditor) { if (useRichEditor) {
// Wrap the content with proper direction styles // Wrap the content with appropriate styling
const userContent = userMessage ? `<div class="force-ltr user-message">${userMessage}</div>` : ''; const userContent = userMessage ? `<div class="user-message">${userMessage}</div>` : '';
const quotedWithStyles = quotedContent ? `<div class="force-ltr quoted-content" style="margin-top: 20px; border-top: 1px solid #e2e2e2; padding-top: 10px;">${quotedContent}</div>` : ''; const quotedWithStyles = quotedContent ? `<div class="quoted-content">${quotedContent}</div>` : '';
const combinedContent = `${userContent}${quotedWithStyles}`;
// Use our centralized sanitizer to ensure proper direction
const combinedContent = sanitizeHtml(`${userContent}${quotedWithStyles}`);
setComposeBody(combinedContent); setComposeBody(combinedContent);
@ -235,7 +227,7 @@ export default function ComposeEmail({
{showCompose && ( {showCompose && (
<div className="fixed inset-0 bg-gray-600/30 backdrop-blur-sm z-50 flex items-center justify-center"> <div className="fixed inset-0 bg-gray-600/30 backdrop-blur-sm z-50 flex items-center justify-center">
{/* Add global styles for email direction */} {/* Add global styles for email direction */}
<style dangerouslySetInnerHTML={{ __html: forceLTRStyles }} /> <style dangerouslySetInnerHTML={{ __html: emailStyles }} />
<div className="w-full max-w-2xl h-[80vh] bg-white rounded-xl shadow-xl flex flex-col mx-4"> <div className="w-full max-w-2xl h-[80vh] bg-white rounded-xl shadow-xl flex flex-col mx-4">
{/* Modal Header */} {/* Modal Header */}
@ -341,58 +333,39 @@ export default function ComposeEmail({
<Label htmlFor="message" className="block text-sm font-medium text-gray-700">Message</Label> <Label htmlFor="message" className="block text-sm font-medium text-gray-700">Message</Label>
{useRichEditor ? ( {useRichEditor ? (
<div className="mt-1 border border-gray-300 rounded-md overflow-hidden flex flex-col"> <>
{/* User input area - clearly separated from quoted content */} <div className="border rounded-md mb-4 overflow-hidden">
<div <div className="flex flex-col h-full">
ref={contentEditableRef}
contentEditable="true"
className="w-full p-3 bg-white min-h-[150px] text-gray-900 email-editor"
onInput={handleUserMessageChange}
onFocus={() => {
// Clear placeholder text when user focuses if they haven't started typing
if (!hasStartedTyping && contentEditableRef.current) {
contentEditableRef.current.innerHTML = '';
}
}}
onBlur={() => {
// Restore placeholder if user hasn't typed anything
if (!hasStartedTyping && contentEditableRef.current && !contentEditableRef.current.innerHTML.trim()) {
contentEditableRef.current.innerHTML = '<p>Write your message here...</p>';
}
}}
dangerouslySetInnerHTML={hasStartedTyping ? { __html: userMessage } : { __html: '<p>Write your message here...</p>' }}
style={{ direction: 'ltr', textAlign: 'left' }}
/>
{/* Original email content with clear visual separation */}
{quotedContent && (
<>
<div className="px-3 py-2 bg-gray-100 border-t border-gray-300 text-xs text-gray-500 font-medium">
{composeSubject.startsWith('Re:') ? 'Original message' : 'Forwarded message'}
</div>
<div <div
className="w-full bg-gray-50 border-t border-gray-200 email-content-wrapper" className="p-3 prose max-w-none flex-grow min-h-[200px]"
style={{ direction: 'ltr' }} ref={contentEditableRef}
> contentEditable="true"
<div onInput={handleUserMessageChange}
className="p-3 text-sm email-content force-ltr" onFocus={() => {
dangerouslySetInnerHTML={{ __html: quotedContent }} // Clear 'Write your message here...' when user focuses on the editor
contentEditable="false" if (!hasStartedTyping && contentEditableRef.current) {
style={{ contentEditableRef.current.innerHTML = '';
direction: 'ltr', }
textAlign: 'left', }}
unicodeBidi: 'isolate', onBlur={() => {
writingMode: 'horizontal-tb', // Restore 'Write your message here...' placeholder if empty
color: '#555', if (!hasStartedTyping && contentEditableRef.current && !contentEditableRef.current.innerHTML.trim()) {
borderLeft: '3px solid #ccc', contentEditableRef.current.innerHTML = '<p>Write your message here...</p>';
paddingLeft: '10px', }
margin: '0 10px', }}
}} dangerouslySetInnerHTML={hasStartedTyping ? { __html: userMessage } : { __html: '<p>Write your message here...</p>' }}
/> />
</div> </div>
</> </div>
{/* Original email content (quoted part) */}
{quotedContent && (
<div
className="p-3 text-sm email-content quoted-content"
dangerouslySetInnerHTML={{ __html: quotedContent }}
contentEditable="false"
/>
)} )}
</div> </>
) : ( ) : (
<Textarea <Textarea
id="message" id="message"
@ -400,7 +373,6 @@ export default function ComposeEmail({
onChange={(e) => setComposeBody(e.target.value)} onChange={(e) => setComposeBody(e.target.value)}
placeholder="Write your message..." placeholder="Write your message..."
className="w-full mt-1 min-h-[200px] bg-white border-gray-300 text-gray-900 resize-none email-editor" className="w-full mt-1 min-h-[200px] bg-white border-gray-300 text-gray-900 resize-none email-editor"
style={{ direction: 'ltr', textAlign: 'left' }}
/> />
)} )}
</div> </div>