'use client'; import React, { useState, useEffect, useRef } from 'react'; import { NewsletterCampaign, NewsletterModule, ProductItem, BadgeTemplate } from '@/types/newsletter'; 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'; import { TopBar } from '@/components/editor/TopBar'; import { ConfigPanel } from '@/components/editor/ConfigPanel'; import { ProductImportModal } from '@/components/editor/ProductImportModal'; import { BadgeEditorModal } from '@/components/editor/BadgeEditorModal'; import { SavedCampaignsModal } from '@/components/editor/SavedCampaignsModal'; import JSZip from 'jszip'; import { prepareCardImages } from '@/lib/cardImages'; import { saveAs } from 'file-saver'; import { ChevronUp, ChevronDown, Copy, Trash2, Anchor, Lock } from 'lucide-react'; export default function Home() { const [campaign, setCampaign] = useState(DEFAULT_CAMPAIGN); const [selectedModuleId, setSelectedModuleId] = useState('mod-products-fantasticky'); // Produkt otvorený v paneli (harmonika); nastaví sa aj klikom na produkt v náhľade const [selectedProductId, setSelectedProductId] = useState(null); const [isSaving, setIsSaving] = useState(false); const [isExportingBrevo, setIsExportingBrevo] = useState(false); const [brevoUrl, setBrevoUrl] = useState(null); // Modály const [isImportOpen, setIsImportOpen] = useState(false); const [isBadgeEditorOpen, setIsBadgeEditorOpen] = useState(false); const [isSavedCampaignsOpen, setIsSavedCampaignsOpen] = useState(false); const [targetProductIdForBadge, setTargetProductIdForBadge] = useState(null); const [availableBadges, setAvailableBadges] = useState(DEFAULT_BADGE_TEMPLATES); // Načítanie dostupných šablón cenoviek pre opakované použitie useEffect(() => { const fetchBadges = async () => { let loaded: BadgeTemplate[] = []; try { const { data, error } = await supabase .from('badges') .select('*') .order('created_at', { ascending: false }); if (data && !error && data.length > 0) { loaded = data.map((d: any) => { const isObj = d.layers_config && !Array.isArray(d.layers_config); return { id: d.id, name: d.name, svgRaw: d.svg_raw || '', layersConfig: isObj ? (d.layers_config.layers || []) : (d.layers_config || []), width: isObj ? (d.layers_config.width || 110) : 110, align: isObj ? (d.layers_config.align || 'center') : 'center', paddingTop: isObj ? (d.layers_config.paddingTop ?? 4) : 4, paddingBottom: isObj ? (d.layers_config.paddingBottom ?? 4) : 4 }; }); } } catch (e) { console.warn('Error fetching badges in page:', e); } try { const local = localStorage.getItem('coop_custom_badges'); if (local) { const parsed = JSON.parse(local); if (Array.isArray(parsed)) { const existingIds = new Set(loaded.map((b) => b.id)); for (const b of parsed) { if (!existingIds.has(b.id)) { loaded.push(b); existingIds.add(b.id); } } } } } catch (e) {} const all = [...loaded]; const existingIds = new Set(all.map((b) => b.id)); for (const preset of DEFAULT_BADGE_TEMPLATES) { if (!existingIds.has(preset.id)) { all.push(preset); } } setAvailableBadges(all); }; fetchBadges(); }, [isBadgeEditorOpen]); // 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'; const isFlyersModule = (m: NewsletterModule) => m.id === 'mod-flyers-row' || (m.type === 'articles_row' && m.title?.toLowerCase().includes('leták')); const isRecipesModule = (m: NewsletterModule) => m.id === 'mod-recipes-row' || (m.type === 'articles_row' && (m.title?.toLowerCase().includes('recept') || m.title?.toLowerCase().includes('článk'))); const isFooterModule = (m: NewsletterModule) => m.type === 'footer'; const isBottomModule = (m: NewsletterModule) => isFlyersModule(m) || isRecipesModule(m) || isFooterModule(m); const isAnchoredModule = (m: NewsletterModule) => isTopModule(m) || isBottomModule(m); const enforceAnchors = (mods: NewsletterModule[]): NewsletterModule[] => { const topMods = mods.filter((m) => isTopModule(m)); const flyerMods = mods.filter((m) => isFlyersModule(m)); const recipeMods = mods.filter((m) => isRecipesModule(m)); const footerMods = mods.filter((m) => isFooterModule(m)); const middleMods = mods.filter((m) => !isAnchoredModule(m)); // announcement je pred headerom, ak existujú oba topMods.sort((a, b) => { if (a.type === 'announcement' && b.type === 'header') return -1; if (a.type === 'header' && b.type === 'announcement') return 1; return 0; }); return [...topMods, ...middleMods, ...flyerMods, ...recipeMods, ...footerMods]; }; // Auto-save sa spustí až po načítaní kampane z databázy. Inak by sa pri pomalšom načítaní // predvolená kampaň uložila ako nová kópia a ďalšie zmeny by sa ukladali do nej. const [isLoaded, setIsLoaded] = useState(false); // Prebiehajúce vloženie novej kampane – kým nemáme jej id, ďalšie vloženie by vytvorilo duplikát const insertInFlight = useRef(false); // Načítanie existujúceho draftu z databázy pri štarte useEffect(() => { async function loadInitial() { try { const { data } = await supabase .from('templates') .select('*') .order('updated_at', { ascending: false }) .limit(1); if (data && data.length > 0) { const dbItem = data[0]; if (Array.isArray(dbItem.data?.modules) && dbItem.data.modules.length > 0) { setCampaign({ id: dbItem.id, title: dbItem.title, preheader: dbItem.data.preheader || DEFAULT_CAMPAIGN.preheader, status: dbItem.status, brevoCampaignId: dbItem.brevo_campaign_id, modules: enforceAnchors(ensureValidityBar(dbItem.data.modules)) }); if (dbItem.brevo_campaign_id) { setBrevoUrl(getBrevoCampaignUrl(dbItem.brevo_campaign_id)); } } } } catch (err) { console.error('Error loading template from Supabase:', err); } finally { setIsLoaded(true); } } loadInitial(); }, []); // Auto-save s debounce (1 sekunda) useEffect(() => { if (!isLoaded) return; const timer = setTimeout(async () => { if (!campaign.id && insertInFlight.current) return; setIsSaving(true); try { if (!campaign.id) { insertInFlight.current = true; const { data } = await supabase .from('templates') .insert([ { title: campaign.title, status: campaign.status, data: { preheader: campaign.preheader, modules: campaign.modules } } ]) .select(); if (data && data.length > 0) { // id nastavíme len ak medzitým nebola otvorená iná kampaň setCampaign((prev) => (prev.id ? prev : { ...prev, id: data[0].id })); } } else { await supabase .from('templates') .update({ title: campaign.title, data: { preheader: campaign.preheader, modules: campaign.modules }, updated_at: new Date().toISOString() }) .eq('id', campaign.id); } } catch (err) { console.error('Auto-save error:', err); } finally { insertInFlight.current = false; setIsSaving(false); } }, 1000); return () => clearTimeout(timer); }, [isLoaded, campaign.title, campaign.preheader, campaign.modules, campaign.id]); const selectedModule = campaign.modules.find((m) => m.id === selectedModuleId) || null; const handleUpdateModule = (updated: NewsletterModule) => { setCampaign((prev) => ({ ...prev, modules: prev.modules.map((m) => (m.id === updated.id ? updated : m)) })); }; // Posun modulu: Hlavička, letáky, recepty a pätička sú ukotvené a bežné moduly sa nemôžu dostať mimo vyhradený stred const moveModule = (index: number, direction: 'up' | 'down') => { const currentMod = campaign.modules[index]; if (!currentMod || isAnchoredModule(currentMod)) return; const topCount = campaign.modules.filter((m) => isTopModule(m)).length; const firstBottomIndex = campaign.modules.findIndex((m) => isBottomModule(m)); const maxAllowedIndex = firstBottomIndex !== -1 ? firstBottomIndex - 1 : campaign.modules.length - 1; const targetIndex = direction === 'up' ? index - 1 : index + 1; if (targetIndex < topCount || targetIndex > maxAllowedIndex) return; const newModules = [...campaign.modules]; const temp = newModules[index]; newModules[index] = newModules[targetIndex]; newModules[targetIndex] = temp; setCampaign((prev) => ({ ...prev, modules: enforceAnchors(newModules) })); }; // Duplikácia: Ukotvené moduly sa nedajú duplikovať const duplicateModule = (index: number) => { const original = campaign.modules[index]; if (isAnchoredModule(original) || original.type === 'validity_bar') return; const clone: NewsletterModule = { ...original, id: `mod-${Date.now()}`, title: `${original.title} (kópia)`, data: JSON.parse(JSON.stringify(original.data)) }; const newModules = [...campaign.modules]; newModules.splice(index + 1, 0, clone); setCampaign((prev) => ({ ...prev, modules: enforceAnchors(newModules) })); setSelectedModuleId(clone.id); }; // Zmazanie: Ukotvené moduly (hlavička, letáky, články/recepty, pätička) sa nedajú vymazať const deleteModule = (index: number) => { const mod = campaign.modules[index]; if (isAnchoredModule(mod)) { 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); setCampaign((prev) => ({ ...prev, modules: enforceAnchors(newModules) })); setSelectedModuleId(newModules[0]?.id || null); }; // Pridanie modulu: Vloží sa vždy PRED spodné bloky (letáky, recepty a pätičku) const handleAddModule = (type: any) => { let newMod: NewsletterModule; if (type === 'banner') { newMod = { id: `mod-banner-${Date.now()}`, type: 'banner', title: 'Nový Banner', data: { imageUrl: `${SUPABASE_ASSETS_BASE}aktualne_letaky.jpg`, 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: '#', buttonBgColor: '#e2001a' } }; } else { newMod = { id: `mod-products-${Date.now()}`, type: 'products_grid', title: 'Nová sekcia produktov', 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`, title: 'Nový produkt 1', imageUrl: `${SUPABASE_ASSETS_BASE}produkt_5.png`, priceMain: '2', priceSub: '49', unitPrice: '1kg = 9,90 €', discountText: '15%', badgeText: 'zľava', cardBgColor: '#feeaea', stores: { potraviny: true, supermarket: true, tempo: true } } ] } }; } setCampaign((prev) => { const firstBottomIdx = prev.modules.findIndex((m) => isBottomModule(m)); const newModules = [...prev.modules]; if (firstBottomIdx !== -1) { newModules.splice(firstBottomIdx, 0, newMod); } else { newModules.push(newMod); } return { ...prev, modules: enforceAnchors(newModules) }; }); setSelectedModuleId(newMod.id); }; const handleImportProducts = (imported: ProductItem[]) => { if (!selectedModuleId) return; const target = campaign.modules.find((m) => m.id === selectedModuleId); if (!target || target.type !== 'products_grid') { alert('Pre import prosím najskôr označte produktovú sekciu.'); return; } const updated = { ...target, data: { ...target.data, products: [...(target.data.products || []), ...imported] } }; handleUpdateModule(updated); }; // Manuálne uloženie kampane const handleManualSave = async () => { setIsSaving(true); try { if (!campaign.id) { const { data, error } = await supabase .from('templates') .insert([ { title: campaign.title, status: campaign.status, data: { preheader: campaign.preheader, modules: campaign.modules } } ]) .select(); if (error) throw error; if (data && data.length > 0) { setCampaign((prev) => ({ ...prev, id: data[0].id })); } } else { const { error } = await supabase .from('templates') .update({ title: campaign.title, data: { preheader: campaign.preheader, modules: campaign.modules }, updated_at: new Date().toISOString() }) .eq('id', campaign.id); if (error) throw error; } alert('Kampaň bola úspešne uložená do databázy!'); } catch (err: any) { alert(`Chyba pri ukladaní: ${err.message}`); } finally { setIsSaving(false); } }; // Duplikácia aktuálnej kampane v Supabase const handleDuplicateCurrentCampaign = async () => { setIsSaving(true); try { const newTitle = `${campaign.title} (kópia)`; const { data, error } = await supabase .from('templates') .insert([ { title: newTitle, status: 'draft', data: { preheader: campaign.preheader, modules: campaign.modules } } ]) .select(); if (error) throw error; if (data && data.length > 0) { setCampaign({ id: data[0].id, title: newTitle, preheader: campaign.preheader, status: 'draft', modules: campaign.modules }); alert(`Kampaň bola zduplikovaná ako "${newTitle}"!`); } } catch (err: any) { alert(`Chyba pri duplikovaní: ${err.message}`); } finally { setIsSaving(false); } }; // Pred exportom sa vizuály produktových kariet uložia ako obrázky (nezmenené sa nenahrávajú znova) const prepareForExport = async (): Promise => { const { campaign: prepared, failed } = await prepareCardImages(campaign); setCampaign((prev) => ({ ...prev, modules: prepared.modules })); if (failed > 0) { alert(`${failed} kariet produktov sa nepodarilo uložiť ako obrázok – v e-maile budú v jednoduchšej podobe.`); } return prepared; }; const handleExportZip = async () => { const prepared = await prepareForExport(); const rawHtml = renderEmailHtml(prepared); let finalHtml = rawHtml; try { const res = await fetch('/api/inline-css', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ html: rawHtml }) }); const data = await res.json(); if (data.html) finalHtml = data.html; } catch (e) { console.warn('Inliner fallback:', e); } const zip = new JSZip(); zip.file('index.html', finalHtml); const blob = await zip.generateAsync({ type: 'blob' }); saveAs(blob, `coop-newsletter-${new Date().toISOString().split('T')[0]}.zip`); }; const handleExportBrevo = async (updateExisting = false) => { setIsExportingBrevo(true); try { const prepared = await prepareForExport(); const rawHtml = renderEmailHtml(prepared); let finalHtml = rawHtml; try { const res = await fetch('/api/inline-css', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ html: rawHtml }) }); const data = await res.json(); if (data.html) finalHtml = data.html; } catch (e) {} const response = await fetch('/api/brevo/export', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ campaignName: `${campaign.title} - ${new Date().toLocaleDateString('sk-SK')}`, subject: campaign.title, htmlContent: finalHtml, updateExisting: updateExisting, existingCampaignId: campaign.brevoCampaignId }) }); const resData = await response.json(); if (resData.success && resData.campaignId) { setCampaign((prev) => ({ ...prev, brevoCampaignId: resData.campaignId, status: 'exported' })); setBrevoUrl(resData.brevoUrl); if (campaign.id) { await supabase .from('templates') .update({ status: 'exported', brevo_campaign_id: resData.campaignId }) .eq('id', campaign.id); } alert( resData.message || (updateExisting ? 'Kampaň bola v Brevo úspešne aktualizovaná!' : 'Kampaň bola úspešne odoslaná do Brevo!') ); } else { alert(`Chyba pri exporte do Brevo: ${resData.error || 'Neznáma chyba'}`); } } catch (err: any) { alert(`Chyba: ${err.message}`); } finally { setIsExportingBrevo(false); } }; const handleClearBrevoId = async () => { setCampaign((prev) => ({ ...prev, brevoCampaignId: undefined })); setBrevoUrl(null); if (campaign.id) { await supabase .from('templates') .update({ brevo_campaign_id: null }) .eq('id', campaign.id); } }; // Vybraný produkt pre editor cenoviek let targetProduct: any = null; if (targetProductIdForBadge && selectedModule?.data?.products) { targetProduct = selectedModule.data.products.find((p: any) => p.id === targetProductIdForBadge) || null; } const handleApplyBadgeToProduct = (badge: BadgeTemplate, renderedPngUrl?: string) => { if (!targetProductIdForBadge || !selectedModule) return; const updatedProducts = (selectedModule.data.products || []).map((p: any) => { if (p.id === targetProductIdForBadge) { return { ...p, badgeId: badge.id, badgeCustomTemplate: badge, badgeWidth: badge.width ?? p.badgeWidth ?? 110, badgeAlign: badge.align ?? p.badgeAlign ?? 'center', badgePaddingTop: badge.paddingTop ?? p.badgePaddingTop ?? 4, badgePaddingBottom: badge.paddingBottom ?? p.badgePaddingBottom ?? 4, customBadgePngUrl: undefined // Používame živý dynamický SVG vektor, žiadna statická fotka }; } return p; }); handleUpdateModule({ ...selectedModule, data: { ...selectedModule.data, products: updatedProducts } }); setAvailableBadges((prev) => { if (prev.some((b) => b.id === badge.id)) { return prev.map((b) => (b.id === badge.id ? badge : b)); } return [badge, ...prev]; }); }; // Hromadná aplikácia cenovky na všetky produkty v celej kampani (všetky sekcie + vernostné zľavy) const handleApplyBadgeToAll = (badge: BadgeTemplate, badgeLayout?: 'below' | 'side') => { setCampaign((prev) => ({ ...prev, modules: prev.modules.map((m) => { if (m.type === 'products_grid' || m.type === 'loyalty_club') { return { ...m, data: { ...m.data, // Produkty s vlastnou PNG cenovkou (výnimky) sa neprepisujú products: (m.data.products || []).map((prod: any) => prod.customBadgePngUrl ? prod : ({ ...prod, badgeId: badge.id, badgeCustomTemplate: badge, badgeWidth: badge.width ?? prod.badgeWidth ?? 110, badgeAlign: badge.align ?? prod.badgeAlign ?? 'center', badgePaddingTop: badge.paddingTop ?? prod.badgePaddingTop ?? 4, badgePaddingBottom: badge.paddingBottom ?? prod.badgePaddingBottom ?? 4, badgeLayout: badgeLayout ?? prod.badgeLayout })) } }; } return m; }) })); }; // 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 handleUpdateAllProductSections = (patch: Record) => { setCampaign((prev) => ({ ...prev, modules: prev.modules.map((m) => m.type === 'products_grid' || m.type === 'loyalty_club' ? { ...m, data: { ...m.data, ...patch } } : m ) })); }; const topCount = campaign.modules.filter((m) => isTopModule(m)).length; const firstBottomIdx = campaign.modules.findIndex((m) => isBottomModule(m)); return (
{/* 1. Horná lišta */} setCampaign((prev) => ({ ...prev, title }))} onOpenSavedCampaigns={() => setIsSavedCampaignsOpen(true)} onDuplicateCampaign={handleDuplicateCurrentCampaign} onExportZip={handleExportZip} onExportBrevo={handleExportBrevo} isExportingBrevo={isExportingBrevo} brevoCampaignUrl={brevoUrl} brevoListingUrl="https://app.brevo.com/campaigns/listing" onClearBrevoId={handleClearBrevoId} onAddModule={handleAddModule} /> {/* 2. Hlavný pracovný priestor */}
{/* Stredné plátno - Presný originálny gradient a čisté rozloženie */}
{/* Zvýraznenie produktu otvoreného v paneli */} {selectedProductId && ( )} {/* E-mail Container 1:1 k originálu */}
{campaign.modules.map((mod, idx) => { const isSelected = mod.id === selectedModuleId; const isAnchored = isAnchoredModule(mod); const isTop = isTopModule(mod); const isFlyers = isFlyersModule(mod); const isRecipes = isRecipesModule(mod); const isFooter = isFooterModule(mod); const canMoveUp = !isAnchored && idx > topCount; const canMoveDown = !isAnchored && idx < (firstBottomIdx !== -1 ? firstBottomIdx - 1 : campaign.modules.length - 1); return (
{ // Klik na kartu produktu otvorí v paneli práve tento produkt const card = (e.target as HTMLElement).closest('[data-product-id]'); if (card) { setSelectedProductId(card.getAttribute('data-product-id')); } else if (mod.id !== selectedModuleId) { setSelectedProductId(null); } setSelectedModuleId(mod.id); }} className={`relative cursor-pointer transition-all duration-150 rounded-2xl ${ isSelected ? 'ring-2 ring-offset-4 ring-offset-[#001a33] ring-red-500 shadow-2xl' : 'hover:ring-1 hover:ring-offset-2 hover:ring-offset-[#001a33] hover:ring-white/30' }`} > {/* Lišta s nástrojmi pre označený modul */} {isSelected && (
{mod.title} {/* Ak je modul ukotvený (Hlavička / Letáky / Recepty / Pätička / Oznamovacia lišta) */} {isAnchored ? (
{mod.type === 'announcement' && ( )} {isFooter ? 'Ukotvená pätička' : isFlyers ? 'Ukotvené letáky' : isRecipes ? 'Ukotvené recepty' : mod.type === 'announcement' ? 'Oznamovacia lišta' : 'Ukotvená hlavička'}
) : ( <> {mod.type === 'validity_bar' && ( )} {mod.type !== 'validity_bar' && ( <> )} )}
)} {/* Vykreslenie modulu: ak je loyalty_club alebo announcement vypnutý, zobrazíme prívetivý placeholder */} {mod.type === 'loyalty_club' && mod.data.enabled === false ? (

Sekcia Vernostné zľavy (Vypnutá)

Táto sekcia je v odosielanom e-maile skrytá. Kliknutím sem ju môžete aktivovať.

) : mod.type === 'validity_bar' && mod.data.enabled === false ? (

Lišta platnosti akcie (Skrytá)

Táto lišta je v e-maile skrytá. Kliknutím sem ju môžete aktivovať.

) : mod.type === 'announcement' && mod.data.enabled === false ? (

Top oznamovacia lišta (Vypnutá / Skrytá)

Táto lišta je v e-maile skrytá. Kliknutím sem ju môžete aktivovať.

) : (
{ // odkazy v náhľade neotvárame, klik slúži na výber modulu / produktu if ((e.target as HTMLElement).closest('a')) e.preventDefault(); }} className="[&_[data-product-id]]:cursor-pointer" /> )}
); })}
{/* Pravý konfiguračný panel */}
{/* Modál Hromadného importu */} setIsImportOpen(false)} onImportProducts={handleImportProducts} /> {/* Modál Editora cenoviek (SVG -> PNG) */} setIsBadgeEditorOpen(false)} onSelectBadge={handleApplyBadgeToProduct} currentDiscount={targetProduct?.discountText || targetProduct?.cardDiscount || '25%'} currentPriceMain={targetProduct?.priceMain || targetProduct?.cardPriceMain || '1'} currentPriceSub={targetProduct?.priceSub || targetProduct?.cardPriceSub || '99'} currentUnitPrice={targetProduct?.unitPrice || targetProduct?.cardUnitPrice || '1kg = 4,91 €'} currentCardPriceMain={targetProduct?.cardPriceMain || undefined} currentCardPriceSub={targetProduct?.cardPriceSub || undefined} currentCardDiscount={targetProduct?.cardDiscount || undefined} /> {/* Modál Moje newslettre (Ukladanie, duplikácia, vytváranie a prepínanie) */} setIsSavedCampaignsOpen(false)} currentCampaign={campaign} onLoadCampaign={(selected: NewsletterCampaign) => { setCampaign({ ...selected, modules: enforceAnchors(ensureValidityBar(selected.modules)) }); setSelectedModuleId(selected.modules[1]?.id || selected.modules[0]?.id || null); if (selected.brevoCampaignId) { setBrevoUrl(getBrevoCampaignUrl(selected.brevoCampaignId)); } else { setBrevoUrl(null); } }} onSaveCurrentAsCopy={async (newTitle: string) => { const { data, error } = await supabase .from('templates') .insert([ { title: newTitle, status: 'draft', data: { preheader: campaign.preheader, modules: campaign.modules } } ]) .select(); if (error) throw error; if (data && data[0]) { setCampaign({ id: data[0].id, title: newTitle, preheader: campaign.preheader, status: 'draft', modules: campaign.modules }); } }} />
); }