From b747a3ba7415237ce8d61b784f1f67e36d12d7d3 Mon Sep 17 00:00:00 2001 From: Jandl-hostacny Date: Wed, 21 Oct 2026 16:49:27 +0200 Subject: [PATCH] feat: predvolena cenovka je sablona Super vyhodne | Cervena (neda sa zmazat) - volba Predvolena COOP cenovka v produkte zrusena; produkty bez sablony dostanu predvolenu sablonu automaticky - sablony z prehliadaca (localStorage) sa pridavaju len ak este nie su ulozene v databaze, zmazane sablony sa uz nevracaju Co-Authored-By: Claude Opus 5.5 --- src/app/page.tsx | 31 +++++++++++++++++++++- src/components/editor/BadgeEditorModal.tsx | 24 ++++++++++++----- src/components/editor/ProductEditor.tsx | 6 +++-- src/lib/badgeUtils.ts | 4 ++- src/types/newsletter.ts | 1 + 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/src/app/page.tsx b/src/app/page.tsx index afadc20..dfb630e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -71,7 +71,8 @@ export default function Home() { if (Array.isArray(parsed)) { const existingIds = new Set(loaded.map((b) => b.id)); for (const b of parsed) { - if (!existingIds.has(b.id)) { + // len šablóny neuložené do databázy – zmazané šablóny sa z prehliadača nesmú vrátiť + if (!existingIds.has(b.id) && String(b.id).startsWith('badge-')) { loaded.push(b); existingIds.add(b.id); } @@ -92,6 +93,34 @@ export default function Home() { fetchBadges(); }, [isBadgeEditorOpen]); + // Predvolená cenovka: produkty bez šablóny (nové, importované bez zhody, staršie s pôvodnou COOP cenovkou) + // dostanú predvolenú šablónu z databázy + const defaultBadge = availableBadges.find((b) => b.isDefault); + useEffect(() => { + if (!defaultBadge) return; + // jednorazové doplnenie chýbajúcej cenovky do dát (zmení stav len keď nejaký produkt šablónu nemá) + // eslint-disable-next-line react-hooks/set-state-in-effect + setCampaign((prev) => { + let changed = false; + const modules = prev.modules.map((m) => { + if (m.type !== 'products_grid') return m; + const products = m.data.products || []; + if (!products.some((p: ProductItem) => !p.badgeCustomTemplate && !p.customBadgePngUrl)) return m; + changed = true; + return { + ...m, + data: { + ...m.data, + products: products.map((p: ProductItem) => + p.badgeCustomTemplate || p.customBadgePngUrl ? p : { ...p, badgeCustomTemplate: defaultBadge, badgeId: defaultBadge.id } + ) + } + }; + }); + return changed ? { ...prev, modules } : prev; + }); + }, [campaign.modules, defaultBadge]); + // Pomocné funkcie pre fixné ukotvenie hlavičky, spodných letákov, receptov a pätičky const isTopModule = (m: NewsletterModule) => m.type === 'header' || m.type === 'announcement'; diff --git a/src/components/editor/BadgeEditorModal.tsx b/src/components/editor/BadgeEditorModal.tsx index 79631e1..4822ee1 100644 --- a/src/components/editor/BadgeEditorModal.tsx +++ b/src/components/editor/BadgeEditorModal.tsx @@ -49,7 +49,8 @@ function toBadgeDbPayload(badge: BadgeTemplate) { align: badge.align || 'center', paddingTop: badge.paddingTop ?? 4, paddingBottom: badge.paddingBottom ?? 4, - importTags: badge.importTags + importTags: badge.importTags, + isDefault: badge.isDefault || undefined } }; } @@ -363,7 +364,8 @@ export const BadgeEditorModal: React.FC = ({ const local = JSON.parse(localStorage.getItem(LOCAL_KEY) || '[]'); if (Array.isArray(local)) { const ids = new Set(loaded.map((b) => b.id)); - for (const b of local as BadgeTemplate[]) if (!ids.has(b.id)) loaded.push(b); + // z prehliadača len šablóny, ktoré ešte neboli uložené do databázy (zmazané sa nesmú vrátiť) + for (const b of local as BadgeTemplate[]) if (!ids.has(b.id) && b.id.startsWith('badge-')) loaded.push(b); } } catch { // localStorage nemusí byť dostupný @@ -553,7 +555,7 @@ export const BadgeEditorModal: React.FC = ({ const duplicateTemplate = async (b: BadgeTemplate) => { if (!confirmDiscard()) return; - const copy: BadgeTemplate = { ...JSON.parse(JSON.stringify(b)), id: newLocalBadgeId(), name: `${b.name} (kópia)` }; + const copy: BadgeTemplate = { ...JSON.parse(JSON.stringify(b)), id: newLocalBadgeId(), name: `${b.name} (kópia)`, isDefault: undefined }; let saved = copy; try { const { data, error } = await supabase.from('badges').insert([toBadgeDbPayload(copy)]).select(); @@ -569,6 +571,10 @@ export const BadgeEditorModal: React.FC = ({ }; const deleteTemplate = async (b: BadgeTemplate) => { + if (b.isDefault) { + alert('Predvolenú cenovku nie je možné zmazať.'); + return; + } if (!confirm(`Zmazať šablónu „${b.name}“? Produkty, ktoré ju už používajú, si ju ponechajú.`)) return; if (!b.id.startsWith('badge-')) { try { @@ -743,9 +749,15 @@ export const BadgeEditorModal: React.FC = ({ - + {b.isDefault ? ( + + predvolená + + ) : ( + + )} ))} diff --git a/src/components/editor/ProductEditor.tsx b/src/components/editor/ProductEditor.tsx index 63a1ef4..61b352c 100644 --- a/src/components/editor/ProductEditor.tsx +++ b/src/components/editor/ProductEditor.tsx @@ -503,11 +503,12 @@ export const ProductEditor: React.FC = ({