feat: reusable badge templates, dynamic price and superscript cents, size/align/padding controls, fix saving
This commit is contained in:
1 parent
f9aa2297ba
commit
5a6788b593
6 files changed
+1196
-359
No files matched your search
+73
-1
@@ -5,6 +5,7 @@ import { NewsletterCampaign, NewsletterModule, ProductItem, BadgeTemplate } from
|
||||
import { DEFAULT_CAMPAIGN, SUPABASE_ASSETS_BASE } from '@/lib/defaultCampaign';
|
||||
import { renderEmailHtml, renderSingleModuleHtml } from '@/lib/emailRenderer';
|
||||
import { supabase } from '@/lib/supabase';
|
||||
import { DEFAULT_BADGE_TEMPLATES } from '@/lib/badgeUtils';
|
||||
import { TopBar } from '@/components/editor/TopBar';
|
||||
import { ConfigPanel } from '@/components/editor/ConfigPanel';
|
||||
import { ProductImportModal } from '@/components/editor/ProductImportModal';
|
||||
@@ -26,6 +27,64 @@ export default function Home() {
|
||||
const [isBadgeEditorOpen, setIsBadgeEditorOpen] = useState(false);
|
||||
const [isSavedCampaignsOpen, setIsSavedCampaignsOpen] = useState(false);
|
||||
const [targetProductIdForBadge, setTargetProductIdForBadge] = useState<string | null>(null);
|
||||
const [availableBadges, setAvailableBadges] = useState<BadgeTemplate[]>(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';
|
||||
@@ -475,7 +534,12 @@ export default function Home() {
|
||||
return {
|
||||
...p,
|
||||
badgeId: badge.id,
|
||||
customBadgePngUrl: renderedPngUrl || p.customBadgePngUrl
|
||||
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;
|
||||
@@ -488,6 +552,13 @@ export default function Home() {
|
||||
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];
|
||||
});
|
||||
};
|
||||
|
||||
const topCount = campaign.modules.filter((m) => isTopModule(m)).length;
|
||||
@@ -651,6 +722,7 @@ export default function Home() {
|
||||
<ConfigPanel
|
||||
module={selectedModule}
|
||||
onUpdateModule={handleUpdateModule}
|
||||
availableBadges={availableBadges}
|
||||
onOpenBadgeManager={(pId) => {
|
||||
setTargetProductIdForBadge(pId);
|
||||
setIsBadgeEditorOpen(true);
|
||||
|
||||
Reference in new issue
Block a user