feat: lista platnosti akcie nad produktmi, platnost na kartach predvolene skryta
- novy blok Lista platnosti akcie (vzhlad ako oznamovacia lista, bez badge a CTA): text + globalna platnost, da sa skryt a posuvat, nie zmazat; do existujucich kampani sa vlozi automaticky nad prvu produktovu sekciu - platnost na kartach produktov sa da zobrazit prepinacom (predvolene skryta), produkty s vlastnou platnostou ju zobrazia vzdy Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5f6a39debe
commit
98fdad535d
5 files changed
+213
-44
No files matched your search
+77
-29
@@ -2,8 +2,8 @@
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { NewsletterCampaign, NewsletterModule, ProductItem, BadgeTemplate } from '@/types/newsletter';
|
||||
import { DEFAULT_CAMPAIGN, SUPABASE_ASSETS_BASE } from '@/lib/defaultCampaign';
|
||||
import { renderEmailHtml, renderSingleModuleHtml } from '@/lib/emailRenderer';
|
||||
import { DEFAULT_CAMPAIGN, SUPABASE_ASSETS_BASE, ensureValidityBar } from '@/lib/defaultCampaign';
|
||||
import { renderEmailHtml, renderSingleModuleHtml, getCampaignValidity } from '@/lib/emailRenderer';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { DEFAULT_BADGE_TEMPLATES } from '@/lib/badgeUtils';
|
||||
import { getBrevoCampaignUrl } from '@/lib/brevo';
|
||||
@@ -142,7 +142,7 @@ export default function Home() {
|
||||
preheader: dbItem.data.preheader || DEFAULT_CAMPAIGN.preheader,
|
||||
status: dbItem.status,
|
||||
brevoCampaignId: dbItem.brevo_campaign_id,
|
||||
modules: enforceAnchors(dbItem.data.modules)
|
||||
modules: enforceAnchors(ensureValidityBar(dbItem.data.modules))
|
||||
});
|
||||
if (dbItem.brevo_campaign_id) {
|
||||
setBrevoUrl(getBrevoCampaignUrl(dbItem.brevo_campaign_id));
|
||||
@@ -234,7 +234,7 @@ export default function Home() {
|
||||
// Duplikácia: Ukotvené moduly sa nedajú duplikovať
|
||||
const duplicateModule = (index: number) => {
|
||||
const original = campaign.modules[index];
|
||||
if (isAnchoredModule(original)) return;
|
||||
if (isAnchoredModule(original) || original.type === 'validity_bar') return;
|
||||
|
||||
const clone: NewsletterModule = {
|
||||
...original,
|
||||
@@ -256,6 +256,10 @@ export default function Home() {
|
||||
alert('Hlavičku, letáky, články/recepty ani pätičku nie je možné vymazať.');
|
||||
return;
|
||||
}
|
||||
if (mod.type === 'validity_bar') {
|
||||
alert('Lištu platnosti akcie nie je možné vymazať, dá sa len skryť.');
|
||||
return;
|
||||
}
|
||||
if (campaign.modules.length <= 1) return;
|
||||
|
||||
const newModules = campaign.modules.filter((_, i) => i !== index);
|
||||
@@ -591,14 +595,15 @@ export default function Home() {
|
||||
}));
|
||||
};
|
||||
|
||||
// Globálna platnosť akcie: prepíše sa do všetkých produktových sekcií aj vernostných zliav
|
||||
// Spoločné nastavenia (globálna platnosť akcie, zobrazenie platnosti na kartách) sa prepíšu
|
||||
// do všetkých produktových sekcií aj vernostných zliav
|
||||
// (produkty s vlastnou platnosťou validityOverride si ju ponechajú)
|
||||
const handleSetGlobalValidity = (validity: string) => {
|
||||
const handleUpdateAllProductSections = (patch: Record<string, unknown>) => {
|
||||
setCampaign((prev) => ({
|
||||
...prev,
|
||||
modules: prev.modules.map((m) =>
|
||||
m.type === 'products_grid' || m.type === 'loyalty_club'
|
||||
? { ...m, data: { ...m.data, globalValidity: validity } }
|
||||
? { ...m, data: { ...m.data, ...patch } }
|
||||
: m
|
||||
)
|
||||
}));
|
||||
@@ -704,6 +709,26 @@ export default function Home() {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{mod.type === 'validity_bar' && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleUpdateModule({
|
||||
...mod,
|
||||
data: { ...mod.data, enabled: mod.data.enabled === false }
|
||||
});
|
||||
}}
|
||||
className={`text-[9px] font-bold px-2 py-0.5 rounded-full border transition-all mr-1 ${
|
||||
mod.data.enabled === false
|
||||
? 'bg-red-500/20 text-red-300 border-red-400/30 hover:bg-red-500/30'
|
||||
: 'bg-emerald-500/20 text-emerald-300 border-emerald-400/30 hover:bg-emerald-500/30'
|
||||
}`}
|
||||
title={mod.data.enabled === false ? 'Zobraziť lištu v e-maile' : 'Skryť lištu v e-maile'}
|
||||
>
|
||||
{mod.data.enabled === false ? 'Skrytá (zapnúť)' : 'Zobrazená'}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
@@ -726,26 +751,30 @@ export default function Home() {
|
||||
>
|
||||
<ChevronDown className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
duplicateModule(idx);
|
||||
}}
|
||||
className="hover:text-blue-400 p-1 ml-1"
|
||||
title="Duplikovať sekciu"
|
||||
>
|
||||
<Copy className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
deleteModule(idx);
|
||||
}}
|
||||
className="hover:text-red-400 p-1 ml-1"
|
||||
title="Zmazať sekciu"
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
{mod.type !== 'validity_bar' && (
|
||||
<>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
duplicateModule(idx);
|
||||
}}
|
||||
className="hover:text-blue-400 p-1 ml-1"
|
||||
title="Duplikovať sekciu"
|
||||
>
|
||||
<Copy className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
deleteModule(idx);
|
||||
}}
|
||||
className="hover:text-red-400 p-1 ml-1"
|
||||
title="Zmazať sekciu"
|
||||
>
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
@@ -770,6 +799,24 @@ export default function Home() {
|
||||
Aktivovať vernostné zľavy
|
||||
</button>
|
||||
</div>
|
||||
) : mod.type === 'validity_bar' && mod.data.enabled === false ? (
|
||||
<div className="p-4 my-2 border-2 border-dashed border-red-500/40 bg-red-950/30 rounded-xl text-center">
|
||||
<p className="text-xs font-bold text-red-300 uppercase tracking-wider">
|
||||
Lišta platnosti akcie (Skrytá)
|
||||
</p>
|
||||
<p className="text-[11px] text-gray-300 mt-0.5">
|
||||
Táto lišta je v e-maile skrytá. Kliknutím sem ju môžete aktivovať.
|
||||
</p>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleUpdateModule({ ...mod, data: { ...mod.data, enabled: true } });
|
||||
}}
|
||||
className="mt-2 px-3 py-1 bg-red-600 hover:bg-red-700 text-white text-xs font-bold rounded-lg transition-colors shadow-sm"
|
||||
>
|
||||
Aktivovať lištu platnosti
|
||||
</button>
|
||||
</div>
|
||||
) : mod.type === 'announcement' && mod.data.enabled === false ? (
|
||||
<div className="p-4 my-2 border-2 border-dashed border-red-500/40 bg-red-950/30 rounded-xl text-center">
|
||||
<p className="text-xs font-bold text-red-300 uppercase tracking-wider">
|
||||
@@ -808,7 +855,8 @@ export default function Home() {
|
||||
module={selectedModule}
|
||||
onUpdateModule={handleUpdateModule}
|
||||
onApplyBadgeToAll={handleApplyBadgeToAll}
|
||||
onSetGlobalValidity={handleSetGlobalValidity}
|
||||
onUpdateAllProductSections={handleUpdateAllProductSections}
|
||||
campaignValidity={getCampaignValidity(campaign)}
|
||||
availableBadges={availableBadges}
|
||||
onOpenBadgeManager={(pId) => {
|
||||
setTargetProductIdForBadge(pId);
|
||||
@@ -846,7 +894,7 @@ export default function Home() {
|
||||
onClose={() => setIsSavedCampaignsOpen(false)}
|
||||
currentCampaign={campaign}
|
||||
onLoadCampaign={(selected: NewsletterCampaign) => {
|
||||
setCampaign({ ...selected, modules: enforceAnchors(selected.modules) });
|
||||
setCampaign({ ...selected, modules: enforceAnchors(ensureValidityBar(selected.modules)) });
|
||||
setSelectedModuleId(selected.modules[1]?.id || selected.modules[0]?.id || null);
|
||||
if (selected.brevoCampaignId) {
|
||||
setBrevoUrl(getBrevoCampaignUrl(selected.brevoCampaignId));
|
||||
|
||||
@@ -21,7 +21,9 @@ interface ConfigPanelProps {
|
||||
module: NewsletterModule | null;
|
||||
onUpdateModule: (updated: NewsletterModule) => void;
|
||||
onApplyBadgeToAll?: (badge: BadgeTemplate, badgeLayout?: 'below' | 'side') => void;
|
||||
onSetGlobalValidity?: (validity: string) => void; // nastaví platnosť vo všetkých produktových sekciách
|
||||
// Zmena nastavení spoločných pre všetky produktové sekcie a vernostné zľavy (platnosť akcie...)
|
||||
onUpdateAllProductSections?: (patch: Record<string, unknown>) => void;
|
||||
campaignValidity?: string; // globálna platnosť akcie (pre Lištu platnosti)
|
||||
onOpenBadgeManager?: (productId: string) => void;
|
||||
onOpenImport?: () => void;
|
||||
availableBadges?: BadgeTemplate[];
|
||||
@@ -183,7 +185,8 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
module,
|
||||
onUpdateModule,
|
||||
onApplyBadgeToAll,
|
||||
onSetGlobalValidity,
|
||||
onUpdateAllProductSections,
|
||||
campaignValidity = '',
|
||||
onOpenBadgeManager,
|
||||
onOpenImport,
|
||||
availableBadges = []
|
||||
@@ -196,6 +199,9 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
);
|
||||
}
|
||||
|
||||
const updateAllProductSections = (patch: Record<string, unknown>) =>
|
||||
onUpdateAllProductSections ? onUpdateAllProductSections(patch) : updateData(patch);
|
||||
|
||||
const updateData = (newData: any) => {
|
||||
onUpdateModule({
|
||||
...module,
|
||||
@@ -280,6 +286,50 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* LIŠTA PLATNOSTI AKCIE */}
|
||||
{module.type === 'validity_bar' && (
|
||||
<div className="space-y-4">
|
||||
<div className="bg-red-50/60 p-3.5 rounded-xl border border-red-200 flex items-center justify-between">
|
||||
<div>
|
||||
<span className="text-xs font-bold text-gray-900 block">Zobraziť v e-maile</span>
|
||||
<span className="text-[11px] text-gray-500">Lišta platnosti akcie</span>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={module.data.enabled !== false}
|
||||
onChange={(e) => updateData({ enabled: e.target.checked })}
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-300 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-red-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-gray-700 mb-1">Text pred dátumom</label>
|
||||
<input
|
||||
type="text"
|
||||
value={module.data.text || ''}
|
||||
onChange={(e) => updateData({ text: e.target.value })}
|
||||
placeholder="napr. Akcia platí"
|
||||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-semibold text-gray-700 mb-1">Globálna platnosť akcie</label>
|
||||
<input
|
||||
type="text"
|
||||
value={campaignValidity}
|
||||
onChange={(e) => updateAllProductSections({ globalValidity: e.target.value })}
|
||||
placeholder="napr. 2. 5. – 15. 5. 2026"
|
||||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||||
/>
|
||||
<p className="text-[10px] text-gray-500 mt-1">Rovnaká platnosť ako v produktových sekciách – zmena sa prejaví všade.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Vlastné HTML pre hlavičku a pätičku */}
|
||||
{CUSTOM_HTML_MODULE_TYPES.includes(module.type) && (
|
||||
<CustomHtmlEditor module={module} updateData={updateData} />
|
||||
@@ -503,15 +553,20 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
<input
|
||||
type="text"
|
||||
value={module.data.globalValidity || ''}
|
||||
onChange={(e) =>
|
||||
onSetGlobalValidity
|
||||
? onSetGlobalValidity(e.target.value)
|
||||
: updateData({ globalValidity: e.target.value })
|
||||
}
|
||||
onChange={(e) => updateAllProductSections({ globalValidity: e.target.value })}
|
||||
placeholder="napr. 2. 5. – 15. 5. 2026"
|
||||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||||
/>
|
||||
<p className="text-[10px] text-gray-500 mt-1">Platí pre všetky produktové sekcie aj vernostné zľavy. Produkty s vlastnou platnosťou si ju ponechajú.</p>
|
||||
<label className="mt-2 flex items-center gap-2 text-[11px] text-gray-700 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={module.data.showCardValidity === true}
|
||||
onChange={(e) => updateAllProductSections({ showCardValidity: e.target.checked })}
|
||||
className="w-3.5 h-3.5 accent-red-600"
|
||||
/>
|
||||
Zobraziť platnosť aj na kartách produktov
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Rozloženie produktov (Počet produktov na riadok) */}
|
||||
@@ -1212,15 +1267,20 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||||
<input
|
||||
type="text"
|
||||
value={module.data.globalValidity || ''}
|
||||
onChange={(e) =>
|
||||
onSetGlobalValidity
|
||||
? onSetGlobalValidity(e.target.value)
|
||||
: updateData({ globalValidity: e.target.value })
|
||||
}
|
||||
onChange={(e) => updateAllProductSections({ globalValidity: e.target.value })}
|
||||
placeholder="napr. 2. 5. – 15. 5. 2026"
|
||||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||||
/>
|
||||
<p className="text-[10px] text-gray-500 mt-1">Platí pre všetky produktové sekcie aj vernostné zľavy. Produkty s vlastnou platnosťou si ju ponechajú.</p>
|
||||
<label className="mt-2 flex items-center gap-2 text-[11px] text-gray-700 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={module.data.showCardValidity === true}
|
||||
onChange={(e) => updateAllProductSections({ showCardValidity: e.target.checked })}
|
||||
className="w-3.5 h-3.5 accent-red-600"
|
||||
/>
|
||||
Zobraziť platnosť aj na kartách produktov
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Farba pozadia vernostných kariet */}
|
||||
|
||||
@@ -1,9 +1,29 @@
|
||||
import { NewsletterCampaign, ProductItem } from '@/types/newsletter';
|
||||
import { NewsletterCampaign, NewsletterModule, ProductItem } from '@/types/newsletter';
|
||||
|
||||
// Verejné úložisko statických obrázkov (logá, ikony, štítky predajní...) v Supabase projekte z .env.
|
||||
// Súbory sú v supabase/assets/ a nahrajú sa príkazom: npm run db:upload-assets
|
||||
export const SUPABASE_ASSETS_BASE = `${(process.env.NEXT_PUBLIC_SUPABASE_URL || '').replace(/\/$/, '')}/storage/v1/object/public/newsletter-assets/`;
|
||||
|
||||
// Lišta platnosti akcie nad produktmi – dá sa skryť a posúvať, nie zmazať
|
||||
export const VALIDITY_BAR_MODULE: NewsletterModule = {
|
||||
id: 'mod-validity-bar',
|
||||
type: 'validity_bar',
|
||||
title: 'Lišta platnosti akcie',
|
||||
data: {
|
||||
text: 'Akcia platí',
|
||||
enabled: true
|
||||
}
|
||||
};
|
||||
|
||||
// Staršie kampane bez lišty platnosti: vloží ju nad prvú produktovú sekciu
|
||||
export function ensureValidityBar(modules: NewsletterModule[]): NewsletterModule[] {
|
||||
if (modules.some((m) => m.type === 'validity_bar')) return modules;
|
||||
const idx = modules.findIndex((m) => m.type === 'products_grid' || m.type === 'loyalty_club');
|
||||
const bar = { ...VALIDITY_BAR_MODULE, data: { ...VALIDITY_BAR_MODULE.data } };
|
||||
if (idx === -1) return modules;
|
||||
return [...modules.slice(0, idx), bar, ...modules.slice(idx)];
|
||||
}
|
||||
|
||||
export const DEFAULT_CAMPAIGN: NewsletterCampaign = {
|
||||
id: '',
|
||||
title: 'COOP Jednota Newsletter',
|
||||
@@ -67,6 +87,7 @@ export const DEFAULT_CAMPAIGN: NewsletterCampaign = {
|
||||
buttonBgColor: '#003399'
|
||||
}
|
||||
},
|
||||
VALIDITY_BAR_MODULE,
|
||||
{
|
||||
id: 'mod-products-fantasticky',
|
||||
type: 'products_grid',
|
||||
|
||||
@@ -203,6 +203,14 @@ export function renderSingleModuleHtml(m: any, campaign: NewsletterCampaign): st
|
||||
return renderModule(m, campaign);
|
||||
}
|
||||
|
||||
// Globálna platnosť akcie kampane (zdieľaná všetkými produktovými sekciami)
|
||||
export function getCampaignValidity(campaign: NewsletterCampaign): string {
|
||||
const mod = (campaign.modules || []).find(
|
||||
(m) => (m.type === 'products_grid' || m.type === 'loyalty_club') && m.data?.globalValidity
|
||||
);
|
||||
return mod?.data.globalValidity || '';
|
||||
}
|
||||
|
||||
// Moduly, pri ktorých sa dá vygenerované HTML nahradiť vlastným (HTML editor)
|
||||
export const CUSTOM_HTML_MODULE_TYPES = ['header', 'footer'];
|
||||
|
||||
@@ -250,6 +258,28 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
|
||||
</tr>
|
||||
</table>`;
|
||||
|
||||
case 'validity_bar': {
|
||||
if (m.data?.enabled === false) {
|
||||
return '';
|
||||
}
|
||||
const validityText = [m.data.text, getCampaignValidity(campaign)].filter(Boolean).join(' ');
|
||||
return `
|
||||
<!-- LIŠTA PLATNOSTI AKCIE -->
|
||||
<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;">
|
||||
<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(validityText)}</span>
|
||||
</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' },
|
||||
@@ -314,7 +344,9 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
|
||||
<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 || '';
|
||||
// Platnosť na kartách je predvolene skrytá (zobrazí sa v Lište platnosti akcie);
|
||||
// produkty s vlastnou platnosťou (validityOverride) ju zobrazia vždy
|
||||
const globalValidity = m.data.showCardValidity === true ? (m.data.globalValidity || '') : '';
|
||||
const products: ProductItem[] = m.data.products || [];
|
||||
const cardBg = m.data.cardBgColor || '#feeaea';
|
||||
const cardBorder = m.data.cardBorderColor || '#f5d4d4';
|
||||
@@ -406,7 +438,7 @@ function renderModule(m: any, campaign: NewsletterCampaign): string {
|
||||
<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')}
|
||||
${renderExactLoyaltyCard(p, m.data.showCardValidity === true ? (m.data.globalValidity || '2. 5. – 15. 5. 2026') : '')}
|
||||
</td>`).join('\n')}
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -7,6 +7,7 @@ export type ModuleType =
|
||||
| 'products_grid'
|
||||
| 'loyalty_club'
|
||||
| 'articles_row'
|
||||
| 'validity_bar'
|
||||
| 'footer';
|
||||
|
||||
export interface StoreTag {
|
||||
@@ -60,6 +61,12 @@ export interface AnnouncementModuleData {
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
// Lišta platnosti akcie nad produktmi (vzhľad ako oznamovacia lišta, bez badge a CTA)
|
||||
export interface ValidityBarModuleData {
|
||||
text: string; // text pred dátumom, napr. "Akcia platí"
|
||||
enabled?: boolean; // false = skrytá v e-maile
|
||||
}
|
||||
|
||||
export interface HeaderModuleData {
|
||||
logoUrl: string;
|
||||
logoLink: string;
|
||||
@@ -104,6 +111,7 @@ export interface ProductsGridModuleData {
|
||||
cardBgColor?: string;
|
||||
cardBorderColor?: string;
|
||||
columns?: 1 | 2;
|
||||
showCardValidity?: boolean; // platnosť na kartách produktov (predvolene skrytá)
|
||||
}
|
||||
|
||||
export interface LoyaltyClubModuleData {
|
||||
|
||||
Reference in new issue
Block a user