- bezne produkty maju volitelne polia Cena s kartou / Zlava s kartou, vernostne produkty pouzivaju svoje existujuce hodnoty - editor cenoviek: tlacidla na pridanie vrstiev a nahlad premennych - jedinecne ID novych vrstiev (rychle pridanie viacerych vrstiev) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
927 lines
63 KiB
TypeScript
927 lines
63 KiB
TypeScript
import { NewsletterCampaign, ProductItem } from '@/types/newsletter';
|
||
import { SUPABASE_ASSETS_BASE } from './defaultCampaign';
|
||
import { renderCleanBadgeSvg } from './badgeUtils';
|
||
import { pickAlt } from './altText';
|
||
|
||
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;">
|
||
͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌ ͏ ‌
|
||
</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':
|
||
if (m.data?.enabled === false) {
|
||
return '';
|
||
}
|
||
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;">›</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="${escapeHtml(pickAlt(m.data.logoAlt, '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;"> </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(pickAlt(m.data.altText, m.data.title, m.title, 'COOP Jednota'))}" 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;"> </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 cols = m.data.columns === 1 ? 1 : 2;
|
||
const rows: ProductItem[][] = [];
|
||
for (let i = 0; i < products.length; i += cols) {
|
||
rows.push(products.slice(i, i + cols));
|
||
}
|
||
|
||
const rowsHtml = rows.map((row) => {
|
||
if (cols === 1) {
|
||
const p = row[0];
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-bottom: 12px;">
|
||
<tr>
|
||
<td width="100%" valign="top">
|
||
${renderExactProductCard(p, globalValidity, cardBg, cardBorder, badgeHdrBg, badgeHdrColor, badgePrcBg, badgePrcColor, badgeCustomTxt, m.data.sectionTitle)}
|
||
</td>
|
||
</tr>
|
||
</table>`;
|
||
}
|
||
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="1" style="margin-bottom: 12px;">
|
||
<tr>
|
||
${row.map((p, idx) => `
|
||
<td width="50%" valign="top" height="100%" style="padding-${idx === 0 ? 'right: 6px' : 'left: 6px'}; padding-bottom: 0; height: 100%;">
|
||
${renderExactProductCard(p, globalValidity, cardBg, cardBorder, badgeHdrBg, badgeHdrColor, badgePrcBg, badgePrcColor, badgeCustomTxt, m.data.sectionTitle)}
|
||
</td>`).join('\n')}
|
||
${row.length === 1 ? '<td width="50%" valign="top" height="100%" style="height: 100%;"></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="${escapeHtml(pickAlt(m.data.headerImageAlt, m.data.title, m.data.sectionTitle, '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="100%" style="padding-${idx === 0 ? 'right: 6px' : 'left: 6px'}; padding-bottom: 0; height: 100%;">
|
||
${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;"> </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%" height="1">
|
||
<tr>
|
||
<!-- Leták 1 -->
|
||
<td width="50%" valign="top" height="100%" style="padding-right: 6px; height: 100%;">
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="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); height: 100%; min-height: 100%;">
|
||
<tr height="1">
|
||
<td valign="top" style="line-height: 0; height: 1px;">
|
||
<a href="${escapeHtml(it1.linkUrl || '#')}">
|
||
<img src="${escapeHtml(it1.imageUrl)}" width="300" alt="${escapeHtml(pickAlt(it1.altText, it1.title, m.data.title, m.title, 'Aktuálny leták'))}" style="display: block; border: 0; width: 100%; max-width: 100%;">
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td valign="bottom" style="padding: 20px 15px 25px 15px; text-align: center; height: 100%;">
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" style="height: 100%;">
|
||
<tr>
|
||
<td valign="top" style="text-align: center; min-height: 44px; padding-bottom: 15px;">
|
||
<h3 class="force-text-white" style="margin: 0; font-size: 17px; color: ${it1.textColor || '#fefefe'}; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; line-height: 1.25;">${escapeHtml(it1.title)}</h3>
|
||
</td>
|
||
</tr>
|
||
<tr height="1">
|
||
<td valign="bottom" align="center" style="text-align: center; height: 1px;">
|
||
<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>
|
||
</tr>
|
||
</table>
|
||
</td>
|
||
<!-- Leták 2 -->
|
||
<td width="50%" valign="top" height="100%" style="padding-left: 6px; height: 100%;">
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="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); height: 100%; min-height: 100%;">
|
||
<tr height="1">
|
||
<td valign="top" style="line-height: 0; height: 1px;">
|
||
<a href="${escapeHtml(it2.linkUrl || '#')}">
|
||
<img src="${escapeHtml(it2.imageUrl)}" width="300" alt="${escapeHtml(pickAlt(it2.altText, it2.title, m.data.title, m.title, 'Aktuálny leták'))}" style="display: block; border: 0; width: 100%; max-width: 100%;">
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td valign="bottom" style="padding: 20px 15px 25px 15px; text-align: center; height: 100%;">
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" style="height: 100%;">
|
||
<tr>
|
||
<td valign="top" style="text-align: center; min-height: 44px; padding-bottom: 15px;">
|
||
<h3 style="margin: 0; font-size: 17px; color: ${it2.textColor || '#29446f'}; font-weight: 700; text-transform: uppercase; letter-spacing: 0.5px; line-height: 1.25;">${escapeHtml(it2.title)}</h3>
|
||
</td>
|
||
</tr>
|
||
<tr height="1">
|
||
<td valign="bottom" align="center" style="text-align: center; height: 1px;">
|
||
<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>
|
||
</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;"> </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%" height="1">
|
||
<tr>
|
||
<!-- Článok 1 -->
|
||
<td width="50%" valign="top" height="100%" style="padding-right: 6px; padding-bottom: 20px; height: 100%;">
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="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); height: 100%; min-height: 100%;">
|
||
<tr height="240">
|
||
<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; height: 240px;">
|
||
<!--[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="${escapeHtml(pickAlt(it1.altText, it1.title, '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: 15px 15px 25px 15px; text-align: center; height: 100%;" valign="middle">
|
||
<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.25;">${escapeHtml(it1.title)}</h3>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</td>
|
||
<!-- Článok 2 -->
|
||
<td width="50%" valign="top" height="100%" style="padding-left: 6px; padding-bottom: 20px; height: 100%;">
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="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); height: 100%; min-height: 100%;">
|
||
<tr height="240">
|
||
<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; height: 240px;">
|
||
<!--[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="${escapeHtml(pickAlt(it2.altText, it2.title, 'Č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: 15px 15px 25px 15px; text-align: center; height: 100%;" valign="middle">
|
||
<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.25;">${escapeHtml(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;"> </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;"> </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;"> </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,
|
||
sectionTitle?: string
|
||
): string {
|
||
const validity = p.validityOverride || globalValidity;
|
||
const effectiveCardBg = p.cardBgColor || cardBg || '#feeaea';
|
||
|
||
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="Potraviny" 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="Supermarket" 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="Tempo" style="display: block; height: 10px; width: auto; border: 0;"></td></tr></table></td></tr>` : ''}
|
||
</table>`;
|
||
|
||
const badgeLayout = p.badgeLayout || 'below';
|
||
|
||
// Pomocná funkcia na render samotnej cenovky (bez obalového <td>)
|
||
const renderBadgeContent = (bWidth: number, bAlign: string, padTop: number, padBottom: number, marginStyle: string) => {
|
||
// Vlastná PNG cenovka (výnimka) má prednosť pred šablónou; po jej odstránení sa vráti šablóna
|
||
if (p.customBadgePngUrl) {
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="${bAlign}" style="${marginStyle} width: ${bWidth}px; padding-top: ${padTop}px; padding-bottom: ${padBottom}px;">
|
||
<tr>
|
||
<td align="${bAlign}">
|
||
<img src="${escapeHtml(p.customBadgePngUrl)}" width="${bWidth}" alt="${escapeHtml(pickAlt(p.title, 'Cenovka'))}" style="display: block; width: 100%; max-width: ${bWidth}px; margin: 0 auto;">
|
||
</td>
|
||
</tr>
|
||
</table>`;
|
||
}
|
||
if (p.badgeCustomTemplate) {
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="${bAlign}" style="${marginStyle} width: ${bWidth}px; padding-top: ${padTop}px; padding-bottom: ${padBottom}px;">
|
||
<tr>
|
||
<td align="${bAlign}">
|
||
${renderCleanBadgeSvg(p.badgeCustomTemplate, p, bWidth)}
|
||
</td>
|
||
</tr>
|
||
</table>`;
|
||
}
|
||
const mainFontSize = Math.max(28, Math.round(bWidth * 0.54));
|
||
const subFontSize = Math.max(14, Math.round(bWidth * 0.27));
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="${bAlign}" style="${marginStyle} width: ${bWidth}px; padding-top: ${padTop}px; padding-bottom: ${padBottom}px;">
|
||
<tr>
|
||
<td align="${bAlign}">
|
||
<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: ${bWidth}px; 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: ${mainFontSize}px;">${escapeHtml(p.priceMain)}</span><sup style="font-size: ${subFontSize}px; vertical-align: top; line-height: 1.2;">${escapeHtml(p.priceSub)}</sup>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
</td>
|
||
</tr>
|
||
</table>`;
|
||
};
|
||
|
||
if (badgeLayout === 'side') {
|
||
// Rozloženie: obrázok vľavo | cenovka vpravo
|
||
const bWidth = p.badgeWidth || (p.badgeCustomTemplate ? (p.badgeCustomTemplate.width || 110) : 95);
|
||
const bAlign = 'center';
|
||
const padTop = p.badgePaddingTop ?? (p.badgeCustomTemplate?.paddingTop ?? 0);
|
||
const padBottom = p.badgePaddingBottom ?? (p.badgeCustomTemplate?.paddingBottom ?? 0);
|
||
const marginStyle = 'margin: 0 auto;';
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" class="glass-product" bgcolor="${effectiveCardBg}" style="background-color: ${effectiveCardBg}; border: 0; border-radius: 16px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15); height: 100%; min-height: 100%;">
|
||
<tr height="1">
|
||
<td colspan="2" style="padding: 15px 15px 0 15px; height: 1px;" 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 width="58%" height="160" style="padding: 8px 4px 8px 8px; text-align: center; height: 160px;" valign="middle">
|
||
<img src="${escapeHtml(p.imageUrl)}" width="180" alt="${escapeHtml(pickAlt(p.imageAlt, p.title, sectionTitle, 'Produkt'))}" style="display: block; width: 100%; max-width: 180px; margin: 0 auto; border-radius: 8px;">
|
||
</td>
|
||
<td width="42%" style="padding: 8px 8px 8px 4px; text-align: center;" valign="middle">
|
||
${renderBadgeContent(bWidth, bAlign, padTop, padBottom, marginStyle)}
|
||
${p.unitPrice ? `<div style="font-size: 8px; color: #666666; font-weight: 500; font-family: Arial, sans-serif; text-align: center; margin-top: 4px;">${escapeHtml(p.unitPrice)}</div>` : ''}
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="2" height="54" style="padding: 0 8px 10px 8px; text-align: center; height: 54px; min-height: 54px;" valign="top">
|
||
<h3 class="force-text-dark" style="margin: 0; font-size: 15px; color: #1a1a1a; font-weight: 600; line-height: 1.25;">${escapeHtml(p.title)}</h3>
|
||
</td>
|
||
</tr>
|
||
</table>`;
|
||
}
|
||
|
||
// Predvolené rozloženie: cenovka pod obrázkom
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" class="glass-product" bgcolor="${effectiveCardBg}" style="background-color: ${effectiveCardBg}; border: 0; border-radius: 16px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15); height: 100%; min-height: 100%;">
|
||
<tr height="1">
|
||
<td style="padding: 15px 15px 0 15px; height: 1px;" 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 height="160">
|
||
<td height="160" style="padding: 0 8px 15px 8px; text-align: center; height: 160px;" valign="middle">
|
||
<img src="${escapeHtml(p.imageUrl)}" width="220" alt="${escapeHtml(pickAlt(p.imageAlt, p.title, sectionTitle, 'Produkt'))}" style="display: block; width: 100%; max-width: 220px; margin: 0 auto; border-radius: 8px;">
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<td height="54" style="padding: 0 8px 10px 8px; text-align: center; height: 54px; min-height: 54px;" valign="top">
|
||
<h3 class="force-text-dark" style="margin: 0; font-size: 15px; color: #1a1a1a; font-weight: 600; line-height: 1.25;">${escapeHtml(p.title)}</h3>
|
||
</td>
|
||
</tr>
|
||
<tr height="1">
|
||
<td style="padding: 0 8px 4px 8px; text-align: center;" valign="bottom">
|
||
${(() => {
|
||
const bWidth = p.badgeWidth || (p.badgeCustomTemplate ? (p.badgeCustomTemplate.width || 110) : 95);
|
||
const bAlign = p.badgeAlign || (p.badgeCustomTemplate ? (p.badgeCustomTemplate.align || 'center') : 'center');
|
||
const padTop = p.badgePaddingTop ?? (p.badgeCustomTemplate?.paddingTop ?? 0);
|
||
const padBottom = p.badgePaddingBottom ?? (p.badgeCustomTemplate?.paddingBottom ?? 0);
|
||
let marginStyle = 'margin: 0 auto;';
|
||
if (bAlign === 'left') {
|
||
marginStyle = 'margin: 0 auto 0 0; margin-right: auto; margin-left: 0;';
|
||
} else if (bAlign === 'right') {
|
||
marginStyle = 'margin: 0 0 0 auto; margin-left: auto; margin-right: 0;';
|
||
}
|
||
return renderBadgeContent(bWidth, bAlign, padTop, padBottom, marginStyle);
|
||
})()}
|
||
</td>
|
||
</tr>
|
||
<tr height="1">
|
||
<td align="center" valign="bottom" style="padding: 2px 8px 12px 8px; text-align: center; height: 1px;">
|
||
${p.unitPrice ? `<div style="font-size: 9px; color: #666666; font-weight: 500; font-family: Arial, sans-serif; text-align: center;">${escapeHtml(p.unitPrice)}</div>` : '<div style="font-size: 9px; line-height: 9px; height: 9px;"> </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="Potraviny" 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="Supermarket" 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="Tempo" style="display: block; height: 10px; width: auto; border: 0;"></td></tr></table></td></tr>` : ''}
|
||
</table>`;
|
||
|
||
const loyaltyBg = p.cardBgColor || '#e6e1d9';
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" class="glass-product card-vernostna" bgcolor="${loyaltyBg}" style="background-color: ${loyaltyBg}; border: 0; border-radius: 16px; box-shadow: 0 4px 15px rgba(0, 0, 0, 0.15); height: 100%; min-height: 100%;">
|
||
<tr height="1">
|
||
<td style="padding: 15px 15px 0 15px; height: 1px;" 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 height="1">
|
||
<td style="padding: 0 8px 15px 8px; text-align: center; height: 160px;" valign="middle">
|
||
<img src="${escapeHtml(p.imageUrl)}" width="220" alt="${escapeHtml(pickAlt(p.imageAlt, p.title, 'Produkt'))}" 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: 100%; min-height: 44px;" valign="top">
|
||
<h3 class="force-text-dark" style="margin: 0; font-size: 15px; color: #1a1a1a; font-weight: 600; line-height: 1.25;">${escapeHtml(p.title)}</h3>
|
||
</td>
|
||
</tr>
|
||
<tr height="1">
|
||
<td style="padding: 0 8px ${p.badgeCustomTemplate || p.customBadgePngUrl ? '4px' : '12px'} 8px; text-align: center; height: 1px;" valign="bottom">
|
||
${(() => {
|
||
// 1. Ak má vernostný produkt vlastnú PNG cenovku (prednosť) alebo dynamickú šablónu cenovky
|
||
if (p.customBadgePngUrl || p.badgeCustomTemplate) {
|
||
const bWidth = p.badgeWidth || p.badgeCustomTemplate?.width || 120;
|
||
const bAlign = p.badgeAlign || p.badgeCustomTemplate?.align || 'center';
|
||
const padTop = p.badgePaddingTop ?? (p.badgeCustomTemplate?.paddingTop ?? 0);
|
||
const padBottom = p.badgePaddingBottom ?? (p.badgeCustomTemplate?.paddingBottom ?? 0);
|
||
|
||
let marginStyle = 'margin: 0 auto;';
|
||
if (bAlign === 'left') {
|
||
marginStyle = 'margin: 0 auto 0 0; margin-right: auto; margin-left: 0;';
|
||
} else if (bAlign === 'right') {
|
||
marginStyle = 'margin: 0 0 0 auto; margin-left: auto; margin-right: 0;';
|
||
}
|
||
|
||
const loyaltyProductData = {
|
||
priceMain: p.cardPriceMain || p.priceMain || '0',
|
||
priceSub: p.cardPriceSub || p.priceSub || '00',
|
||
discountText: p.cardDiscount || p.discountText || '',
|
||
unitPrice: p.cardUnitPrice || p.unitPrice || '',
|
||
cardPriceMain: p.cardPriceMain,
|
||
cardPriceSub: p.cardPriceSub,
|
||
cardDiscount: p.cardDiscount
|
||
};
|
||
|
||
return `
|
||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" align="${bAlign}" style="${marginStyle} width: ${bWidth}px; padding-top: ${padTop}px; padding-bottom: ${padBottom}px;">
|
||
<tr>
|
||
<td align="${bAlign}">
|
||
${p.customBadgePngUrl
|
||
? `<img src="${escapeHtml(p.customBadgePngUrl)}" width="${bWidth}" alt="${escapeHtml(pickAlt(p.title, 'Cenovka'))}" style="display: block; width: 100%; max-width: ${bWidth}px; margin: 0 auto;">`
|
||
: renderCleanBadgeSvg(p.badgeCustomTemplate, loyaltyProductData, bWidth)}
|
||
</td>
|
||
</tr>
|
||
</table>`;
|
||
}
|
||
|
||
// 2. Predvolený Dual Sticker Block (Bez karty / S kartou) 1:1
|
||
return `
|
||
<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>
|
||
<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>
|
||
${p.badgeCustomTemplate || p.customBadgePngUrl ? `
|
||
<tr height="1">
|
||
<td align="center" valign="bottom" style="padding: 2px 8px 12px 8px; text-align: center; height: 1px;">
|
||
${p.cardUnitPrice || p.unitPrice ? `<div style="font-size: 9px; color: #666666; font-weight: 500; font-family: Arial, sans-serif; text-align: center;">${escapeHtml(p.cardUnitPrice || p.unitPrice)}</div>` : '<div style="font-size: 9px; line-height: 9px; height: 9px;"> </div>'}
|
||
</td>
|
||
</tr>` : ''}
|
||
</table>`;
|
||
}
|
||
|
||
function escapeHtml(str: string): string {
|
||
if (!str) return '';
|
||
return String(str)
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>')
|
||
.replace(/"/g, '"')
|
||
.replace(/'/g, ''');
|
||
}
|