feat: premenne {cena_s_kartou} a {zlava_s_kartou} v cenovkach (uloha 12)
- bezne produkty maju volitelne polia Cena s kartou / Zlava s kartou, vernostne produkty pouzivaju svoje existujuce hodnoty - editor cenoviek: tlacidla na pridanie vrstiev a nahlad premennych - jedinecne ID novych vrstiev (rychle pridanie viacerych vrstiev) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
22a9a51d00
commit
3bd93fde20
6 files changed
+138
-43
No files matched your search
@@ -835,6 +835,9 @@ export default function Home() {
|
|||||||
currentPriceMain={targetProduct?.priceMain || targetProduct?.cardPriceMain || '1'}
|
currentPriceMain={targetProduct?.priceMain || targetProduct?.cardPriceMain || '1'}
|
||||||
currentPriceSub={targetProduct?.priceSub || targetProduct?.cardPriceSub || '99'}
|
currentPriceSub={targetProduct?.priceSub || targetProduct?.cardPriceSub || '99'}
|
||||||
currentUnitPrice={targetProduct?.unitPrice || targetProduct?.cardUnitPrice || '1kg = 4,91 €'}
|
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) */}
|
{/* Modál Moje newslettre (Ukladanie, duplikácia, vytváranie a prepínanie) */}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { BadgeTemplate, BadgeLayer } from '@/types/newsletter';
|
import { BadgeTemplate, BadgeLayer } from '@/types/newsletter';
|
||||||
import { supabase } from '@/lib/supabase';
|
import { supabase } from '@/lib/supabase';
|
||||||
import { DEFAULT_BADGE_TEMPLATES, renderCleanBadgeSvg, svgToCleanPng } from '@/lib/badgeUtils';
|
import { DEFAULT_BADGE_TEMPLATES, renderCleanBadgeSvg, svgToCleanPng, BADGE_PRICE_TOKEN_RE, badgePriceParts, replaceBadgeTextVars } from '@/lib/badgeUtils';
|
||||||
import { Tag, Plus, Check, Trash2, X, Upload, Eye, Move, AlignLeft, AlignCenter, AlignRight, ZoomIn, ZoomOut, Copy } from 'lucide-react';
|
import { Tag, Plus, Check, Trash2, X, Upload, Eye, Move, AlignLeft, AlignCenter, AlignRight, ZoomIn, ZoomOut, Copy } from 'lucide-react';
|
||||||
|
|
||||||
// Riadok tabuľky badges v Supabase pre danú šablónu
|
// Riadok tabuľky badges v Supabase pre danú šablónu
|
||||||
@@ -34,6 +34,9 @@ interface BadgeEditorModalProps {
|
|||||||
currentPriceMain?: string;
|
currentPriceMain?: string;
|
||||||
currentPriceSub?: string;
|
currentPriceSub?: string;
|
||||||
currentUnitPrice?: string;
|
currentUnitPrice?: string;
|
||||||
|
currentCardPriceMain?: string;
|
||||||
|
currentCardPriceSub?: string;
|
||||||
|
currentCardDiscount?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
||||||
@@ -43,7 +46,10 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
currentDiscount = '25%',
|
currentDiscount = '25%',
|
||||||
currentPriceMain = '1',
|
currentPriceMain = '1',
|
||||||
currentPriceSub = '99',
|
currentPriceSub = '99',
|
||||||
currentUnitPrice = '1kg = 4,91 €'
|
currentUnitPrice = '1kg = 4,91 €',
|
||||||
|
currentCardPriceMain = '1',
|
||||||
|
currentCardPriceSub = '49',
|
||||||
|
currentCardDiscount = '30%'
|
||||||
}) => {
|
}) => {
|
||||||
const POPULAR_FONTS = [
|
const POPULAR_FONTS = [
|
||||||
{ name: 'Poppins', source: 'google' as const },
|
{ name: 'Poppins', source: 'google' as const },
|
||||||
@@ -391,7 +397,7 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
const addTextLayer = (presetText: string = 'Text') => {
|
const addTextLayer = (presetText: string = 'Text') => {
|
||||||
if (!activeBadge) return;
|
if (!activeBadge) return;
|
||||||
const newL: BadgeLayer = {
|
const newL: BadgeLayer = {
|
||||||
id: `l-${Date.now()}`,
|
id: `l-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
text: presetText,
|
text: presetText,
|
||||||
x: 70,
|
x: 70,
|
||||||
@@ -538,6 +544,17 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Vykreslenie vrstvy v React náhľade s centami ako horný index (sup) a BEZ znaku €
|
// Vykreslenie vrstvy v React náhľade s centami ako horný index (sup) a BEZ znaku €
|
||||||
|
// Ceny produktu, pre ktorý sa cenovka upravuje (náhľad premenných)
|
||||||
|
const previewProduct = {
|
||||||
|
priceMain: currentPriceMain,
|
||||||
|
priceSub: currentPriceSub,
|
||||||
|
discountText: currentDiscount,
|
||||||
|
unitPrice: currentUnitPrice,
|
||||||
|
cardPriceMain: currentCardPriceMain,
|
||||||
|
cardPriceSub: currentCardPriceSub,
|
||||||
|
cardDiscount: currentCardDiscount
|
||||||
|
};
|
||||||
|
|
||||||
const renderLayerVisualContent = (layer: BadgeLayer) => {
|
const renderLayerVisualContent = (layer: BadgeLayer) => {
|
||||||
const raw = layer.text || '';
|
const raw = layer.text || '';
|
||||||
const baseFontSize = layer.fontSize || 16;
|
const baseFontSize = layer.fontSize || 16;
|
||||||
@@ -545,12 +562,14 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
const subY = layer.indexOffsetY !== undefined ? `${layer.indexOffsetY}px` : '-10px';
|
const subY = layer.indexOffsetY !== undefined ? `${layer.indexOffsetY}px` : '-10px';
|
||||||
const subX = layer.indexOffsetX !== undefined ? `${layer.indexOffsetX}px` : '2px';
|
const subX = layer.indexOffsetX !== undefined ? `${layer.indexOffsetX}px` : '2px';
|
||||||
|
|
||||||
if (raw.includes('{cena}')) {
|
const priceMatch = raw.match(BADGE_PRICE_TOKEN_RE);
|
||||||
const parts = raw.split('{cena}');
|
if (priceMatch) {
|
||||||
|
const [tokMain, tokSub] = badgePriceParts(priceMatch[1], previewProduct);
|
||||||
|
const idx = priceMatch.index || 0;
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{parts[0]}
|
{replaceBadgeTextVars(raw.slice(0, idx), previewProduct)}
|
||||||
<span>{currentPriceMain}</span>
|
<span>{tokMain}</span>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
@@ -560,9 +579,9 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
lineHeight: 1
|
lineHeight: 1
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{currentPriceSub}
|
{tokSub}
|
||||||
</span>
|
</span>
|
||||||
{parts[1]}
|
{replaceBadgeTextVars(raw.slice(idx + priceMatch[0].length), previewProduct)}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -588,13 +607,7 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const replaced = raw
|
return replaceBadgeTextVars(raw, previewProduct);
|
||||||
.replace(/{cela_suma}/g, currentPriceMain)
|
|
||||||
.replace(/{zlava}/g, currentDiscount.replace('-', ''))
|
|
||||||
.replace(/{jednotkova_cena}/g, currentUnitPrice)
|
|
||||||
.replace(/{mena}/g, '€');
|
|
||||||
|
|
||||||
return replaced;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Aplikovanie cenovky na produkt: čisté vektorové SVG a čistý PNG (BEZ akéhokoľvek screenshotu nástrojov/rámčekov)
|
// Aplikovanie cenovky na produkt: čisté vektorové SVG a čistý PNG (BEZ akéhokoľvek screenshotu nástrojov/rámčekov)
|
||||||
@@ -604,12 +617,7 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
try {
|
try {
|
||||||
const cleanSvg = renderCleanBadgeSvg(
|
const cleanSvg = renderCleanBadgeSvg(
|
||||||
activeBadge,
|
activeBadge,
|
||||||
{
|
previewProduct,
|
||||||
priceMain: currentPriceMain,
|
|
||||||
priceSub: currentPriceSub,
|
|
||||||
discountText: currentDiscount,
|
|
||||||
unitPrice: currentUnitPrice
|
|
||||||
},
|
|
||||||
activeBadge.width || 110
|
activeBadge.width || 110
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -709,12 +717,7 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: renderCleanBadgeSvg(
|
__html: renderCleanBadgeSvg(
|
||||||
b,
|
b,
|
||||||
{
|
previewProduct,
|
||||||
priceMain: currentPriceMain,
|
|
||||||
priceSub: currentPriceSub,
|
|
||||||
discountText: currentDiscount,
|
|
||||||
unitPrice: currentUnitPrice
|
|
||||||
},
|
|
||||||
90
|
90
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
@@ -876,6 +879,13 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
<span className="bg-slate-800 px-2 py-0.5 rounded font-mono text-emerald-300">
|
<span className="bg-slate-800 px-2 py-0.5 rounded font-mono text-emerald-300">
|
||||||
{'{zlava}'} → {currentDiscount.replace('-', '')}
|
{'{zlava}'} → {currentDiscount.replace('-', '')}
|
||||||
</span>
|
</span>
|
||||||
|
<span className="bg-slate-800 px-2 py-0.5 rounded font-mono text-amber-300">
|
||||||
|
{'{cena_s_kartou}'} → {currentCardPriceMain}
|
||||||
|
<sup>{currentCardPriceSub}</sup>
|
||||||
|
</span>
|
||||||
|
<span className="bg-slate-800 px-2 py-0.5 rounded font-mono text-emerald-300">
|
||||||
|
{'{zlava_s_kartou}'} → {currentCardDiscount.replace('-', '')}
|
||||||
|
</span>
|
||||||
<span className="bg-slate-800 px-2 py-0.5 rounded font-mono text-blue-300">
|
<span className="bg-slate-800 px-2 py-0.5 rounded font-mono text-blue-300">
|
||||||
{'{mena}'} → €
|
{'{mena}'} → €
|
||||||
</span>
|
</span>
|
||||||
@@ -1032,6 +1042,18 @@ export const BadgeEditorModal: React.FC<BadgeEditorModalProps> = ({
|
|||||||
>
|
>
|
||||||
+ Zľava %
|
+ Zľava %
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => addTextLayer('{cena_s_kartou}')}
|
||||||
|
className="text-[11px] font-bold bg-amber-50 text-amber-800 border border-amber-200 hover:bg-amber-100 px-2 py-1 rounded-lg"
|
||||||
|
>
|
||||||
|
+ Cena s kartou
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => addTextLayer('-{zlava_s_kartou}')}
|
||||||
|
className="text-[11px] font-bold bg-red-50 text-red-800 border border-red-200 hover:bg-red-100 px-2 py-1 rounded-lg"
|
||||||
|
>
|
||||||
|
+ Zľava s kartou
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => addTextLayer('€')}
|
onClick={() => addTextLayer('€')}
|
||||||
className="text-[11px] font-bold bg-blue-50 text-blue-800 border border-blue-200 hover:bg-blue-100 px-2 py-1 rounded-lg"
|
className="text-[11px] font-bold bg-blue-50 text-blue-800 border border-blue-200 hover:bg-blue-100 px-2 py-1 rounded-lg"
|
||||||
|
|||||||
@@ -656,6 +656,52 @@ export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Cena s kartou (voliteľné) – premenné {cena_s_kartou} a {zlava_s_kartou} v cenovke */}
|
||||||
|
<div className="grid grid-cols-3 gap-2 p-2 rounded-lg bg-amber-50/60 border border-amber-100">
|
||||||
|
<div>
|
||||||
|
<label className="text-[10px] text-gray-500">S kartou (€)</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={p.cardPriceMain || ''}
|
||||||
|
onChange={(e) => {
|
||||||
|
const products = [...module.data.products];
|
||||||
|
products[pIdx].cardPriceMain = e.target.value;
|
||||||
|
updateData({ products });
|
||||||
|
}}
|
||||||
|
placeholder="—"
|
||||||
|
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-[10px] text-gray-500">Centy</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={p.cardPriceSub || ''}
|
||||||
|
onChange={(e) => {
|
||||||
|
const products = [...module.data.products];
|
||||||
|
products[pIdx].cardPriceSub = e.target.value;
|
||||||
|
updateData({ products });
|
||||||
|
}}
|
||||||
|
placeholder="—"
|
||||||
|
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-[10px] text-gray-500">Zľava s kartou</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={p.cardDiscount || ''}
|
||||||
|
onChange={(e) => {
|
||||||
|
const products = [...module.data.products];
|
||||||
|
products[pIdx].cardDiscount = e.target.value;
|
||||||
|
updateData({ products });
|
||||||
|
}}
|
||||||
|
placeholder="—"
|
||||||
|
className="w-full text-xs border border-gray-300 rounded p-1 bg-white"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Predajne */}
|
{/* Predajne */}
|
||||||
<div>
|
<div>
|
||||||
<label className="text-[10px] text-gray-500 block mb-1">Dostupnosť (Piktogramy)</label>
|
<label className="text-[10px] text-gray-500 block mb-1">Dostupnosť (Piktogramy)</label>
|
||||||
|
|||||||
+32
-14
@@ -8,6 +8,30 @@ export interface BadgeProductData {
|
|||||||
priceSub: string;
|
priceSub: string;
|
||||||
discountText?: string;
|
discountText?: string;
|
||||||
unitPrice?: string;
|
unitPrice?: string;
|
||||||
|
cardPriceMain?: string; // cena s kartou → {cena_s_kartou}
|
||||||
|
cardPriceSub?: string;
|
||||||
|
cardDiscount?: string; // zľava s kartou → {zlava_s_kartou}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Premenné ceny s centami v hornom indexe: {cena} a {cena_s_kartou}
|
||||||
|
export const BADGE_PRICE_TOKEN_RE = /\{(cena|cena_s_kartou)\}/;
|
||||||
|
|
||||||
|
// Nahradenie jednoduchých textových premenných (bez horného indexu)
|
||||||
|
export function replaceBadgeTextVars(text: string, product: BadgeProductData): string {
|
||||||
|
return text
|
||||||
|
.replace(/{cela_suma}/g, product.priceMain || '0')
|
||||||
|
.replace(/{zlava_s_kartou}/g, (product.cardDiscount || '').replace('-', ''))
|
||||||
|
.replace(/{zlava}/g, (product.discountText || '').replace('-', ''))
|
||||||
|
.replace(/{jednotkova_cena}/g, product.unitPrice || '')
|
||||||
|
.replace(/{mena}/g, '€');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Celé eurá a centy pre danú cenovú premennú
|
||||||
|
export function badgePriceParts(token: string, product: BadgeProductData): [string, string] {
|
||||||
|
if (token === 'cena_s_kartou') {
|
||||||
|
return [product.cardPriceMain || '', product.cardPriceSub || ''];
|
||||||
|
}
|
||||||
|
return [product.priceMain || '0', product.priceSub || '00'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,10 +45,7 @@ export function renderCleanBadgeSvg(
|
|||||||
product: BadgeProductData,
|
product: BadgeProductData,
|
||||||
overrideWidth?: number
|
overrideWidth?: number
|
||||||
): string {
|
): string {
|
||||||
const pMain = product.priceMain || '0';
|
|
||||||
const pSub = product.priceSub || '00';
|
const pSub = product.priceSub || '00';
|
||||||
const discount = (product.discountText || '').replace('-', '');
|
|
||||||
const unitPrice = product.unitPrice || '';
|
|
||||||
|
|
||||||
// Získanie viewBox alebo predvolených rozmerov
|
// Získanie viewBox alebo predvolených rozmerov
|
||||||
let vb = '0 0 140 95';
|
let vb = '0 0 140 95';
|
||||||
@@ -88,23 +109,20 @@ export function renderCleanBadgeSvg(
|
|||||||
|
|
||||||
// Formátovanie textu: ak obsahuje {cena} alebo {centy}, centy vložíme do <tspan> ako horný index
|
// Formátovanie textu: ak obsahuje {cena} alebo {centy}, centy vložíme do <tspan> ako horný index
|
||||||
let contentSvg = '';
|
let contentSvg = '';
|
||||||
if (rawText.includes('{cena}')) {
|
const priceMatch = rawText.match(BADGE_PRICE_TOKEN_RE);
|
||||||
const parts = rawText.split('{cena}');
|
if (priceMatch) {
|
||||||
const before = escapeXml(parts[0] || '');
|
const [tokMain, tokSub] = badgePriceParts(priceMatch[1], product);
|
||||||
const after = escapeXml(parts[1] || '');
|
const idx = priceMatch.index || 0;
|
||||||
contentSvg = `${before}${escapeXml(pMain)}<tspan font-size="${subFontSize}px" dx="${subDx}" dy="${subDy}" font-weight="${fontWeight}">${escapeXml(pSub)}</tspan>${after ? `<tspan dy="${revertDy}">${after}</tspan>` : ''}`;
|
const before = escapeXml(replaceBadgeTextVars(rawText.slice(0, idx), product));
|
||||||
|
const after = escapeXml(replaceBadgeTextVars(rawText.slice(idx + priceMatch[0].length), product));
|
||||||
|
contentSvg = `${before}${escapeXml(tokMain)}<tspan font-size="${subFontSize}px" dx="${subDx}" dy="${subDy}" font-weight="${fontWeight}">${escapeXml(tokSub)}</tspan>${after ? `<tspan dy="${revertDy}">${after}</tspan>` : ''}`;
|
||||||
} else if (rawText.includes('{centy}')) {
|
} else if (rawText.includes('{centy}')) {
|
||||||
const parts = rawText.split('{centy}');
|
const parts = rawText.split('{centy}');
|
||||||
const before = escapeXml(parts[0] || '');
|
const before = escapeXml(parts[0] || '');
|
||||||
const after = escapeXml(parts[1] || '');
|
const after = escapeXml(parts[1] || '');
|
||||||
contentSvg = `${before}<tspan font-size="${subFontSize}px" dx="${subDx}" dy="${subDy}" font-weight="${fontWeight}">${escapeXml(pSub)}</tspan>${after ? `<tspan dy="${revertDy}">${after}</tspan>` : ''}`;
|
contentSvg = `${before}<tspan font-size="${subFontSize}px" dx="${subDx}" dy="${subDy}" font-weight="${fontWeight}">${escapeXml(pSub)}</tspan>${after ? `<tspan dy="${revertDy}">${after}</tspan>` : ''}`;
|
||||||
} else {
|
} else {
|
||||||
let replaced = rawText
|
contentSvg = escapeXml(replaceBadgeTextVars(rawText, product));
|
||||||
.replace(/{cela_suma}/g, pMain)
|
|
||||||
.replace(/{zlava}/g, discount)
|
|
||||||
.replace(/{jednotkova_cena}/g, unitPrice)
|
|
||||||
.replace(/{mena}/g, '€');
|
|
||||||
contentSvg = escapeXml(replaced);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return `<text x="${layer.x}" y="${layer.y}" text-anchor="${anchor}" dominant-baseline="central" font-family="${fontFamily}" font-size="${fontSize}px" font-weight="${fontWeight}" fill="${fill}">${contentSvg}</text>`;
|
return `<text x="${layer.x}" y="${layer.y}" text-anchor="${anchor}" dominant-baseline="central" font-family="${fontFamily}" font-size="${fontSize}px" font-weight="${fontWeight}" fill="${fill}">${contentSvg}</text>`;
|
||||||
|
|||||||
@@ -830,7 +830,10 @@ function renderExactLoyaltyCard(p: any, validity: string): string {
|
|||||||
priceMain: p.cardPriceMain || p.priceMain || '0',
|
priceMain: p.cardPriceMain || p.priceMain || '0',
|
||||||
priceSub: p.cardPriceSub || p.priceSub || '00',
|
priceSub: p.cardPriceSub || p.priceSub || '00',
|
||||||
discountText: p.cardDiscount || p.discountText || '',
|
discountText: p.cardDiscount || p.discountText || '',
|
||||||
unitPrice: p.cardUnitPrice || p.unitPrice || ''
|
unitPrice: p.cardUnitPrice || p.unitPrice || '',
|
||||||
|
cardPriceMain: p.cardPriceMain,
|
||||||
|
cardPriceSub: p.cardPriceSub,
|
||||||
|
cardDiscount: p.cardDiscount
|
||||||
};
|
};
|
||||||
|
|
||||||
return `
|
return `
|
||||||
|
|||||||
@@ -24,6 +24,9 @@ export interface ProductItem {
|
|||||||
priceSub: string; // napr. "99" alebo "89"
|
priceSub: string; // napr. "99" alebo "89"
|
||||||
unitPrice: string; // napr. "1kg = 4,91 €"
|
unitPrice: string; // napr. "1kg = 4,91 €"
|
||||||
discountText: string; // napr. "-23%" alebo "23%"
|
discountText: string; // napr. "-23%" alebo "23%"
|
||||||
|
cardPriceMain?: string; // cena s kartou (vernostná), celé eurá
|
||||||
|
cardPriceSub?: string; // cena s kartou, centy
|
||||||
|
cardDiscount?: string; // zľava s kartou, napr. "30%"
|
||||||
badgeText: string; // napr. "AKCIA" alebo "SUPER CENA"
|
badgeText: string; // napr. "AKCIA" alebo "SUPER CENA"
|
||||||
badgeId?: string; // priradená cenovka z databázy
|
badgeId?: string; // priradená cenovka z databázy
|
||||||
badgeCustomTemplate?: BadgeTemplate; // Uložená dynamická šablóna cenovky (bez fixnej ceny)
|
badgeCustomTemplate?: BadgeTemplate; // Uložená dynamická šablóna cenovky (bez fixnej ceny)
|
||||||
|
|||||||
Reference in new issue
Block a user