import React, { useState, useEffect } from 'react'; import { db, storage } from '../../firebase/config'; import { ref, onValue, push, set, remove, update } from 'firebase/database'; import { ref as sRef, uploadBytes, getDownloadURL } from 'firebase/storage'; import { Plus, Trash2, Edit3, X, Image as ImageIcon, Save, Palette, Upload, Loader2, ListTree, ChefHat } from 'lucide-react'; export default function MenuEditor() { const [products, setProducts] = useState([]); const [inventory, setInventory] = useState([]); const [formData, setFormData] = useState({ name: '', price: '', category: 'Principales', image: '', variants: [], ingredients: [], extras: [] }); const [editingItem, setEditingItem] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [menuTheme, setMenuTheme] = useState('dark'); const [uploading, setUploading] = useState(false); useEffect(() => { onValue(ref(db, 'menu'), (snapshot) => { const data = snapshot.val(); setProducts(data ? Object.keys(data).map(id => ({ id, ...data[id] })) : []); }); onValue(ref(db, 'inventory'), (snapshot) => { const data = snapshot.val(); setInventory(data ? Object.keys(data).map(id => ({ id, ...data[id] })) : []); }); onValue(ref(db, 'config/menuTheme'), (snapshot) => { if (snapshot.exists()) setMenuTheme(snapshot.val()); }); }, []); const handleToggleTheme = async () => { await set(ref(db, 'config/menuTheme'), menuTheme === 'dark' ? 'light' : 'dark'); }; const handleImageUpload = async (e, isEditing = false) => { const file = e.target.files[0]; if (!file || !file.type.startsWith('image/')) return; setUploading(true); try { const storagePath = `menu/${Date.now()}_${file.name}`; const fileRef = sRef(storage, storagePath); await uploadBytes(fileRef, file); const url = await getDownloadURL(fileRef); if (isEditing) setEditingItem(prev => ({ ...prev, image: url })); else setFormData(prev => ({ ...prev, image: url })); } catch (error) { console.error(error); } finally { setUploading(false); } }; const handleAddProduct = async (e) => { e.preventDefault(); if (!formData.name || !formData.price) return; const newRef = push(ref(db, 'menu')); await set(newRef, { ...formData, price: parseFloat(formData.price), active: true }); setFormData({ name: '', price: '', category: 'Principales', image: '', variants: [], ingredients: [], extras: [] }); }; const handleDelete = async (id) => { if(window.confirm('¿Eliminar producto?')) await remove(ref(db, `menu/${id}`)); }; const addIngredientToProduct = (isEditing) => { const newIng = { id: '', qty: 1 }; if (isEditing) setEditingItem({ ...editingItem, ingredients: [...(editingItem.ingredients || []), newIng] }); else setFormData({ ...formData, ingredients: [...formData.ingredients, newIng] }); }; const addExtraToProduct = (isEditing) => { const newExtra = { name: '', price: 0 }; if (isEditing) setEditingItem({ ...editingItem, extras: [...(editingItem.extras || []), newExtra] }); else setFormData({ ...formData, extras: [...(formData.extras || []), newExtra] }); }; const handleSaveEdit = async () => { const { id, ...updates } = editingItem; await update(ref(db, `menu/${id}`), { ...updates, price: parseFloat(updates.price) }); setIsModalOpen(false); }; const seedMenu = async () => { if (!window.confirm('¿Deseas cargar el menú de ejemplo de hamburguesas? Esto no borrará tus platos actuales.')) return; const examples = [ { name: 'Hamburgesa Clásica', price: 12.50, category: 'Fuertes', image: '/images/burger_classic.png', active: true, ingredients: [], extras: [{ name: 'Queso Extra', price: 1.50 }, { name: 'Tocineta', price: 2.00 }] }, { name: 'Pollo Crispy Burger', price: 11.00, category: 'Fuertes', image: '/images/burger_chicken.png', active: true, ingredients: [], extras: [{ name: 'Salsa Picante', price: 0.50 }] }, { name: 'Vegan Delight', price: 13.00, category: 'Fuertes', image: '/images/burger_vegan.png', active: true, ingredients: [], extras: [{ name: 'Aguacate', price: 1.50 }] }, { name: 'Papas Supremas', price: 8.50, category: 'Entradas', image: 'https://images.unsplash.com/photo-1573080496219-bb080dd4f877?auto=format&fit=crop&q=80&w=1000', active: true, ingredients: [], extras: [] } ]; for (const item of examples) { const newRef = push(ref(db, 'menu')); await set(newRef, item); } alert('Menú de ejemplo cargado con éxito'); }; return (

Carta & Recetas

Gestión de productos y consumo de insumos

Agregar Platillo

setFormData({...formData, name: e.target.value})} style={inputStyle} />
setFormData({...formData, price: e.target.value})} style={inputStyle} />
{formData.ingredients.length > 0 && (
{formData.ingredients.map((ing, idx) => (
{ const newIngs = [...formData.ingredients]; newIngs[idx].qty = parseFloat(e.target.value); setFormData({...formData, ingredients: newIngs}); }} style={{...inputStyle, padding: '0.4rem', width: '60px'}} />
))}
)}
{(formData.extras || []).map((ext, idx) => (
{ const newExts = [...formData.extras]; newExts[idx].name = e.target.value; setFormData({...formData, extras: newExts}); }} style={{...inputStyle, padding: '0.4rem', width: '120px'}} /> { const newExts = [...formData.extras]; newExts[idx].price = parseFloat(e.target.value); setFormData({...formData, extras: newExts}); }} style={{...inputStyle, padding: '0.4rem', width: '60px'}} />
))}
{products.map(item => (
{item.image && {item.name}}

{item.name}

${item.price}
{item.category} {item.ingredients?.length > 0 && }
))}
{isModalOpen && editingItem && (

Editar: {editingItem.name}

setEditingItem({...editingItem, name: e.target.value})} style={inputStyle} />
setEditingItem({...editingItem, price: e.target.value})} style={inputStyle} />
{(editingItem.ingredients || []).map((ing, i) => (
{ const ings = [...editingItem.ingredients]; ings[i].qty = parseFloat(e.target.value); setEditingItem({...editingItem, ingredients: ings}); }} style={{...inputStyle, flex: 1}} />
))}
{(editingItem.extras || []).map((ext, i) => (
{ const exts = [...(editingItem.extras || [])]; exts[i].name = e.target.value; setEditingItem({...editingItem, extras: exts}); }} style={{...inputStyle, flex: 2}} /> { const exts = [...(editingItem.extras || [])]; exts[i].price = parseFloat(e.target.value); setEditingItem({...editingItem, extras: exts}); }} style={{...inputStyle, flex: 1}} />
))}
)}
); } const inputStyle = { width: '100%', padding: '0.8rem', borderRadius: '8px', background: 'rgba(255,255,255,0.05)', border: '1px solid var(--border-subtle)', color: '#fff', outline: 'none' }; const labelStyle = { display: 'block', fontSize: '0.8rem', color: 'var(--text-muted)', marginBottom: '0.4rem' }; const actionBtnStyle = { width: '32px', height: '32px', borderRadius: '8px', border: 'none', background: 'rgba(0,0,0,0.6)', color: '#fff', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center' };