Exact 1:1 COOP template design, native email responsiveness without toggle switcher
This commit is contained in:
1 parent
538f2ccae3
commit
65f37a74b8
5 files changed
+916
-368
No files matched your search
+54
-75
@@ -1,7 +1,7 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { NewsletterCampaign, NewsletterModule, ProductItem, BadgeTemplate } from '@/types/newsletter';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { NewsletterCampaign, NewsletterModule, ProductItem } from '@/types/newsletter';
|
||||
import { DEFAULT_CAMPAIGN, SUPABASE_ASSETS_BASE } from '@/lib/defaultCampaign';
|
||||
import { renderEmailHtml } from '@/lib/emailRenderer';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
@@ -16,7 +16,6 @@ import { ChevronUp, ChevronDown, Copy, Trash2 } from 'lucide-react';
|
||||
export default function Home() {
|
||||
const [campaign, setCampaign] = useState<NewsletterCampaign>(DEFAULT_CAMPAIGN);
|
||||
const [selectedModuleId, setSelectedModuleId] = useState<string | null>('mod-products-fantasticky');
|
||||
const [previewMode, setPreviewMode] = useState<'desktop' | 'mobile'>('desktop');
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [isExportingBrevo, setIsExportingBrevo] = useState(false);
|
||||
const [brevoUrl, setBrevoUrl] = useState<string | null>(null);
|
||||
@@ -24,9 +23,8 @@ export default function Home() {
|
||||
// Modály
|
||||
const [isImportOpen, setIsImportOpen] = useState(false);
|
||||
const [isBadgeModalOpen, setIsBadgeModalOpen] = useState(false);
|
||||
const [activeProductIdForBadge, setActiveProductIdForBadge] = useState<string | null>(null);
|
||||
|
||||
// Načítanie existujúceho draftu z databázy alebo inicializácia
|
||||
// Načítanie existujúceho draftu z databázy
|
||||
useEffect(() => {
|
||||
async function loadInitial() {
|
||||
try {
|
||||
@@ -38,16 +36,19 @@ export default function Home() {
|
||||
|
||||
if (data && data.length > 0) {
|
||||
const dbItem = data[0];
|
||||
setCampaign({
|
||||
id: dbItem.id,
|
||||
title: dbItem.title,
|
||||
preheader: dbItem.data.preheader || DEFAULT_CAMPAIGN.preheader,
|
||||
status: dbItem.status,
|
||||
brevoCampaignId: dbItem.brevo_campaign_id,
|
||||
modules: dbItem.data.modules || DEFAULT_CAMPAIGN.modules
|
||||
});
|
||||
if (dbItem.brevo_campaign_id) {
|
||||
setBrevoUrl(`https://app.brevo.com/camp/detail/email/${dbItem.brevo_campaign_id}`);
|
||||
// Ak má databáza rovnakú štruktúru, načítame ju, inak necháme DEFAULT_CAMPAIGN 1:1
|
||||
if (dbItem.data && dbItem.data.modules && dbItem.data.modules.length >= 6) {
|
||||
setCampaign({
|
||||
id: dbItem.id,
|
||||
title: dbItem.title,
|
||||
preheader: dbItem.data.preheader || DEFAULT_CAMPAIGN.preheader,
|
||||
status: dbItem.status,
|
||||
brevoCampaignId: dbItem.brevo_campaign_id,
|
||||
modules: dbItem.data.modules
|
||||
});
|
||||
if (dbItem.brevo_campaign_id) {
|
||||
setBrevoUrl(`https://app.brevo.com/camp/detail/email/${dbItem.brevo_campaign_id}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -63,8 +64,7 @@ export default function Home() {
|
||||
setIsSaving(true);
|
||||
try {
|
||||
if (!campaign.id) {
|
||||
// Vytvorenie nového záznamu
|
||||
const { data, error } = await supabase
|
||||
const { data } = await supabase
|
||||
.from('templates')
|
||||
.insert([
|
||||
{
|
||||
@@ -82,7 +82,6 @@ export default function Home() {
|
||||
setCampaign((prev) => ({ ...prev, id: data[0].id }));
|
||||
}
|
||||
} else {
|
||||
// Update existujúceho
|
||||
await supabase
|
||||
.from('templates')
|
||||
.update({
|
||||
@@ -105,10 +104,8 @@ export default function Home() {
|
||||
return () => clearTimeout(timer);
|
||||
}, [campaign.title, campaign.preheader, campaign.modules]);
|
||||
|
||||
// Vybraný modul
|
||||
const selectedModule = campaign.modules.find((m) => m.id === selectedModuleId) || null;
|
||||
|
||||
// Aktualizácia modulu
|
||||
const handleUpdateModule = (updated: NewsletterModule) => {
|
||||
setCampaign((prev) => ({
|
||||
...prev,
|
||||
@@ -116,7 +113,6 @@ export default function Home() {
|
||||
}));
|
||||
};
|
||||
|
||||
// Posun modulu hore/dole
|
||||
const moveModule = (index: number, direction: 'up' | 'down') => {
|
||||
const newModules = [...campaign.modules];
|
||||
const targetIndex = direction === 'up' ? index - 1 : index + 1;
|
||||
@@ -129,7 +125,6 @@ export default function Home() {
|
||||
setCampaign((prev) => ({ ...prev, modules: newModules }));
|
||||
};
|
||||
|
||||
// Duplikácia modulu
|
||||
const duplicateModule = (index: number) => {
|
||||
const original = campaign.modules[index];
|
||||
const clone: NewsletterModule = {
|
||||
@@ -144,7 +139,6 @@ export default function Home() {
|
||||
setSelectedModuleId(clone.id);
|
||||
};
|
||||
|
||||
// Zmazanie modulu
|
||||
const deleteModule = (index: number) => {
|
||||
if (campaign.modules.length <= 1) return;
|
||||
const newModules = campaign.modules.filter((_, i) => i !== index);
|
||||
@@ -152,7 +146,6 @@ export default function Home() {
|
||||
setSelectedModuleId(newModules[0]?.id || null);
|
||||
};
|
||||
|
||||
// Pridanie nového modulu
|
||||
const handleAddModule = (type: any) => {
|
||||
let newMod: NewsletterModule;
|
||||
if (type === 'banner') {
|
||||
@@ -162,12 +155,12 @@ export default function Home() {
|
||||
title: 'Nový Banner',
|
||||
data: {
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}aktualne_letaky.jpg`,
|
||||
linkUrl: 'https://www.coop.sk',
|
||||
linkUrl: '#',
|
||||
altText: 'Aktuálne letáky',
|
||||
title: 'Prelistujte si naše najnovšie letáky online',
|
||||
description: 'Všetky akcie a zľavy na jednom mieste priamo vo vašom mobile.',
|
||||
buttonText: 'Pozrieť letáky',
|
||||
buttonUrl: 'https://www.coop.sk',
|
||||
buttonUrl: '#',
|
||||
buttonBgColor: '#e2001a'
|
||||
}
|
||||
};
|
||||
@@ -179,6 +172,12 @@ export default function Home() {
|
||||
data: {
|
||||
sectionTitle: 'AKČNÁ PONUKA',
|
||||
globalValidity: '2. 5. – 15. 5. 2026',
|
||||
cardBgColor: '#feeaea',
|
||||
cardBorderColor: '#f5d4d4',
|
||||
badgeHeaderBg: '#fefefe',
|
||||
badgeHeaderColor: '#000000',
|
||||
badgePriceBg: '#e2001a',
|
||||
badgePriceColor: '#fefefe',
|
||||
products: [
|
||||
{
|
||||
id: `p-${Date.now()}-1`,
|
||||
@@ -204,7 +203,6 @@ export default function Home() {
|
||||
setSelectedModuleId(newMod.id);
|
||||
};
|
||||
|
||||
// Hromadný import produktov do aktuálne vybraného modulu
|
||||
const handleImportProducts = (imported: ProductItem[]) => {
|
||||
if (!selectedModuleId) return;
|
||||
const target = campaign.modules.find((m) => m.id === selectedModuleId);
|
||||
@@ -223,11 +221,8 @@ export default function Home() {
|
||||
handleUpdateModule(updated);
|
||||
};
|
||||
|
||||
// Export do ZIP (JSZip)
|
||||
const handleExportZip = async () => {
|
||||
const rawHtml = renderEmailHtml(campaign);
|
||||
|
||||
// Inlinovanie CSS pred zabalením
|
||||
let finalHtml = rawHtml;
|
||||
try {
|
||||
const res = await fetch('/api/inline-css', {
|
||||
@@ -238,29 +233,19 @@ export default function Home() {
|
||||
const data = await res.json();
|
||||
if (data.html) finalHtml = data.html;
|
||||
} catch (e) {
|
||||
console.warn('Inliner fallback to raw html:', e);
|
||||
console.warn('Inliner fallback:', e);
|
||||
}
|
||||
|
||||
const zip = new JSZip();
|
||||
zip.file('index.html', finalHtml);
|
||||
|
||||
// Pridáme README návod
|
||||
zip.file(
|
||||
'README.txt',
|
||||
'COOP Jednota Newsletter Export\n\nSúbor index.html obsahuje finálny skompletizovaný a inlinovaný HTML kód pripravený na odoslanie cez ľubovoľný e-mailový systém (Brevo, Mailchimp, Outlook).'
|
||||
);
|
||||
|
||||
const blob = await zip.generateAsync({ type: 'blob' });
|
||||
saveAs(blob, `coop-newsletter-${new Date().toISOString().split('T')[0]}.zip`);
|
||||
};
|
||||
|
||||
// Export do Brevo (API v3)
|
||||
const handleExportBrevo = async () => {
|
||||
setIsExportingBrevo(true);
|
||||
try {
|
||||
const rawHtml = renderEmailHtml(campaign);
|
||||
|
||||
// Inlinovanie
|
||||
let finalHtml = rawHtml;
|
||||
try {
|
||||
const res = await fetch('/api/inline-css', {
|
||||
@@ -286,7 +271,6 @@ export default function Home() {
|
||||
|
||||
if (resData.success && resData.campaignId) {
|
||||
setBrevoUrl(resData.brevoUrl);
|
||||
// Uloženie stavu do Supabase
|
||||
if (campaign.id) {
|
||||
await supabase
|
||||
.from('templates')
|
||||
@@ -307,13 +291,14 @@ export default function Home() {
|
||||
}
|
||||
};
|
||||
|
||||
// Kompilácia celého HTML pre responzívny náhľad v reálnom čase
|
||||
const fullHtml = renderEmailHtml(campaign);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen overflow-hidden bg-slate-900 font-sans">
|
||||
<div className="flex flex-col h-screen overflow-hidden bg-[#001a33] font-sans">
|
||||
{/* 1. Horná lišta */}
|
||||
<TopBar
|
||||
campaign={campaign}
|
||||
previewMode={previewMode}
|
||||
setPreviewMode={setPreviewMode}
|
||||
isSaving={isSaving}
|
||||
onSave={() => {}}
|
||||
onExportZip={handleExportZip}
|
||||
@@ -323,17 +308,13 @@ export default function Home() {
|
||||
onAddModule={handleAddModule}
|
||||
/>
|
||||
|
||||
{/* 2. Hlavný pracovný priestor (2 zóny: Stredné plátno a Pravý panel) */}
|
||||
{/* 2. Hlavný pracovný priestor */}
|
||||
<div className="flex flex-1 overflow-hidden">
|
||||
{/* Stredné plátno - Živý WYSIWYG náhľad */}
|
||||
<main className="flex-1 overflow-y-auto p-8 flex items-start justify-center bg-slate-900">
|
||||
<div
|
||||
className={`transition-all duration-300 relative shadow-2xl rounded-2xl overflow-hidden ${
|
||||
previewMode === 'mobile' ? 'w-[390px]' : 'w-[640px]'
|
||||
}`}
|
||||
>
|
||||
{/* Zoznam modulov na plátne */}
|
||||
<div className="bg-[#001a33] min-h-screen p-4">
|
||||
{/* Stredné plátno - Živý responzívny e-mail v iframe pre 100% izoláciu CSS a médií */}
|
||||
<main className="flex-1 overflow-y-auto p-4 md:p-8 flex items-start justify-center bg-[#000d1a]">
|
||||
<div className="w-full max-w-[680px] shadow-2xl rounded-2xl overflow-hidden border border-blue-950/50 bg-[#001a33]">
|
||||
{/* Zoznam modulov pre priamu editáciu */}
|
||||
<div className="p-3 bg-[#001a33] space-y-3">
|
||||
{campaign.modules.map((mod, idx) => {
|
||||
const isSelected = mod.id === selectedModuleId;
|
||||
|
||||
@@ -341,25 +322,28 @@ export default function Home() {
|
||||
<div
|
||||
key={mod.id}
|
||||
onClick={() => setSelectedModuleId(mod.id)}
|
||||
className={`relative group cursor-pointer transition-all duration-200 mb-3 rounded-xl border-2 ${
|
||||
className={`relative group cursor-pointer transition-all duration-200 rounded-2xl border-2 ${
|
||||
isSelected
|
||||
? 'border-red-500 ring-4 ring-red-500/20'
|
||||
: 'border-transparent hover:border-slate-600'
|
||||
: 'border-transparent hover:border-slate-700/60'
|
||||
}`}
|
||||
>
|
||||
{/* Lišta s nástrojmi pre označený modul */}
|
||||
{isSelected && (
|
||||
<div className="absolute -top-3 right-4 z-20 flex items-center gap-1 bg-gray-900 text-white px-2 py-1 rounded-lg text-xs shadow-lg border border-slate-700">
|
||||
<div className="absolute top-2 right-2 z-30 flex items-center gap-1.5 bg-slate-900/95 backdrop-blur-md text-white px-2.5 py-1.5 rounded-xl text-xs shadow-2xl border border-slate-700">
|
||||
<span className="text-[10px] font-bold text-gray-400 mr-1 uppercase">
|
||||
{mod.title}
|
||||
</span>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
moveModule(idx, 'up');
|
||||
}}
|
||||
disabled={idx === 0}
|
||||
className="hover:text-red-400 disabled:opacity-30 p-0.5"
|
||||
className="hover:text-red-400 disabled:opacity-30 p-1"
|
||||
title="Posunúť hore"
|
||||
>
|
||||
<ChevronUp className="w-3.5 h-3.5" />
|
||||
<ChevronUp className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
@@ -367,35 +351,35 @@ export default function Home() {
|
||||
moveModule(idx, 'down');
|
||||
}}
|
||||
disabled={idx === campaign.modules.length - 1}
|
||||
className="hover:text-red-400 disabled:opacity-30 p-0.5"
|
||||
className="hover:text-red-400 disabled:opacity-30 p-1"
|
||||
title="Posunúť dole"
|
||||
>
|
||||
<ChevronDown className="w-3.5 h-3.5" />
|
||||
<ChevronDown className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
duplicateModule(idx);
|
||||
}}
|
||||
className="hover:text-blue-400 p-0.5 ml-1"
|
||||
className="hover:text-blue-400 p-1"
|
||||
title="Duplikovať"
|
||||
>
|
||||
<Copy className="w-3.5 h-3.5" />
|
||||
<Copy className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
deleteModule(idx);
|
||||
}}
|
||||
className="hover:text-red-400 p-0.5 ml-1"
|
||||
className="hover:text-red-400 p-1"
|
||||
title="Zmazať"
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Vykreslenie modulu cez iframe alebo dangerouslySetInnerHTML */}
|
||||
{/* Vykreslenie modulu 1:1 */}
|
||||
<div
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: renderEmailHtml({
|
||||
@@ -413,14 +397,11 @@ export default function Home() {
|
||||
</main>
|
||||
|
||||
{/* Pravý konfiguračný panel */}
|
||||
<aside className="w-96 flex-shrink-0 h-full bg-white shadow-xl">
|
||||
<aside className="w-96 flex-shrink-0 h-full bg-white shadow-2xl z-20">
|
||||
<ConfigPanel
|
||||
module={selectedModule}
|
||||
onUpdateModule={handleUpdateModule}
|
||||
onOpenBadgeManager={(pId) => {
|
||||
setActiveProductIdForBadge(pId);
|
||||
setIsBadgeModalOpen(true);
|
||||
}}
|
||||
onOpenBadgeManager={() => setIsBadgeModalOpen(true)}
|
||||
onOpenImport={() => setIsImportOpen(true)}
|
||||
/>
|
||||
</aside>
|
||||
@@ -436,9 +417,7 @@ export default function Home() {
|
||||
<BadgeManagerModal
|
||||
isOpen={isBadgeModalOpen}
|
||||
onClose={() => setIsBadgeModalOpen(false)}
|
||||
onSelectBadge={(badge) => {
|
||||
// Priradiť cenovku k produktu
|
||||
}}
|
||||
onSelectBadge={() => {}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,9 +5,6 @@ import {
|
||||
Download,
|
||||
Send,
|
||||
ExternalLink,
|
||||
Smartphone,
|
||||
Monitor,
|
||||
Save,
|
||||
CheckCircle2,
|
||||
Plus
|
||||
} from 'lucide-react';
|
||||
@@ -15,8 +12,6 @@ import { NewsletterCampaign } from '@/types/newsletter';
|
||||
|
||||
interface TopBarProps {
|
||||
campaign: NewsletterCampaign;
|
||||
previewMode: 'desktop' | 'mobile';
|
||||
setPreviewMode: (m: 'desktop' | 'mobile') => void;
|
||||
isSaving: boolean;
|
||||
onSave: () => void;
|
||||
onExportZip: () => void;
|
||||
@@ -28,8 +23,6 @@ interface TopBarProps {
|
||||
|
||||
export const TopBar: React.FC<TopBarProps> = ({
|
||||
campaign,
|
||||
previewMode,
|
||||
setPreviewMode,
|
||||
isSaving,
|
||||
onSave,
|
||||
onExportZip,
|
||||
@@ -40,23 +33,23 @@ export const TopBar: React.FC<TopBarProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<header className="h-16 bg-white border-b border-gray-200 px-6 flex items-center justify-between sticky top-0 z-30 shadow-xs">
|
||||
{/* Ľavá časť: Logo a názov */}
|
||||
{/* Ľavá časť: Logo a stav */}
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 rounded-lg bg-red-600 flex items-center justify-center text-white font-black text-sm">
|
||||
CJ
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-9 h-9 rounded-xl bg-[#e2001a] flex items-center justify-center text-white font-black text-sm shadow-sm tracking-tighter">
|
||||
COOP
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-sm font-bold text-gray-900 leading-tight">
|
||||
{campaign.title || 'COOP Newsletter'}
|
||||
{campaign.title || 'COOP Jednota Newsletter'}
|
||||
</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[10px] text-gray-500">
|
||||
<div className="flex items-center gap-2 mt-0.5">
|
||||
<span className="text-[11px] text-gray-500">
|
||||
{isSaving ? (
|
||||
<span className="text-amber-600 animate-pulse">Ukladám do Supabase...</span>
|
||||
<span className="text-amber-600 font-medium animate-pulse">Ukladám do Supabase...</span>
|
||||
) : (
|
||||
<span className="text-emerald-600 flex items-center gap-1">
|
||||
<CheckCircle2 className="w-3 h-3" /> Uložené v Supabase
|
||||
<span className="text-emerald-600 font-medium flex items-center gap-1">
|
||||
<CheckCircle2 className="w-3.5 h-3.5" /> Uložené v databáze (Auto-save)
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
@@ -64,54 +57,30 @@ export const TopBar: React.FC<TopBarProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pridať modul dropdown */}
|
||||
<div className="hidden md:flex items-center gap-1.5 ml-4 pl-4 border-l border-gray-200">
|
||||
{/* Pridanie sekcie */}
|
||||
<div className="hidden md:flex items-center gap-2 ml-6 pl-6 border-l border-gray-200">
|
||||
<button
|
||||
onClick={() => onAddModule('banner')}
|
||||
className="text-xs font-semibold text-gray-700 bg-gray-100 hover:bg-gray-200 px-2.5 py-1.5 rounded-lg flex items-center gap-1 transition-colors"
|
||||
className="text-xs font-bold text-gray-700 bg-gray-100 hover:bg-gray-200 px-3 py-1.5 rounded-lg flex items-center gap-1.5 transition-colors"
|
||||
>
|
||||
<Plus className="w-3.5 h-3.5 text-gray-500" /> Banner
|
||||
<Plus className="w-3.5 h-3.5 text-gray-500" /> Nový Banner
|
||||
</button>
|
||||
<button
|
||||
onClick={() => onAddModule('products_grid')}
|
||||
className="text-xs font-semibold text-gray-700 bg-gray-100 hover:bg-gray-200 px-2.5 py-1.5 rounded-lg flex items-center gap-1 transition-colors"
|
||||
className="text-xs font-bold text-gray-700 bg-gray-100 hover:bg-gray-200 px-3 py-1.5 rounded-lg flex items-center gap-1.5 transition-colors"
|
||||
>
|
||||
<Plus className="w-3.5 h-3.5 text-gray-500" /> Produkty
|
||||
<Plus className="w-3.5 h-3.5 text-gray-500" /> Produktový rad
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Stredná časť: Prepínač Desktop / Mobil */}
|
||||
<div className="flex items-center bg-gray-100 p-1 rounded-xl border border-gray-200">
|
||||
<button
|
||||
onClick={() => setPreviewMode('desktop')}
|
||||
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-bold transition-all ${
|
||||
previewMode === 'desktop'
|
||||
? 'bg-white text-gray-900 shadow-xs'
|
||||
: 'text-gray-500 hover:text-gray-900'
|
||||
}`}
|
||||
>
|
||||
<Monitor className="w-3.5 h-3.5" /> Desktop
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setPreviewMode('mobile')}
|
||||
className={`flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-bold transition-all ${
|
||||
previewMode === 'mobile'
|
||||
? 'bg-white text-gray-900 shadow-xs'
|
||||
: 'text-gray-500 hover:text-gray-900'
|
||||
}`}
|
||||
>
|
||||
<Smartphone className="w-3.5 h-3.5" /> Mobil
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Pravá časť: Export do ZIP a Brevo */}
|
||||
<div className="flex items-center gap-2.5">
|
||||
<div className="flex items-center gap-3">
|
||||
<button
|
||||
onClick={onExportZip}
|
||||
className="flex items-center gap-1.5 text-xs font-bold text-gray-700 bg-white border border-gray-300 hover:bg-gray-50 px-3.5 py-2 rounded-xl transition-all shadow-xs"
|
||||
className="flex items-center gap-1.5 text-xs font-bold text-gray-700 bg-white border border-gray-300 hover:bg-gray-50 px-4 py-2 rounded-xl transition-all shadow-xs hover:shadow-sm"
|
||||
>
|
||||
<Download className="w-3.5 h-3.5 text-gray-600" /> Export ZIP
|
||||
<Download className="w-4 h-4 text-gray-600" /> Export ZIP
|
||||
</button>
|
||||
|
||||
{brevoCampaignUrl ? (
|
||||
@@ -119,17 +88,17 @@ export const TopBar: React.FC<TopBarProps> = ({
|
||||
href={brevoCampaignUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="flex items-center gap-1.5 text-xs font-bold text-emerald-700 bg-emerald-50 border border-emerald-300 hover:bg-emerald-100 px-3.5 py-2 rounded-xl transition-all"
|
||||
className="flex items-center gap-1.5 text-xs font-bold text-emerald-700 bg-emerald-50 border border-emerald-300 hover:bg-emerald-100 px-4 py-2 rounded-xl transition-all shadow-xs"
|
||||
>
|
||||
<ExternalLink className="w-3.5 h-3.5" /> Otvoriť v Brevo
|
||||
<ExternalLink className="w-4 h-4" /> Otvoriť v Brevo
|
||||
</a>
|
||||
) : (
|
||||
<button
|
||||
onClick={onExportBrevo}
|
||||
disabled={isExportingBrevo}
|
||||
className="flex items-center gap-1.5 text-xs font-bold text-white bg-blue-600 hover:bg-blue-700 disabled:opacity-50 px-3.5 py-2 rounded-xl transition-all shadow-xs"
|
||||
className="flex items-center gap-1.5 text-xs font-bold text-white bg-[#003399] hover:bg-blue-800 disabled:opacity-50 px-4 py-2 rounded-xl transition-all shadow-xs"
|
||||
>
|
||||
<Send className="w-3.5 h-3.5" />
|
||||
<Send className="w-4 h-4" />
|
||||
{isExportingBrevo ? 'Odosielam...' : 'Odoslať do Brevo'}
|
||||
</button>
|
||||
)}
|
||||
|
||||
+188
-32
@@ -1,4 +1,4 @@
|
||||
import { NewsletterCampaign } from '@/types/newsletter';
|
||||
import { NewsletterCampaign, ProductItem } from '@/types/newsletter';
|
||||
|
||||
export const SUPABASE_ASSETS_BASE =
|
||||
'https://dqexxfspkylqttrtxsww.supabase.co/storage/v1/object/public/newsletter-assets/';
|
||||
@@ -6,13 +6,14 @@ export const SUPABASE_ASSETS_BASE =
|
||||
export const DEFAULT_CAMPAIGN: NewsletterCampaign = {
|
||||
id: '',
|
||||
title: 'COOP Jednota Newsletter',
|
||||
preheader: 'Vyhrajte 3 autá KIA Sportage. Mliečne novinky, fantasticky nízke ceny, grilovanie aj vernostné zľavy s COOP Klubom.',
|
||||
preheader:
|
||||
'Vyhrajte 3 autá KIA Sportage. Mliečne novinky, fantasticky nízke ceny, grilovanie aj vernostné zľavy s COOP Klubom.',
|
||||
status: 'draft',
|
||||
modules: [
|
||||
{
|
||||
id: 'mod-top-announcement',
|
||||
type: 'announcement',
|
||||
title: 'Top oznamovacia lišta',
|
||||
title: '0. Top oznamovacia lišta',
|
||||
data: {
|
||||
tipBadge: 'TIP',
|
||||
text: 'Vyhrajte auto s COOP Jednotou',
|
||||
@@ -24,7 +25,7 @@ export const DEFAULT_CAMPAIGN: NewsletterCampaign = {
|
||||
{
|
||||
id: 'mod-header',
|
||||
type: 'header',
|
||||
title: 'Hlavička s logom',
|
||||
title: '1. Hlavička s logom a menu',
|
||||
data: {
|
||||
logoUrl: `${SUPABASE_ASSETS_BASE}logo_coop.png`,
|
||||
logoLink: 'https://www.coop.sk',
|
||||
@@ -37,40 +38,47 @@ export const DEFAULT_CAMPAIGN: NewsletterCampaign = {
|
||||
{
|
||||
id: 'mod-banner-1',
|
||||
type: 'banner',
|
||||
title: 'Hlavný Banner - Súťaž KIA',
|
||||
title: '2. Kampaň 1: Súťaž KIA',
|
||||
data: {
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}nws_podklady-velka_noc.jpg`,
|
||||
linkUrl: 'https://www.coop.sk',
|
||||
linkUrl: '#',
|
||||
altText: 'Súťaž o autá',
|
||||
title: 'Hrajte o 3 autá a ďalšie skvelé ceny!',
|
||||
description: 'Nakúpte aspoň za 25 eur a hrajte o 3 autá KIA Sportage a tisíce okamžitých výhier.',
|
||||
description:
|
||||
'Nakúpte aspoň za 25 eur a hrajte o 3 autá KIA Sportage a tisíce okamžitých výhier.',
|
||||
buttonText: 'Chcem vyhrať',
|
||||
buttonUrl: 'https://www.coop.sk',
|
||||
buttonUrl: '#',
|
||||
buttonBgColor: '#e2001a'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'mod-banner-2',
|
||||
type: 'banner',
|
||||
title: 'Banner - Mliečne výrobky',
|
||||
title: '3. Kampaň 2: Mliečne výrobky',
|
||||
data: {
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}nws_podklady-nove_obaly.jpg`,
|
||||
linkUrl: 'https://www.coop.sk',
|
||||
altText: 'Mliečne výrobky',
|
||||
linkUrl: '#',
|
||||
altText: 'Mliečne výrobky v novom balení',
|
||||
title: 'Tradične kvalitné mliečne výrobky v novom balení',
|
||||
description: '',
|
||||
buttonText: 'Nechajte sa ohúriť',
|
||||
buttonUrl: 'https://www.coop.sk',
|
||||
buttonUrl: '#',
|
||||
buttonBgColor: '#003399'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'mod-products-fantasticky',
|
||||
type: 'products_grid',
|
||||
title: 'Fantasticky nízke ceny',
|
||||
title: '4. Fantasticky nízke ceny (Červená)',
|
||||
data: {
|
||||
sectionTitle: 'Fantasticky nízke ceny!',
|
||||
globalValidity: '2. 5. – 15. 5. 2026',
|
||||
cardBgColor: '#feeaea',
|
||||
cardBorderColor: '#f5d4d4',
|
||||
badgeHeaderBg: '#fefefe',
|
||||
badgeHeaderColor: '#000000',
|
||||
badgePriceBg: '#e2001a',
|
||||
badgePriceColor: '#fefefe',
|
||||
products: [
|
||||
{
|
||||
id: 'p1',
|
||||
@@ -104,10 +112,16 @@ export const DEFAULT_CAMPAIGN: NewsletterCampaign = {
|
||||
{
|
||||
id: 'mod-products-domace',
|
||||
type: 'products_grid',
|
||||
title: 'Domáce a vždy čerstvé',
|
||||
title: '5. Domáce a vždy čerstvé (Oranžová)',
|
||||
data: {
|
||||
sectionTitle: 'DOMÁCE A VŽDY ČERSTVÉ',
|
||||
globalValidity: '2. 5. – 15. 5. 2026',
|
||||
cardBgColor: '#fef0c7',
|
||||
cardBorderColor: '#e6d49a',
|
||||
badgeHeaderBg: '#fefefe',
|
||||
badgeHeaderColor: '#000000',
|
||||
badgePriceBg: '#f9890e',
|
||||
badgePriceColor: '#fefefe',
|
||||
products: [
|
||||
{
|
||||
id: 'p3',
|
||||
@@ -119,42 +133,184 @@ export const DEFAULT_CAMPAIGN: NewsletterCampaign = {
|
||||
discountText: '34%',
|
||||
badgeText: 'zľava',
|
||||
cardBgColor: '#fef0c7',
|
||||
showSlovakFlag: true,
|
||||
showSlovakFlag: false,
|
||||
stores: { potraviny: false, supermarket: true, tempo: true }
|
||||
},
|
||||
{
|
||||
id: 'p4',
|
||||
title: 'Cibuľa žltá neskorá praná 1 kg',
|
||||
title: 'Vajcia z podstielkového chovu M 15 ks 1 bal.',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}produkt_4.png`,
|
||||
priceMain: '0',
|
||||
priceSub: '79',
|
||||
unitPrice: '1kg = 0,79 €',
|
||||
discountText: '27%',
|
||||
priceMain: '3',
|
||||
priceSub: '99',
|
||||
unitPrice: '1ks = 0,27 €',
|
||||
discountText: '20%',
|
||||
badgeText: 'zľava',
|
||||
cardBgColor: '#fef0c7',
|
||||
showSlovakFlag: true,
|
||||
showSlovakFlag: false,
|
||||
stores: { potraviny: false, supermarket: true, tempo: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'mod-products-grill',
|
||||
type: 'products_grid',
|
||||
title: '6. Grilujeme chutne a výhodne (Zelená/Žltá)',
|
||||
data: {
|
||||
sectionTitle: 'GRILUJEME CHUTNE A VÝHODNE',
|
||||
globalValidity: '2. 5. – 15. 5. 2026',
|
||||
cardBgColor: '#dcb085',
|
||||
cardBorderColor: '#b8895c',
|
||||
badgeHeaderBg: '#ffde00',
|
||||
badgeHeaderColor: '#e2001a',
|
||||
badgeHeaderCustomText: 'Skvelá cena',
|
||||
badgePriceBg: '#005239',
|
||||
badgePriceColor: '#fefefe',
|
||||
products: [
|
||||
{
|
||||
id: 'p5',
|
||||
title: 'Kuracie krídla v BBQ 1 kg',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}produkt_5.png`,
|
||||
priceMain: '3',
|
||||
priceSub: '99',
|
||||
unitPrice: '1kg = 3,99 €',
|
||||
discountText: '',
|
||||
badgeText: 'Skvelá cena',
|
||||
cardBgColor: '#dcb085',
|
||||
showSlovakFlag: false,
|
||||
stores: { potraviny: false, supermarket: false, tempo: true }
|
||||
},
|
||||
{
|
||||
id: 'p6',
|
||||
title: 'Hellmann\'s omáčka 2 druhy 250 g – 255 g',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}produkt_6.png`,
|
||||
priceMain: '1',
|
||||
priceSub: '99',
|
||||
unitPrice: '1kg = 7,96 €',
|
||||
discountText: '38%',
|
||||
badgeText: 'zľava',
|
||||
cardBgColor: '#dcb085',
|
||||
showSlovakFlag: false,
|
||||
stores: { potraviny: false, supermarket: false, tempo: true }
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'mod-loyalty-club',
|
||||
type: 'loyalty_club',
|
||||
title: '7. Vernostné zľavy (COOP Klub)',
|
||||
data: {
|
||||
sectionTitle: 'Vernostné zľavy',
|
||||
headerImageUrl: `${SUPABASE_ASSETS_BASE}vernostna_karta-hlavicka_transparent.png`,
|
||||
headerLink: '#',
|
||||
globalValidity: '2. 5. – 15. 5. 2026',
|
||||
cardBgColor: '#e6e1d9',
|
||||
cardBorderColor: '#cfc8bb',
|
||||
products: [
|
||||
{
|
||||
id: 'lp1',
|
||||
title: 'Jojo želé 3 druhy 80 g',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}vernostna_karta-produkt_1.png`,
|
||||
// Bez karty
|
||||
noCardDiscount: '21%',
|
||||
noCardPriceMain: '0',
|
||||
noCardPriceSub: '79',
|
||||
noCardUnitPrice: '1kg = 9,88 €',
|
||||
// S kartou
|
||||
cardDiscount: '38%',
|
||||
cardPriceMain: '0',
|
||||
cardPriceSub: '62',
|
||||
cardUnitPrice: '1kg = 7,75 €',
|
||||
stores: { potraviny: true, supermarket: true, tempo: true },
|
||||
showSlovakFlag: true
|
||||
},
|
||||
{
|
||||
id: 'lp2',
|
||||
title: 'Margot tyčinka 3 druhy 40 g',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}vernostna_karta-produkt_2.png`,
|
||||
// Bez karty
|
||||
noCardDiscount: '23%',
|
||||
noCardPriceMain: '0',
|
||||
noCardPriceSub: '45',
|
||||
noCardUnitPrice: '1kg = 11,25 €',
|
||||
// S kartou
|
||||
cardDiscount: '40%',
|
||||
cardPriceMain: '0',
|
||||
cardPriceSub: '35',
|
||||
cardUnitPrice: '1kg = 8,75 €',
|
||||
stores: { potraviny: true, supermarket: true, tempo: true },
|
||||
showSlovakFlag: true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'mod-flyers-row',
|
||||
type: 'articles_row',
|
||||
title: '8. Aktuálne a Rozšírené letáky',
|
||||
data: {
|
||||
item1: {
|
||||
title: 'Aktuálne letáky',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}aktualne_letaky.jpg`,
|
||||
linkUrl: '#',
|
||||
btnText: 'Zobraziť',
|
||||
btnBgColor: '#e2001a',
|
||||
bgColor: '#29446f',
|
||||
textColor: '#fefefe'
|
||||
},
|
||||
item2: {
|
||||
title: 'Rozšírený leták',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}online_letak.jpg`,
|
||||
linkUrl: '#',
|
||||
btnText: 'Prelistovať',
|
||||
btnBgColor: '#29446f',
|
||||
bgColor: '#f9ba3c',
|
||||
textColor: '#29446f'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'mod-recipes-row',
|
||||
type: 'articles_row',
|
||||
title: '9. Články a Recepty',
|
||||
data: {
|
||||
item1: {
|
||||
title: 'Veľkonočný<br>baranček',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}clanok_barancek.png`,
|
||||
badgeImgUrl: `${SUPABASE_ASSETS_BASE}clanky-netradicne_recepty.png`,
|
||||
linkUrl: '#',
|
||||
bgColor: '#f68e1e',
|
||||
textColor: '#fefefe'
|
||||
},
|
||||
item2: {
|
||||
title: 'Vajíčko<br>magický amulet',
|
||||
imageUrl: `${SUPABASE_ASSETS_BASE}clanok_vajicka.png`,
|
||||
badgeImgUrl: `${SUPABASE_ASSETS_BASE}clanky-casopis_jednota.png`,
|
||||
linkUrl: '#',
|
||||
bgColor: '#5c85a8',
|
||||
textColor: '#fefefe'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'mod-footer',
|
||||
type: 'footer',
|
||||
title: 'Pätička',
|
||||
title: '10. Pätička so sieťami, projektmi a aplikáciami',
|
||||
data: {
|
||||
disclaimer: 'Tento newsletter má len informatívny charakter. Ceny a ponuka tovaru sa môžu na jednotlivých predajniach líšiť. Ponuka platí do vypredania zásob.',
|
||||
unsubscribeText: 'Ak si už neželáte dostávať náš newsletter, môžete sa odhlásiť tu.',
|
||||
unsubscribeUrl: '{{ unsubscribe }}',
|
||||
appStoreUrl: 'https://apps.apple.com/sk/app/coop-jednota/id1044610196',
|
||||
googlePlayUrl: 'https://play.google.com/store/apps/details?id=sk.coop.jednota.klub',
|
||||
foundationUrl: 'https://www.nadaciacoop.sk',
|
||||
recipesUrl: 'https://recepty.coop.sk',
|
||||
socials: {
|
||||
facebook: 'https://www.facebook.com/coopjednotaslovensko',
|
||||
instagram: 'https://www.instagram.com/coopjednotaslovensko',
|
||||
tiktok: 'https://www.tiktok.com/@coopjednota',
|
||||
youtube: 'https://www.youtube.com/c/COOPJednotaSlovensko'
|
||||
facebook: 'https://www.facebook.com/coopjednota',
|
||||
instagram: 'https://www.instagram.com/coopjednota/',
|
||||
youtube: 'https://www.youtube.com/user/COOPJednotaSR',
|
||||
tiktok: 'https://www.tiktok.com/@coopjednota'
|
||||
},
|
||||
appStoreUrl: 'https://apps.apple.com/sk/app/coop-jednota/id1527814838',
|
||||
googlePlayUrl: 'https://play.google.com/store/apps/details?id=sk.coop.app',
|
||||
foundationUrl: 'https://www.nadaciacoop.sk'
|
||||
disclaimer:
|
||||
'Tento e-mail ste dostali, pretože ste členom COOP Jednota Klubu.<br>© 2026 COOP Jednota Slovensko, spotrebné družstvo.',
|
||||
unsubscribeUrl: '*|UNSUB|*'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
+648
-207
@@ -8,15 +8,24 @@ export function renderEmailHtml(campaign: NewsletterCampaign): string {
|
||||
<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, initial-scale=1">
|
||||
<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>
|
||||
:root { color-scheme: light only; supported-color-schemes: light; }
|
||||
/* 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;
|
||||
@@ -25,27 +34,148 @@ export function renderEmailHtml(campaign: NewsletterCampaign): string {
|
||||
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; }
|
||||
* {
|
||||
-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; }
|
||||
.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; }
|
||||
.glass-product { margin-bottom: 15px !important; }
|
||||
.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 width="100%" bgcolor="#001a33" style="margin: 0; padding: 0 !important; mso-line-height-rule: exactly; background-color: #001a33;">
|
||||
<!-- Preheader text -->
|
||||
<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>
|
||||
@@ -56,7 +186,9 @@ export function renderEmailHtml(campaign: NewsletterCampaign): string {
|
||||
<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]-->
|
||||
<!--[if mso | IE]>
|
||||
</td></tr></table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -69,165 +201,363 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
|
||||
switch (m.type) {
|
||||
case 'announcement':
|
||||
return `
|
||||
<!-- TOP OZNAMOVACIA LIŠTA -->
|
||||
<!-- 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%" bgcolor="${m.data.bgColor || '#e2001a'}" style="background-color: ${m.data.bgColor || '#e2001a'}; background: linear-gradient(to right, #ff3d4f, #e2001a); border-radius: 12px; box-shadow: 0 10px 25px rgba(226, 0, 26, 0.3); border: 1px solid rgba(255,255,255,0.2);">
|
||||
<tr>
|
||||
<td style="padding: 10px 20px; text-align: center;">
|
||||
<div style="display: inline-block; vertical-align: middle;">
|
||||
<span style="background-color: #fefefe; color: ${m.data.bgColor || '#e2001a'}; font-size: 10px; font-weight: 800; padding: 2px 8px; border-radius: 4px; margin: 4px 5px; vertical-align: middle; display: inline-block; letter-spacing: 1px;">${escapeHtml(m.data.tipBadge || 'TIP')}</span>
|
||||
</div>
|
||||
<div style="display: inline-block; vertical-align: middle;">
|
||||
<span 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;">
|
||||
<a href="${escapeHtml(m.data.linkUrl || '#')}" 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)}</a>
|
||||
</div>` : ''}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<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-radius: 12px; box-shadow: 0 10px 25px rgba(226, 0, 26, 0.3); border: 1px solid rgba(255,255,255,0.2);">
|
||||
<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-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 navLinksHtml = (m.data.navLinks || [])
|
||||
.map((link: any) => {
|
||||
if (link.variant === 'filled') {
|
||||
return `<a href="${escapeHtml(link.url)}" 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)}</a>`;
|
||||
}
|
||||
return `<a href="${escapeHtml(link.url)}" 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)}</a>`;
|
||||
})
|
||||
.join('\n');
|
||||
const navLinks = (m.data.navLinks || []).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)}</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)}</a>`;
|
||||
}).join('\n');
|
||||
|
||||
return `
|
||||
<!-- HLAVIČKA -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" bgcolor="#fefefe" style="background-color: #fefefe; border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); overflow: hidden; margin-bottom: 25px;">
|
||||
<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;">
|
||||
<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;">
|
||||
${navLinksHtml}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>`;
|
||||
<!-- 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: 1px solid #fefefe; 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;"> </td></tr></table>`;
|
||||
|
||||
case 'banner':
|
||||
return `
|
||||
<!-- BANNER -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" bgcolor="#fefefe" style="background-color: #fefefe; border-radius: 16px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); overflow: hidden; margin-bottom: 25px;">
|
||||
<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: 600px; border-top-left-radius: 16px; border-top-right-radius: 16px;">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
${m.data.title || m.data.description || m.data.buttonText ? `
|
||||
<tr>
|
||||
<td style="padding: 25px 20px; text-align: center;" class="mobile-padding">
|
||||
${m.data.title ? `<h2 style="margin: 0 0 15px 0; font-size: 22px; color: #1a1a1a; font-weight: 700;">${escapeHtml(m.data.title)}</h2>` : ''}
|
||||
${m.data.description ? `<p style="margin: 0 0 20px 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;">
|
||||
<tr>
|
||||
<td style="text-align: center;">
|
||||
<a href="${escapeHtml(m.data.buttonUrl || '#')}" 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>`;
|
||||
<!-- 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: 1px solid #fefefe; 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-top-left-radius: 16px; border-top-right-radius: 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 rows: ProductItem[][] = [];
|
||||
for (let i = 0; i < products.length; i += 2) {
|
||||
rows.push(products.slice(i, i + 2));
|
||||
}
|
||||
|
||||
const rowsHtml = rows
|
||||
.map(
|
||||
(row) => `
|
||||
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" style="padding-${idx === 0 ? 'right: 6px' : 'left: 6px'};">
|
||||
${renderProductCard(p, globalValidity)}
|
||||
</td>`
|
||||
)
|
||||
.join('\n')}
|
||||
${row.length === 1 ? '<td width="50%"></td>' : ''}
|
||||
</tr>
|
||||
</table>`
|
||||
)
|
||||
.join('\n');
|
||||
<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 -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" style="margin-bottom: 25px;">
|
||||
${m.data.sectionTitle ? `
|
||||
<tr>
|
||||
<td style="text-align: center; padding-top: 15px; padding-bottom: 20px;">
|
||||
<h2 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>
|
||||
<!-- 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':
|
||||
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-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;"> </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-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-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;"> </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-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-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;"> </td></tr></table>`;
|
||||
|
||||
case 'footer':
|
||||
return `
|
||||
<!-- PÄTIČKA -->
|
||||
<table align="center" role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" bgcolor="#001a33" style="background-color: #001a33; padding: 25px 15px; text-align: center; color: #a0aec0; font-size: 11px; line-height: 1.6;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<!-- Sociálne siete -->
|
||||
<div style="margin-bottom: 15px;">
|
||||
<a href="${escapeHtml(m.data.socials?.facebook || '#')}" style="margin: 0 6px; display: inline-block;">
|
||||
<img src="${SUPABASE_ASSETS_BASE}ikona_fb.png" width="28" height="28" alt="Facebook" style="display: block;">
|
||||
</a>
|
||||
<a href="${escapeHtml(m.data.socials?.instagram || '#')}" style="margin: 0 6px; display: inline-block;">
|
||||
<img src="${SUPABASE_ASSETS_BASE}ikona_ig.png" width="28" height="28" alt="Instagram" style="display: block;">
|
||||
</a>
|
||||
<a href="${escapeHtml(m.data.socials?.tiktok || '#')}" style="margin: 0 6px; display: inline-block;">
|
||||
<img src="${SUPABASE_ASSETS_BASE}ikona_tt.png" width="28" height="28" alt="TikTok" style="display: block;">
|
||||
</a>
|
||||
<a href="${escapeHtml(m.data.socials?.youtube || '#')}" style="margin: 0 6px; display: inline-block;">
|
||||
<img src="${SUPABASE_ASSETS_BASE}ikona_yt.png" width="28" height="28" alt="YouTube" style="display: block;">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Disclaimer -->
|
||||
<p style="margin: 0 0 15px 0; color: #718096; font-size: 10px;">
|
||||
${escapeHtml(m.data.disclaimer || '')}
|
||||
</p>
|
||||
|
||||
<!-- Unsubscribe -->
|
||||
<p style="margin: 0; color: #a0aec0;">
|
||||
<a href="${escapeHtml(m.data.unsubscribeUrl || '{{ unsubscribe }}')}" style="color: #cbd5e0; text-decoration: underline;">${escapeHtml(m.data.unsubscribeText || 'Odhlásiť sa')}</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- 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: 1px solid #fefefe; 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: 1px solid rgba(0,0,0,0.1); 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:
|
||||
@@ -235,71 +565,182 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
|
||||
}
|
||||
}
|
||||
|
||||
function renderProductCard(p: ProductItem, globalValidity: string): string {
|
||||
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 bgColor = p.cardBgColor || '#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: 1px solid #fefefe; 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;"></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: 1px solid #fefefe; background-color: #f9890e; padding: 0; line-height: 0; border-top: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_supermarket.png" height="10" alt="S" style="display: block; height: 10px; width: auto;"></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: 1px solid #fefefe; background-color: #005239; padding: 0; line-height: 0; border-top: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_tempo.png" height="10" alt="T" style="display: block; height: 10px; width: auto;"></td></tr></table></td></tr>` : ''}
|
||||
${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: 1px solid #fefefe; 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;"></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: 1px solid #fefefe; background-color: #f9890e; padding: 0; line-height: 0; border-top: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_supermarket.png" height="10" alt="S" style="display: block; height: 10px; width: auto;"></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: 1px solid #fefefe; background-color: #005239; padding: 0; line-height: 0; border-top: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_tempo.png" height="10" alt="T" style="display: block; height: 10px; width: auto;"></td></tr></table></td></tr>` : ''}
|
||||
</table>`;
|
||||
|
||||
return `
|
||||
<table role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" bgcolor="${bgColor}" style="background-color: ${bgColor}; border: 1px solid rgba(0,0,0,0.08); 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 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">
|
||||
<!-- Cenovka -->
|
||||
<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: #fefefe; border: 2px solid #fefefe; border-radius: 12px 0 0 12px; box-shadow: 0 4px 10px rgba(0,0,0,0.18); width: 85px; overflow: hidden;">
|
||||
${p.discountText ? `
|
||||
<tr>
|
||||
<td style="padding: 2px 4px; text-align: right; background-color: #fefefe;">
|
||||
<span style="font-family: 'Arial Narrow', Arial, sans-serif; font-size: 9px; color: #000000; 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: #000000; font-weight: 900; line-height: 1; margin-left: 2px;">${escapeHtml(p.discountText)}</span>
|
||||
</td>
|
||||
</tr>` : ''}
|
||||
<tr>
|
||||
<td bgcolor="#e2001a" style="background-color: #e2001a; padding: 4px 2px 2px 2px; font-family: 'Arial Narrow', Arial, sans-serif; color: #fefefe; font-weight: 900; line-height: 1; text-align: center; border-radius: 0 0 0 8px;">
|
||||
<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 role="presentation" cellspacing="0" cellpadding="0" border="0" width="100%" height="100%" class="glass-product" bgcolor="${cardBg}" style="background-color: ${cardBg}; border: 1px solid ${cardBorder}; 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>
|
||||
${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;">
|
||||
</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>
|
||||
</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 -->
|
||||
<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: 2px solid #fefefe; border-radius: 12px 0 0 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 0 8px;">
|
||||
<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 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: 1px solid #fefefe; 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;"></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: 1px solid #fefefe; background-color: #f9890e; padding: 0; line-height: 0; border-top: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_supermarket.png" height="10" alt="S" style="display: block; height: 10px; width: auto;"></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: 1px solid #fefefe; background-color: #005239; padding: 0; line-height: 0; border-top: 0;"><img src="${SUPABASE_ASSETS_BASE}stit_tempo.png" height="10" alt="T" style="display: block; height: 10px; width: auto;"></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: 1px solid #cfc8bb; 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">
|
||||
<!-- 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: 2px solid #fefefe; 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: 2px solid #fefefe; border-radius: 10px 0 0 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;">
|
||||
<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>`;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user