1649 lines
79 KiB
TypeScript
1649 lines
79 KiB
TypeScript
'use client';
|
||
|
||
import React from 'react';
|
||
import { NewsletterModule, ProductItem, BadgeTemplate } from '@/types/newsletter';
|
||
import { Plus, Trash2, Image as ImageIcon, Tag, Store, Globe, Palette, Check } from 'lucide-react';
|
||
import { SUPABASE_ASSETS_BASE } from '@/lib/defaultCampaign';
|
||
import { ImageUploadInput } from './ImageUploadInput';
|
||
|
||
const PRODUCT_BG_PRESETS = [
|
||
{ label: 'Červená', sub: 'Fantasticky', color: '#feeaea', border: '#f5d4d4' },
|
||
{ label: 'Žltá', sub: 'Domáce', color: '#fef0c7', border: '#e6d49a' },
|
||
{ label: 'Hnedá', sub: 'Gril', color: '#dcb085', border: '#c49a6c' },
|
||
{ label: 'Sivá', sub: 'Neutrálna', color: '#e6e1d9', border: '#d5cfc5' },
|
||
{ label: 'Zelená', sub: 'Bio', color: '#e8f5e9', border: '#c8e6c9' },
|
||
{ label: 'Biela', sub: 'Čistá', color: '#ffffff', border: '#e5e7eb' },
|
||
];
|
||
|
||
interface ConfigPanelProps {
|
||
module: NewsletterModule | null;
|
||
onUpdateModule: (updated: NewsletterModule) => void;
|
||
onApplyBadgeToAll?: (badge: BadgeTemplate) => void;
|
||
onOpenBadgeManager?: (productId: string) => void;
|
||
onOpenImport?: () => void;
|
||
availableBadges?: BadgeTemplate[];
|
||
}
|
||
|
||
export const ConfigPanel: React.FC<ConfigPanelProps> = ({
|
||
module,
|
||
onUpdateModule,
|
||
onApplyBadgeToAll,
|
||
onOpenBadgeManager,
|
||
onOpenImport,
|
||
availableBadges = []
|
||
}) => {
|
||
if (!module) {
|
||
return (
|
||
<div className="h-full flex items-center justify-center p-6 text-center text-gray-400">
|
||
<p className="text-sm">Vyberte modul v náhľade e-mailu pre úpravu jeho vlastností.</p>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
const updateData = (newData: any) => {
|
||
onUpdateModule({
|
||
...module,
|
||
data: { ...module.data, ...newData }
|
||
});
|
||
};
|
||
|
||
return (
|
||
<div className="h-full overflow-y-auto p-5 space-y-6 bg-white border-l border-gray-200">
|
||
<div className="border-b border-gray-100 pb-3 space-y-1.5">
|
||
<div className="flex items-center justify-between">
|
||
<span className="text-[10px] font-bold uppercase tracking-wider text-red-600 bg-red-50 px-2 py-0.5 rounded">
|
||
{module.type}
|
||
</span>
|
||
<span className="text-[10px] text-gray-400 font-medium">Názov modulu v editore</span>
|
||
</div>
|
||
<input
|
||
type="text"
|
||
value={module.title}
|
||
onChange={(e) => onUpdateModule({ ...module, title: e.target.value })}
|
||
placeholder="Názov modulu..."
|
||
className="w-full text-base font-bold text-gray-900 border border-gray-200 hover:border-gray-300 focus:border-red-500 rounded-lg px-2.5 py-1.5 bg-gray-50/50 hover:bg-white focus:bg-white focus:outline-none focus:ring-1 focus:ring-red-500 transition-all"
|
||
/>
|
||
</div>
|
||
|
||
{/* TOP ANNOUNCEMENT */}
|
||
{module.type === 'announcement' && (
|
||
<div className="space-y-4">
|
||
{/* Toggle zapnuté / vypnuté */}
|
||
<div className="bg-red-50/60 p-3.5 rounded-xl border border-red-200 flex items-center justify-between">
|
||
<div>
|
||
<span className="text-xs font-bold text-gray-900 block">Zobraziť v e-maile</span>
|
||
<span className="text-[11px] text-gray-500">Top oznamovacia lišta</span>
|
||
</div>
|
||
<label className="relative inline-flex items-center cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={module.data.enabled !== false}
|
||
onChange={(e) => updateData({ enabled: e.target.checked })}
|
||
className="sr-only peer"
|
||
/>
|
||
<div className="w-11 h-6 bg-gray-300 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-red-600"></div>
|
||
</label>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Text badge (napr. TIP)</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.tipBadge || ''}
|
||
onChange={(e) => updateData({ tipBadge: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Hlavný text oznamu</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.text || ''}
|
||
onChange={(e) => updateData({ text: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Text odkazu</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.linkText || ''}
|
||
onChange={(e) => updateData({ linkText: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Cieľová URL</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.linkUrl || ''}
|
||
onChange={(e) => updateData({ linkUrl: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* HEADER */}
|
||
{module.type === 'header' && (() => {
|
||
const navLinks = module.data.navLinks || [
|
||
{ label: 'Letáky', url: 'https://www.coop.sk/sk/letaky', variant: 'outline' },
|
||
{ label: 'COOP Klub', url: 'https://www.coopklub.sk', variant: 'filled' }
|
||
];
|
||
|
||
const updateNavLink = (index: number, patch: Partial<typeof navLinks[0]>) => {
|
||
const updated = [...navLinks];
|
||
updated[index] = { ...updated[index], ...patch };
|
||
updateData({ navLinks: updated });
|
||
};
|
||
|
||
return (
|
||
<div className="space-y-5">
|
||
<ImageUploadInput
|
||
label="Logo COOP Jednota"
|
||
value={module.data.logoUrl || ''}
|
||
onChange={(url) => updateData({ logoUrl: url })}
|
||
/>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Odkaz loga</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.logoLink || ''}
|
||
onChange={(e) => updateData({ logoLink: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
placeholder="https://www.coop.sk"
|
||
/>
|
||
</div>
|
||
|
||
{/* Tlačidlá v hlavičke */}
|
||
<div className="pt-2 border-t border-gray-200 space-y-4">
|
||
<span className="text-xs font-bold text-gray-800 uppercase tracking-wider block">
|
||
Tlačidlá v hlavičke
|
||
</span>
|
||
|
||
{/* Tlačidlo 1 (Letáky) */}
|
||
<div className="bg-gray-50 p-3 rounded-xl border border-gray-200 space-y-2">
|
||
<div className="flex items-center justify-between">
|
||
<span className="text-xs font-bold text-gray-700">Tlačidlo 1 (Letáky)</span>
|
||
<span className="text-[10px] bg-red-100 text-red-700 font-bold px-2 py-0.5 rounded">
|
||
{navLinks[0]?.variant === 'filled' ? 'Plné' : 'Obrys'}
|
||
</span>
|
||
</div>
|
||
<div>
|
||
<label className="block text-[11px] text-gray-500 mb-1">Text tlačidla</label>
|
||
<input
|
||
type="text"
|
||
value={navLinks[0]?.label || ''}
|
||
onChange={(e) => updateNavLink(0, { label: e.target.value })}
|
||
className="w-full text-xs font-bold border border-gray-300 rounded-lg p-2 bg-white"
|
||
placeholder="Letáky"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-[11px] text-gray-500 mb-1">Cieľový odkaz (URL)</label>
|
||
<input
|
||
type="text"
|
||
value={navLinks[0]?.url || ''}
|
||
onChange={(e) => updateNavLink(0, { url: e.target.value })}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-2 bg-white"
|
||
placeholder="https://www.coop.sk/sk/letaky"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-[11px] text-gray-500 mb-1">Štýl zobrazenia</label>
|
||
<select
|
||
value={navLinks[0]?.variant || 'outline'}
|
||
onChange={(e) => updateNavLink(0, { variant: e.target.value as any })}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-2 bg-white font-medium"
|
||
>
|
||
<option value="outline">Červený obrys (Biele pozadie, červený text)</option>
|
||
<option value="filled">Modré plné tlačidlo (Biele písmo)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Tlačidlo 2 (COOP Klub) */}
|
||
<div className="bg-gray-50 p-3 rounded-xl border border-gray-200 space-y-2">
|
||
<div className="flex items-center justify-between">
|
||
<span className="text-xs font-bold text-gray-700">Tlačidlo 2 (COOP Klub)</span>
|
||
<span className="text-[10px] bg-blue-100 text-blue-700 font-bold px-2 py-0.5 rounded">
|
||
{navLinks[1]?.variant === 'filled' ? 'Plné modré' : 'Obrys'}
|
||
</span>
|
||
</div>
|
||
<div>
|
||
<label className="block text-[11px] text-gray-500 mb-1">Text tlačidla</label>
|
||
<input
|
||
type="text"
|
||
value={navLinks[1]?.label || ''}
|
||
onChange={(e) => updateNavLink(1, { label: e.target.value })}
|
||
className="w-full text-xs font-bold border border-gray-300 rounded-lg p-2 bg-white"
|
||
placeholder="COOP Klub"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-[11px] text-gray-500 mb-1">Cieľový odkaz (URL)</label>
|
||
<input
|
||
type="text"
|
||
value={navLinks[1]?.url || ''}
|
||
onChange={(e) => updateNavLink(1, { url: e.target.value })}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-2 bg-white"
|
||
placeholder="https://www.coopklub.sk"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-[11px] text-gray-500 mb-1">Štýl zobrazenia</label>
|
||
<select
|
||
value={navLinks[1]?.variant || 'filled'}
|
||
onChange={(e) => updateNavLink(1, { variant: e.target.value as any })}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-2 bg-white font-medium"
|
||
>
|
||
<option value="filled">Modré plné tlačidlo (Biele písmo)</option>
|
||
<option value="outline">Červený obrys (Biele pozadie, červený text)</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
})()}
|
||
|
||
{/* BANNER */}
|
||
{module.type === 'banner' && (
|
||
<div className="space-y-4">
|
||
<ImageUploadInput
|
||
label="Obrázok bannera"
|
||
value={module.data.imageUrl || ''}
|
||
onChange={(url) => updateData({ imageUrl: url })}
|
||
/>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Odkaz bannera</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.linkUrl || ''}
|
||
onChange={(e) => updateData({ linkUrl: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Nadpis pod bannerom</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.title || ''}
|
||
onChange={(e) => updateData({ title: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Popis</label>
|
||
<textarea
|
||
value={module.data.description || ''}
|
||
onChange={(e) => updateData({ description: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2 h-20"
|
||
/>
|
||
</div>
|
||
<div className="grid grid-cols-2 gap-3">
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Text tlačidla</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.buttonText || ''}
|
||
onChange={(e) => updateData({ buttonText: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Farba tlačidla</label>
|
||
<input
|
||
type="color"
|
||
value={module.data.buttonBgColor || '#e2001a'}
|
||
onChange={(e) => updateData({ buttonBgColor: e.target.value })}
|
||
className="w-full h-9 rounded-lg cursor-pointer border border-gray-300 p-1"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* PRODUCTS GRID */}
|
||
{module.type === 'products_grid' && (
|
||
<div className="space-y-5">
|
||
<div className="flex items-center justify-between">
|
||
<h3 className="text-xs font-bold text-gray-800 uppercase tracking-wider">
|
||
Nastavenia sekcie
|
||
</h3>
|
||
{onOpenImport && (
|
||
<button
|
||
onClick={onOpenImport}
|
||
className="text-xs font-bold text-red-600 hover:text-red-700 bg-red-50 hover:bg-red-100 px-2.5 py-1 rounded-lg transition-colors"
|
||
>
|
||
Hromadný import
|
||
</button>
|
||
)}
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Názov sekcie</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.sectionTitle || ''}
|
||
onChange={(e) => updateData({ sectionTitle: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2 font-bold"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Globálna platnosť akcie</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.globalValidity || ''}
|
||
onChange={(e) => updateData({ globalValidity: e.target.value })}
|
||
placeholder="napr. 2. 5. – 15. 5. 2026"
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
|
||
{/* Farba pozadia skupiny produktov */}
|
||
<div className="bg-gray-50 p-3.5 rounded-xl border border-gray-200 space-y-2.5">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-1.5">
|
||
<Palette className="w-3.5 h-3.5 text-gray-700" />
|
||
<label className="text-xs font-bold text-gray-800">Farba pozadia produktov</label>
|
||
</div>
|
||
<span className="text-[10px] font-mono font-bold px-1.5 py-0.5 bg-white border border-gray-200 rounded text-gray-700 uppercase">
|
||
{module.data.cardBgColor || '#feeaea'}
|
||
</span>
|
||
</div>
|
||
|
||
{/* Rýchle predvoľby */}
|
||
<div className="grid grid-cols-3 gap-1.5">
|
||
{PRODUCT_BG_PRESETS.map((preset) => {
|
||
const currentBg = (module.data.cardBgColor || '#feeaea').toLowerCase();
|
||
const isSelected = currentBg === preset.color.toLowerCase();
|
||
return (
|
||
<button
|
||
key={preset.color}
|
||
type="button"
|
||
onClick={() => {
|
||
const newColor = preset.color;
|
||
const newBorder = preset.border;
|
||
const updatedProducts = (module.data.products || []).map((p: ProductItem) => ({
|
||
...p,
|
||
cardBgColor: newColor,
|
||
}));
|
||
updateData({
|
||
cardBgColor: newColor,
|
||
cardBorderColor: newBorder,
|
||
products: updatedProducts,
|
||
});
|
||
}}
|
||
className={`flex items-center gap-1.5 px-2 py-1.5 rounded-lg border text-[11px] font-medium transition-all text-left ${
|
||
isSelected
|
||
? 'border-red-600 bg-white shadow-xs ring-1 ring-red-500 font-bold'
|
||
: 'border-gray-200 bg-white hover:border-gray-300 text-gray-700'
|
||
}`}
|
||
>
|
||
<span
|
||
className="w-3.5 h-3.5 rounded-full border border-black/15 shrink-0 flex items-center justify-center"
|
||
style={{ backgroundColor: preset.color }}
|
||
>
|
||
{isSelected && <Check className="w-2.5 h-2.5 text-gray-800" />}
|
||
</span>
|
||
<span className="truncate">{preset.label}</span>
|
||
</button>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{/* Vlastná farba (Color Picker + HEX input) */}
|
||
<div className="flex items-center gap-2 pt-2 border-t border-gray-200">
|
||
<span className="text-[10px] text-gray-500 font-semibold shrink-0">Vlastná:</span>
|
||
<div className="flex items-center gap-1.5 flex-1">
|
||
<input
|
||
type="color"
|
||
value={module.data.cardBgColor || '#feeaea'}
|
||
onChange={(e) => {
|
||
const newColor = e.target.value;
|
||
const updatedProducts = (module.data.products || []).map((p: ProductItem) => ({
|
||
...p,
|
||
cardBgColor: newColor,
|
||
}));
|
||
updateData({
|
||
cardBgColor: newColor,
|
||
products: updatedProducts,
|
||
});
|
||
}}
|
||
className="w-7 h-7 rounded border border-gray-300 cursor-pointer p-0.5 bg-white shrink-0"
|
||
/>
|
||
<input
|
||
type="text"
|
||
value={module.data.cardBgColor || '#feeaea'}
|
||
onChange={(e) => {
|
||
const newColor = e.target.value;
|
||
const updatedProducts = (module.data.products || []).map((p: ProductItem) => ({
|
||
...p,
|
||
cardBgColor: newColor,
|
||
}));
|
||
updateData({
|
||
cardBgColor: newColor,
|
||
products: updatedProducts,
|
||
});
|
||
}}
|
||
placeholder="#feeaea"
|
||
className="w-full text-xs font-mono border border-gray-300 rounded px-2 py-1 bg-white uppercase text-gray-800 font-bold"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Zoznam produktov */}
|
||
<div className="space-y-4 pt-2">
|
||
<div className="flex items-center justify-between">
|
||
<span className="text-xs font-bold text-gray-700">
|
||
Produkty ({module.data.products?.length || 0})
|
||
</span>
|
||
<button
|
||
onClick={() => {
|
||
const newP: ProductItem = {
|
||
id: `p-${Date.now()}`,
|
||
title: 'Nový produkt',
|
||
imageUrl: `${SUPABASE_ASSETS_BASE}produkt_1.png`,
|
||
priceMain: '1',
|
||
priceSub: '99',
|
||
unitPrice: '1kg = 4,99 €',
|
||
discountText: '20%',
|
||
badgeText: 'zľava',
|
||
cardBgColor: module.data.cardBgColor || '#feeaea',
|
||
stores: { potraviny: true, supermarket: true, tempo: true }
|
||
};
|
||
updateData({ products: [...(module.data.products || []), newP] });
|
||
}}
|
||
className="text-xs font-bold text-white bg-gray-900 hover:bg-black px-2.5 py-1 rounded-lg flex items-center gap-1"
|
||
>
|
||
<Plus className="w-3.5 h-3.5" /> Pridať produkt
|
||
</button>
|
||
</div>
|
||
|
||
{(module.data.products || []).map((p: ProductItem, pIdx: number) => (
|
||
<div
|
||
key={p.id}
|
||
className="p-3 bg-gray-50 rounded-xl border border-gray-200 space-y-3 relative group"
|
||
>
|
||
<div className="flex items-center justify-between">
|
||
<span className="text-xs font-bold text-gray-900 truncate max-w-[180px]">
|
||
{p.title || `Produkt ${pIdx + 1}`}
|
||
</span>
|
||
<button
|
||
onClick={() => {
|
||
const updated = (module.data.products || []).filter((_: any, i: number) => i !== pIdx);
|
||
updateData({ products: updated });
|
||
}}
|
||
className="text-gray-400 hover:text-red-600 p-1"
|
||
>
|
||
<Trash2 className="w-4 h-4" />
|
||
</button>
|
||
</div>
|
||
|
||
<div>
|
||
<input
|
||
type="text"
|
||
value={p.title}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].title = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="Názov produktu"
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-medium"
|
||
/>
|
||
</div>
|
||
|
||
<ImageUploadInput
|
||
label="Obrázok produktu"
|
||
value={p.imageUrl || ''}
|
||
onChange={(url) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].imageUrl = url;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="https://...produkt.png alebo nahrajte súbor"
|
||
/>
|
||
|
||
<div>
|
||
<label className="text-[10px] text-gray-500 font-semibold block mb-0.5">Platnosť akcie pre tento produkt (override)</label>
|
||
<input
|
||
type="text"
|
||
value={p.validityOverride || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].validityOverride = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder={`Predvolená: ${module.data.globalValidity || '2. 5. – 15. 5. 2026'}`}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white placeholder:text-gray-400"
|
||
/>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div>
|
||
<label className="text-[10px] text-gray-500">Cena (€)</label>
|
||
<input
|
||
type="text"
|
||
value={p.priceMain}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].priceMain = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
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.priceSub}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].priceSub = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div>
|
||
<label className="text-[10px] text-gray-500">Zľava %</label>
|
||
<input
|
||
type="text"
|
||
value={p.discountText}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].discountText = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[10px] text-gray-500">Merná cena</label>
|
||
<input
|
||
type="text"
|
||
value={p.unitPrice}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].unitPrice = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white text-[10px]"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Predajne */}
|
||
<div>
|
||
<label className="text-[10px] text-gray-500 block mb-1">Dostupnosť (Piktogramy)</label>
|
||
<div className="flex gap-2 text-[10px]">
|
||
<label className="flex items-center gap-1 cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={p.stores?.potraviny}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].stores.potraviny = e.target.checked;
|
||
updateData({ products });
|
||
}}
|
||
/>
|
||
<span>Potraviny</span>
|
||
</label>
|
||
<label className="flex items-center gap-1 cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={p.stores?.supermarket}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].stores.supermarket = e.target.checked;
|
||
updateData({ products });
|
||
}}
|
||
/>
|
||
<span>Supermarket</span>
|
||
</label>
|
||
<label className="flex items-center gap-1 cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={p.stores?.tempo}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].stores.tempo = e.target.checked;
|
||
updateData({ products });
|
||
}}
|
||
/>
|
||
<span>Tempo</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Grafická cenovka a šablóna */}
|
||
<div className="pt-2 border-t border-gray-200 space-y-2.5">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-1.5">
|
||
<Tag className="w-3.5 h-3.5 text-red-600" />
|
||
<span className="text-xs font-bold text-gray-800">Cenovka</span>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => onOpenBadgeManager && onOpenBadgeManager(p.id)}
|
||
className="text-[11px] font-bold text-red-600 hover:text-red-700 bg-red-50 hover:bg-red-100 border border-red-200 px-2.5 py-1 rounded-lg transition-colors"
|
||
>
|
||
Otvoriť Editor cenoviek
|
||
</button>
|
||
</div>
|
||
|
||
{/* Výber opakovane použiteľnej šablóny */}
|
||
<div>
|
||
<label className="text-[10px] text-gray-500 font-semibold block mb-0.5">
|
||
Šablóna cenovky
|
||
</label>
|
||
<select
|
||
value={p.badgeCustomTemplate?.id || (p.customBadgePngUrl ? 'custom_png' : 'default_coop')}
|
||
onChange={(e) => {
|
||
const val = e.target.value;
|
||
const products = [...module.data.products];
|
||
if (val === 'default_coop') {
|
||
products[pIdx].badgeCustomTemplate = undefined;
|
||
products[pIdx].customBadgePngUrl = undefined;
|
||
products[pIdx].badgeId = undefined;
|
||
} else {
|
||
const found = (availableBadges || []).find((b) => b.id === val);
|
||
if (found) {
|
||
products[pIdx].badgeCustomTemplate = found;
|
||
products[pIdx].badgeId = found.id;
|
||
products[pIdx].badgeWidth = found.width ?? products[pIdx].badgeWidth ?? 110;
|
||
products[pIdx].badgeAlign = found.align ?? products[pIdx].badgeAlign ?? 'center';
|
||
products[pIdx].badgePaddingTop = found.paddingTop ?? products[pIdx].badgePaddingTop ?? 4;
|
||
products[pIdx].badgePaddingBottom = found.paddingBottom ?? products[pIdx].badgePaddingBottom ?? 4;
|
||
products[pIdx].customBadgePngUrl = undefined;
|
||
}
|
||
}
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-1.5 bg-white font-medium"
|
||
>
|
||
<option value="default_coop">Predvolená COOP cenovka (červeno-biela)</option>
|
||
{(availableBadges || []).map((b) => (
|
||
<option key={b.id} value={b.id}>
|
||
{b.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
|
||
{/* Tlačidlá aplikácie cenovky */}
|
||
{p.badgeCustomTemplate && (
|
||
<div className="space-y-1.5">
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
if (confirm(`Naozaj chcete aplikovať šablónu "${p.badgeCustomTemplate?.name}" na všetky produkty v tejto sekcii?`)) {
|
||
const products = (module.data.products || []).map((prod: ProductItem) => ({
|
||
...prod,
|
||
badgeCustomTemplate: p.badgeCustomTemplate,
|
||
badgeId: p.badgeCustomTemplate?.id,
|
||
badgeWidth: p.badgeWidth || p.badgeCustomTemplate?.width || 110,
|
||
badgeAlign: p.badgeAlign || p.badgeCustomTemplate?.align || 'center',
|
||
badgePaddingTop: p.badgePaddingTop ?? p.badgeCustomTemplate?.paddingTop ?? 4,
|
||
badgePaddingBottom: p.badgePaddingBottom ?? p.badgeCustomTemplate?.paddingBottom ?? 4,
|
||
customBadgePngUrl: undefined
|
||
}));
|
||
updateData({ products });
|
||
}
|
||
}}
|
||
className="w-full py-1.5 text-[11px] font-bold text-slate-700 bg-slate-100 hover:bg-slate-200 border border-slate-300 rounded-lg transition-colors text-center"
|
||
>
|
||
Použiť pre všetky produkty v tejto sekcii
|
||
</button>
|
||
{onApplyBadgeToAll && (
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
if (confirm(`Naozaj chcete aplikovať šablónu "${p.badgeCustomTemplate?.name}" na VŠETKY produkty v celom newsletteri (vrátane vernostných zliav)?`)) {
|
||
onApplyBadgeToAll({
|
||
...p.badgeCustomTemplate!,
|
||
width: p.badgeWidth || p.badgeCustomTemplate?.width || 110,
|
||
align: p.badgeAlign || p.badgeCustomTemplate?.align || 'center',
|
||
paddingTop: p.badgePaddingTop ?? p.badgeCustomTemplate?.paddingTop ?? 4,
|
||
paddingBottom: p.badgePaddingBottom ?? p.badgeCustomTemplate?.paddingBottom ?? 4
|
||
});
|
||
}
|
||
}}
|
||
className="w-full py-1.5 text-[11px] font-bold text-red-700 bg-red-50 hover:bg-red-100 border border-red-200 rounded-lg transition-colors text-center flex items-center justify-center gap-1.5"
|
||
>
|
||
<Globe className="w-3 h-3 text-red-600" />
|
||
<span>Použiť v celom newsletteri</span>
|
||
</button>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* Rýchle ovládanie veľkosti (Width), zarovnania a paddingu */}
|
||
<div className="bg-gray-50 p-2.5 rounded-xl border border-gray-200 space-y-2">
|
||
{/* Šírka */}
|
||
<div>
|
||
<div className="flex justify-between items-center text-[10px] text-gray-600 mb-0.5">
|
||
<span className="font-semibold">Veľkosť cenovky (Šírka)</span>
|
||
<span className="font-bold text-gray-800 bg-white px-1.5 py-0.2 rounded border border-gray-200">
|
||
{p.badgeWidth || (p.badgeCustomTemplate ? 110 : 95)} px
|
||
</span>
|
||
</div>
|
||
<input
|
||
type="range"
|
||
min="70"
|
||
max="180"
|
||
step="2"
|
||
value={p.badgeWidth || (p.badgeCustomTemplate ? 110 : 95)}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgeWidth = Number(e.target.value);
|
||
updateData({ products });
|
||
}}
|
||
className="w-full accent-red-600"
|
||
/>
|
||
</div>
|
||
|
||
{/* Zarovnanie */}
|
||
<div>
|
||
<span className="text-[10px] text-gray-600 font-semibold block mb-1">Zarovnanie</span>
|
||
<div className="grid grid-cols-3 gap-1 bg-gray-200 p-0.5 rounded-lg text-[10px] font-bold text-center">
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgeAlign = 'left';
|
||
updateData({ products });
|
||
}}
|
||
className={`py-1 rounded transition-all ${
|
||
(p.badgeAlign || 'center') === 'left'
|
||
? 'bg-white text-gray-900 shadow-xs'
|
||
: 'text-gray-600 hover:text-gray-900'
|
||
}`}
|
||
>
|
||
Vľavo
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgeAlign = 'center';
|
||
updateData({ products });
|
||
}}
|
||
className={`py-1 rounded transition-all ${
|
||
(p.badgeAlign || 'center') === 'center'
|
||
? 'bg-white text-gray-900 shadow-xs'
|
||
: 'text-gray-600 hover:text-gray-900'
|
||
}`}
|
||
>
|
||
Na stred
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgeAlign = 'right';
|
||
updateData({ products });
|
||
}}
|
||
className={`py-1 rounded transition-all ${
|
||
(p.badgeAlign || 'center') === 'right'
|
||
? 'bg-white text-gray-900 shadow-xs'
|
||
: 'text-gray-600 hover:text-gray-900'
|
||
}`}
|
||
>
|
||
Vpravo
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Padding zhora a zdola */}
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div>
|
||
<label className="text-[9px] text-gray-600 font-semibold block">Odsadenie zhora (px)</label>
|
||
<input
|
||
type="number"
|
||
min="0"
|
||
max="40"
|
||
value={p.badgePaddingTop ?? (p.badgeCustomTemplate?.paddingTop ?? 4)}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgePaddingTop = Number(e.target.value);
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-1 bg-white font-medium"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[9px] text-gray-600 font-semibold block">Odsadenie zdola (px)</label>
|
||
<input
|
||
type="number"
|
||
min="0"
|
||
max="40"
|
||
value={p.badgePaddingBottom ?? (p.badgeCustomTemplate?.paddingBottom ?? 4)}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgePaddingBottom = Number(e.target.value);
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-1 bg-white font-medium"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* LOYALTY CLUB (VERNOSTNÉ ZĽAVY) */}
|
||
{module.type === 'loyalty_club' && (
|
||
<div className="space-y-5">
|
||
{/* Toggle zapnuté / vypnuté */}
|
||
<div className="bg-red-50/60 p-3.5 rounded-xl border border-red-200 flex items-center justify-between">
|
||
<div>
|
||
<span className="text-xs font-bold text-gray-900 block">Zobraziť v e-maile</span>
|
||
<span className="text-[11px] text-gray-500">Sekcia Vernostné zľavy</span>
|
||
</div>
|
||
<label className="relative inline-flex items-center cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={module.data.enabled !== false}
|
||
onChange={(e) => updateData({ enabled: e.target.checked })}
|
||
className="sr-only peer"
|
||
/>
|
||
<div className="w-11 h-6 bg-gray-300 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-red-600"></div>
|
||
</label>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Názov sekcie</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.sectionTitle || ''}
|
||
onChange={(e) => updateData({ sectionTitle: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2 font-bold"
|
||
/>
|
||
</div>
|
||
|
||
<ImageUploadInput
|
||
label="Obrázok banneru Vernostných zliav"
|
||
value={module.data.headerImageUrl || ''}
|
||
onChange={(url) => updateData({ headerImageUrl: url })}
|
||
/>
|
||
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Odkaz banneru</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.headerLink || ''}
|
||
onChange={(e) => updateData({ headerLink: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Globálna platnosť akcie</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.globalValidity || ''}
|
||
onChange={(e) => updateData({ globalValidity: e.target.value })}
|
||
placeholder="napr. 2. 5. – 15. 5. 2026"
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
|
||
{/* Farba pozadia vernostných kariet */}
|
||
<div className="bg-gray-50 p-3.5 rounded-xl border border-gray-200 space-y-2.5">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-1.5">
|
||
<Palette className="w-3.5 h-3.5 text-gray-700" />
|
||
<label className="text-xs font-bold text-gray-800">Farba pozadia produktov</label>
|
||
</div>
|
||
<span className="text-[10px] font-mono font-bold px-1.5 py-0.5 bg-white border border-gray-200 rounded text-gray-700 uppercase">
|
||
{module.data.cardBgColor || '#e6e1d9'}
|
||
</span>
|
||
</div>
|
||
|
||
{/* Rýchle predvoľby */}
|
||
<div className="grid grid-cols-3 gap-1.5">
|
||
{PRODUCT_BG_PRESETS.map((preset) => {
|
||
const currentBg = (module.data.cardBgColor || '#e6e1d9').toLowerCase();
|
||
const isSelected = currentBg === preset.color.toLowerCase();
|
||
return (
|
||
<button
|
||
key={preset.color}
|
||
type="button"
|
||
onClick={() => {
|
||
const newColor = preset.color;
|
||
const updatedProducts = (module.data.products || []).map((p: any) => ({
|
||
...p,
|
||
cardBgColor: newColor,
|
||
}));
|
||
updateData({
|
||
cardBgColor: newColor,
|
||
products: updatedProducts,
|
||
});
|
||
}}
|
||
className={`flex items-center gap-1.5 px-2 py-1.5 rounded-lg border text-[11px] font-medium transition-all text-left ${
|
||
isSelected
|
||
? 'border-red-600 bg-white shadow-xs ring-1 ring-red-500 font-bold'
|
||
: 'border-gray-200 bg-white hover:border-gray-300 text-gray-700'
|
||
}`}
|
||
>
|
||
<span
|
||
className="w-3.5 h-3.5 rounded-full border border-black/15 shrink-0 flex items-center justify-center"
|
||
style={{ backgroundColor: preset.color }}
|
||
>
|
||
{isSelected && <Check className="w-2.5 h-2.5 text-gray-800" />}
|
||
</span>
|
||
<span className="truncate">{preset.label}</span>
|
||
</button>
|
||
);
|
||
})}
|
||
</div>
|
||
|
||
{/* Vlastná farba (Color Picker + HEX input) */}
|
||
<div className="flex items-center gap-2 pt-2 border-t border-gray-200">
|
||
<span className="text-[10px] text-gray-500 font-semibold shrink-0">Vlastná:</span>
|
||
<div className="flex items-center gap-1.5 flex-1">
|
||
<input
|
||
type="color"
|
||
value={module.data.cardBgColor || '#e6e1d9'}
|
||
onChange={(e) => {
|
||
const newColor = e.target.value;
|
||
const updatedProducts = (module.data.products || []).map((p: any) => ({
|
||
...p,
|
||
cardBgColor: newColor,
|
||
}));
|
||
updateData({
|
||
cardBgColor: newColor,
|
||
products: updatedProducts,
|
||
});
|
||
}}
|
||
className="w-7 h-7 rounded border border-gray-300 cursor-pointer p-0.5 bg-white shrink-0"
|
||
/>
|
||
<input
|
||
type="text"
|
||
value={module.data.cardBgColor || '#e6e1d9'}
|
||
onChange={(e) => {
|
||
const newColor = e.target.value;
|
||
const updatedProducts = (module.data.products || []).map((p: any) => ({
|
||
...p,
|
||
cardBgColor: newColor,
|
||
}));
|
||
updateData({
|
||
cardBgColor: newColor,
|
||
products: updatedProducts,
|
||
});
|
||
}}
|
||
placeholder="#e6e1d9"
|
||
className="w-full text-xs font-mono border border-gray-300 rounded px-2 py-1 bg-white uppercase text-gray-800 font-bold"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 2 Vernostné produkty */}
|
||
<div className="space-y-4 pt-2">
|
||
<span className="text-xs font-bold text-gray-800 uppercase tracking-wider block">
|
||
Vernostné produkty ({module.data.products?.length || 0})
|
||
</span>
|
||
|
||
{(module.data.products || []).map((p: any, pIdx: number) => (
|
||
<div key={p.id || pIdx} className="p-3 bg-gray-50 rounded-xl border border-gray-200 space-y-3">
|
||
<span className="text-xs font-bold text-gray-900 block truncate">
|
||
{p.title || `Vernostný produkt ${pIdx + 1}`}
|
||
</span>
|
||
|
||
<div>
|
||
<label className="text-[10px] text-gray-500 font-semibold block mb-0.5">Názov produktu</label>
|
||
<input
|
||
type="text"
|
||
value={p.title || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].title = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-medium"
|
||
/>
|
||
</div>
|
||
|
||
<ImageUploadInput
|
||
label="Obrázok produktu"
|
||
value={p.imageUrl || ''}
|
||
onChange={(url) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].imageUrl = url;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="https://...produkt.png alebo nahrajte súbor"
|
||
/>
|
||
|
||
<div>
|
||
<label className="text-[10px] text-gray-500 font-semibold block mb-0.5">Platnosť akcie pre tento produkt (override)</label>
|
||
<input
|
||
type="text"
|
||
value={p.validityOverride || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].validityOverride = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder={`Predvolená: ${module.data.globalValidity || '2. 5. – 15. 5. 2026'}`}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white placeholder:text-gray-400"
|
||
/>
|
||
</div>
|
||
|
||
{/* Sekcia Bez karty */}
|
||
<div className="p-2.5 bg-red-50/40 rounded-lg border border-red-100 space-y-2">
|
||
<span className="text-[11px] font-bold text-red-700 block">Bez karty</span>
|
||
<div className="grid grid-cols-3 gap-1.5">
|
||
<div>
|
||
<label className="text-[9px] text-gray-500">Zľava</label>
|
||
<input
|
||
type="text"
|
||
value={p.noCardDiscount || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].noCardDiscount = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="21%"
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[9px] text-gray-500">Cena (€)</label>
|
||
<input
|
||
type="text"
|
||
value={p.noCardPriceMain || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].noCardPriceMain = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="0"
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[9px] text-gray-500">Centy</label>
|
||
<input
|
||
type="text"
|
||
value={p.noCardPriceSub || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].noCardPriceSub = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="79"
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label className="text-[9px] text-gray-500">Merná cena (bez karty)</label>
|
||
<input
|
||
type="text"
|
||
value={p.noCardUnitPrice || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].noCardUnitPrice = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="1kg = 9,88 €"
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Sekcia S kartou */}
|
||
<div className="p-2.5 bg-amber-50/50 rounded-lg border border-amber-200 space-y-2">
|
||
<span className="text-[11px] font-bold text-amber-900 block">S kartou (Klub)</span>
|
||
<div className="grid grid-cols-3 gap-1.5">
|
||
<div>
|
||
<label className="text-[9px] text-gray-500">Zľava</label>
|
||
<input
|
||
type="text"
|
||
value={p.cardDiscount || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].cardDiscount = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="38%"
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[9px] text-gray-500">Cena (€)</label>
|
||
<input
|
||
type="text"
|
||
value={p.cardPriceMain || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].cardPriceMain = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="0"
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[9px] 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="62"
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label className="text-[9px] text-gray-500">Merná cena (s kartou)</label>
|
||
<input
|
||
type="text"
|
||
value={p.cardUnitPrice || ''}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].cardUnitPrice = e.target.value;
|
||
updateData({ products });
|
||
}}
|
||
placeholder="1kg = 7,75 €"
|
||
className="w-full text-xs border border-gray-300 rounded p-1 bg-white"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Predajne */}
|
||
<div>
|
||
<label className="text-[10px] text-gray-500 block mb-1">Dostupnosť (Piktogramy)</label>
|
||
<div className="flex gap-2 text-[10px]">
|
||
<label className="flex items-center gap-1 cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={p.stores?.potraviny}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].stores.potraviny = e.target.checked;
|
||
updateData({ products });
|
||
}}
|
||
/>
|
||
<span>Potraviny</span>
|
||
</label>
|
||
<label className="flex items-center gap-1 cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={p.stores?.supermarket}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].stores.supermarket = e.target.checked;
|
||
updateData({ products });
|
||
}}
|
||
/>
|
||
<span>Supermarket</span>
|
||
</label>
|
||
<label className="flex items-center gap-1 cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={p.stores?.tempo}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].stores.tempo = e.target.checked;
|
||
updateData({ products });
|
||
}}
|
||
/>
|
||
<span>Tempo</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Grafická cenovka a šablóna pre vernostné produkty */}
|
||
<div className="pt-2 border-t border-gray-200 space-y-2.5">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-1.5">
|
||
<Tag className="w-3.5 h-3.5 text-red-600" />
|
||
<span className="text-xs font-bold text-gray-800">Cenovka</span>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
onClick={() => onOpenBadgeManager && onOpenBadgeManager(p.id)}
|
||
className="text-[11px] font-bold text-red-600 hover:text-red-700 bg-red-50 hover:bg-red-100 border border-red-200 px-2.5 py-1 rounded-lg transition-colors"
|
||
>
|
||
Otvoriť Editor cenoviek
|
||
</button>
|
||
</div>
|
||
|
||
{/* Výber šablóny */}
|
||
<div>
|
||
<label className="text-[10px] text-gray-500 font-semibold block mb-0.5">
|
||
Šablóna cenovky
|
||
</label>
|
||
<select
|
||
value={p.badgeCustomTemplate?.id || 'default_loyalty'}
|
||
onChange={(e) => {
|
||
const val = e.target.value;
|
||
const products = [...module.data.products];
|
||
if (val === 'default_loyalty') {
|
||
products[pIdx].badgeCustomTemplate = undefined;
|
||
products[pIdx].badgeId = undefined;
|
||
} else {
|
||
const found = (availableBadges || []).find((b) => b.id === val);
|
||
if (found) {
|
||
products[pIdx].badgeCustomTemplate = found;
|
||
products[pIdx].badgeId = found.id;
|
||
products[pIdx].badgeWidth = found.width ?? products[pIdx].badgeWidth ?? 120;
|
||
products[pIdx].badgeAlign = found.align ?? products[pIdx].badgeAlign ?? 'center';
|
||
products[pIdx].badgePaddingTop = found.paddingTop ?? products[pIdx].badgePaddingTop ?? 4;
|
||
products[pIdx].badgePaddingBottom = found.paddingBottom ?? products[pIdx].badgePaddingBottom ?? 4;
|
||
}
|
||
}
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-1.5 bg-white font-medium"
|
||
>
|
||
<option value="default_loyalty">Predvolený Dual sticker (Bez karty / S kartou)</option>
|
||
{(availableBadges || []).map((b) => (
|
||
<option key={b.id} value={b.id}>
|
||
{b.name}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</div>
|
||
|
||
{/* Tlačidlá aplikácie cenovky */}
|
||
{p.badgeCustomTemplate && (
|
||
<div className="space-y-1.5">
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
if (confirm(`Naozaj chcete aplikovať šablónu "${p.badgeCustomTemplate?.name}" na všetky vernostné produkty?`)) {
|
||
const products = (module.data.products || []).map((prod: any) => ({
|
||
...prod,
|
||
badgeCustomTemplate: p.badgeCustomTemplate,
|
||
badgeId: p.badgeCustomTemplate?.id,
|
||
badgeWidth: p.badgeWidth || p.badgeCustomTemplate?.width || 120,
|
||
badgeAlign: p.badgeAlign || p.badgeCustomTemplate?.align || 'center',
|
||
badgePaddingTop: p.badgePaddingTop ?? p.badgeCustomTemplate?.paddingTop ?? 4,
|
||
badgePaddingBottom: p.badgePaddingBottom ?? p.badgeCustomTemplate?.paddingBottom ?? 4
|
||
}));
|
||
updateData({ products });
|
||
}
|
||
}}
|
||
className="w-full py-1.5 text-[11px] font-bold text-slate-700 bg-slate-100 hover:bg-slate-200 border border-slate-300 rounded-lg transition-colors text-center"
|
||
>
|
||
Použiť pre všetky produkty v tejto sekcii
|
||
</button>
|
||
{onApplyBadgeToAll && (
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
if (confirm(`Naozaj chcete aplikovať šablónu "${p.badgeCustomTemplate?.name}" na VŠETKY produkty v celom newsletteri?`)) {
|
||
onApplyBadgeToAll({
|
||
...p.badgeCustomTemplate!,
|
||
width: p.badgeWidth || p.badgeCustomTemplate?.width || 120,
|
||
align: p.badgeAlign || p.badgeCustomTemplate?.align || 'center',
|
||
paddingTop: p.badgePaddingTop ?? p.badgeCustomTemplate?.paddingTop ?? 4,
|
||
paddingBottom: p.badgePaddingBottom ?? p.badgeCustomTemplate?.paddingBottom ?? 4
|
||
});
|
||
}
|
||
}}
|
||
className="w-full py-1.5 text-[11px] font-bold text-red-700 bg-red-50 hover:bg-red-100 border border-red-200 rounded-lg transition-colors text-center flex items-center justify-center gap-1.5"
|
||
>
|
||
<Globe className="w-3 h-3 text-red-600" />
|
||
<span>Použiť v celom newsletteri</span>
|
||
</button>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* Rýchle ovládanie veľkosti (Width), zarovnania a paddingu pre vernostnú cenovku */}
|
||
{p.badgeCustomTemplate && (
|
||
<div className="bg-gray-50 p-2.5 rounded-xl border border-gray-200 space-y-2">
|
||
{/* Šírka */}
|
||
<div>
|
||
<div className="flex justify-between items-center text-[10px] text-gray-600 mb-0.5">
|
||
<span className="font-semibold">Veľkosť cenovky (Šírka)</span>
|
||
<span className="font-bold text-gray-800 bg-white px-1.5 py-0.2 rounded border border-gray-200">
|
||
{p.badgeWidth || (p.badgeCustomTemplate ? 120 : 140)} px
|
||
</span>
|
||
</div>
|
||
<input
|
||
type="range"
|
||
min="80"
|
||
max="180"
|
||
step="2"
|
||
value={p.badgeWidth || (p.badgeCustomTemplate ? 120 : 140)}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgeWidth = Number(e.target.value);
|
||
updateData({ products });
|
||
}}
|
||
className="w-full accent-red-600 cursor-pointer"
|
||
/>
|
||
</div>
|
||
|
||
{/* Zarovnanie */}
|
||
<div>
|
||
<span className="text-[10px] text-gray-600 font-semibold block mb-1">
|
||
Zarovnanie cenovky
|
||
</span>
|
||
<div className="grid grid-cols-3 gap-1 bg-gray-200/70 p-0.5 rounded-lg text-xs font-semibold text-center">
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgeAlign = 'left';
|
||
updateData({ products });
|
||
}}
|
||
className={`py-1 rounded transition-all ${
|
||
(p.badgeAlign || 'center') === 'left'
|
||
? 'bg-white text-gray-900 shadow-xs'
|
||
: 'text-gray-600 hover:text-gray-900'
|
||
}`}
|
||
>
|
||
Vľavo
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgeAlign = 'center';
|
||
updateData({ products });
|
||
}}
|
||
className={`py-1 rounded transition-all ${
|
||
(p.badgeAlign || 'center') === 'center'
|
||
? 'bg-white text-gray-900 shadow-xs'
|
||
: 'text-gray-600 hover:text-gray-900'
|
||
}`}
|
||
>
|
||
Na stred
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgeAlign = 'right';
|
||
updateData({ products });
|
||
}}
|
||
className={`py-1 rounded transition-all ${
|
||
(p.badgeAlign || 'center') === 'right'
|
||
? 'bg-white text-gray-900 shadow-xs'
|
||
: 'text-gray-600 hover:text-gray-900'
|
||
}`}
|
||
>
|
||
Vpravo
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Padding zhora a zdola */}
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div>
|
||
<label className="text-[9px] text-gray-600 font-semibold block">Odsadenie zhora (px)</label>
|
||
<input
|
||
type="number"
|
||
min="0"
|
||
max="40"
|
||
value={p.badgePaddingTop ?? (p.badgeCustomTemplate?.paddingTop ?? 4)}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgePaddingTop = Number(e.target.value);
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-1 bg-white font-medium"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[9px] text-gray-600 font-semibold block">Odsadenie zdola (px)</label>
|
||
<input
|
||
type="number"
|
||
min="0"
|
||
max="40"
|
||
value={p.badgePaddingBottom ?? (p.badgeCustomTemplate?.paddingBottom ?? 4)}
|
||
onChange={(e) => {
|
||
const products = [...module.data.products];
|
||
products[pIdx].badgePaddingBottom = Number(e.target.value);
|
||
updateData({ products });
|
||
}}
|
||
className="w-full text-xs border border-gray-300 rounded-lg p-1 bg-white font-medium"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* ARTICLES ROW (LETÁKY ALEBO ČLÁNKY) */}
|
||
{module.type === 'articles_row' && (
|
||
<div className="space-y-5">
|
||
{module.data.item1?.btnText ? (
|
||
/* AK SÚ TO LETÁKY */
|
||
<div className="space-y-4">
|
||
<div className="p-3 bg-blue-50/50 rounded-xl border border-blue-100">
|
||
<span className="text-xs font-bold text-blue-900 block mb-1">
|
||
Leták 1 (Ľavý stĺpec)
|
||
</span>
|
||
<p className="text-[11px] text-gray-500 mb-3">Môžete upraviť nadpis letáku, cieľový odkaz a náhľadový obrázok.</p>
|
||
<div className="space-y-3">
|
||
<div>
|
||
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Nadpis letáku</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.item1?.title || ''}
|
||
onChange={(e) => updateData({
|
||
item1: { ...module.data.item1, title: e.target.value }
|
||
})}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold"
|
||
placeholder="Aktuálne letáky"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Cieľová URL (kam to smeruje)</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.item1?.linkUrl || ''}
|
||
onChange={(e) => updateData({
|
||
item1: { ...module.data.item1, linkUrl: e.target.value }
|
||
})}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white"
|
||
placeholder="https://www.coop.sk/sk/letaky"
|
||
/>
|
||
</div>
|
||
<ImageUploadInput
|
||
label="Náhľadový obrázok letáku (PNG/JPG)"
|
||
value={module.data.item1?.imageUrl || ''}
|
||
onChange={(url) => updateData({
|
||
item1: { ...module.data.item1, imageUrl: url }
|
||
})}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-3 bg-amber-50/50 rounded-xl border border-amber-100">
|
||
<span className="text-xs font-bold text-amber-900 block mb-1">
|
||
Leták 2 (Pravý stĺpec)
|
||
</span>
|
||
<p className="text-[11px] text-gray-500 mb-3">Môžete upraviť nadpis letáku, cieľový odkaz a náhľadový obrázok.</p>
|
||
<div className="space-y-3">
|
||
<div>
|
||
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Nadpis letáku</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.item2?.title || ''}
|
||
onChange={(e) => updateData({
|
||
item2: { ...module.data.item2, title: e.target.value }
|
||
})}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold"
|
||
placeholder="Rozšírený leták"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Cieľová URL (kam to smeruje)</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.item2?.linkUrl || ''}
|
||
onChange={(e) => updateData({
|
||
item2: { ...module.data.item2, linkUrl: e.target.value }
|
||
})}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white"
|
||
placeholder="https://www.coop.sk/sk/letaky"
|
||
/>
|
||
</div>
|
||
<ImageUploadInput
|
||
label="Náhľadový obrázok letáku (PNG/JPG)"
|
||
value={module.data.item2?.imageUrl || ''}
|
||
onChange={(url) => updateData({
|
||
item2: { ...module.data.item2, imageUrl: url }
|
||
})}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
) : (
|
||
/* AK SÚ TO ČLÁNKY (VEĽKONOČNÝ BARANČEK / VAJÍČKO AMULET) */
|
||
<div className="space-y-4">
|
||
<div className="p-3 bg-orange-50/50 rounded-xl border border-orange-100">
|
||
<span className="text-xs font-bold text-orange-900 block mb-1">
|
||
Článok 1 (Recepty)
|
||
</span>
|
||
<p className="text-[11px] text-gray-500 mb-3">Logá a gradienty sú na pevno. Môžete upraviť text, odkaz a obrázok v pozadí.</p>
|
||
<div className="space-y-3">
|
||
<div>
|
||
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Názov / Text článku</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.item1?.title || ''}
|
||
onChange={(e) => updateData({
|
||
item1: { ...module.data.item1, title: e.target.value }
|
||
})}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Cieľová URL (odkaz)</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.item1?.linkUrl || ''}
|
||
onChange={(e) => updateData({
|
||
item1: { ...module.data.item1, linkUrl: e.target.value }
|
||
})}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white"
|
||
/>
|
||
</div>
|
||
<ImageUploadInput
|
||
label="Obrázok v pozadí"
|
||
value={module.data.item1?.imageUrl || ''}
|
||
onChange={(url) => updateData({
|
||
item1: { ...module.data.item1, imageUrl: url }
|
||
})}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="p-3 bg-blue-50/50 rounded-xl border border-blue-100">
|
||
<span className="text-xs font-bold text-blue-900 block mb-1">
|
||
Článok 2 (Časopis Jednota)
|
||
</span>
|
||
<p className="text-[11px] text-gray-500 mb-3">Logá a gradienty sú na pevno. Môžete upraviť text, odkaz a obrázok v pozadí.</p>
|
||
<div className="space-y-3">
|
||
<div>
|
||
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Názov / Text článku</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.item2?.title || ''}
|
||
onChange={(e) => updateData({
|
||
item2: { ...module.data.item2, title: e.target.value }
|
||
})}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white font-bold"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="text-[10px] text-gray-600 font-semibold block mb-0.5">Cieľová URL (odkaz)</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.item2?.linkUrl || ''}
|
||
onChange={(e) => updateData({
|
||
item2: { ...module.data.item2, linkUrl: e.target.value }
|
||
})}
|
||
className="w-full text-xs border border-gray-300 rounded p-1.5 bg-white"
|
||
/>
|
||
</div>
|
||
<ImageUploadInput
|
||
label="Obrázok v pozadí"
|
||
value={module.data.item2?.imageUrl || ''}
|
||
onChange={(url) => updateData({
|
||
item2: { ...module.data.item2, imageUrl: url }
|
||
})}
|
||
/>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
)}
|
||
|
||
{/* FOOTER */}
|
||
{module.type === 'footer' && (
|
||
<div className="space-y-4">
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Právny text (Disclaimer)</label>
|
||
<textarea
|
||
value={module.data.disclaimer || ''}
|
||
onChange={(e) => updateData({ disclaimer: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2 h-24"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Odkaz pre odhlásenie (Unsubscribe URL)</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.unsubscribeUrl || ''}
|
||
onChange={(e) => updateData({ unsubscribeUrl: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">Google Play URL</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.googlePlayUrl || ''}
|
||
onChange={(e) => updateData({ googlePlayUrl: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-semibold text-gray-700 mb-1">App Store URL</label>
|
||
<input
|
||
type="text"
|
||
value={module.data.appStoreUrl || ''}
|
||
onChange={(e) => updateData({ appStoreUrl: e.target.value })}
|
||
className="w-full text-sm border border-gray-300 rounded-lg p-2"
|
||
/>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|