diff --git a/src/app/page.tsx b/src/app/page.tsx index f351710..4ab5d1c 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1023,6 +1023,8 @@ export default function Home() { currentCardPriceMain={targetProduct?.cardPriceMain || undefined} currentCardPriceSub={targetProduct?.cardPriceSub || undefined} currentCardDiscount={targetProduct?.cardDiscount || undefined} + currentAppPriceMain={targetProduct?.appPriceMain || undefined} + currentAppPriceSub={targetProduct?.appPriceSub || undefined} /> {/* Modál Moje newslettre (Ukladanie, duplikácia, vytváranie a prepínanie) */} diff --git a/src/components/editor/BadgeEditorModal.tsx b/src/components/editor/BadgeEditorModal.tsx index e8921b0..47f434c 100644 --- a/src/components/editor/BadgeEditorModal.tsx +++ b/src/components/editor/BadgeEditorModal.tsx @@ -108,6 +108,7 @@ const TOKENS: Array<{ token: string; label: string }> = [ { token: '{zlava}', label: 'Zľava' }, { token: '{cena_s_kartou}', label: 'Cena s kartou' }, { token: '{zlava_s_kartou}', label: 'Zľava s kartou' }, + { token: '{cena_app}', label: 'Cena v appke' }, { token: '{jednotkova_cena}', label: 'Jedn. cena' }, { token: '{mena}', label: '€' } ]; @@ -118,6 +119,7 @@ const QUICK_LAYERS: Array<{ label: string; text: string; fontSize: number }> = [ { label: 'Zľava', text: '-{zlava}', fontSize: 14 }, { label: 'Cena s kartou', text: '{cena_s_kartou}', fontSize: 40 }, { label: 'Zľava s kartou', text: '-{zlava_s_kartou}', fontSize: 14 }, + { label: 'Cena v appke', text: '{cena_app}', fontSize: 40 }, { label: 'Text', text: 'AKCIA', fontSize: 16 } ]; @@ -174,9 +176,14 @@ const ImportTagsEditor: React.FC<{ tags: BadgeImportTags; onChange: (tags: Badge + Appka +
- Pri importe ZIP-u sa šablóna priradí produktom podľa stĺpcov Zľava grafická (prázdna = základná, s výkričníkom podľa stĺpca Výkričník), Farba cenovky a Pôvod. + Pri importe ZIP-u sa šablóna priradí produktom podľa stĺpcov Zľava grafická (prázdna = základná, s výkričníkom podľa stĺpca Výkričník), Farba cenovky a Pôvod. Cenovka pre appkáčov sa dá produktom, ktoré majú vyplnenú Cenu pre appkáčov.
); @@ -270,6 +277,8 @@ interface BadgeEditorModalProps { currentCardPriceMain?: string; currentCardPriceSub?: string; currentCardDiscount?: string; + currentAppPriceMain?: string; + currentAppPriceSub?: string; } interface DragState { @@ -290,7 +299,9 @@ export const BadgeEditorModal: React.FC+ štítok na fotke: {p.extras.join(' · ')} +
+ )}
- {p.badge && p.badgeMatch === 'origin' ? (
+ {p.badge && p.badgeMissing.length ? (
- cenovka: {p.badge.name} – šablóna „{p.badgeLabel}“ so SK chýba, použije sa variant bez pôvodu
+ cenovka: {p.badge.name} – chýba {p.badgeMissing.join(' a ')} pre „{p.badgeLabel}“
) : p.badge ? (
cenovka: {p.badge.name}
diff --git a/src/lib/badgeUtils.ts b/src/lib/badgeUtils.ts
index 28602c5..10a2310 100644
--- a/src/lib/badgeUtils.ts
+++ b/src/lib/badgeUtils.ts
@@ -69,10 +69,12 @@ export interface BadgeProductData {
cardPriceMain?: string; // cena s kartou → {cena_s_kartou}
cardPriceSub?: string;
cardDiscount?: string; // zľava s kartou → {zlava_s_kartou}
+ appPriceMain?: string; // cena pre appkáčov → {cena_app}
+ appPriceSub?: string;
}
-// Premenné ceny s centami v hornom indexe: {cena} a {cena_s_kartou}
-export const BADGE_PRICE_TOKEN_RE = /\{(cena|cena_s_kartou)\}/;
+// Premenné ceny s centami v hornom indexe: {cena}, {cena_s_kartou} a {cena_app}
+export const BADGE_PRICE_TOKEN_RE = /\{(cena|cena_s_kartou|cena_app)\}/;
// Nahradenie jednoduchých textových premenných (bez horného indexu)
export function replaceBadgeTextVars(text: string, product: BadgeProductData): string {
@@ -89,6 +91,9 @@ export function badgePriceParts(token: string, product: BadgeProductData): [stri
if (token === 'cena_s_kartou') {
return [product.cardPriceMain || '', product.cardPriceSub || ''];
}
+ if (token === 'cena_app') {
+ return [product.appPriceMain || '', product.appPriceSub || ''];
+ }
return [product.priceMain || '0', product.priceSub || '00'];
}
diff --git a/src/lib/podkladyZip.ts b/src/lib/podkladyZip.ts
index a6d9faf..5cdd218 100644
--- a/src/lib/podkladyZip.ts
+++ b/src/lib/podkladyZip.ts
@@ -1,7 +1,7 @@
// Import ZIP-u s podkladmi z Databázy produktov: tabuľka podklady_*.xlsx (jeden riadok = jeden produkt)
// a fotky v priečinkoch
${words.slice(best).join(' ')}`;
+ }
+ return { id: `lbl-${Date.now()}-${idx}`, text: label, x: 28, y: 14 + idx * 14, size: 11, bg: '#e2001a', color: '#ffffff', rotate: 0 };
}
// ---------- jednoduché čítanie .xlsx (prvý hárok) ----------
@@ -136,6 +165,8 @@ export async function readPodkladyZip(file: File, badges: BadgeTemplate[]): Prom
titleAlt: col('Názov produktu'),
price: col('Akciová cena (leták)', 'Cena (xlsx podklady)'),
cardPrice: col('Cena s vernostnou kartou'),
+ appPrice: col('Cena pre appkáčov'),
+ extras: col('Doplnkové grafiky'),
unitPrice: col('Jednotková cena'),
discount: col('Zľava %'),
badge: col('Zľava grafická'),
@@ -166,7 +197,8 @@ export async function readPodkladyZip(file: File, badges: BadgeTemplate[]): Prom
// prázdna „Zľava grafická“ = základná cenovka (s výkričníkom podľa stĺpca Výkričník)
const type = graphic || (norm(get(row, c.exclaim)) === 'ano' ? 'ZÁKLADNÁ !' : 'ZÁKLADNÁ');
const tries = [[graphic, colorText, origin], [graphic, colorText], [graphic]].map((parts) => parts.filter(Boolean).join(' | '));
- const byTags = findBadgeByTags(badges, type, color, origin);
+ const appPrice = toNumber(get(row, c.appPrice));
+ const byTags = findBadgeByTags(badges, type, color, origin, appPrice != null);
const byName = !byTags && graphic ? tries.map((t) => findBadgeByCode(badges, t)).find(Boolean) : undefined;
const formats = norm(get(row, c.formats));
@@ -178,16 +210,23 @@ export async function readPodkladyZip(file: File, badges: BadgeTemplate[]): Prom
title: get(row, c.title) || get(row, c.titleAlt) || ean,
price: toNumber(get(row, c.price)),
cardPrice: toNumber(get(row, c.cardPrice)),
+ appPrice,
unitPrice: formatUnitPrice(get(row, c.unitPrice)),
discount: discount ? `${Math.round(discount)}%` : '',
- badgeLabel: [BADGE_IMPORT_TYPES.find((t) => t.value === type)?.label || type, colorText, origin].filter(Boolean).join(' | '),
+ badgeLabel: [BADGE_IMPORT_TYPES.find((t) => t.value === type)?.label || type, colorText, origin, appPrice != null ? 'appka' : '']
+ .filter(Boolean)
+ .join(' | '),
badge: byTags?.badge || byName,
- badgeMatch: byTags ? byTags.match : byName ? 'exact' : undefined,
+ badgeMissing: byTags?.missing || [],
color,
stores: formats
? { potraviny: formats.includes('potraviny'), supermarket: formats.includes('supermarket'), tempo: formats.includes('tempo') }
: { potraviny: true, supermarket: true, tempo: true },
deposit: deposit ? formatEur(deposit) : '',
+ extras: get(row, c.extras)
+ .split(/[;\n]/)
+ .map((s) => s.trim())
+ .filter(Boolean),
photo: photoFile ? await photoFile.async('blob') : undefined,
photoName: photoFile ? photoFile.name.split('/').pop()! : ''
});
@@ -199,6 +238,7 @@ export async function readPodkladyZip(file: File, badges: BadgeTemplate[]): Prom
export function podkladyToProductItem(p: PodkladyProduct, imageUrl: string, idx: number): ProductItem {
const price = splitPrice(p.price ?? 0);
const card = p.cardPrice != null ? splitPrice(p.cardPrice) : null;
+ const app = p.appPrice != null ? splitPrice(p.appPrice) : null;
return {
...(p.badge ? { badgeCustomTemplate: p.badge, badgeId: p.badge.id } : {}),
id: `zip-${Date.now()}-${idx}`,
@@ -209,6 +249,8 @@ export function podkladyToProductItem(p: PodkladyProduct, imageUrl: string, idx:
unitPrice: p.unitPrice,
discountText: p.discount,
...(card ? { cardPriceMain: card.main, cardPriceSub: card.sub } : {}),
+ ...(app ? { appPriceMain: app.main, appPriceSub: app.sub } : {}),
+ ...(p.extras.length ? { labels: p.extras.map(extraLabel) } : {}),
note: p.deposit ? `+ záloha ${p.deposit} €` : '',
badgeText: 'zľava',
stores: p.stores,
diff --git a/src/lib/productCard.ts b/src/lib/productCard.ts
index ad3d3e7..d53ea65 100644
--- a/src/lib/productCard.ts
+++ b/src/lib/productCard.ts
@@ -205,7 +205,7 @@ export function cardVisualKey(p: CardProduct, ctx: CardContext): string {
p.customBadgePngUrl, badgeWidthFor(p, ctx.variant),
t ? [t.svgRaw, t.layersConfig, t.width] : null,
p.priceMain, p.priceSub, p.discountText, p.badgeText, p.unitPrice,
- p.cardPriceMain, p.cardPriceSub, p.cardDiscount, p.cardUnitPrice,
+ p.cardPriceMain, p.cardPriceSub, p.cardDiscount, p.cardUnitPrice, p.appPriceMain, p.appPriceSub,
p.noCardPriceMain, p.noCardPriceSub, p.noCardDiscount, p.noCardUnitPrice,
p.stores, p.storesOffsetX ?? DEFAULT_STORES_OFFSET_X, p.storesOffsetY ?? DEFAULT_STORES_OFFSET_Y, p.storesSize ?? DEFAULT_STORES_SIZE,
p.labels || [], p.extraPhotos || [], photoStack(p)
@@ -339,6 +339,9 @@ function renderVisualPreview(p: CardProduct, ctx: CardContext, key: string): str