Files
Coop-NL/src/lib/emailRenderer.ts
T

776 lines
53 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 { NewsletterCampaign, ProductItem } from '@/types/newsletter';
import { SUPABASE_ASSETS_BASE } from './defaultCampaign';
export function renderEmailHtml(campaign: NewsletterCampaign): string {
const renderedModules = campaign.modules.map((m) => renderModule(m, campaign)).join('\n');
return `<!DOCTYPE html>
<html lang="sk" xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="x-apple-disable-message-reformatting">
<meta name="color-scheme" content="light only">
<meta name="supported-color-schemes" content="light">
<meta name="format-detection" content="telephone=no, date=no, address=no, email=no, url=no">
<title>${escapeHtml(campaign.title)}</title>
<!-- Web Font (Moderný font Poppins) -->
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700;800;900&display=swap" rel="stylesheet">
<style>
/* Vynútený light režim — bráni dark mode inverzii v klientoch */
:root {
color-scheme: light only;
supported-color-schemes: light;
}
/* CSS Reset pre e-maily */
html, body {
margin: 0 auto !important;
padding: 0 !important;
height: 100% !important;
width: 100% !important;
font-family: 'Poppins', Helvetica, Arial, sans-serif !important;
background-color: #001a33;
color-scheme: light only;
-webkit-color-scheme: light only;
}
* {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
table, td {
mso-table-lspace: 0pt !important;
mso-table-rspace: 0pt !important;
}
img {
-ms-interpolation-mode: bicubic;
border: 0;
height: auto;
line-height: 100%;
outline: none;
text-decoration: none;
max-width: 100%;
}
a {
text-decoration: none;
}
/* Responzívne štýly pre mobilné zariadenia */
@media screen and (max-width: 600px) {
.email-container {
width: 100% !important;
margin: auto !important;
padding: 0 10px !important;
box-sizing: border-box;
}
.stack-column,
.stack-column-center {
display: block !important;
width: 100% !important;
max-width: 100% !important;
direction: ltr !important;
padding-left: 0 !important;
padding-right: 0 !important;
}
.stack-column-center {
text-align: center !important;
}
.mobile-padding {
padding-left: 15px !important;
padding-right: 15px !important;
}
.mobile-spacer {
height: 15px !important;
display: block !important;
}
.btn {
display: inline-block !important;
width: auto !important;
box-sizing: border-box;
}
.glass-product {
margin-bottom: 15px !important;
}
.logo-img {
width: 90px !important;
}
.header-link {
display: block !important;
margin: 3px 0 3px auto !important;
padding: 4px 10px !important;
width: 75px !important;
font-size: 9px !important;
text-align: center !important;
margin-right: 0 !important;
}
.mobile-header-cell {
padding: 3px 0 !important;
}
.stack-column-center a {
display: inline-block !important;
width: auto !important;
margin: 5px 3px !important;
vertical-align: middle;
}
.top-msg { font-size: 11px !important; line-height: 1.4 !important; }
.top-tip { font-size: 10px !important; padding: 1px 6px !important; }
.top-link { font-size: 11px !important; }
}
/* ====== DARK MODE OVERRIDE — Outlook.com / O365 web / dark-mode klienty ====== */
[data-ogsc] body, [data-ogsb] body { background-color: #001a33 !important; }
[data-ogsc] .bg-gradient-mso, [data-ogsb] .bg-gradient-mso { background-color: #001a33 !important; }
[data-ogsc] .card-fantasticky, [data-ogsb] .card-fantasticky { background-color: #feeaea !important; }
[data-ogsc] .card-domace, [data-ogsb] .card-domace { background-color: #fef0c7 !important; }
[data-ogsc] .card-grill, [data-ogsb] .card-grill { background-color: #dcb085 !important; }
[data-ogsc] .card-vernostna, [data-ogsb] .card-vernostna { background-color: #e6e1d9 !important; }
[data-ogsc] .card-white-bg, [data-ogsb] .card-white-bg { background-color: #fefefe !important; }
[data-ogsc] .force-text-dark, [data-ogsb] .force-text-dark { color: #1a1a1a !important; }
[data-ogsc] .force-text-white, [data-ogsb] .force-text-white { color: #fefefe !important; }
[data-ogsc] .force-bg-red, [data-ogsb] .force-bg-red { background-color: #e2001a !important; }
[data-ogsc] .force-bg-blue, [data-ogsb] .force-bg-blue { background-color: #003399 !important; }
[data-ogsc] .force-bg-darkblue, [data-ogsb] .force-bg-darkblue { background-color: #29446f !important; }
[data-ogsc] .force-bg-yellow, [data-ogsb] .force-bg-yellow { background-color: #f9ba3c !important; }
[data-ogsc] .force-bg-yellow2, [data-ogsb] .force-bg-yellow2 { background-color: #ffde00 !important; }
[data-ogsc] .force-bg-orange, [data-ogsb] .force-bg-orange { background-color: #f68e1e !important; }
[data-ogsc] .force-bg-green, [data-ogsb] .force-bg-green { background-color: #005239 !important; }
[data-ogsc] .force-bg-articleblue, [data-ogsb] .force-bg-articleblue { background-color: #5c85a8 !important; }
@media (prefers-color-scheme: dark) {
:root { color-scheme: light only !important; supported-color-schemes: light !important; }
html, body, table, td, div, p, span, h1, h2, h3, h4 { color-scheme: light only !important; }
body, .bg-gradient-mso { background-color: #001a33 !important; }
.card-fantasticky { background-color: #feeaea !important; }
.card-domace { background-color: #fef0c7 !important; }
.card-grill { background-color: #dcb085 !important; }
.card-vernostna { background-color: #e6e1d9 !important; }
.card-white-bg { background-color: #fefefe !important; }
.force-text-dark { color: #1a1a1a !important; }
.force-text-white { color: #fefefe !important; }
.force-bg-red { background-color: #e2001a !important; }
.force-bg-blue { background-color: #003399 !important; }
.force-bg-darkblue { background-color: #29446f !important; }
.force-bg-yellow { background-color: #f9ba3c !important; }
.force-bg-yellow2 { background-color: #ffde00 !important; }
.force-bg-orange { background-color: #f68e1e !important; }
.force-bg-green { background-color: #005239 !important; }
.force-bg-articleblue { background-color: #5c85a8 !important; }
}
</style>
<!--[if mso]>
<style type="text/css">
body, table, td { font-family: Arial, Helvetica, sans-serif !important; }
.bg-gradient-mso { background-color: #001a33 !important; }
</style>
<![endif]-->
</head>
<body class="body bg-gradient-mso" width="100%" bgcolor="#001a33" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #001a33;">
<!-- Preheader (skrytý — zobrazí sa v náhľade doručenej pošty) -->
<div style="display: none; max-height: 0; max-width: 0; overflow: hidden; opacity: 0; font-size: 1px; line-height: 1px; color: #fefefe; mso-hide: all;">
${escapeHtml(campaign.preheader || '')}
</div>
<div style="display: none; max-height: 0; max-width: 0; overflow: hidden; opacity: 0; font-size: 1px; line-height: 1px; color: #fefefe; mso-hide: all;">
&#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204; &#847; &#8204;
</div>
<center style="width: 100%; background-color: #001a33;">
<table width="100%" cellpadding="0" cellspacing="0" border="0" bgcolor="#001a33" style="background-color: #001a33; background-image: linear-gradient(135deg, #005bb5 0%, #000d1a 100%);">
<tr>
<td align="center" valign="top">
<!--[if mso | IE]>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="600" align="center" style="width:600px;"><tr><td align="center" valign="top" style="padding-top:15px; padding-bottom:30px;">
<![endif]-->
<div style="max-width: 600px; margin: 0 auto; padding-top: 15px; padding-bottom: 30px;" class="email-container">
${renderedModules}
</div>
<!--[if mso | IE]>
</td></tr></table>
<![endif]-->
</td>
</tr>
</table>
</center>
</body>
</html>`;
}
export function renderSingleModuleHtml(m: any, campaign: NewsletterCampaign): string {
return renderModule(m, campaign);
}
function renderModule(m: any, campaign: NewsletterCampaign): string {
switch (m.type) {
case 'announcement':
return `
<!-- 0. TOP OZNAMOVACIA LIŠTA -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin: 15px 0 20px 0;">
<tr>
<td align="center">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" class="force-bg-red" bgcolor="#e2001a" style="background-color: #e2001a; background: linear-gradient(to right, #ff3d4f, #e2001a); border: 0; border-radius: 12px; box-shadow: 0 10px 25px rgba(226, 0, 26, 0.3);">
<tr>
<td style="padding: 10px 20px; text-align: center;">
<!--[if mso]><table role="presentation" border="0" cellspacing="0" cellpadding="0" align="center" width="600"><tr><td align="center" valign="middle"><![endif]-->
<div style="display: inline-block; vertical-align: middle;" class="stack-column-center">
<span class="top-tip" style="background-color: #fefefe; color: #e2001a; font-size: 10px; font-weight: 800; padding: 2px 8px; border: 0; border-radius: 4px; margin: 4px 5px; vertical-align: middle; display: inline-block; letter-spacing: 1px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">${escapeHtml(m.data.tipBadge || 'TIP')}</span>
</div>
<div style="display: inline-block; vertical-align: middle;" class="stack-column-center">
<span class="top-msg force-text-white" style="color: #fefefe; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; vertical-align: middle; display: inline-block; padding: 5px 10px;">${escapeHtml(m.data.text || '')}</span>
</div>
${m.data.linkText ? `
<div style="display: inline-block; vertical-align: middle;" class="stack-column-center">
<a href="${escapeHtml(m.data.linkUrl || '#')}" class="top-link" style="color: #ffde00; font-size: 11px; font-weight: 800; text-decoration: none; text-transform: uppercase; display: inline-block; padding: 5px 10px;">${escapeHtml(m.data.linkText)} <span style="font-size: 14px; line-height: 1;">&rsaquo;</span></a>
</div>` : ''}
<!--[if mso]></td></tr></table><![endif]-->
</td>
</tr>
</table>
</td>
</tr>
</table>`;
case 'header':
const rawNav = m.data.navLinks && m.data.navLinks.length > 0 ? m.data.navLinks : [
{ label: 'Letáky', url: 'https://www.coop.sk/sk/letaky', variant: 'outline' },
{ label: 'COOP Klub', url: 'https://www.coopklub.sk', variant: 'filled' }
];
const navLinks = rawNav.map((link: any) => {
if (link.variant === 'filled') {
return `<a href="${escapeHtml(link.url || '#')}" class="header-link force-text-white force-bg-blue" style="color: #fefefe; font-size: 12px; font-weight: 700; text-decoration: none; text-transform: uppercase; padding: 10px 16px; background-color: #003399; border-radius: 20px; display: inline-block; letter-spacing: 0.5px; box-shadow: 0 4px 10px rgba(0, 51, 153, 0.2);">${escapeHtml(link.label || 'Odkaz')}</a>`;
}
return `<a href="${escapeHtml(link.url || '#')}" class="header-link" style="color: #e2001a; font-size: 12px; font-weight: 700; text-decoration: none; text-transform: uppercase; padding: 8px 16px; border: 2px solid #e2001a; border-radius: 20px; margin-right: 6px; display: inline-block; letter-spacing: 0.5px;">${escapeHtml(link.label || 'Odkaz')}</a>`;
}).join('\n');
return `
<!-- 1. HLAVIČKA -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" class="card-white card-white-bg" bgcolor="#fefefe" style="background-color: #fefefe; border: 0; border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); overflow: hidden;">
<tr>
<td style="padding: 15px 20px;" class="mobile-padding">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td width="35%" valign="middle" style="text-align: left;" class="mobile-header-cell">
<a href="${escapeHtml(m.data.logoLink || 'https://www.coop.sk')}" target="_blank">
<img src="${escapeHtml(m.data.logoUrl)}" width="130" alt="COOP Jednota" style="display: inline-block; border: 0; border-radius: 8px;" class="logo-img">
</a>
</td>
<td width="65%" valign="middle" style="text-align: right;" class="mobile-header-cell">
${navLinks}
</td>
</tr>
</table>
</td>
</tr>
</table>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td height="25" style="font-size: 25px; line-height: 25px;">&nbsp;</td></tr></table>`;
case 'banner':
return `
<!-- KAMPAŇ BANNER -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" class="card-white card-white-bg" bgcolor="#fefefe" style="background-color: #fefefe; border: 0; border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); overflow: hidden;">
<tr>
<td>
<a href="${escapeHtml(m.data.linkUrl || '#')}">
<img src="${escapeHtml(m.data.imageUrl)}" width="600" alt="${escapeHtml(m.data.altText || '')}" style="display: block; border: 0; width: 100%; max-width: 100%; border-radius: ${m.data.title || m.data.description || m.data.buttonText ? '16px 16px 0 0' : '16px'};">
</a>
</td>
</tr>
${m.data.title || m.data.description || m.data.buttonText ? `
<tr>
<td style="padding: 30px 20px; text-align: center;" class="mobile-padding">
${m.data.title ? `<h1 class="force-text-dark" style="margin: 0 0 15px 0; font-size: 24px; color: #1a1a1a; font-weight: 700;">${escapeHtml(m.data.title)}</h1>` : ''}
${m.data.description ? `<p class="force-text-dark" style="margin: 0 0 25px 0; font-size: 15px; line-height: 1.5; color: #555555;">${escapeHtml(m.data.description)}</p>` : ''}
${m.data.buttonText ? `
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin: auto;" class="btn-table">
<tr>
<td style="text-align: center;">
<a href="${escapeHtml(m.data.buttonUrl || '#')}" class="btn force-text-white" style="background-color: ${m.data.buttonBgColor || '#e2001a'}; color: #fefefe; font-family: 'Poppins', sans-serif; font-size: 13px; font-weight: 800; text-decoration: none; padding: 12px 30px; border-radius: 25px; display: inline-block; text-transform: uppercase; letter-spacing: 0.5px; box-shadow: 0 4px 12px rgba(226, 0, 26, 0.35);">${escapeHtml(m.data.buttonText)}</a>
</td>
</tr>
</table>` : ''}
</td>
</tr>` : ''}
</table>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td height="25" style="font-size: 25px; line-height: 25px;">&nbsp;</td></tr></table>`;
case 'products_grid':
const globalValidity = m.data.globalValidity || '';
const products: ProductItem[] = m.data.products || [];
const cardBg = m.data.cardBgColor || '#feeaea';
const cardBorder = m.data.cardBorderColor || '#f5d4d4';
const badgeHdrBg = m.data.badgeHeaderBg || '#fefefe';
const badgeHdrColor = m.data.badgeHeaderColor || '#000000';
const badgePrcBg = m.data.badgePriceBg || '#e2001a';
const badgePrcColor = m.data.badgePriceColor || '#fefefe';
const badgeCustomTxt = m.data.badgeHeaderCustomText || null;
const rows: ProductItem[][] = [];
for (let i = 0; i < products.length; i += 2) {
rows.push(products.slice(i, i + 2));
}
const rowsHtml = rows.map((row) => `
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-bottom: 12px;">
<tr>
${row.map((p, idx) => `
<td width="50%" valign="top" height="1" style="padding-${idx === 0 ? 'right: 6px' : 'left: 6px'}; padding-bottom: 0;">
${renderExactProductCard(p, globalValidity, cardBg, cardBorder, badgeHdrBg, badgeHdrColor, badgePrcBg, badgePrcColor, badgeCustomTxt)}
</td>`).join('\n')}
${row.length === 1 ? '<td width="50%" valign="top"></td>' : ''}
</tr>
</table>
`).join('\n');
return `
<!-- PRODUKTOVÁ SEKCIA: ${escapeHtml(m.data.sectionTitle || '')} -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
${m.data.sectionTitle ? `
<tr>
<td style="text-align: center; padding-top: 25px; padding-bottom: 25px;">
<h2 class="force-text-white" style="margin: 0; font-size: 24px; color: #fefefe; font-weight: 900; text-transform: uppercase; text-shadow: 0px 2px 5px rgba(0,0,0,0.5);">${escapeHtml(m.data.sectionTitle)}</h2>
</td>
</tr>` : ''}
<tr>
<td>
${rowsHtml}
</td>
</tr>
</table>`;
case 'loyalty_club':
if (m.data.enabled === false) {
return '';
}
const lProducts = m.data.products || [];
return `
<!-- 7. VERNOSTNÉ ZĽAVY (COOP KLUB) -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td style="text-align: center; padding-top: 25px; padding-bottom: 25px;">
<h2 class="force-text-white" style="margin: 0; font-size: 24px; color: #fefefe; font-weight: 900; text-transform: uppercase; text-shadow: 0px 2px 5px rgba(0,0,0,0.5);">${escapeHtml(m.data.sectionTitle || 'Vernostné zľavy')}</h2>
</td>
</tr>
<!-- Banner karta -->
<tr>
<td style="padding-bottom: 20px;">
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" class="card-white card-vernostna" bgcolor="#e6e1d9" style="background-color: #e6e1d9; border: 0; border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); overflow: hidden;">
<tr>
<td>
<a href="${escapeHtml(m.data.headerLink || '#')}">
<img src="${escapeHtml(m.data.headerImageUrl)}" width="600" alt="Vernostné zľavy" style="display: block; border: 0; width: 100%; max-width: 100%; border-radius: 16px;">
</a>
</td>
</tr>
</table>
</td>
</tr>
<!-- Produktové karty - 2 vedľa seba -->
<tr>
<td>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
${lProducts.map((p: any, idx: number) => `
<td width="50%" valign="top" height="1" style="padding-${idx === 0 ? 'right: 6px' : 'left: 6px'}; padding-bottom: 0;">
${renderExactLoyaltyCard(p, m.data.globalValidity || '2. 5. – 15. 5. 2026')}
</td>`).join('\n')}
</tr>
</table>
</td>
</tr>
</table>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td height="25" style="font-size: 25px; line-height: 25px;">&nbsp;</td></tr></table>`;
case 'articles_row':
const it1 = m.data.item1;
const it2 = m.data.item2;
// Ak ide o letáky
if (it1?.btnText) {
return `
<!-- DVA STĹPCE - LETÁKY -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<!-- Leták 1 -->
<td width="50%" valign="top" style="padding-right: 6px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" bgcolor="${it1.bgColor}" style="background-color: ${it1.bgColor}; border: 0; border-radius: 16px; overflow: hidden; box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25);">
<tr>
<td>
<a href="${escapeHtml(it1.linkUrl || '#')}">
<img src="${escapeHtml(it1.imageUrl)}" width="300" alt="${escapeHtml(it1.title)}" style="display: block; border: 0; width: 100%; max-width: 100%;">
</a>
</td>
</tr>
<tr>
<td style="padding: 25px 15px 30px 15px; text-align: center;">
<h3 class="force-text-white" style="margin: 0 0 15px 0; font-size: 17px; color: ${it1.textColor || '#fefefe'}; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;">${escapeHtml(it1.title)}</h3>
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin: auto;" class="btn-table">
<tr>
<td style="text-align: center;">
<a href="${escapeHtml(it1.linkUrl || '#')}" class="btn force-text-white" style="background-color: ${it1.btnBgColor || '#e2001a'}; color: #fefefe; font-family: 'Poppins', sans-serif; font-size: 12px; font-weight: 800; text-decoration: none; padding: 10px 24px; border-radius: 25px; display: inline-block; text-transform: uppercase; letter-spacing: 0.5px; box-shadow: 0 4px 12px rgba(226, 0, 26, 0.35);">${escapeHtml(it1.btnText)}</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<!-- Leták 2 -->
<td width="50%" valign="top" style="padding-left: 6px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" bgcolor="${it2.bgColor}" style="background-color: ${it2.bgColor}; border: 0; border-radius: 16px; overflow: hidden; box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25);">
<tr>
<td>
<a href="${escapeHtml(it2.linkUrl || '#')}">
<img src="${escapeHtml(it2.imageUrl)}" width="300" alt="${escapeHtml(it2.title)}" style="display: block; border: 0; width: 100%; max-width: 100%;">
</a>
</td>
</tr>
<tr>
<td style="padding: 25px 15px 30px 15px; text-align: center;">
<h3 style="margin: 0 0 15px 0; font-size: 17px; color: ${it2.textColor || '#29446f'}; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px;">${escapeHtml(it2.title)}</h3>
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin: auto;" class="btn-table">
<tr>
<td style="text-align: center;">
<a href="${escapeHtml(it2.linkUrl || '#')}" class="btn force-text-white" style="background-color: ${it2.btnBgColor || '#29446f'}; color: #fefefe; font-family: 'Poppins', sans-serif; font-size: 12px; font-weight: 800; text-decoration: none; padding: 10px 24px; border-radius: 25px; display: inline-block; text-transform: uppercase; letter-spacing: 0.5px; box-shadow: 0 4px 12px rgba(41, 68, 111, 0.3);">${escapeHtml(it2.btnText)}</a>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td height="25" style="font-size: 25px; line-height: 25px;">&nbsp;</td></tr></table>`;
}
// Inak články / recepty
return `
<!-- ČLÁNKY / RECEPTY (2 stĺpce) -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<!-- Článok 1 -->
<td width="50%" valign="top" style="padding-right: 6px; padding-bottom: 20px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" bgcolor="${it1.bgColor}" style="background-color: ${it1.bgColor}; border: 0; border-radius: 16px; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.15);">
<tr>
<td background="${escapeHtml(it1.imageUrl)}" bgcolor="${it1.bgColor}" width="300" height="240" valign="bottom" style="background-image: url('${escapeHtml(it1.imageUrl)}'); background-size: cover; background-position: center;">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:300px;height:240px;">
<v:fill type="frame" src="${escapeHtml(it1.imageUrl)}" color="${it1.bgColor}" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<div style="background: linear-gradient(to bottom, rgba(246, 142, 30, 0), rgba(246, 142, 30, 1)); height: 80px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%">
<tr>
<td align="center" valign="bottom" style="padding-bottom: 10px;">
<img src="${escapeHtml(it1.badgeImgUrl)}" width="70" alt="Recepty" style="display: block; border: 0; margin: 0 auto;">
</td>
</tr>
</table>
</div>
<!--[if gte mso 9]></v:textbox></v:rect><![endif]-->
</td>
</tr>
<tr>
<td style="padding: 10px 15px 25px 15px; text-align: center; height: 60px;" valign="top">
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: #fefefe; font-weight: 800; text-transform: uppercase; letter-spacing: 0.8px; line-height: 1.2;">${it1.title}</h3>
</td>
</tr>
</table>
</td>
<!-- Článok 2 -->
<td width="50%" valign="top" style="padding-left: 6px; padding-bottom: 20px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" bgcolor="${it2.bgColor}" style="background-color: ${it2.bgColor}; border: 0; border-radius: 16px; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.15);">
<tr>
<td background="${escapeHtml(it2.imageUrl)}" bgcolor="${it2.bgColor}" width="300" height="240" valign="bottom" style="background-image: url('${escapeHtml(it2.imageUrl)}'); background-size: cover; background-position: center;">
<!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:300px;height:240px;">
<v:fill type="frame" src="${escapeHtml(it2.imageUrl)}" color="${it2.bgColor}" />
<v:textbox inset="0,0,0,0">
<![endif]-->
<div style="background: linear-gradient(to bottom, rgba(92, 133, 168, 0), rgba(92, 133, 168, 1)); height: 80px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%">
<tr>
<td align="center" valign="bottom" style="padding-bottom: 10px;">
<img src="${escapeHtml(it2.badgeImgUrl)}" width="70" alt="Časopis Jednota" style="display: block; border: 0; margin: 0 auto;">
</td>
</tr>
</table>
</div>
<!--[if gte mso 9]></v:textbox></v:rect><![endif]-->
</td>
</tr>
<tr>
<td style="padding: 10px 15px 25px 15px; text-align: center; height: 60px;" valign="top">
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: #fefefe; font-weight: 800; text-transform: uppercase; letter-spacing: 0.8px; line-height: 1.2;">${it2.title}</h3>
</td>
</tr>
</table>
</td>
</tr>
</table>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%"><tr><td height="25" style="font-size: 25px; line-height: 25px;">&nbsp;</td></tr></table>`;
case 'footer':
return `
<!-- 9. PÄTIČKA (1:1 s originálnou šablónou) -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" class="card-white card-white-bg" bgcolor="#fefefe" style="background-color: #fefefe; border: 0; border-radius: 16px; padding: 40px 20px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);">
<tr>
<td style="padding: 30px 10px;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<!-- Sekcia 1: Aplikácia -->
<td width="33.33%" valign="top" class="stack-column-center" style="padding: 10px; text-align: center;">
<h4 class="force-text-dark" style="margin: 0 0 15px 0; font-size: 14px; color: #444444; font-weight: 700; text-align: center;">Aplikácia</h4>
<a href="${escapeHtml(m.data.googlePlayUrl || 'https://play.google.com/store/apps/details?id=sk.coop.jednota.klub')}" target="_blank" style="display: block; margin-bottom: 10px;">
<img src="${SUPABASE_ASSETS_BASE}logo-google_play.png" width="120" alt="Google Play" style="display: block; border: 0; margin: 0 auto;">
</a>
<a href="${escapeHtml(m.data.appStoreUrl || 'https://apps.apple.com/sk/app/coop-jednota/id1044610196')}" target="_blank" style="display: block;">
<img src="${SUPABASE_ASSETS_BASE}logo-app_store.png" width="120" alt="App Store" style="display: block; border: 0; margin: 0 auto;">
</a>
</td>
<!-- Sekcia 2: Sociálne siete -->
<td width="33.33%" valign="top" class="stack-column-center" style="padding: 10px; text-align: center;">
<h4 class="force-text-dark" style="margin: 0 0 15px 0; font-size: 14px; color: #444444; font-weight: 700; text-align: center;">Sledujte nás</h4>
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" style="margin: 0 auto;">
<tr>
<td style="padding: 0 5px;"><a href="${escapeHtml(m.data.socials?.facebook || '#')}" target="_blank"><img src="${SUPABASE_ASSETS_BASE}ikona_fb.png" width="30" alt="Facebook" style="display: block; border: 0;"></a></td>
<td style="padding: 0 5px;"><a href="${escapeHtml(m.data.socials?.instagram || '#')}" target="_blank"><img src="${SUPABASE_ASSETS_BASE}ikona_ig.png" width="30" alt="Instagram" style="display: block; border: 0;"></a></td>
<td style="padding: 0 5px;"><a href="${escapeHtml(m.data.socials?.youtube || '#')}" target="_blank"><img src="${SUPABASE_ASSETS_BASE}ikona_yt.png" width="30" alt="YouTube" style="display: block; border: 0;"></a></td>
<td style="padding: 0 5px;"><a href="${escapeHtml(m.data.socials?.tiktok || '#')}" target="_blank"><img src="${SUPABASE_ASSETS_BASE}ikona_tt.png" width="30" alt="TikTok" style="display: block; border: 0;"></a></td>
</tr>
</table>
</td>
<!-- Sekcia 3: Naše projekty -->
<td width="33.33%" valign="top" class="stack-column-center" style="padding: 10px; text-align: center;">
<h4 class="force-text-dark" style="margin: 0 0 15px 0; font-size: 14px; color: #444444; font-weight: 700; text-align: center;">Projekty</h4>
<a href="${escapeHtml(m.data.foundationUrl || 'https://www.nadaciacoop.sk')}" target="_blank" style="display: block; margin-bottom: 10px;">
<img src="${SUPABASE_ASSETS_BASE}logo-COOP_nadacia.png" width="120" alt="Nadácia COOP Jednota" style="display: block; border: 0; margin: 0 auto;">
</a>
<a href="${escapeHtml(m.data.recipesUrl || 'https://recepty.coop.sk')}" target="_blank" style="display: block;">
<img src="${SUPABASE_ASSETS_BASE}logo-netradicne_recepty.png" width="120" alt="Netradičné recepty" style="display: block; border: 0; margin: 0 auto;">
</a>
</td>
</tr>
</table>
<!-- Disclaimer a Unsubscribe -->
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-top: 15px; border-top: 0; padding-top: 15px;">
<tr>
<td class="force-text-dark" style="text-align: center; font-size: 11px; color: #666666; line-height: 1.5;">
<a href="${escapeHtml(m.data.recipesUrl || 'https://recepty.coop.sk')}" style="color: #444444; text-decoration: underline;">Prihláste sa</a> aj na odber newslettera (Ne)tradičných receptov.
<div style="height: 8px; line-height: 8px; font-size: 1px;">&nbsp;</div>
Ak sa chcete znova prihlásiť na odber newslettera, <a href="https://www.coop.sk" style="color: #444444; text-decoration: underline;">kliknite sem.</a>
<div style="height: 8px; line-height: 8px; font-size: 1px;">&nbsp;</div>
Pre odhlásenie z odoberania newslettera <a href="${escapeHtml(m.data.unsubscribeUrl || '*|UNSUB|*')}" style="color: #444444; text-decoration: underline;">kliknite sem.</a><br><br>
${m.data.disclaimer}
</td>
</tr>
</table>
</td>
</tr>
</table>`;
default:
return '';
}
}
function renderExactProductCard(
p: ProductItem,
globalValidity: string,
cardBg: string,
cardBorder: string,
badgeHdrBg: string,
badgeHdrColor: string,
badgePrcBg: string,
badgePrcColor: string,
badgeCustomTxt: string | null
): string {
const validity = p.validityOverride || globalValidity;
const storesHtml = `
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="right">
${p.stores?.potraviny ? `<tr><td align="right" style="line-height: 0;"><table role="presentation" cellspacing="0" cellpadding="0" border="0" align="right"><tr><td style="border: 0; background-color: #e2001a; padding: 0; line-height: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_potraviny.png" height="10" alt="P" style="display: block; height: 10px; width: auto; border: 0;"></td></tr></table></td></tr>` : ''}
${p.stores?.supermarket ? `<tr><td align="right" style="line-height: 0;"><table role="presentation" cellspacing="0" cellpadding="0" border="0" align="right"><tr><td style="border: 0; background-color: #f9890e; padding: 0; line-height: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_supermarket.png" height="10" alt="S" style="display: block; height: 10px; width: auto; border: 0;"></td></tr></table></td></tr>` : ''}
${p.stores?.tempo ? `<tr><td align="right" style="line-height: 0;"><table role="presentation" cellspacing="0" cellpadding="0" border="0" align="right"><tr><td style="border: 0; background-color: #005239; padding: 0; line-height: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_tempo.png" height="10" alt="T" style="display: block; height: 10px; width: auto; border: 0;"></td></tr></table></td></tr>` : ''}
</table>`;
return `
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" class="glass-product" bgcolor="${cardBg}" style="background-color: ${cardBg}; border: 0; border-radius: 16px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);">
<tr>
<td style="padding: 15px 15px 0 15px;" valign="top">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td style="font-size: 9px; color: #666666; font-weight: 500;" valign="top">${escapeHtml(validity)}</td>
<td align="right">${storesHtml}</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding: 0 8px 15px 8px; text-align: center; height: 160px;" valign="middle">
<img src="${escapeHtml(p.imageUrl)}" width="220" alt="${escapeHtml(p.title)}" style="display: block; width: 100%; max-width: 220px; margin: 0 auto; border-radius: 8px;">
</td>
</tr>
<tr>
<td style="padding: 0 8px 10px 8px; text-align: center; height: 50px;" valign="top">
<h3 class="force-text-dark" style="margin: 0; font-size: 15px; color: #1a1a1a; font-weight: 600;">${escapeHtml(p.title)}</h3>
</td>
</tr>
<tr height="1">
<td style="padding: 0 8px 12px 8px; text-align: center;" valign="bottom">
<!-- Vyladená Cenovka Premium v8/v11 1:1 alebo vyrenderovaná PNG cenovka z editora -->
${p.customBadgePngUrl ? `
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" style="margin: 0 auto;">
<tr>
<td align="center">
<img src="${escapeHtml(p.customBadgePngUrl)}" width="110" alt="Cenovka" style="display: block; margin: 0 auto; max-width: 120px;">
</td>
</tr>
</table>` : `
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="center" style="width: 95px; margin: 0 auto;">
<tr>
<td align="center">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="background-color: ${badgeHdrBg}; border: 0; border-radius: 12px; box-shadow: 0 4px 10px rgba(0,0,0,0.18); width: 85px; overflow: hidden;">
${badgeCustomTxt ? `
<tr>
<td bgcolor="${badgeHdrBg}" style="padding: 4px 4px; text-align: center; background-color: ${badgeHdrBg};">
<span style="font-family: 'Arial Narrow', Arial, sans-serif; font-size: 10px; color: ${badgeHdrColor}; font-weight: 800; text-transform: uppercase;">${escapeHtml(badgeCustomTxt)}</span>
</td>
</tr>` : (p.discountText ? `
<tr>
<td style="padding: 2px 4px; text-align: right; background-color: ${badgeHdrBg};">
<span style="font-family: 'Arial Narrow', Arial, sans-serif; font-size: 9px; color: ${badgeHdrColor}; font-weight: 700; text-transform: lowercase;">${escapeHtml(p.badgeText || 'zľava')}</span>
<span style="font-family: 'Arial Narrow', Arial, sans-serif; font-size: 20px; color: ${badgeHdrColor}; font-weight: 900; line-height: 1; margin-left: 2px;">${escapeHtml(p.discountText)}</span>
</td>
</tr>` : '')}
<tr>
<td class="force-text-white" bgcolor="${badgePrcBg}" style="background-color: ${badgePrcBg}; padding: 4px 2px 2px 2px; font-family: 'Arial Narrow', Arial, sans-serif; color: ${badgePrcColor}; font-weight: 900; line-height: 1; text-align: center; border-radius: 0 0 12px 12px;">
<span style="font-size: 52px;">${escapeHtml(p.priceMain)}</span><sup style="font-size: 26px; vertical-align: top; line-height: 1.2;">${escapeHtml(p.priceSub)}</sup>
</td>
</tr>
</table>
</td>
</tr>
${p.showSlovakFlag ? `
<tr>
<td align="right" style="line-height: 0; padding: 0;">
<img src="${SUPABASE_ASSETS_BASE}vlajka_srdce.png" width="40" alt="SK" style="display: block; margin-top: -26px; margin-right: -10px; padding: 4px; filter: drop-shadow(1px 0 0 #fefefe) drop-shadow(-1px 0 0 #fefefe) drop-shadow(0 1px 0 #fefefe) drop-shadow(0 -1px 0 #fefefe);">
</td>
</tr>` : ''}
</table>`}
${p.unitPrice ? `<div style="font-size: 9px; color: #666666; margin-top: 4px; font-weight: 500; font-family: Arial, sans-serif;">${escapeHtml(p.unitPrice)}</div>` : ''}
</td>
</tr>
</table>`;
}
function renderExactLoyaltyCard(p: any, validity: string): string {
const cardValidity = p.validityOverride || validity;
const storesHtml = `
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="right">
${p.stores?.potraviny ? `<tr><td align="right" style="line-height: 0;"><table role="presentation" cellspacing="0" cellpadding="0" border="0" align="right"><tr><td style="border: 0; background-color: #e2001a; padding: 0; line-height: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_potraviny.png" height="10" alt="P" style="display: block; height: 10px; width: auto; border: 0;"></td></tr></table></td></tr>` : ''}
${p.stores?.supermarket ? `<tr><td align="right" style="line-height: 0;"><table role="presentation" cellspacing="0" cellpadding="0" border="0" align="right"><tr><td style="border: 0; background-color: #f9890e; padding: 0; line-height: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_supermarket.png" height="10" alt="S" style="display: block; height: 10px; width: auto; border: 0;"></td></tr></table></td></tr>` : ''}
${p.stores?.tempo ? `<tr><td align="right" style="line-height: 0;"><table role="presentation" cellspacing="0" cellpadding="0" border="0" align="right"><tr><td style="border: 0; background-color: #005239; padding: 0; line-height: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_tempo.png" height="10" alt="T" style="display: block; height: 10px; width: auto; border: 0;"></td></tr></table></td></tr>` : ''}
</table>`;
return `
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" class="glass-product card-vernostna" bgcolor="#e6e1d9" style="background-color: #e6e1d9; border: 0; border-radius: 16px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15);">
<tr>
<td style="padding: 15px 15px 0 15px;" valign="top">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%">
<tr>
<td style="font-size: 9px; color: #666666; font-weight: 500;" valign="top">${escapeHtml(cardValidity)}</td>
<td align="right">${storesHtml}</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="padding: 0 8px 15px 8px; text-align: center; height: 160px;" valign="middle">
<img src="${escapeHtml(p.imageUrl)}" width="220" alt="${escapeHtml(p.title)}" style="display: block; width: 100%; max-width: 220px; margin: 0 auto; border-radius: 8px;">
</td>
</tr>
<tr>
<td style="padding: 0 8px 10px 8px; text-align: center; height: 50px;" valign="top">
<h3 class="force-text-dark" style="margin: 0; font-size: 15px; color: #1a1a1a; font-weight: 600;">${escapeHtml(p.title)}</h3>
</td>
</tr>
<tr height="1">
<td style="padding: 0 8px 12px 8px; text-align: center;" valign="bottom">
<!-- Dual Sticker Block (Bez karty / S kartou) 1:1 -->
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" style="margin: 0 auto; width: 140px;">
<tr>
<td colspan="2">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" style="width: 140px; margin: 0 auto;">
<tr>
<!-- Bez karty -->
<td width="42%" valign="bottom" style="padding-right: 0;">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="background-color: #fefefe; border: 0; border-radius: 10px 0 0 10px; box-shadow: -2px 4px 8px rgba(0,0,0,0.12); overflow: hidden;">
<tr>
<td class="force-bg-red" bgcolor="#e2001a" style="background-color: #e2001a; padding: 4px 2px; text-align: center;">
<div style="font-size: 6px; color: #fefefe; font-weight: 700; text-transform: uppercase; line-height: 1; margin-bottom: 1px;">Bez karty</div>
<div style="font-family: 'Arial Narrow', Arial, sans-serif; font-size: 8px; color: #fefefe; font-weight: 900; line-height: 1;">zľava ${escapeHtml(p.noCardDiscount)}</div>
</td>
</tr>
<tr>
<td style="padding: 2px; text-align: center; color: #000000; font-family: 'Arial Narrow', Arial, sans-serif; font-weight: 900; line-height: 1;">
<span style="font-size: 20px;">${escapeHtml(p.noCardPriceMain)}</span><sup style="font-size: 10px; vertical-align: top; line-height: 1.2;">${escapeHtml(p.noCardPriceSub)}</sup>
</td>
</tr>
</table>
</td>
<!-- S kartou -->
<td width="58%" valign="top">
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="background-color: #fefefe; border: 0; border-radius: 0 10px 10px 0; box-shadow: 4px 4px 12px rgba(0,0,0,0.15); overflow: hidden;">
<tr>
<td style="background-color: #fefefe; padding: 5px 4px 2px 4px; text-align: right;">
<div style="font-size: 7px; color: #e2001a; font-weight: 800; text-transform: uppercase; line-height: 1; text-align: center; margin-bottom: 1px;">S kartou</div>
<div style="text-align: right; line-height: 1;">
<span style="font-family: 'Arial Narrow', Arial, sans-serif; font-size: 8px; color: #000000; font-weight: 700; text-transform: lowercase;">zľava</span>
<span style="font-family: 'Arial Narrow', Arial, sans-serif; font-size: 18px; color: #000000; font-weight: 900; margin-left: 1px;">${escapeHtml(p.cardDiscount)}</span>
</div>
</td>
</tr>
<tr>
<td class="force-bg-red force-text-white" bgcolor="#e2001a" style="background-color: #e2001a; padding: 3px 2px; text-align: center; color: #fefefe; font-family: 'Arial Narrow', Arial, sans-serif; font-weight: 900; line-height: 1; border-radius: 0 0 10px 0;">
<span style="font-size: 48px;">${escapeHtml(p.cardPriceMain)}</span><sup style="font-size: 24px; vertical-align: top; line-height: 1.2;">${escapeHtml(p.cardPriceSub)}</sup>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
${p.showSlovakFlag ? `
<tr>
<td colspan="2" align="right" style="line-height: 0; padding: 0;">
<img src="${SUPABASE_ASSETS_BASE}vlajka_srdce.png" width="40" alt="SK" style="display: block; margin-top: -26px; margin-right: -10px; padding: 4px; filter: drop-shadow(1px 0 0 #fefefe) drop-shadow(-1px 0 0 #fefefe) drop-shadow(0 1px 0 #fefefe) drop-shadow(0 -1px 0 #fefefe);">
</td>
</tr>` : ''}
<tr>
<td width="42%" align="center" style="padding-top: 6px;">
<div style="font-size: 8px; color: #666666; opacity: 0.7; font-weight: 500; font-family: Arial, sans-serif;">${escapeHtml(p.noCardUnitPrice)}</div>
</td>
<td width="58%" align="center" style="padding-top: 6px;">
<div style="font-size: 9px; color: #e2001a; font-weight: 800; font-family: Arial, sans-serif;">${escapeHtml(p.cardUnitPrice)}</div>
</td>
</tr>
</table>
</td>
</tr>
</table>`;
}
function escapeHtml(str: string): string {
if (!str) return '';
return String(str)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}