190 lines
6.7 KiB
TypeScript
190 lines
6.7 KiB
TypeScript
/**
|
|
* Wrapper HTML para templates de email do SGSE
|
|
* Aplica estilo governamental profissional com logo e assinatura padronizada
|
|
*/
|
|
|
|
/**
|
|
* Obtém a URL base do sistema para uso em links de email
|
|
*/
|
|
function getBaseUrl(): string {
|
|
// Em produção, usar variável de ambiente
|
|
const url = process.env.SITE_URL || 'http://localhost:5173';
|
|
// Garantir que tenha protocolo
|
|
if (!url.match(/^https?:\/\//i)) {
|
|
return `http://${url}`;
|
|
}
|
|
return url;
|
|
}
|
|
|
|
/**
|
|
* Gera o HTML do header com logo do Governo de PE
|
|
* Usa URL estática do SvelteKit para servir a logo
|
|
*/
|
|
function generateHeader(): string {
|
|
const baseUrl = getBaseUrl();
|
|
// URL da logo na pasta static do SvelteKit
|
|
const logoUrl = `${baseUrl}/logo_governo_PE.png`;
|
|
return `
|
|
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color: #0052A5; padding: 20px 0;">
|
|
<tr>
|
|
<td align="center">
|
|
<table width="600" cellpadding="0" cellspacing="0" border="0">
|
|
<tr>
|
|
<td style="text-align: center; padding: 20px 0;">
|
|
<img src="${logoUrl}" alt="Governo de Pernambuco" style="max-width: 200px; height: auto; display: block; margin: 0 auto;" />
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* Gera o HTML do footer com assinatura SGSE
|
|
*/
|
|
function generateFooter(): string {
|
|
const baseUrl = getBaseUrl();
|
|
const currentYear = new Date().getFullYear();
|
|
|
|
return `
|
|
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color: #f5f5f5; border-top: 3px solid #0052A5; margin-top: 30px;">
|
|
<tr>
|
|
<td align="center">
|
|
<table width="600" cellpadding="0" cellspacing="0" border="0" style="padding: 30px 20px;">
|
|
<tr>
|
|
<td style="text-align: center; font-family: Arial, sans-serif; color: #333333; font-size: 14px; line-height: 1.6;">
|
|
<p style="margin: 0 0 10px 0; font-weight: bold; color: #0052A5; font-size: 16px;">
|
|
SGSE - Sistema de Gerenciamento de Secretaria
|
|
</p>
|
|
<p style="margin: 0 0 10px 0; color: #666666;">
|
|
Secretaria de Esportes do Estado de Pernambuco
|
|
</p>
|
|
<p style="margin: 0 0 15px 0; color: #666666; font-size: 12px;">
|
|
Este é um email automático do sistema. Por favor, não responda diretamente a este email.
|
|
</p>
|
|
<hr style="border: none; border-top: 1px solid #dddddd; margin: 20px 0;" />
|
|
<p style="margin: 0; color: #999999; font-size: 11px;">
|
|
© ${currentYear} Secretaria de Esportes - Governo de Pernambuco. Todos os direitos reservados.
|
|
</p>
|
|
<p style="margin: 5px 0 0 0; color: #999999; font-size: 11px;">
|
|
<a href="${baseUrl}" style="color: #0052A5; text-decoration: none;">Acessar Sistema</a> |
|
|
<a href="${baseUrl}/ti/notificacoes" style="color: #0052A5; text-decoration: none;">Central de Notificações</a>
|
|
</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* Envolve o conteúdo HTML do email com template profissional governamental
|
|
* @param conteudoHTML - Conteúdo HTML do corpo do email
|
|
* @param titulo - Título do email (usado no meta)
|
|
* @returns HTML completo do email pronto para envio
|
|
*/
|
|
export function wrapEmailHTML(conteudoHTML: string, titulo?: string): string {
|
|
// Se o conteúdo já estiver dentro de um wrapper completo, retornar como está
|
|
if (conteudoHTML.includes('<!DOCTYPE html>') || conteudoHTML.includes('<html')) {
|
|
return conteudoHTML;
|
|
}
|
|
|
|
// Garantir que o conteúdo tenha estrutura básica
|
|
let conteudoProcessado = conteudoHTML.trim();
|
|
|
|
// Se não tiver tags HTML básicas, envolver em parágrafo
|
|
if (!conteudoProcessado.match(/^<[a-z]/i)) {
|
|
conteudoProcessado = `<p style="margin: 0 0 15px 0;">${conteudoProcessado}</p>`;
|
|
}
|
|
|
|
const header = generateHeader();
|
|
const footer = generateFooter();
|
|
const emailTitle = titulo || 'Notificação do SGSE';
|
|
|
|
return `
|
|
<!DOCTYPE html>
|
|
<html lang="pt-BR">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<title>${emailTitle}</title>
|
|
<!--[if mso]>
|
|
<style type="text/css">
|
|
body, table, td {font-family: Arial, sans-serif !important;}
|
|
</style>
|
|
<![endif]-->
|
|
</head>
|
|
<body style="margin: 0; padding: 0; background-color: #f5f5f5; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;">
|
|
<!-- Wrapper principal -->
|
|
<table width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color: #f5f5f5; padding: 20px 0;">
|
|
<tr>
|
|
<td align="center">
|
|
<!-- Container do conteúdo -->
|
|
<table width="600" cellpadding="0" cellspacing="0" border="0" style="background-color: #ffffff; border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); overflow: hidden;">
|
|
<!-- Header -->
|
|
${header}
|
|
|
|
<!-- Corpo do email -->
|
|
<tr>
|
|
<td style="padding: 30px 20px;">
|
|
<table width="100%" cellpadding="0" cellspacing="0" border="0">
|
|
<tr>
|
|
<td style="font-family: Arial, sans-serif; color: #333333; font-size: 14px; line-height: 1.6;">
|
|
${conteudoProcessado}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- Footer -->
|
|
<tr>
|
|
<td>
|
|
${footer}
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
|
|
<!-- Espaçamento inferior -->
|
|
<table width="600" cellpadding="0" cellspacing="0" border="0">
|
|
<tr>
|
|
<td style="padding: 20px 0; text-align: center; font-family: Arial, sans-serif; color: #999999; font-size: 11px;">
|
|
<p style="margin: 0;">Se você não solicitou este email, pode ignorá-lo com segurança.</p>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</td>
|
|
</tr>
|
|
</table>
|
|
</body>
|
|
</html>
|
|
`.trim();
|
|
}
|
|
|
|
/**
|
|
* Converte texto plano em HTML básico
|
|
* @param texto - Texto plano
|
|
* @returns HTML formatado
|
|
*/
|
|
export function textToHTML(texto: string): string {
|
|
return texto
|
|
.split('\n')
|
|
.map((linha) => {
|
|
const linhaTrim = linha.trim();
|
|
if (!linhaTrim) return '<br />';
|
|
// Detectar links
|
|
const linkRegex = /(https?:\/\/[^\s]+)/g;
|
|
const linhaComLinks = linhaTrim.replace(
|
|
linkRegex,
|
|
'<a href="$1" style="color: #0052A5; text-decoration: underline;">$1</a>'
|
|
);
|
|
return `<p style="margin: 0 0 15px 0;">${linhaComLinks}</p>`;
|
|
})
|
|
.join('');
|
|
}
|