courrier preview
This commit is contained in:
parent
6c9f2d86a6
commit
c4958d7e4c
@ -15,7 +15,7 @@ import {
|
|||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import RichTextEditor from '@/components/ui/rich-text-editor';
|
import RichEmailEditor from '@/components/email/RichEmailEditor';
|
||||||
import { processContentWithDirection } from '@/lib/utils/text-direction';
|
import { processContentWithDirection } from '@/lib/utils/text-direction';
|
||||||
|
|
||||||
// Import from the centralized utils
|
// Import from the centralized utils
|
||||||
@ -137,14 +137,6 @@ export default function ComposeEmail(props: ComposeEmailProps) {
|
|||||||
// Focus the editor
|
// Focus the editor
|
||||||
editorRef.current.focus();
|
editorRef.current.focus();
|
||||||
|
|
||||||
// Put cursor at the beginning
|
|
||||||
const selection = window.getSelection();
|
|
||||||
const range = document.createRange();
|
|
||||||
range.setStart(editorRef.current, 0);
|
|
||||||
range.collapse(true);
|
|
||||||
selection?.removeAllRanges();
|
|
||||||
selection?.addRange(range);
|
|
||||||
|
|
||||||
// Also make sure editor container is scrolled to top
|
// Also make sure editor container is scrolled to top
|
||||||
editorRef.current.scrollTop = 0;
|
editorRef.current.scrollTop = 0;
|
||||||
|
|
||||||
@ -216,6 +208,9 @@ export default function ComposeEmail(props: ComposeEmailProps) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get initial direction for the content
|
||||||
|
const { direction } = processContentWithDirection(emailContent);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full max-h-[80vh] bg-white border rounded-md shadow-md">
|
<div className="flex flex-col h-full max-h-[80vh] bg-white border rounded-md shadow-md">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
@ -348,17 +343,13 @@ export default function ComposeEmail(props: ComposeEmailProps) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Message Body */}
|
{/* Message Body */}
|
||||||
<RichTextEditor
|
<RichEmailEditor
|
||||||
ref={editorRef}
|
|
||||||
initialContent={emailContent}
|
initialContent={emailContent}
|
||||||
initialDirection={processContentWithDirection(emailContent).direction}
|
|
||||||
onChange={(html) => {
|
onChange={(html) => {
|
||||||
// Store the content
|
|
||||||
setEmailContent(html);
|
setEmailContent(html);
|
||||||
// Direction will be handled automatically by the RichTextEditor based on content
|
|
||||||
}}
|
}}
|
||||||
className="min-h-[320px] border rounded-md bg-white text-gray-800 flex-1"
|
|
||||||
placeholder="Write your message here..."
|
placeholder="Write your message here..."
|
||||||
|
minHeight="320px"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Attachments */}
|
{/* Attachments */}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
import 'quill/dist/quill.snow.css';
|
import 'quill/dist/quill.snow.css';
|
||||||
import { sanitizeHtml } from '@/lib/utils/email-utils';
|
import { sanitizeHtml } from '@/lib/utils/email-utils';
|
||||||
|
import { processContentWithDirection } from '@/lib/utils/text-direction';
|
||||||
|
|
||||||
interface RichEmailEditorProps {
|
interface RichEmailEditorProps {
|
||||||
initialContent: string;
|
initialContent: string;
|
||||||
@ -58,6 +59,7 @@ const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
|||||||
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
|
||||||
[{ 'indent': '-1'}, { 'indent': '+1' }],
|
[{ 'indent': '-1'}, { 'indent': '+1' }],
|
||||||
[{ 'align': [] }],
|
[{ 'align': [] }],
|
||||||
|
[{ 'direction': 'rtl' }], // Add direction to toolbar
|
||||||
['link'],
|
['link'],
|
||||||
['clean'],
|
['clean'],
|
||||||
];
|
];
|
||||||
@ -79,19 +81,20 @@ const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
|||||||
theme: 'snow',
|
theme: 'snow',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Process initial content to detect direction
|
||||||
|
const { direction, html: processedContent } = processContentWithDirection(initialContent);
|
||||||
|
|
||||||
// Set initial content properly
|
// Set initial content properly
|
||||||
if (initialContent) {
|
if (initialContent) {
|
||||||
try {
|
try {
|
||||||
console.log('Setting initial content in editor', {
|
console.log('Setting initial content in editor', {
|
||||||
length: initialContent.length,
|
length: initialContent.length,
|
||||||
startsWithHtml: initialContent.trim().startsWith('<')
|
startsWithHtml: initialContent.trim().startsWith('<'),
|
||||||
|
direction
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure content is properly sanitized before injecting it
|
// Make sure content is properly sanitized before injecting it
|
||||||
const cleanContent = initialContent
|
const cleanContent = sanitizeHtml(processedContent || initialContent);
|
||||||
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '') // Remove scripts
|
|
||||||
.replace(/on\w+="[^"]*"/g, '') // Remove event handlers
|
|
||||||
.replace(/(javascript|jscript|vbscript|mocha):/gi, 'removed:'); // Remove protocol handlers
|
|
||||||
|
|
||||||
// First, directly set the content
|
// First, directly set the content
|
||||||
if (editorRef.current) {
|
if (editorRef.current) {
|
||||||
@ -112,6 +115,12 @@ const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
|||||||
// Insert clean content
|
// Insert clean content
|
||||||
quillRef.current.clipboard.dangerouslyPasteHTML(0, content);
|
quillRef.current.clipboard.dangerouslyPasteHTML(0, content);
|
||||||
|
|
||||||
|
// Set the direction for the content
|
||||||
|
quillRef.current.format('direction', direction);
|
||||||
|
if (direction === 'rtl') {
|
||||||
|
quillRef.current.format('align', 'right');
|
||||||
|
}
|
||||||
|
|
||||||
// Set cursor at the beginning (before the quoted content)
|
// Set cursor at the beginning (before the quoted content)
|
||||||
quillRef.current.setSelection(0, 0);
|
quillRef.current.setSelection(0, 0);
|
||||||
|
|
||||||
@ -188,11 +197,20 @@ const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
|||||||
// Preserve cursor position if possible
|
// Preserve cursor position if possible
|
||||||
const selection = quillRef.current.getSelection();
|
const selection = quillRef.current.getSelection();
|
||||||
|
|
||||||
|
// Process content to ensure correct direction
|
||||||
|
const { direction, html: processedContent } = processContentWithDirection(initialContent);
|
||||||
|
|
||||||
// First clear the content
|
// First clear the content
|
||||||
quillRef.current.root.innerHTML = '';
|
quillRef.current.root.innerHTML = '';
|
||||||
|
|
||||||
// Then insert the new content at position 0
|
// Then insert the new content at position 0
|
||||||
quillRef.current.clipboard.dangerouslyPasteHTML(0, sanitizeHtml(initialContent));
|
quillRef.current.clipboard.dangerouslyPasteHTML(0, sanitizeHtml(processedContent || initialContent));
|
||||||
|
|
||||||
|
// Set the direction for the content
|
||||||
|
quillRef.current.format('direction', direction);
|
||||||
|
if (direction === 'rtl') {
|
||||||
|
quillRef.current.format('align', 'right');
|
||||||
|
}
|
||||||
|
|
||||||
// Force update
|
// Force update
|
||||||
quillRef.current.update();
|
quillRef.current.update();
|
||||||
@ -235,6 +253,9 @@ const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
|||||||
<span className="ql-formats">
|
<span className="ql-formats">
|
||||||
<select className="ql-align"></select>
|
<select className="ql-align"></select>
|
||||||
</span>
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-direction" value="rtl"></button>
|
||||||
|
</span>
|
||||||
<span className="ql-formats">
|
<span className="ql-formats">
|
||||||
<button className="ql-link"></button>
|
<button className="ql-link"></button>
|
||||||
</span>
|
</span>
|
||||||
@ -268,6 +289,7 @@ const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.rich-email-editor-container {
|
.rich-email-editor-container {
|
||||||
@ -296,6 +318,17 @@ const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add RTL support styles */
|
||||||
|
:global([dir="rtl"] .ql-editor) {
|
||||||
|
text-align: right;
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.ql-editor[dir="rtl"]) {
|
||||||
|
text-align: right;
|
||||||
|
direction: rtl;
|
||||||
|
}
|
||||||
|
|
||||||
:global(.ql-container) {
|
:global(.ql-container) {
|
||||||
border: none !important;
|
border: none !important;
|
||||||
height: auto !important;
|
height: auto !important;
|
||||||
@ -339,6 +372,14 @@ const RichEmailEditor: React.FC<RichEmailEditorProps> = ({
|
|||||||
font-size: 13px !important;
|
font-size: 13px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* RTL blockquote styling */
|
||||||
|
:global(.ql-editor[dir="rtl"] blockquote),
|
||||||
|
:global([dir="rtl"] .ql-editor blockquote) {
|
||||||
|
border-left: none !important;
|
||||||
|
border-right: 2px solid #ddd !important;
|
||||||
|
padding: 10px 15px 10px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fix table rendering */
|
/* Fix table rendering */
|
||||||
:global(.ql-editor table) {
|
:global(.ql-editor table) {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user