compose mime
This commit is contained in:
parent
0dbc7706cd
commit
87a0879166
@ -115,7 +115,7 @@ function EmailContent({ email }: { email: Email }) {
|
|||||||
try {
|
try {
|
||||||
if (!email.body) {
|
if (!email.body) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setContent(null);
|
setContent(<div className="text-gray-500">No content available</div>);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -124,7 +124,7 @@ function EmailContent({ email }: { email: Email }) {
|
|||||||
const formattedEmail = email.body.trim();
|
const formattedEmail = email.body.trim();
|
||||||
if (!formattedEmail) {
|
if (!formattedEmail) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setContent(null);
|
setContent(<div className="text-gray-500">No content available</div>);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -137,7 +137,7 @@ function EmailContent({ email }: { email: Email }) {
|
|||||||
setContent(
|
setContent(
|
||||||
<div
|
<div
|
||||||
className="email-content prose prose-sm max-w-none dark:prose-invert"
|
className="email-content prose prose-sm max-w-none dark:prose-invert"
|
||||||
dangerouslySetInnerHTML={{ __html: parsedEmail.html }}
|
dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(parsedEmail.html) }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (parsedEmail.text) {
|
} else if (parsedEmail.text) {
|
||||||
@ -147,7 +147,7 @@ function EmailContent({ email }: { email: Email }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
setContent(null);
|
setContent(<div className="text-gray-500">No content available</div>);
|
||||||
}
|
}
|
||||||
setError(null);
|
setError(null);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@ -181,7 +181,7 @@ function EmailContent({ email }: { email: Email }) {
|
|||||||
return <div className="text-red-500">{error}</div>;
|
return <div className="text-red-500">{error}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return content;
|
return content || <div className="text-gray-500">No content available</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderEmailContent(email: Email) {
|
function renderEmailContent(email: Email) {
|
||||||
@ -330,15 +330,29 @@ function getReplyBody(email: Email, type: 'reply' | 'reply-all' | 'forward' = 'r
|
|||||||
function EmailPreview({ email }: { email: Email }) {
|
function EmailPreview({ email }: { email: Email }) {
|
||||||
const [preview, setPreview] = useState<string>('');
|
const [preview, setPreview] = useState<string>('');
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let mounted = true;
|
let mounted = true;
|
||||||
|
|
||||||
async function loadPreview() {
|
async function loadPreview() {
|
||||||
|
if (!email?.body) {
|
||||||
|
if (mounted) setPreview('No content available');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
const decoded = await decodeEmail(email.body);
|
const decoded = await decodeEmail(email.body);
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setPreview(decoded.text || cleanHtml(decoded.html || ''));
|
if (decoded.text) {
|
||||||
|
setPreview(decoded.text.substring(0, 150) + '...');
|
||||||
|
} else if (decoded.html) {
|
||||||
|
const cleanText = decoded.html.replace(/<[^>]*>/g, ' ').trim();
|
||||||
|
setPreview(cleanText.substring(0, 150) + '...');
|
||||||
|
} else {
|
||||||
|
setPreview('No preview available');
|
||||||
|
}
|
||||||
setError(null);
|
setError(null);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -347,6 +361,8 @@ function EmailPreview({ email }: { email: Email }) {
|
|||||||
setError('Error generating preview');
|
setError('Error generating preview');
|
||||||
setPreview('');
|
setPreview('');
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
if (mounted) setIsLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,7 +371,11 @@ function EmailPreview({ email }: { email: Email }) {
|
|||||||
return () => {
|
return () => {
|
||||||
mounted = false;
|
mounted = false;
|
||||||
};
|
};
|
||||||
}, [email.body]);
|
}, [email?.body]);
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <span className="text-gray-400">Loading preview...</span>;
|
||||||
|
}
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return <span className="text-red-500 text-xs">{error}</span>;
|
return <span className="text-red-500 text-xs">{error}</span>;
|
||||||
|
|||||||
@ -113,12 +113,11 @@ export default function ComposeEmail({
|
|||||||
body: JSON.stringify({ email: emailToProcess.body }),
|
body: JSON.stringify({ email: emailToProcess.body }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed to parse email');
|
throw new Error(data.error || 'Failed to parse email');
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsedEmail = await response.json();
|
|
||||||
|
|
||||||
// Format the reply/forward content
|
// Format the reply/forward content
|
||||||
const quotedContent = forwardFrom ? `
|
const quotedContent = forwardFrom ? `
|
||||||
<div style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;">
|
<div style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;">
|
||||||
@ -129,14 +128,14 @@ export default function ComposeEmail({
|
|||||||
To: ${emailToProcess.to}<br/>
|
To: ${emailToProcess.to}<br/>
|
||||||
${emailToProcess.cc ? `Cc: ${emailToProcess.cc}<br/>` : ''}
|
${emailToProcess.cc ? `Cc: ${emailToProcess.cc}<br/>` : ''}
|
||||||
<br/>
|
<br/>
|
||||||
${parsedEmail.html || parsedEmail.text || 'No content available'}
|
${data.html || data.text || 'No content available'}
|
||||||
</div>
|
</div>
|
||||||
` : `
|
` : `
|
||||||
<div style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;">
|
<div style="border-top: 1px solid #e5e7eb; padding-top: 20px; margin-top: 20px; color: #6b7280; font-size: 0.875rem;">
|
||||||
On ${new Date(emailToProcess.date).toLocaleString()}, ${emailToProcess.from} wrote:
|
On ${new Date(emailToProcess.date).toLocaleString()}, ${emailToProcess.from} wrote:
|
||||||
</div>
|
</div>
|
||||||
<blockquote style="margin: 0; padding-left: 1em; border-left: 2px solid #e5e7eb; color: #6b7280;">
|
<blockquote style="margin: 0; padding-left: 1em; border-left: 2px solid #e5e7eb; color: #6b7280;">
|
||||||
${parsedEmail.html || parsedEmail.text || 'No content available'}
|
${data.html || data.text || 'No content available'}
|
||||||
</blockquote>
|
</blockquote>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@ -160,6 +159,7 @@ export default function ComposeEmail({
|
|||||||
|
|
||||||
// Update compose state
|
// Update compose state
|
||||||
setComposeBody(formattedContent);
|
setComposeBody(formattedContent);
|
||||||
|
setLocalContent(formattedContent);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error initializing compose content:', error);
|
console.error('Error initializing compose content:', error);
|
||||||
@ -171,6 +171,8 @@ export default function ComposeEmail({
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
composeBodyRef.current.innerHTML = errorContent;
|
composeBodyRef.current.innerHTML = errorContent;
|
||||||
|
setComposeBody(errorContent);
|
||||||
|
setLocalContent(errorContent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user