Spaces:
Running
Running
Antigravity AI commited on
Commit ·
9a80bc9
1
Parent(s): 9a2f2fa
Upgrade Menu design, add QR/Logo assets and Seed Data feature
Browse files- public/images/logo.png +3 -0
- public/images/qr_menu.png +3 -0
- src/components/admin/DashboardOverview.jsx +47 -3
- src/index.css +17 -0
- src/pages/AdminDashboard.jsx +4 -3
- src/pages/CustomerMenu.jsx +166 -165
public/images/logo.png
ADDED
|
Git LFS Details
|
public/images/qr_menu.png
ADDED
|
Git LFS Details
|
src/components/admin/DashboardOverview.jsx
CHANGED
|
@@ -22,9 +22,48 @@ export default function DashboardOverview() {
|
|
| 22 |
{ title: 'Stock Bajo', value: stats.stockBajo, icon: <AlertCircle size={24} color="var(--warning)" />, bg: 'rgba(245, 166, 35, 0.1)' }
|
| 23 |
];
|
| 24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
return (
|
| 26 |
<div className="animate-fade-in">
|
| 27 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: '1.5rem', marginBottom: '3rem' }}>
|
| 30 |
{cards.map((card, i) => (
|
|
@@ -41,9 +80,14 @@ export default function DashboardOverview() {
|
|
| 41 |
</div>
|
| 42 |
|
| 43 |
<div className="glass-card">
|
| 44 |
-
<h3 className="text-gradient">
|
| 45 |
-
<p style={{ color: 'var(--text-muted)',
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
</div>
|
| 47 |
</div>
|
| 48 |
);
|
| 49 |
}
|
|
|
|
|
|
| 22 |
{ title: 'Stock Bajo', value: stats.stockBajo, icon: <AlertCircle size={24} color="var(--warning)" />, bg: 'rgba(245, 166, 35, 0.1)' }
|
| 23 |
];
|
| 24 |
|
| 25 |
+
const seedData = async () => {
|
| 26 |
+
if (!window.confirm('¿Deseas cargar toda la información de ejemplo en el sistema? Esto agregará productos, insumos y mesas.')) return;
|
| 27 |
+
|
| 28 |
+
// 1. Sembrar Menú
|
| 29 |
+
const menuRef = ref(db, 'menu');
|
| 30 |
+
const menuExamples = [
|
| 31 |
+
{ name: 'Hamburgesa Trufada', price: 18.50, category: 'Fuertes', image: '/images/burger_classic.png', active: true, ingredients: [], extras: [] },
|
| 32 |
+
{ name: 'Pizza Prosciutto', price: 22.00, category: 'Pizzas', image: 'https://images.unsplash.com/photo-1513104890138-7c749659a591?auto=format&fit=crop&q=80&w=1000', active: true, ingredients: [], extras: [] },
|
| 33 |
+
{ name: 'Limonada de Coco', price: 6.50, category: 'Bebidas', image: 'https://images.unsplash.com/photo-1543648964-1699e74bf300?auto=format&fit=crop&q=80&w=1000', active: true, ingredients: [], extras: [] },
|
| 34 |
+
{ name: 'Ensalada César', price: 14.00, category: 'Entradas', image: 'https://images.unsplash.com/photo-1550304943-4f24f54ddde9?auto=format&fit=crop&q=80&w=1000', active: true, ingredients: [], extras: [] },
|
| 35 |
+
{ name: 'Volcán de Chocolate', price: 9.50, category: 'Postres', image: 'https://images.unsplash.com/photo-1624353365286-3f8d62daad51?auto=format&fit=crop&q=80&w=1000', active: true, ingredients: [], extras: [] }
|
| 36 |
+
];
|
| 37 |
+
for (const item of menuExamples) { await set(push(menuRef), item); }
|
| 38 |
+
|
| 39 |
+
// 2. Sembrar Inventario
|
| 40 |
+
const invRef = ref(db, 'inventory');
|
| 41 |
+
const invExamples = [
|
| 42 |
+
{ name: 'Harina de Trigo', quantity: 100, unit: 'Kg', minStock: 20 },
|
| 43 |
+
{ name: 'Tomate Cherry', quantity: 15, unit: 'Kg', minStock: 5 },
|
| 44 |
+
{ name: 'Queso Mozzarella', quantity: 40, unit: 'Kg', minStock: 10 },
|
| 45 |
+
{ name: 'Carne de Res Premium', quantity: 25, unit: 'Kg', minStock: 8 },
|
| 46 |
+
{ name: 'Limones', quantity: 200, unit: 'Und', minStock: 50 }
|
| 47 |
+
];
|
| 48 |
+
for (const item of invExamples) { await set(push(invRef), item); }
|
| 49 |
+
|
| 50 |
+
// 3. Sembrar Mesas
|
| 51 |
+
const tableRef = ref(db, 'config/tables');
|
| 52 |
+
for (let i = 1; i <= 8; i++) {
|
| 53 |
+
await set(push(tableRef), { number: i, capacity: i > 4 ? 6 : 4, status: 'available', x: 0, y: 0 });
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
alert('Sistema poblado con datos de ejemplo con éxito.');
|
| 57 |
+
};
|
| 58 |
+
|
| 59 |
return (
|
| 60 |
<div className="animate-fade-in">
|
| 61 |
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1.5rem' }}>
|
| 62 |
+
<h2 className="text-gradient" style={{ fontSize: '2rem', fontWeight: '800' }}>Resumen General</h2>
|
| 63 |
+
<button onClick={seedData} className="btn-glass" style={{ borderColor: 'var(--info)', color: 'var(--info)' }}>
|
| 64 |
+
Cargar Datos de Ejemplo
|
| 65 |
+
</button>
|
| 66 |
+
</div>
|
| 67 |
|
| 68 |
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: '1.5rem', marginBottom: '3rem' }}>
|
| 69 |
{cards.map((card, i) => (
|
|
|
|
| 80 |
</div>
|
| 81 |
|
| 82 |
<div className="glass-card">
|
| 83 |
+
<h3 className="text-gradient" style={{ marginBottom: '1rem' }}>Misión del Sistema</h3>
|
| 84 |
+
<p style={{ color: 'var(--text-muted)', lineHeight: '1.6' }}>
|
| 85 |
+
Este sistema está diseñado para gestionar de manera integral un restaurante moderno.
|
| 86 |
+
Desde la recepción del cliente en la <strong>Carta Digital</strong>, pasando por la toma de pedidos en el
|
| 87 |
+
<strong> POS de Meseros</strong>, hasta la preparación coordinada en la <strong>Pantalla de Cocina</strong>.
|
| 88 |
+
</p>
|
| 89 |
</div>
|
| 90 |
</div>
|
| 91 |
);
|
| 92 |
}
|
| 93 |
+
|
src/index.css
CHANGED
|
@@ -187,3 +187,20 @@ button {
|
|
| 187 |
.animate-fade-in {
|
| 188 |
animation: fadeIn 0.4s ease-out forwards;
|
| 189 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 187 |
.animate-fade-in {
|
| 188 |
animation: fadeIn 0.4s ease-out forwards;
|
| 189 |
}
|
| 190 |
+
|
| 191 |
+
.menu-card-hover:hover {
|
| 192 |
+
transform: translateY(-15px) scale(1.02) !important;
|
| 193 |
+
box-shadow: 0 30px 60px rgba(0,0,0,0.5) !important;
|
| 194 |
+
border-color: var(--primary) !important;
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
.menu-card-hover:hover .card-image {
|
| 198 |
+
transform: scale(1.1);
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
.text-gradient {
|
| 202 |
+
background: linear-gradient(135deg, #fff 0%, var(--primary) 100%);
|
| 203 |
+
-webkit-background-clip: text;
|
| 204 |
+
-webkit-text-fill-color: transparent;
|
| 205 |
+
background-clip: text;
|
| 206 |
+
}
|
src/pages/AdminDashboard.jsx
CHANGED
|
@@ -38,9 +38,10 @@ export default function AdminDashboard() {
|
|
| 38 |
<div className="app-container">
|
| 39 |
{/* Sidebar */}
|
| 40 |
<aside className="glass-panel" style={{ width: '280px', borderRadius: '0', borderRight: '1px solid var(--border-subtle)', display: 'flex', flexDirection: 'column' }}>
|
| 41 |
-
<div style={{ padding: '
|
| 42 |
-
<
|
| 43 |
-
<
|
|
|
|
| 44 |
</div>
|
| 45 |
|
| 46 |
<nav style={{ flex: 1, padding: '1.5rem 1rem', display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
|
|
|
|
| 38 |
<div className="app-container">
|
| 39 |
{/* Sidebar */}
|
| 40 |
<aside className="glass-panel" style={{ width: '280px', borderRadius: '0', borderRight: '1px solid var(--border-subtle)', display: 'flex', flexDirection: 'column' }}>
|
| 41 |
+
<div style={{ padding: '2.5rem 1.5rem', borderBottom: '1px solid rgba(255,255,255,0.05)', textAlign: 'center' }}>
|
| 42 |
+
<img src="/images/logo.png" alt="Logo" style={{ height: '50px', marginBottom: '1rem', filter: 'drop-shadow(0 0 10px var(--primary-glow))' }} />
|
| 43 |
+
<h1 className="text-gradient" style={{ fontSize: '1.5rem', fontWeight: '900', letterSpacing: '-1px' }}>ADMIN<span style={{color:'var(--primary)'}}>OS</span></h1>
|
| 44 |
+
<p style={{ color: 'var(--text-muted)', fontSize: '0.75rem', marginTop: '0.25rem', opacity: 0.7 }}>{currentUser?.email}</p>
|
| 45 |
</div>
|
| 46 |
|
| 47 |
<nav style={{ flex: 1, padding: '1.5rem 1rem', display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
|
src/pages/CustomerMenu.jsx
CHANGED
|
@@ -8,31 +8,27 @@ export default function CustomerMenu() {
|
|
| 8 |
const [menuItems, setMenuItems] = useState([]);
|
| 9 |
const [categories, setCategories] = useState([]);
|
| 10 |
const [activeCategory, setActiveCategory] = useState('Todos');
|
| 11 |
-
const [menuTheme, setMenuTheme] = useState('dark');
|
| 12 |
const [feedback, setFeedback] = useState({ rating: 5, comment: '' });
|
| 13 |
const [submitted, setSubmitted] = useState(false);
|
|
|
|
| 14 |
const navigate = useNavigate();
|
| 15 |
|
| 16 |
useEffect(() => {
|
| 17 |
-
// Escuchar el menú
|
| 18 |
const menuRef = ref(db, 'menu');
|
| 19 |
onValue(menuRef, (snapshot) => {
|
| 20 |
const data = snapshot.val();
|
| 21 |
if (data) {
|
| 22 |
const list = Object.keys(data).map(id => ({ id, ...data[id] })).filter(item => item.active !== false);
|
| 23 |
setMenuItems(list);
|
| 24 |
-
|
| 25 |
const cats = [...new Set(list.map(item => item.category))];
|
| 26 |
setCategories(['Todos', ...cats]);
|
| 27 |
}
|
| 28 |
});
|
| 29 |
|
| 30 |
-
// Escuchar el tema configurado por el admin
|
| 31 |
const themeRef = ref(db, 'config/menuTheme');
|
| 32 |
onValue(themeRef, (snapshot) => {
|
| 33 |
-
if (snapshot.exists())
|
| 34 |
-
setMenuTheme(snapshot.val());
|
| 35 |
-
}
|
| 36 |
});
|
| 37 |
}, []);
|
| 38 |
|
|
@@ -41,14 +37,14 @@ export default function CustomerMenu() {
|
|
| 41 |
: menuItems.filter(item => item.category === activeCategory);
|
| 42 |
|
| 43 |
const isDark = menuTheme === 'dark';
|
| 44 |
-
|
| 45 |
const themeColors = {
|
| 46 |
-
bg: isDark ? '#
|
| 47 |
text: isDark ? '#ffffff' : '#1a1a1a',
|
| 48 |
-
muted: isDark ? 'rgba(255,255,255,0.
|
| 49 |
-
card: isDark ? 'rgba(255,255,255,0.
|
| 50 |
border: isDark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)',
|
| 51 |
-
accent: '#FF6B6B'
|
|
|
|
| 52 |
};
|
| 53 |
|
| 54 |
return (
|
|
@@ -57,70 +53,81 @@ export default function CustomerMenu() {
|
|
| 57 |
background: themeColors.bg,
|
| 58 |
color: themeColors.text,
|
| 59 |
fontFamily: "'Outfit', sans-serif",
|
| 60 |
-
transition: 'all 0.
|
|
|
|
| 61 |
}}>
|
| 62 |
|
| 63 |
-
{/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
<section style={{
|
| 65 |
-
height: '
|
| 66 |
-
background: `linear-gradient(rgba(0,0,0,
|
| 67 |
-
backgroundSize: 'cover', backgroundPosition: 'center'
|
| 68 |
}}>
|
| 69 |
-
<div style={{ textAlign: 'center', padding: '0 20px' }} className="animate-
|
| 70 |
-
<
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
</button>
|
| 76 |
</div>
|
| 77 |
</div>
|
| 78 |
-
|
| 79 |
-
{/* Badges */}
|
| 80 |
-
<div style={{
|
| 81 |
-
position: 'absolute', bottom: '-40px', left: '50%', transform: 'translateX(-50%)',
|
| 82 |
-
display: 'flex', gap: '30px', width: '100%', justifyContent: 'center', maxWidth: '800px'
|
| 83 |
-
}}>
|
| 84 |
-
{[
|
| 85 |
-
{ icon: <Star size={20} />, text: "4.9 Estrellas" },
|
| 86 |
-
{ icon: <Clock size={20} />, text: "30-45 min" },
|
| 87 |
-
{ icon: <MapPin size={20} />, text: "Centro Histórico" }
|
| 88 |
-
].map((badge, i) => (
|
| 89 |
-
<div key={i} className="glass-card" style={{
|
| 90 |
-
padding: '15px 25px', borderRadius: '15px', display: 'flex', alignItems: 'center', gap: '10px',
|
| 91 |
-
background: isDark ? 'rgba(30,30,30,0.8)' : 'rgba(255,255,255,0.9)',
|
| 92 |
-
color: isDark ? '#fff' : '#1a1a1a', border: `1px solid ${themeColors.border}`,
|
| 93 |
-
boxShadow: '0 10px 30px rgba(0,0,0,0.1)'
|
| 94 |
-
}}>
|
| 95 |
-
<span style={{ color: themeColors.accent }}>{badge.icon}</span>
|
| 96 |
-
<span style={{ fontWeight: '600', fontSize: '0.9rem' }}>{badge.text}</span>
|
| 97 |
-
</div>
|
| 98 |
-
))}
|
| 99 |
-
</div>
|
| 100 |
</section>
|
| 101 |
|
| 102 |
-
{/*
|
| 103 |
-
<
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
<div style={{ width: '60px', height: '4px', background: themeColors.accent, margin: '0 auto', borderRadius: '2px' }}></div>
|
| 107 |
-
</div>
|
| 108 |
-
|
| 109 |
-
{/* Category Tabs */}
|
| 110 |
<div style={{
|
| 111 |
-
|
| 112 |
-
|
|
|
|
|
|
|
| 113 |
}}>
|
| 114 |
{categories.map(cat => (
|
| 115 |
<button
|
| 116 |
key={cat}
|
| 117 |
onClick={() => setActiveCategory(cat)}
|
| 118 |
style={{
|
| 119 |
-
padding: '12px
|
| 120 |
-
background: activeCategory === cat ? themeColors.
|
| 121 |
color: activeCategory === cat ? '#fff' : themeColors.text,
|
| 122 |
-
fontWeight: '
|
| 123 |
-
|
| 124 |
}}
|
| 125 |
>
|
| 126 |
{cat}
|
|
@@ -128,142 +135,136 @@ export default function CustomerMenu() {
|
|
| 128 |
))}
|
| 129 |
</div>
|
| 130 |
|
| 131 |
-
{/*
|
| 132 |
<div style={{
|
| 133 |
display: 'grid',
|
| 134 |
-
gridTemplateColumns: 'repeat(auto-fill, minmax(
|
| 135 |
-
gap: '
|
| 136 |
}}>
|
| 137 |
{filteredItems.map(item => (
|
| 138 |
-
<div key={item.id}
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
|
|
|
| 142 |
|
| 143 |
-
{/*
|
| 144 |
-
<div style={{ height: '
|
| 145 |
<img
|
| 146 |
src={item.image || 'https://images.unsplash.com/photo-1546069901-ba9599a7e63c?auto=format&fit=crop&q=80&w=1760'}
|
| 147 |
alt={item.name}
|
| 148 |
-
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
|
|
| 149 |
/>
|
| 150 |
<div style={{
|
| 151 |
-
position: 'absolute', top: '
|
| 152 |
-
background: 'rgba(0,0,0,0.
|
| 153 |
-
borderRadius: '
|
|
|
|
| 154 |
}}>
|
| 155 |
${item.price}
|
| 156 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
</div>
|
| 158 |
|
| 159 |
-
{/*
|
| 160 |
-
<div style={{ padding: '
|
| 161 |
-
<div style={{ display: 'flex',
|
| 162 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 163 |
</div>
|
| 164 |
-
<
|
| 165 |
-
|
| 166 |
-
<
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
</div>
|
| 174 |
</div>
|
| 175 |
</div>
|
| 176 |
))}
|
| 177 |
</div>
|
| 178 |
-
</
|
| 179 |
-
|
| 180 |
-
{/* Feedback Section */}
|
| 181 |
-
<section style={{ maxWidth: '800px', margin: '100px auto', padding: '40px', textAlign: 'center' }}>
|
| 182 |
-
<div className="glass-card" style={{ padding: '3rem', border: `1px solid ${themeColors.border}`, background: themeColors.card }}>
|
| 183 |
-
{submitted ? (
|
| 184 |
-
<div className="animate-fade-in">
|
| 185 |
-
<Star size={50} color={themeColors.accent} fill={themeColors.accent} style={{ marginBottom: '1rem' }} />
|
| 186 |
-
<h2 style={{ fontSize: '2rem', fontWeight: '800' }}>¡Gracias por tu Feedback!</h2>
|
| 187 |
-
<p style={{ color: themeColors.muted, marginTop: '1rem' }}>Tu opinión nos ayuda a mejorar cada día.</p>
|
| 188 |
-
</div>
|
| 189 |
-
) : (
|
| 190 |
-
<>
|
| 191 |
-
<h2 style={{ fontSize: '2rem', fontWeight: '800', marginBottom: '1rem' }}>¿Qué te pareció tu visita?</h2>
|
| 192 |
-
<p style={{ color: themeColors.muted, marginBottom: '2rem' }}>Déjanos tu comentario para seguir brindando la mejor calidad.</p>
|
| 193 |
-
|
| 194 |
-
<div style={{ display: 'flex', justifyContent: 'center', gap: '10px', marginBottom: '2rem' }}>
|
| 195 |
-
{[1,2,3,4,5].map(star => (
|
| 196 |
-
<button
|
| 197 |
-
key={star}
|
| 198 |
-
onClick={() => setFeedback({...feedback, rating: star})}
|
| 199 |
-
style={{ background: 'none', border: 'none', cursor: 'pointer', transition: 'transform 0.2s' }}
|
| 200 |
-
onMouseEnter={e => e.currentTarget.style.transform = 'scale(1.2)'}
|
| 201 |
-
onMouseLeave={e => e.currentTarget.style.transform = 'scale(1)'}
|
| 202 |
-
>
|
| 203 |
-
<Star size={32} color={star <= feedback.rating ? themeColors.accent : themeColors.muted} fill={star <= feedback.rating ? themeColors.accent : 'transparent'} />
|
| 204 |
-
</button>
|
| 205 |
-
))}
|
| 206 |
-
</div>
|
| 207 |
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
| 226 |
-
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 234 |
</div>
|
|
|
|
| 235 |
</section>
|
| 236 |
|
| 237 |
-
{/* Footer */}
|
| 238 |
-
<footer style={{
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
<
|
| 245 |
-
<div style={{ display: 'flex', justifyContent: 'center', gap: '
|
| 246 |
-
<
|
| 247 |
-
<
|
|
|
|
| 248 |
</div>
|
| 249 |
-
<div style={{
|
| 250 |
-
© {new Date().getFullYear()}
|
| 251 |
</div>
|
| 252 |
</div>
|
| 253 |
</footer>
|
| 254 |
|
| 255 |
-
{/* Admin Quick Back (Floating) */}
|
| 256 |
-
<button
|
| 257 |
-
onClick={() => navigate('/login')}
|
| 258 |
-
style={{
|
| 259 |
-
position: 'fixed', bottom: '30px', right: '30px', width: '50px', height: '50px', borderRadius: '50%',
|
| 260 |
-
background: themeColors.accent, color: '#fff', border: 'none', cursor: 'pointer',
|
| 261 |
-
boxShadow: '0 10px 20px rgba(0,0,0,0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 100
|
| 262 |
-
}}
|
| 263 |
-
title="Admin Login"
|
| 264 |
-
>
|
| 265 |
-
<Utensils size={24} />
|
| 266 |
-
</button>
|
| 267 |
</div>
|
| 268 |
);
|
| 269 |
}
|
|
|
|
|
|
| 8 |
const [menuItems, setMenuItems] = useState([]);
|
| 9 |
const [categories, setCategories] = useState([]);
|
| 10 |
const [activeCategory, setActiveCategory] = useState('Todos');
|
| 11 |
+
const [menuTheme, setMenuTheme] = useState('dark');
|
| 12 |
const [feedback, setFeedback] = useState({ rating: 5, comment: '' });
|
| 13 |
const [submitted, setSubmitted] = useState(false);
|
| 14 |
+
const [cartCount, setCartCount] = useState(0);
|
| 15 |
const navigate = useNavigate();
|
| 16 |
|
| 17 |
useEffect(() => {
|
|
|
|
| 18 |
const menuRef = ref(db, 'menu');
|
| 19 |
onValue(menuRef, (snapshot) => {
|
| 20 |
const data = snapshot.val();
|
| 21 |
if (data) {
|
| 22 |
const list = Object.keys(data).map(id => ({ id, ...data[id] })).filter(item => item.active !== false);
|
| 23 |
setMenuItems(list);
|
|
|
|
| 24 |
const cats = [...new Set(list.map(item => item.category))];
|
| 25 |
setCategories(['Todos', ...cats]);
|
| 26 |
}
|
| 27 |
});
|
| 28 |
|
|
|
|
| 29 |
const themeRef = ref(db, 'config/menuTheme');
|
| 30 |
onValue(themeRef, (snapshot) => {
|
| 31 |
+
if (snapshot.exists()) setMenuTheme(snapshot.val());
|
|
|
|
|
|
|
| 32 |
});
|
| 33 |
}, []);
|
| 34 |
|
|
|
|
| 37 |
: menuItems.filter(item => item.category === activeCategory);
|
| 38 |
|
| 39 |
const isDark = menuTheme === 'dark';
|
|
|
|
| 40 |
const themeColors = {
|
| 41 |
+
bg: isDark ? '#050505' : '#f8f9fa',
|
| 42 |
text: isDark ? '#ffffff' : '#1a1a1a',
|
| 43 |
+
muted: isDark ? 'rgba(255,255,255,0.5)' : 'rgba(0,0,0,0.5)',
|
| 44 |
+
card: isDark ? 'rgba(255,255,255,0.02)' : 'rgba(255,255,255,0.8)',
|
| 45 |
border: isDark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)',
|
| 46 |
+
accent: '#FF6B6B',
|
| 47 |
+
accentGradient: 'linear-gradient(135deg, #FF6B6B 0%, #FF4757 100%)'
|
| 48 |
};
|
| 49 |
|
| 50 |
return (
|
|
|
|
| 53 |
background: themeColors.bg,
|
| 54 |
color: themeColors.text,
|
| 55 |
fontFamily: "'Outfit', sans-serif",
|
| 56 |
+
transition: 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)',
|
| 57 |
+
overflowX: 'hidden'
|
| 58 |
}}>
|
| 59 |
|
| 60 |
+
{/* Floating Header */}
|
| 61 |
+
<header style={{
|
| 62 |
+
position: 'fixed', top: 0, left: 0, width: '100%', zIndex: 1000,
|
| 63 |
+
padding: '20px 40px', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
| 64 |
+
background: 'rgba(0,0,0,0.2)', backdropFilter: 'blur(20px)', borderBottom: `1px solid ${themeColors.border}`
|
| 65 |
+
}}>
|
| 66 |
+
<div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
|
| 67 |
+
<img src="/images/logo.png" alt="Logo" style={{ height: '40px', filter: isDark ? 'invert(0)' : 'invert(1)' }} />
|
| 68 |
+
<span style={{ fontSize: '1.5rem', fontWeight: '900', letterSpacing: '-1px' }}>RESTAURANT<span style={{color: themeColors.accent}}>OS</span></span>
|
| 69 |
+
</div>
|
| 70 |
+
<div style={{ display: 'flex', gap: '15px' }}>
|
| 71 |
+
<button onClick={() => navigate('/login')} style={{ background: 'none', border: 'none', color: themeColors.text, cursor: 'pointer', fontWeight: '600' }}>Admin</button>
|
| 72 |
+
<div style={{ position: 'relative', cursor: 'pointer' }}>
|
| 73 |
+
<Utensils size={24} />
|
| 74 |
+
{cartCount > 0 && <span style={{ position: 'absolute', top: '-8px', right: '-8px', background: themeColors.accent, color: '#fff', borderRadius: '50%', width: '18px', height: '18px', fontSize: '0.7rem', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: '800' }}>{cartCount}</span>}
|
| 75 |
+
</div>
|
| 76 |
+
</div>
|
| 77 |
+
</header>
|
| 78 |
+
|
| 79 |
+
{/* Hero Section with Parallax Effect */}
|
| 80 |
<section style={{
|
| 81 |
+
height: '85vh', position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'center',
|
| 82 |
+
background: `linear-gradient(rgba(0,0,0,0.5), ${themeColors.bg}), url('https://images.unsplash.com/photo-1504674900247-0877df9cc836?auto=format&fit=crop&q=80&w=2070')`,
|
| 83 |
+
backgroundSize: 'cover', backgroundPosition: 'center', backgroundAttachment: 'fixed'
|
| 84 |
}}>
|
| 85 |
+
<div style={{ textAlign: 'center', padding: '0 20px', maxWidth: '900px' }} className="animate-fade-in">
|
| 86 |
+
<div style={{
|
| 87 |
+
display: 'inline-flex', alignItems: 'center', gap: '10px', padding: '8px 20px',
|
| 88 |
+
borderRadius: '40px', background: 'rgba(255,107,107,0.1)', border: '1px solid rgba(255,107,107,0.2)',
|
| 89 |
+
color: themeColors.accent, fontWeight: '700', fontSize: '0.85rem', marginBottom: '2rem', textTransform: 'uppercase', letterSpacing: '2px'
|
| 90 |
+
}}>
|
| 91 |
+
<ChefHat size={16} /> Experiencia Gastronómica Única
|
| 92 |
+
</div>
|
| 93 |
+
<h1 style={{ fontSize: '5rem', fontWeight: '900', marginBottom: '1.5rem', letterSpacing: '-3px', lineHeight: '0.9' }}>
|
| 94 |
+
Sabor que despierta tus <span className="text-gradient">sentidos.</span>
|
| 95 |
+
</h1>
|
| 96 |
+
<p style={{ fontSize: '1.4rem', color: themeColors.muted, maxWidth: '700px', margin: '0 auto', lineHeight: '1.5' }}>
|
| 97 |
+
Una selección exclusiva de platos preparados por chefs de clase mundial, usando ingredientes locales de la más alta calidad.
|
| 98 |
+
</p>
|
| 99 |
+
|
| 100 |
+
<div style={{ marginTop: '3rem', display: 'flex', gap: '1.5rem', justifyContent: 'center' }}>
|
| 101 |
+
<button className="btn-primary" style={{ padding: '18px 40px', borderRadius: '40px', fontSize: '1.1rem', fontWeight: '700', boxShadow: '0 20px 40px rgba(255,107,107,0.3)' }}>
|
| 102 |
+
Ver Especialidades
|
| 103 |
+
</button>
|
| 104 |
+
<button className="btn-glass" style={{ padding: '18px 40px', borderRadius: '40px', fontSize: '1.1rem', fontWeight: '700' }}>
|
| 105 |
+
Nuestra Historia
|
| 106 |
</button>
|
| 107 |
</div>
|
| 108 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
</section>
|
| 110 |
|
| 111 |
+
{/* Main Content Area */}
|
| 112 |
+
<main style={{ maxWidth: '1400px', margin: '0 auto', padding: '80px 40px' }}>
|
| 113 |
+
|
| 114 |
+
{/* Categories Navigation */}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
<div style={{
|
| 116 |
+
position: 'sticky', top: '100px', zIndex: 100, marginBottom: '60px',
|
| 117 |
+
display: 'flex', justifyContent: 'center', gap: '12px',
|
| 118 |
+
background: 'rgba(0,0,0,0.05)', padding: '10px', borderRadius: '50px', backdropFilter: 'blur(10px)',
|
| 119 |
+
width: 'fit-content', margin: '0 auto 60px'
|
| 120 |
}}>
|
| 121 |
{categories.map(cat => (
|
| 122 |
<button
|
| 123 |
key={cat}
|
| 124 |
onClick={() => setActiveCategory(cat)}
|
| 125 |
style={{
|
| 126 |
+
padding: '12px 28px', borderRadius: '40px', border: 'none', cursor: 'pointer',
|
| 127 |
+
background: activeCategory === cat ? themeColors.accentGradient : 'transparent',
|
| 128 |
color: activeCategory === cat ? '#fff' : themeColors.text,
|
| 129 |
+
fontWeight: '700', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
| 130 |
+
whiteSpace: 'nowrap', fontSize: '0.95rem'
|
| 131 |
}}
|
| 132 |
>
|
| 133 |
{cat}
|
|
|
|
| 135 |
))}
|
| 136 |
</div>
|
| 137 |
|
| 138 |
+
{/* Dynamic Grid */}
|
| 139 |
<div style={{
|
| 140 |
display: 'grid',
|
| 141 |
+
gridTemplateColumns: 'repeat(auto-fill, minmax(400px, 1fr))',
|
| 142 |
+
gap: '40px'
|
| 143 |
}}>
|
| 144 |
{filteredItems.map(item => (
|
| 145 |
+
<div key={item.id} style={{
|
| 146 |
+
background: themeColors.card, borderRadius: '30px', overflow: 'hidden',
|
| 147 |
+
border: `1px solid ${themeColors.border}`, transition: 'all 0.4s ease',
|
| 148 |
+
position: 'relative'
|
| 149 |
+
}} className="menu-card-hover">
|
| 150 |
|
| 151 |
+
{/* Image Container */}
|
| 152 |
+
<div style={{ height: '300px', overflow: 'hidden', position: 'relative' }}>
|
| 153 |
<img
|
| 154 |
src={item.image || 'https://images.unsplash.com/photo-1546069901-ba9599a7e63c?auto=format&fit=crop&q=80&w=1760'}
|
| 155 |
alt={item.name}
|
| 156 |
+
style={{ width: '100%', height: '100%', objectFit: 'cover', transition: 'transform 0.6s ease' }}
|
| 157 |
+
className="card-image"
|
| 158 |
/>
|
| 159 |
<div style={{
|
| 160 |
+
position: 'absolute', top: '20px', right: '20px',
|
| 161 |
+
background: 'rgba(0,0,0,0.8)', color: '#fff', padding: '8px 20px',
|
| 162 |
+
borderRadius: '30px', fontWeight: '900', fontSize: '1.2rem', backdropFilter: 'blur(10px)',
|
| 163 |
+
boxShadow: '0 10px 20px rgba(0,0,0,0.2)'
|
| 164 |
}}>
|
| 165 |
${item.price}
|
| 166 |
</div>
|
| 167 |
+
{item.category === 'Fuertes' && (
|
| 168 |
+
<div style={{
|
| 169 |
+
position: 'absolute', top: '20px', left: '20px',
|
| 170 |
+
background: themeColors.accentGradient, color: '#fff', padding: '5px 15px',
|
| 171 |
+
borderRadius: '30px', fontSize: '0.7rem', fontWeight: '800', textTransform: 'uppercase'
|
| 172 |
+
}}>
|
| 173 |
+
Popular
|
| 174 |
+
</div>
|
| 175 |
+
)}
|
| 176 |
</div>
|
| 177 |
|
| 178 |
+
{/* Content Container */}
|
| 179 |
+
<div style={{ padding: '35px' }}>
|
| 180 |
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '15px' }}>
|
| 181 |
+
<div>
|
| 182 |
+
<h3 style={{ fontSize: '1.8rem', fontWeight: '800', marginBottom: '8px' }}>{item.name}</h3>
|
| 183 |
+
<div style={{ display: 'flex', gap: '15px', color: themeColors.muted, fontSize: '0.85rem' }}>
|
| 184 |
+
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}><Clock size={14} /> 25 min</span>
|
| 185 |
+
<span style={{ display: 'flex', alignItems: 'center', gap: '5px' }}><ChefHat size={14} /> Chef Selection</span>
|
| 186 |
+
</div>
|
| 187 |
+
</div>
|
| 188 |
</div>
|
| 189 |
+
<p style={{ color: themeColors.muted, fontSize: '1rem', lineHeight: '1.6', marginBottom: '25px' }}>
|
| 190 |
+
Preparado magistralmente con técnicas artesanales y los mejores ingredientes seleccionados para garantizar una explosión de sabor.
|
| 191 |
+
</p>
|
| 192 |
+
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
| 193 |
+
<div style={{ display: 'flex', gap: '5px' }}>
|
| 194 |
+
{[1,2,3,4,5].map(s => <Star key={s} size={14} fill={themeColors.accent} color={themeColors.accent} />)}
|
| 195 |
+
</div>
|
| 196 |
+
<button
|
| 197 |
+
onClick={() => setCartCount(c => c + 1)}
|
| 198 |
+
style={{
|
| 199 |
+
background: themeColors.accentGradient, border: 'none', color: '#fff',
|
| 200 |
+
width: '45px', height: '45px', borderRadius: '15px', cursor: 'pointer',
|
| 201 |
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
| 202 |
+
boxShadow: '0 10px 20px rgba(255,107,107,0.2)'
|
| 203 |
+
}}>
|
| 204 |
+
<Plus size={24} />
|
| 205 |
+
</button>
|
| 206 |
</div>
|
| 207 |
</div>
|
| 208 |
</div>
|
| 209 |
))}
|
| 210 |
</div>
|
| 211 |
+
</main>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
|
| 213 |
+
{/* QR & Info Section */}
|
| 214 |
+
<section style={{
|
| 215 |
+
background: isDark ? 'rgba(255,255,255,0.02)' : 'rgba(0,0,0,0.02)',
|
| 216 |
+
padding: '100px 40px', borderTop: `1px solid ${themeColors.border}`
|
| 217 |
+
}}>
|
| 218 |
+
<div style={{ maxWidth: '1200px', margin: '0 auto', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '100px', alignItems: 'center' }}>
|
| 219 |
+
<div>
|
| 220 |
+
<h2 style={{ fontSize: '3rem', fontWeight: '900', marginBottom: '2rem', lineHeight: '1' }}>Lleva el menú en tu bolsillo.</h2>
|
| 221 |
+
<p style={{ fontSize: '1.2rem', color: themeColors.muted, marginBottom: '2.5rem' }}>
|
| 222 |
+
Escanea el código QR para acceder a nuestra carta digital actualizada en tiempo real, ver promociones exclusivas y realizar tu pedido.
|
| 223 |
+
</p>
|
| 224 |
+
<div style={{ display: 'flex', gap: '30px' }}>
|
| 225 |
+
<div style={{ textAlign: 'center' }}>
|
| 226 |
+
<div style={{ fontSize: '2.5rem', fontWeight: '900', color: themeColors.accent }}>100%</div>
|
| 227 |
+
<div style={{ fontSize: '0.8rem', textTransform: 'uppercase', letterSpacing: '1px', fontWeight: '700' }}>Digital</div>
|
| 228 |
+
</div>
|
| 229 |
+
<div style={{ textAlign: 'center' }}>
|
| 230 |
+
<div style={{ fontSize: '2.5rem', fontWeight: '900', color: themeColors.accent }}>0</div>
|
| 231 |
+
<div style={{ fontSize: '0.8rem', textTransform: 'uppercase', letterSpacing: '1px', fontWeight: '700' }}>Contacto</div>
|
| 232 |
+
</div>
|
| 233 |
+
<div style={{ textAlign: 'center' }}>
|
| 234 |
+
<div style={{ fontSize: '2.5rem', fontWeight: '900', color: themeColors.accent }}>24/7</div>
|
| 235 |
+
<div style={{ fontSize: '0.8rem', textTransform: 'uppercase', letterSpacing: '1px', fontWeight: '700' }}>Soporte</div>
|
| 236 |
+
</div>
|
| 237 |
+
</div>
|
| 238 |
+
</div>
|
| 239 |
+
<div style={{ display: 'flex', justifyContent: 'center' }}>
|
| 240 |
+
<div className="glass-card" style={{ padding: '40px', borderRadius: '40px', position: 'relative' }}>
|
| 241 |
+
<img src="/images/qr_menu.png" alt="QR Code" style={{ width: '300px', borderRadius: '20px' }} />
|
| 242 |
+
<div style={{ position: 'absolute', top: '-20px', right: '-20px', background: themeColors.accentGradient, padding: '15px', borderRadius: '50%', color: '#fff', fontWeight: '900' }}>SCAN</div>
|
| 243 |
+
</div>
|
| 244 |
</div>
|
| 245 |
+
</div>
|
| 246 |
</section>
|
| 247 |
|
| 248 |
+
{/* Modern Footer */}
|
| 249 |
+
<footer style={{ padding: '100px 40px', borderTop: `1px solid ${themeColors.border}`, textAlign: 'center' }}>
|
| 250 |
+
<div style={{ maxWidth: '800px', margin: '0 auto' }}>
|
| 251 |
+
<img src="/images/logo.png" alt="Logo" style={{ height: '60px', marginBottom: '30px', filter: isDark ? 'invert(0)' : 'invert(1)' }} />
|
| 252 |
+
<h2 style={{ fontSize: '2.5rem', fontWeight: '900', marginBottom: '1.5rem' }}>RESTAURANT OS</h2>
|
| 253 |
+
<p style={{ color: themeColors.muted, fontSize: '1.1rem', marginBottom: '40px' }}>
|
| 254 |
+
Donde la innovación se encuentra con la tradición culinaria. Únete a nuestra comunidad para recibir noticias y eventos.
|
| 255 |
+
</p>
|
| 256 |
+
<div style={{ display: 'flex', justifyContent: 'center', gap: '30px', marginBottom: '60px' }}>
|
| 257 |
+
<Instagram size={32} style={{ cursor: 'pointer', transition: 'transform 0.3s' }} />
|
| 258 |
+
<Facebook size={32} style={{ cursor: 'pointer', transition: 'transform 0.3s' }} />
|
| 259 |
+
<MessageSquare size={32} style={{ cursor: 'pointer', transition: 'transform 0.3s' }} />
|
| 260 |
</div>
|
| 261 |
+
<div style={{ fontSize: '0.9rem', color: themeColors.muted, borderTop: `1px solid ${themeColors.border}`, paddingTop: '40px' }}>
|
| 262 |
+
© {new Date().getFullYear()} Restaurant OS Premium Management System. Designed with Passion.
|
| 263 |
</div>
|
| 264 |
</div>
|
| 265 |
</footer>
|
| 266 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
</div>
|
| 268 |
);
|
| 269 |
}
|
| 270 |
+
|