ultisuite-client/lib/print-conversation.ts
2026-05-16 20:30:50 +02:00

176 lines
4.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { Email } from "@/lib/email-data"
import { formatMailDetailDate } from "@/lib/mail-date"
import { cleanSenderName } from "@/lib/sender-display"
function escapeHtml(s: string): string {
return s
.replace(/&/g, "&")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
}
type PrintSegment = {
fromName: string
fromEmail: string
date: string
bodyHtml: string
}
function buildSegments(email: Email): PrintSegment[] {
const conv = email.conversation ?? []
const segments: PrintSegment[] = []
for (const msg of conv) {
segments.push({
fromName: cleanSenderName(msg.sender),
fromEmail: msg.senderEmail,
date: formatMailDetailDate(msg.date),
bodyHtml: msg.body,
})
}
const mainName = cleanSenderName(email.sender)
const mainEmail =
email.senderEmail ||
`${mainName.toLowerCase().replace(/\s+/g, ".")}@example.com`
segments.push({
fromName: mainName,
fromEmail: mainEmail,
date: formatMailDetailDate(email.date),
bodyHtml:
email.body ??
`<p style="color:#5f6368;margin:0;">${escapeHtml(email.preview)}</p>`,
})
return segments
}
function buildPrintHtml(email: Email): string {
const subject = escapeHtml(email.subject)
const segments = buildSegments(email)
const blocks = segments
.map(
(seg) => `
<article class="msg">
<header class="msg-hdr">
<div class="row"><span class="lbl">De</span><span class="val">${escapeHtml(seg.fromName)} &lt;${escapeHtml(seg.fromEmail)}&gt;</span></div>
<div class="row"><span class="lbl">À</span><span class="val">moi</span></div>
<div class="row"><span class="lbl">Date</span><span class="val">${escapeHtml(seg.date)}</span></div>
</header>
<div class="msg-body">${seg.bodyHtml}</div>
</article>`
)
.join("")
return `<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>${subject}</title>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; img-src https: data:;">
<style>
* { box-sizing: border-box; }
body {
margin: 0;
padding: 20px 24px 32px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
font-size: 14px;
line-height: 1.5;
color: #202124;
background: #fff;
}
.thread-subject {
font-size: 18px;
font-weight: 600;
margin: 0 0 20px;
padding-bottom: 14px;
border-bottom: 1px solid #dadce0;
}
.msg {
margin: 0 0 28px;
padding: 0 0 22px;
border-bottom: 1px solid #eceff1;
page-break-inside: avoid;
}
.msg:last-of-type { border-bottom: none; padding-bottom: 0; margin-bottom: 0; }
.msg-hdr {
font-size: 12px;
color: #5f6368;
margin-bottom: 14px;
}
.msg-hdr .row {
display: flex;
gap: 10px;
margin-bottom: 4px;
align-items: baseline;
}
.msg-hdr .lbl {
flex: 0 0 52px;
font-weight: 600;
color: #3c4043;
}
.msg-hdr .val { flex: 1; min-width: 0; word-break: break-word; }
.msg-body {
font-size: 14px;
line-height: 1.6;
color: #202124;
}
.msg-body a { color: #1a73e8; }
.msg-body img { max-width: 100%; height: auto; }
.msg-body pre, .msg-body code { background: #f6f8fa; border-radius: 3px; font-size: 13px; }
.msg-body pre { padding: 10px; overflow-x: auto; }
.msg-body code { padding: 2px 5px; }
@media print {
body { padding: 12px 16px; }
.msg-body a { color: #000; text-decoration: underline; }
}
</style>
</head>
<body>
<h1 class="thread-subject">${subject}</h1>
${blocks}
</body>
</html>`
}
/**
* Ouvre un nouvel onglet avec la conversation en mise en page imprimable
* (en-têtes De / À / Date par message), puis déclenche la boîte dimpression du système.
*/
export function openConversationPrint(email: Email): void {
if (typeof window === "undefined") return
const html = buildPrintHtml(email)
const win = window.open("", "_blank", "noopener,noreferrer")
if (!win) {
window.alert(
"Impossible douvrir la fenêtre dimpression. Vérifiez que les fenêtres pop-up ne sont pas bloquées pour ce site."
)
return
}
win.document.open()
win.document.write(html)
win.document.close()
const runPrint = () => {
try {
win.focus()
win.print()
} catch {
/* ignore */
}
}
if (win.document.readyState === "complete") {
window.setTimeout(runPrint, 0)
} else {
win.addEventListener("load", () => window.setTimeout(runPrint, 0), { once: true })
}
}