import { useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { Plus, Gift, Power, Pencil, Trash2, X, Info } from 'lucide-react' import toast from 'react-hot-toast' import client from '../../../api/client' import Button from '../../../ui/Button' import Modal from '../../../ui/Modal' import { ConfirmModal } from '../../../ui/Modal' // ─── API ───────────────────────────────────────────────────────────────────── const api = { list: () => client.get('/api/pricing/deals').then(r => r.data), create: body => client.post('/api/pricing/deals', body).then(r => r.data), update: (id,b) => client.put(`/api/pricing/deals/${id}`, b).then(r => r.data), toggle: id => client.patch(`/api/pricing/deals/${id}/toggle`).then(r => r.data), remove: id => client.delete(`/api/pricing/deals/${id}`), modifiers: () => client.get('/api/pricing/modifiers').then(r => r.data), products: () => client.get('/api/products', { params: { all: true } }).then(r => r.data), categories:() => client.get('/api/products/categories').then(r => r.data), } const COLORS = [ '#6366f1','#8b5cf6','#ec4899','#f43f5e','#f97316', '#eab308','#22c55e','#14b8a6','#0ea5e9','#64748b', ] const CONDITION_TYPES = [ { value: 'min_item_quantity', label: 'Ελάχιστη ποσότητα αντικειμένου' }, { value: 'min_order_value', label: 'Ελάχιστη αξία παραγγελίας' }, { value: 'time_range', label: 'Ώρα ημέρας' }, { value: 'day_of_week', label: 'Ημέρα εβδομάδας' }, { value: 'date_range', label: 'Εύρος ημερομηνιών' }, { value: 'order_channel', label: 'Κανάλι παραγγελίας' }, { value: 'price_group_active',label: 'Ομάδα τιμής ενεργή' }, ] const DAYS = ['Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο','Κυριακή'] const CHANNELS = ['pos','online','qr','takeaway'] const ACTION_TYPES = [ { value: 'apply_modifier', label: 'Εφαρμογή τροποποιητή' }, { value: 'set_price', label: 'Ορισμός τιμής' }, { value: 'add_amount', label: '± Ποσό €' }, { value: 'add_percent', label: '± Ποσοστό %' }, { value: 'free_item', label: 'Δωρεάν προϊόν' }, { value: 'free_choice', label: 'Επιλογή δωρεάν προϊόντος' }, ] // ─── Reuse condition editor (simplified for deals) ──────────────────────────── function ConditionRow({ cond, onChange, onRemove, groups }) { const set = (k, v) => onChange({ ...cond, params: { ...cond.params, [k]: v } }) const setType = t => onChange({ condition_type: t, params: {} }) return (
{cond.condition_type === 'min_item_quantity' && (
set('min', Number(e.target.value))} />
)} {cond.condition_type === 'min_order_value' && (
set('min', Number(e.target.value))} />
)} {cond.condition_type === 'time_range' && (
set('from', e.target.value)} />
set('to', e.target.value)} />
)} {cond.condition_type === 'day_of_week' && (
{DAYS.map((d, i) => ( ))}
)} {cond.condition_type === 'date_range' && (
set('from', e.target.value)} />
set('to', e.target.value)} />
)} {cond.condition_type === 'order_channel' && (
{CHANNELS.map(ch => ( ))}
)} {cond.condition_type === 'price_group_active' && (
)}
) } // ─── Shared multi-picker (same logic as ModifiersTab) ───────────────────────── function MultiPicker({ items, selected, onToggle, labelKey = 'name', valueKey = 'id' }) { return (
{items.length === 0 && (

Δεν βρέθηκαν αποτελέσματα

)} {items.map(item => { const val = item[valueKey] const checked = selected.includes(val) return (
onToggle(val)} className={`flex items-center gap-2.5 px-3 py-1.5 cursor-pointer transition-colors text-[12px] border-b border-slate-100 last:border-0 ${ checked ? 'bg-sky-50 text-sky-700' : 'hover:bg-slate-50 text-slate-700' }`}>
{checked && }
{item[labelKey]}
) })}
) } function TagPicker({ selected, onToggle, onAdd, allTags }) { const [draft, setDraft] = useState('') const handleAdd = () => { const tag = draft.trim() if (tag && !selected.includes(tag)) onAdd(tag) setDraft('') } return (
{allTags.length > 0 && (
{allTags.map(tag => { const active = selected.includes(tag) return ( ) })}
)} {selected.length > 0 && (
{selected.map(tag => ( {tag} ))}
)}
setDraft(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') { e.preventDefault(); handleAdd() } }} />
) } // ─── Deal target row ────────────────────────────────────────────────────────── function DealTargetRow({ target, onChange, onRemove, products, categories, allTags }) { const ids = target.target_ids ?? [] const tags = target.target_tags ?? [] const setIds = v => onChange({ ...target, target_ids: v, target_id: v[0] ?? null }) const setTags = v => onChange({ ...target, target_tags: v, target_tag: v[0] ?? null }) const toggleId = id => setIds(ids.includes(id) ? ids.filter(x => x !== id) : [...ids, id]) const toggleTag = tag => setTags(tags.includes(tag) ? tags.filter(x => x !== tag) : [...tags, tag]) return (
{target.target_type === 'item' && ( )} {target.target_type === 'category' && ( )} {target.target_type === 'tag' && ( setTags([...tags, tag])} allTags={allTags} /> )}
) } // ─── Deal form ──────────────────────────────────────────────────────────────── const DEAL_TABS = [ { key: 'info', label: 'Πληροφορίες' }, { key: 'trigger', label: 'Trigger & Συνθήκες' }, { key: 'action', label: 'Ενέργεια' }, ] function DealForm({ initial, onSave, onCancel, saving, modifiers, groups, activeTab, onTabChange }) { const { data: products = [] } = useQuery({ queryKey: ['products-all-pricing'], queryFn: () => client.get('/api/products/', { params: { all: true } }).then(r => r.data), }) const { data: categories = [] } = useQuery({ queryKey: ['categories'], queryFn: () => client.get('/api/products/categories').then(r => r.data), staleTime: 60_000, }) const { data: allTags = [] } = useQuery({ queryKey: ['product-tags'], queryFn: () => client.get('/api/products/tags').then(r => r.data), staleTime: 60_000, }) const normalizeTarget = t => ({ ...t, target_ids: t.target_ids ?? (t.target_id != null ? [t.target_id] : []), target_tags: t.target_tags ?? (t.target_tag ? [t.target_tag] : []), }) const blank = { name: '', description: '', color: COLORS[6], is_active: true, sort_order: 0, action_type: 'free_item', action_modifier_id: null, action_value: null, action_free_item_id: null, action_free_target_type: 'item', action_free_target_ids: [], action_free_quantity: 1, conditions: [], targets: [{ target_type: 'any', target_id: null, target_tag: null, target_ids: [], target_tags: [] }], } const [f, setF] = useState(initial ? { ...blank, ...initial, conditions: initial.conditions ?? [], targets: (initial.targets ?? [{ target_type: 'any', target_id: null, target_tag: null, target_ids: [], target_tags: [] }]).map(normalizeTarget), action_free_target_ids: initial.action_free_target_ids ?? [], } : blank) const set = (k, v) => setF(p => ({ ...p, [k]: v })) const addCond = () => set('conditions', [...f.conditions, { condition_type: 'min_item_quantity', params: { min: 1 } }]) const updCond = (i, c) => set('conditions', f.conditions.map((x, j) => j === i ? c : x)) const remCond = i => set('conditions', f.conditions.filter((_, j) => j !== i)) const addTarget = () => set('targets', [...f.targets, { target_type: 'any', target_id: null, target_tag: null, target_ids: [], target_tags: [] }]) const updTarget = (i, t) => set('targets', f.targets.map((x, j) => j === i ? t : x)) const remTarget = i => set('targets', f.targets.filter((_, j) => j !== i)) const toggleFreeId = id => { const ids = f.action_free_target_ids ?? [] set('action_free_target_ids', ids.includes(id) ? ids.filter(x => x !== id) : [...ids, id]) } function submit(e) { e.preventDefault() if (!f.name.trim()) return toast.error('Απαιτείται όνομα') onSave({ ...f, action_free_target_ids: f.action_free_target_ids?.length ? f.action_free_target_ids : null, }) } return (
{/* ── Info tab ── */} {activeTab === 'info' && ( <>
set('name', e.target.value)} placeholder="π.χ. 3+1 Μπύρες" autoFocus />
set('description', e.target.value)} />
{COLORS.map(c => (
)} {/* ── Trigger & Conditions tab ── */} {activeTab === 'trigger' && ( <>
Trigger Αγορά αυτών

Ποια προϊόντα πρέπει να υπάρχουν στην παραγγελία για να ενεργοποιηθεί η προσφορά;

{f.targets.map((t, i) => ( updTarget(i, v)} onRemove={() => remTarget(i)} products={products} categories={categories} allTags={allTags} /> ))}
Επιπλέον Συνθήκες (προαιρετικά)
{f.conditions.length === 0 && (

Χωρίς επιπλέον συνθήκες — αρκεί μόνο το trigger.

)} {f.conditions.map((c, i) => ( updCond(i, v)} onRemove={() => remCond(i)} groups={groups} /> ))}
)} {/* ── Action tab ── */} {activeTab === 'action' && (
{ACTION_TYPES.map(({ value, label }) => ( ))}
{f.action_type === 'apply_modifier' && (

Εμφανίζονται μόνο τροποποιητές χωρίς συνθήκες (χειροκίνητοι).

)} {(f.action_type === 'set_price' || f.action_type === 'add_amount' || f.action_type === 'add_percent') && (
set('action_value', Number(e.target.value))} />
)} {f.action_type === 'free_item' && (
set('action_free_quantity', Number(e.target.value))} />
)} {f.action_type === 'free_choice' && (
{[['item','Προϊόντα'],['category','Κατηγορία'],['tag','Ετικέτα']].map(([v,l]) => ( ))}
{f.action_free_target_type === 'item' && (
{products.map(p => ( ))}
)} {f.action_free_target_type === 'category' && (
{categories.map(c => ( ))}
)} {f.action_free_target_type === 'tag' && (