opengraph stuff
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { Mail } from 'lucide-react';
|
||||
import { useClient } from 'hooks/useClient';
|
||||
import { useGlobal } from 'hooks/useGlobal';
|
||||
import type { EmailMessage } from 'types';
|
||||
|
||||
const HtmlBody = ({ html }: { html: string }) => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const iframe = iframeRef.current;
|
||||
if (!iframe) return;
|
||||
const doc = iframe.contentDocument;
|
||||
if (!doc) return;
|
||||
doc.open();
|
||||
doc.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; font-size: 14px; margin: 0; padding: 16px; color: #e0e0e0; background: transparent; }
|
||||
a { color: #60a5fa; }
|
||||
img { max-width: 100%; height: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>${html}</body>
|
||||
</html>
|
||||
`);
|
||||
doc.close();
|
||||
}, [html]);
|
||||
|
||||
return <iframe ref={iframeRef} className="h-full w-full border-0" sandbox="allow-same-origin" title="Email body" />;
|
||||
};
|
||||
|
||||
export const EmailReader = () => {
|
||||
const client = useClient();
|
||||
const [selectedId] = useGlobal<string | null>('EMAIL_SELECTED', null);
|
||||
|
||||
const { data: message, isLoading } = useQuery({
|
||||
queryKey: ['email-message', selectedId],
|
||||
queryFn: () => client.get<EmailMessage>(`/email/messages/${selectedId}`),
|
||||
enabled: !!selectedId,
|
||||
});
|
||||
|
||||
if (!selectedId) {
|
||||
return (
|
||||
<div className="flex h-full flex-col items-center justify-center gap-2 text-sm opacity-50">
|
||||
<Mail className="h-10 w-10" />
|
||||
Select an email to read
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center text-sm opacity-50">
|
||||
Loading...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!message) return null;
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col overflow-hidden">
|
||||
<div className="flex flex-col gap-1 border-b px-4 py-3">
|
||||
<h2 className="text-lg font-semibold">{message.subject}</h2>
|
||||
<div className="flex flex-col gap-0.5 text-sm opacity-70">
|
||||
<div>
|
||||
<span className="font-medium">From:</span> {message.from}
|
||||
</div>
|
||||
<div>
|
||||
<span className="font-medium">To:</span> {message.to}
|
||||
</div>
|
||||
{message.cc && (
|
||||
<div>
|
||||
<span className="font-medium">Cc:</span> {message.cc}
|
||||
</div>
|
||||
)}
|
||||
<div className="text-xs opacity-60">{new Date(message.date).toLocaleString()}</div>
|
||||
</div>
|
||||
{message.attachments.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1.5 pt-1">
|
||||
{message.attachments.map((att: { filename: string; size: number; contentType: string }, i: number) => (
|
||||
<span key={i} className="rounded bg-accent px-2 py-0.5 text-xs">
|
||||
{att.filename} ({Math.round(att.size / 1024)}KB)
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 overflow-auto">
|
||||
{message.html ? (
|
||||
<HtmlBody html={message.html} />
|
||||
) : (
|
||||
<pre className="whitespace-pre-wrap p-4 text-sm">{message.text}</pre>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user