feat: zakladne cenovky (s vykricnikom a bez) v tagoch sablon pre import
Prazdna Zlava graficka v podkladoch = zakladna cenovka; stlpec Vykricnik rozlisi variant s vykricnikom. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
08fb233da0
commit
11392722e2
3 files changed
+23
-14
No files matched your search
@@ -5,7 +5,7 @@
|
|||||||
// v súradniciach viewBoxu. Klávesnica: šípky posun (Shift = viac), Delete zmaže vrstvu, Ctrl+Z / Ctrl+Y späť / znova,
|
// v súradniciach viewBoxu. Klávesnica: šípky posun (Shift = viac), Delete zmaže vrstvu, Ctrl+Z / Ctrl+Y späť / znova,
|
||||||
// Ctrl+S uloží.
|
// Ctrl+S uloží.
|
||||||
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { BadgeTemplate, BadgeLayer, BadgeImportTags, BadgeColor } from '@/types/newsletter';
|
import { BadgeTemplate, BadgeLayer, BadgeImportTags, BadgeColor, BADGE_IMPORT_TYPES } from '@/types/newsletter';
|
||||||
import { supabase } from '@/lib/supabase';
|
import { supabase } from '@/lib/supabase';
|
||||||
import { renderCleanBadgeSvg, BadgeProductData, BadgeRow, badgeFromRow, badgeCode } from '@/lib/badgeUtils';
|
import { renderCleanBadgeSvg, BadgeProductData, BadgeRow, badgeFromRow, badgeCode } from '@/lib/badgeUtils';
|
||||||
import {
|
import {
|
||||||
@@ -149,7 +149,6 @@ function loadFont(layer: BadgeLayer) {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
// Tagy šablóny pre import podkladov: ktorým riadkom tabuľky (Zľava grafická + Farba cenovky + Pôvod) patrí
|
// Tagy šablóny pre import podkladov: ktorým riadkom tabuľky (Zľava grafická + Farba cenovky + Pôvod) patrí
|
||||||
const BADGE_TYPES = ['SUPER CENA', 'SUPER VÝHODNÉ'];
|
|
||||||
const ImportTagsEditor: React.FC<{ tags: BadgeImportTags; onChange: (tags: BadgeImportTags) => void }> = ({ tags, onChange }) => {
|
const ImportTagsEditor: React.FC<{ tags: BadgeImportTags; onChange: (tags: BadgeImportTags) => void }> = ({ tags, onChange }) => {
|
||||||
const cls = 'w-full text-[11px] border border-gray-300 rounded-lg px-2 py-1.5 bg-white';
|
const cls = 'w-full text-[11px] border border-gray-300 rounded-lg px-2 py-1.5 bg-white';
|
||||||
return (
|
return (
|
||||||
@@ -158,10 +157,10 @@ const ImportTagsEditor: React.FC<{ tags: BadgeImportTags; onChange: (tags: Badge
|
|||||||
<span className="text-[10px] font-semibold text-gray-600">Typ</span>
|
<span className="text-[10px] font-semibold text-gray-600">Typ</span>
|
||||||
<select value={tags.type || ''} onChange={(e) => onChange({ ...tags, type: e.target.value || undefined })} className={cls}>
|
<select value={tags.type || ''} onChange={(e) => onChange({ ...tags, type: e.target.value || undefined })} className={cls}>
|
||||||
<option value="">— nepoužiť pri importe —</option>
|
<option value="">— nepoužiť pri importe —</option>
|
||||||
{BADGE_TYPES.map((t) => (
|
{BADGE_IMPORT_TYPES.map((t) => (
|
||||||
<option key={t} value={t}>{t}</option>
|
<option key={t.value} value={t.value}>{t.label}</option>
|
||||||
))}
|
))}
|
||||||
{tags.type && !BADGE_TYPES.includes(tags.type) && <option value={tags.type}>{tags.type}</option>}
|
{tags.type && !BADGE_IMPORT_TYPES.some((t) => t.value === tags.type) && <option value={tags.type}>{tags.type}</option>}
|
||||||
</select>
|
</select>
|
||||||
<span className="text-[10px] font-semibold text-gray-600">Farba</span>
|
<span className="text-[10px] font-semibold text-gray-600">Farba</span>
|
||||||
<select value={tags.color || ''} onChange={(e) => onChange({ ...tags, color: (e.target.value || undefined) as BadgeColor | undefined })} className={cls}>
|
<select value={tags.color || ''} onChange={(e) => onChange({ ...tags, color: (e.target.value || undefined) as BadgeColor | undefined })} className={cls}>
|
||||||
@@ -177,7 +176,7 @@ const ImportTagsEditor: React.FC<{ tags: BadgeImportTags; onChange: (tags: Badge
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[10px] text-gray-400 leading-snug">
|
<p className="text-[10px] text-gray-400 leading-snug">
|
||||||
Pri importe ZIP-u sa šablóna priradí produktom so stĺpcami Zľava grafická, Farba cenovky a Pôvod podľa týchto tagov.
|
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.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Import ZIP-u s podkladmi z Databázy produktov: tabuľka podklady_*.xlsx (jeden riadok = jeden produkt)
|
// Import ZIP-u s podkladmi z Databázy produktov: tabuľka podklady_*.xlsx (jeden riadok = jeden produkt)
|
||||||
// a fotky v priečinkoch <EAN>/web/*.png.
|
// a fotky v priečinkoch <EAN>/web/*.png.
|
||||||
import JSZip from 'jszip';
|
import JSZip from 'jszip';
|
||||||
import { BadgeColor, BadgeTemplate, ProductItem } from '@/types/newsletter';
|
import { BADGE_IMPORT_TYPES, BadgeColor, BadgeTemplate, ProductItem } from '@/types/newsletter';
|
||||||
import { findBadgeByCode } from './badgeUtils';
|
import { findBadgeByCode } from './badgeUtils';
|
||||||
import { CARD_BG_BY_BADGE_COLOR } from './productCard';
|
import { CARD_BG_BY_BADGE_COLOR } from './productCard';
|
||||||
|
|
||||||
@@ -43,14 +43,13 @@ function toBadgeColor(value: string): BadgeColor | undefined {
|
|||||||
// opačne nie – zahraničný produkt nesmie dostať cenovku so slovenskou vlajkou.
|
// opačne nie – zahraničný produkt nesmie dostať cenovku so slovenskou vlajkou.
|
||||||
function findBadgeByTags(
|
function findBadgeByTags(
|
||||||
badges: BadgeTemplate[],
|
badges: BadgeTemplate[],
|
||||||
graphic: string,
|
type: string,
|
||||||
color: BadgeColor | undefined,
|
color: BadgeColor | undefined,
|
||||||
origin: string
|
origin: string
|
||||||
): { badge: BadgeTemplate; match: 'exact' | 'origin' } | undefined {
|
): { badge: BadgeTemplate; match: 'exact' | 'origin' } | undefined {
|
||||||
if (!graphic) return undefined;
|
|
||||||
const sk = norm(origin) === 'sk' ? 'SK' : '';
|
const sk = norm(origin) === 'sk' ? 'SK' : '';
|
||||||
const candidates = badges.filter(
|
const candidates = badges.filter(
|
||||||
(b) => b.importTags?.type && norm(b.importTags.type) === norm(graphic) && (!b.importTags.color || b.importTags.color === color)
|
(b) => b.importTags?.type && norm(b.importTags.type) === norm(type) && (!b.importTags.color || b.importTags.color === color)
|
||||||
);
|
);
|
||||||
// presná farba má prednosť pred „hocijakou“
|
// presná farba má prednosť pred „hocijakou“
|
||||||
const rank = (b: BadgeTemplate) => (b.importTags?.color ? 0 : 1);
|
const rank = (b: BadgeTemplate) => (b.importTags?.color ? 0 : 1);
|
||||||
@@ -143,7 +142,8 @@ export async function readPodkladyZip(file: File, badges: BadgeTemplate[]): Prom
|
|||||||
color: col('Farba cenovky'),
|
color: col('Farba cenovky'),
|
||||||
origin: col('Pôvod'),
|
origin: col('Pôvod'),
|
||||||
formats: col('Formát'),
|
formats: col('Formát'),
|
||||||
deposit: col('Zálohovanie')
|
deposit: col('Zálohovanie'),
|
||||||
|
exclaim: col('Výkričník')
|
||||||
};
|
};
|
||||||
if (c.ean < 0) throw new Error('Tabuľka nemá stĺpec EAN – nejde o podklady z Databázy produktov?');
|
if (c.ean < 0) throw new Error('Tabuľka nemá stĺpec EAN – nejde o podklady z Databázy produktov?');
|
||||||
const get = (row: string[], i: number) => (i >= 0 ? String(row[i] ?? '').trim() : '');
|
const get = (row: string[], i: number) => (i >= 0 ? String(row[i] ?? '').trim() : '');
|
||||||
@@ -163,8 +163,10 @@ export async function readPodkladyZip(file: File, badges: BadgeTemplate[]): Prom
|
|||||||
const colorText = get(row, c.color);
|
const colorText = get(row, c.color);
|
||||||
const color = toBadgeColor(colorText);
|
const color = toBadgeColor(colorText);
|
||||||
const origin = get(row, c.origin);
|
const origin = get(row, c.origin);
|
||||||
|
// 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 tries = [[graphic, colorText, origin], [graphic, colorText], [graphic]].map((parts) => parts.filter(Boolean).join(' | '));
|
||||||
const byTags = findBadgeByTags(badges, graphic, color, origin);
|
const byTags = findBadgeByTags(badges, type, color, origin);
|
||||||
const byName = !byTags && graphic ? tries.map((t) => findBadgeByCode(badges, t)).find(Boolean) : undefined;
|
const byName = !byTags && graphic ? tries.map((t) => findBadgeByCode(badges, t)).find(Boolean) : undefined;
|
||||||
|
|
||||||
const formats = norm(get(row, c.formats));
|
const formats = norm(get(row, c.formats));
|
||||||
@@ -178,7 +180,7 @@ export async function readPodkladyZip(file: File, badges: BadgeTemplate[]): Prom
|
|||||||
cardPrice: toNumber(get(row, c.cardPrice)),
|
cardPrice: toNumber(get(row, c.cardPrice)),
|
||||||
unitPrice: formatUnitPrice(get(row, c.unitPrice)),
|
unitPrice: formatUnitPrice(get(row, c.unitPrice)),
|
||||||
discount: discount ? `${Math.round(discount)}%` : '',
|
discount: discount ? `${Math.round(discount)}%` : '',
|
||||||
badgeLabel: tries[0],
|
badgeLabel: [BADGE_IMPORT_TYPES.find((t) => t.value === type)?.label || type, colorText, origin].filter(Boolean).join(' | '),
|
||||||
badge: byTags?.badge || byName,
|
badge: byTags?.badge || byName,
|
||||||
badgeMatch: byTags ? byTags.match : byName ? 'exact' : undefined,
|
badgeMatch: byTags ? byTags.match : byName ? 'exact' : undefined,
|
||||||
color,
|
color,
|
||||||
|
|||||||
@@ -243,10 +243,18 @@ export interface BadgeTemplate {
|
|||||||
importTags?: BadgeImportTags; // podľa čoho sa šablóna vyberie pri importe podkladov (ZIP)
|
importTags?: BadgeImportTags; // podľa čoho sa šablóna vyberie pri importe podkladov (ZIP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Druhy cenoviek v podkladoch: „Zľava grafická“, a keď je prázdna, základná cenovka s výkričníkom alebo bez
|
||||||
|
export const BADGE_IMPORT_TYPES = [
|
||||||
|
{ value: 'SUPER CENA', label: 'SUPER CENA' },
|
||||||
|
{ value: 'SUPER VÝHODNÉ', label: 'SUPER VÝHODNÉ' },
|
||||||
|
{ value: 'ZÁKLADNÁ !', label: 'Základná s výkričníkom' },
|
||||||
|
{ value: 'ZÁKLADNÁ', label: 'Základná (bez nápisu)' }
|
||||||
|
];
|
||||||
|
|
||||||
// Tagy šablóny cenovky pre import podkladov – zodpovedajú stĺpcom tabuľky z Databázy produktov
|
// Tagy šablóny cenovky pre import podkladov – zodpovedajú stĺpcom tabuľky z Databázy produktov
|
||||||
export type BadgeColor = 'cervena' | 'oranzova' | 'zelena';
|
export type BadgeColor = 'cervena' | 'oranzova' | 'zelena';
|
||||||
export interface BadgeImportTags {
|
export interface BadgeImportTags {
|
||||||
type?: string; // „Zľava grafická“, napr. SUPER CENA, SUPER VÝHODNÉ
|
type?: string; // druh cenovky – jeden z BADGE_IMPORT_TYPES (SUPER CENA, SUPER VÝHODNÉ, ZÁKLADNÁ, ZÁKLADNÁ !)
|
||||||
color?: BadgeColor; // „Farba cenovky“
|
color?: BadgeColor; // „Farba cenovky“
|
||||||
origin?: 'SK' | ''; // „Pôvod“: SK alebo bez pôvodu
|
origin?: 'SK' | ''; // „Pôvod“: SK alebo bez pôvodu
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user