mail page fix design

This commit is contained in:
alma 2025-04-21 22:08:48 +02:00
parent 7fc90a4940
commit 30684cb3b9
3 changed files with 67 additions and 86 deletions

View File

@ -1433,10 +1433,11 @@ export default function CourrierPage() {
// Get the formatted original email content
const originalContent = getReplyBody(selectedEmail, type);
// Format with clear separator
// Create a clean structure with clear separation
const formattedContent = `
<div id="original-email" dir="ltr" style="margin-top: 20px; border-top: 1px solid #e0e0e0; padding-top: 10px; color: #555;">
<div id="new-reply-area" dir="ltr" style="margin-bottom: 20px; min-height: 40px;"></div>
<div id="original-email" dir="ltr" style="border-top: 1px solid #e0e0e0; padding-top: 10px; color: #555;">
${originalContent}
</div>
`;

View File

@ -57,60 +57,65 @@ export default function ComposeEmail({
originalEmail
}: ComposeEmailProps) {
const composeBodyRef = useRef<HTMLDivElement>(null);
const newReplyRef = useRef<HTMLDivElement>(null);
const [showOriginalContent, setShowOriginalContent] = useState(true);
const [localContent, setLocalContent] = useState('');
useEffect(() => {
if (composeBodyRef.current) {
const decodedContent = decodeComposeContent(composeBody);
// Create the clear structure with proper content
composeBodyRef.current.innerHTML = `
<div id="new-reply-area" dir="ltr" style="margin-bottom: 20px; min-height: 40px; direction: ltr; text-align: left; unicode-bidi: normal;"></div>
<div class="original-email" dir="ltr" style="border-top: 1px solid #e0e0e0; padding-top: 10px; color: #555; direction: ltr; text-align: left; unicode-bidi: normal;">
${decodedContent}
</div>
`;
// Place cursor in the new reply area
const newReplyArea = composeBodyRef.current.querySelector('#new-reply-area');
if (newReplyArea) {
const range = document.createRange();
const sel = window.getSelection();
range.setStart(newReplyArea, 0);
range.collapse(true);
sel?.removeAllRanges();
sel?.addRange(range);
}
}
}, [composeBody]);
// Enhanced input handler to prevent text reversal
const handleInput = (e: React.FormEvent<HTMLDivElement>) => {
if (composeBodyRef.current) {
// Get the current HTML content
const fullContent = e.currentTarget.innerHTML;
// Split at the divider to separate new reply from original content
const parts = fullContent.split('<div class="original-email"');
// Only update the first part (user's input) and preserve original email
if (parts.length > 1) {
// Extract user-typed content (ensuring it's not reversed)
const userContent = parts[0];
// Only initialize once when empty or first loading
if (!composeBody || composeBody.trim() === '') {
// Simple structure with one area for new text and one for original
composeBodyRef.current.innerHTML = `
<div id="new-reply-area" dir="ltr" style="margin-bottom: 20px; min-height: 40px;"></div>
<div id="original-email" dir="ltr" style="border-top: 1px solid #e0e0e0; padding-top: 10px; color: #555;">
${composeBody ? decodeComposeContent(composeBody) : ''}
</div>
`;
// Keep original content as is
const originalContent = '<div class="original-email"' + parts[1];
// Update the compose body with encoded content
const encodedContent = encodeComposeContent(userContent + originalContent);
setComposeBody(encodedContent);
// Place cursor at the beginning of new reply area
const newReplyArea = composeBodyRef.current.querySelector('#new-reply-area');
if (newReplyArea) {
const range = document.createRange();
const sel = window.getSelection();
range.setStart(newReplyArea, 0);
range.collapse(true);
sel?.removeAllRanges();
sel?.addRange(range);
}
} else {
// If no original content yet, just encode the user's input
const encodedContent = encodeComposeContent(fullContent);
setComposeBody(encodedContent);
// For existing content, just update the original email part
const originalEmailDiv = composeBodyRef.current.querySelector('#original-email');
if (originalEmailDiv) {
originalEmailDiv.innerHTML = decodeComposeContent(composeBody);
}
}
}
}, []); // Only run once on initial mount, not on every composeBody change
// Modified input handler to prevent nested structures
const handleInput = (e: React.FormEvent<HTMLDivElement>) => {
// Get raw content from the editable div
const currentContent = e.currentTarget.innerHTML;
// Store the original content reference
const originalEmailDiv = e.currentTarget.querySelector('#original-email');
const originalContent = originalEmailDiv?.innerHTML || '';
// Extract user-typed content (everything before original-email div)
const userContent = currentContent.split('<div id="original-email"')[0];
// Update local state
setLocalContent(userContent);
// Combine new reply and original formatted correctly
const combinedContent = `
${userContent}
<div id="original-email" dir="ltr" style="border-top: 1px solid #e0e0e0; padding-top: 10px; color: #555;">
${originalContent}
</div>
`;
// Update the compose body
setComposeBody(combinedContent);
};
const handleFileAttachment = async (e: React.ChangeEvent<HTMLInputElement>) => {
@ -261,20 +266,12 @@ export default function ComposeEmail({
</div>
{/* Original Email Content Preview */}
{originalEmail && showOriginalContent && (
{originalEmail && (
<div className="border rounded-md p-4 bg-gray-50">
<div className="flex items-center justify-between mb-2">
<h4 className="text-sm font-medium text-gray-700">
{originalEmail.type === 'forward' ? 'Forwarded Message' : 'Original Message'}
</h4>
<Button
variant="ghost"
size="sm"
onClick={() => setShowOriginalContent(false)}
className="text-gray-500 hover:text-gray-700"
>
<X className="h-4 w-4" />
</Button>
</div>
<div
className="prose max-w-none text-sm text-gray-600"
@ -293,9 +290,7 @@ export default function ComposeEmail({
className="w-full h-full mt-1 bg-white border border-gray-300 rounded-md p-2 text-gray-900 overflow-y-auto"
style={{
minHeight: '200px',
direction: 'ltr',
textAlign: 'left',
unicodeBidi: 'normal'
direction: 'ltr'
}}
dir="ltr"
spellCheck="true"

View File

@ -1,15 +1,12 @@
/**
* Simple MIME decoder for compose message box
* Handles basic email content and text direction
* Handles basic email content without creating nested structures
*/
export function decodeComposeContent(content: string): string {
if (!content) return '';
// Debug logging
console.log("Before decode:", content);
// Basic HTML cleaning without any string manipulation that could reverse text
// Basic HTML cleaning without creating nested structures
let cleaned = content
// Remove script and style tags
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
@ -29,8 +26,6 @@ export function decodeComposeContent(content: string): string {
.replace(/<br\s*\/?>/gi, '\n')
.replace(/<p[^>]*>/gi, '\n')
.replace(/<\/p>/gi, '\n')
.replace(/<div[^>]*>/gi, '\n')
.replace(/<\/div>/gi, '\n')
// Handle lists
.replace(/<ul[^>]*>/gi, '\n')
.replace(/<\/ul>/gi, '\n')
@ -59,22 +54,15 @@ export function decodeComposeContent(content: string): string {
// Clean up whitespace
.replace(/\s+/g, ' ')
.trim();
// Debug logging
console.log("After decode:", cleaned);
// Ensure all content has proper direction
cleaned = `<div dir="ltr" style="direction: ltr; text-align: left; unicode-bidi: normal;">${cleaned}</div>`;
// Do NOT wrap in additional divs
return cleaned;
}
export function encodeComposeContent(content: string): string {
if (!content) return '';
// Debug logging
console.log("Before encode:", content);
// Basic HTML encoding without reversing
// Basic HTML encoding without adding structure
const encoded = content
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
@ -82,9 +70,6 @@ export function encodeComposeContent(content: string): string {
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/\n/g, '<br>');
// Debug logging
console.log("After encode:", encoded);
return encoded;
}