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:
Jakub_HostacnyandClaude Opus 5.5 committed 2026-10-19 16:42:59 +02:00
1 parent 5f6a39debe
commit 98fdad535d
5 files changed
+213 -44

No files matched your search

+72 -12
View File
@@ -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 */}