Skip Finance Management module

This commit is contained in:
gpt-engineer-app[bot]
2025-10-10 23:20:14 +00:00
parent e167225412
commit 957c95e59c
7 changed files with 1074 additions and 8 deletions

View File

@@ -37,7 +37,8 @@ import {
Megaphone,
ChevronDown,
ChevronRight,
Hotel
Hotel,
UtensilsCrossed
} from 'lucide-react';
const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
@@ -61,6 +62,7 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
{ icon: Settings, label: 'Admin Panel', path: '/dashboard/admin' },
{ icon: Plus, label: 'Channel Manager', path: '/dashboard/channel-manager' },
{ icon: Hotel, label: 'Hotel Management', path: '/dashboard/hotel-management' },
{ icon: UtensilsCrossed, label: 'Restaurant POS', path: '/dashboard/restaurant-pos' },
{ icon: Wallet, label: 'Wallet', path: '/dashboard/wallet' },
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
];

View File

@@ -0,0 +1,274 @@
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Separator } from '@/components/ui/separator';
import { Receipt, Users, CreditCard, Percent } from 'lucide-react';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { toast } from 'sonner';
interface Bill {
id: string;
tableNumber: number;
items: BillItem[];
subtotal: number;
tip: number;
total: number;
status: 'open' | 'split' | 'paid';
splits?: number;
}
interface BillItem {
name: string;
quantity: number;
price: number;
}
const BillManagement = () => {
const [bills, setBills] = useState<Bill[]>([
{
id: '1',
tableNumber: 5,
items: [
{ name: 'Paella Valenciana', quantity: 2, price: 18.50 },
{ name: 'Gazpacho', quantity: 2, price: 6.50 },
{ name: 'Vino Tinto', quantity: 1, price: 12.00 }
],
subtotal: 62.00,
tip: 6.20,
total: 68.20,
status: 'open'
},
{
id: '2',
tableNumber: 3,
items: [
{ name: 'Pulpo a la Gallega', quantity: 1, price: 16.00 }
],
subtotal: 16.00,
tip: 0,
total: 16.00,
status: 'open'
}
]);
const [selectedBill, setSelectedBill] = useState<Bill | null>(null);
const [tipPercentage, setTipPercentage] = useState('10');
const [splitCount, setSplitCount] = useState('2');
const calculateTip = (subtotal: number, percentage: string) => {
const percent = parseFloat(percentage) || 0;
return (subtotal * percent) / 100;
};
const applySplitBill = () => {
if (!selectedBill) return;
const splits = parseInt(splitCount) || 2;
const amountPerPerson = selectedBill.total / splits;
setBills(bills.map(bill =>
bill.id === selectedBill.id
? { ...bill, status: 'split', splits }
: bill
));
toast.success(`Cuenta dividida en ${splits} partes: €${amountPerPerson.toFixed(2)} por persona`);
};
const applyTip = (billId: string) => {
setBills(bills.map(bill => {
if (bill.id === billId) {
const tip = calculateTip(bill.subtotal, tipPercentage);
return {
...bill,
tip,
total: bill.subtotal + tip
};
}
return bill;
}));
toast.success(`Propina aplicada: €${calculateTip(selectedBill?.subtotal || 0, tipPercentage).toFixed(2)}`);
};
const closeBill = (billId: string) => {
setBills(bills.map(bill =>
bill.id === billId ? { ...bill, status: 'paid' } : bill
));
toast.success('Cuenta cerrada correctamente');
};
return (
<div className="space-y-6">
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{bills.filter(b => b.status !== 'paid').map((bill) => (
<Card key={bill.id}>
<CardHeader>
<div className="flex justify-between items-start">
<CardTitle className="text-lg">Mesa {bill.tableNumber}</CardTitle>
<Badge variant={bill.status === 'split' ? 'default' : 'secondary'}>
{bill.status === 'split' ? `Dividida (${bill.splits})` : 'Abierta'}
</Badge>
</div>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
{bill.items.map((item, idx) => (
<div key={idx} className="flex justify-between text-sm">
<span>{item.quantity}x {item.name}</span>
<span>{(item.quantity * item.price).toFixed(2)}</span>
</div>
))}
</div>
<Separator />
<div className="space-y-1 text-sm">
<div className="flex justify-between">
<span>Subtotal:</span>
<span>{bill.subtotal.toFixed(2)}</span>
</div>
<div className="flex justify-between text-muted-foreground">
<span>Propina:</span>
<span>{bill.tip.toFixed(2)}</span>
</div>
<div className="flex justify-between font-bold text-base pt-1">
<span>Total:</span>
<span className="text-primary">{bill.total.toFixed(2)}</span>
</div>
</div>
{bill.status === 'split' && (
<div className="bg-primary/10 p-2 rounded text-sm">
<div className="font-medium">Por persona:</div>
<div className="text-lg font-bold text-primary">
{(bill.total / (bill.splits || 1)).toFixed(2)}
</div>
</div>
)}
<div className="flex gap-2 pt-2">
<Dialog>
<DialogTrigger asChild>
<Button
variant="outline"
size="sm"
className="flex-1 gap-2"
onClick={() => setSelectedBill(bill)}
>
<Users className="h-4 w-4" />
Dividir
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Dividir Cuenta - Mesa {bill.tableNumber}</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div>
<Label htmlFor="split-count">Número de Personas</Label>
<Input
id="split-count"
type="number"
min="2"
value={splitCount}
onChange={(e) => setSplitCount(e.target.value)}
/>
</div>
<div className="p-4 bg-muted rounded-lg">
<div className="text-sm text-muted-foreground">Monto por persona:</div>
<div className="text-2xl font-bold text-primary">
{(bill.total / (parseInt(splitCount) || 2)).toFixed(2)}
</div>
</div>
<Button className="w-full" onClick={applySplitBill}>
Aplicar División
</Button>
</div>
</DialogContent>
</Dialog>
<Dialog>
<DialogTrigger asChild>
<Button
variant="outline"
size="sm"
className="flex-1 gap-2"
onClick={() => setSelectedBill(bill)}
>
<Percent className="h-4 w-4" />
Propina
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Agregar Propina - Mesa {bill.tableNumber}</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div>
<Label htmlFor="tip-percentage">Porcentaje de Propina</Label>
<Input
id="tip-percentage"
type="number"
min="0"
max="100"
value={tipPercentage}
onChange={(e) => setTipPercentage(e.target.value)}
/>
</div>
<div className="grid grid-cols-3 gap-2">
<Button variant="outline" onClick={() => setTipPercentage('5')}>5%</Button>
<Button variant="outline" onClick={() => setTipPercentage('10')}>10%</Button>
<Button variant="outline" onClick={() => setTipPercentage('15')}>15%</Button>
</div>
<div className="p-4 bg-muted rounded-lg">
<div className="flex justify-between text-sm mb-2">
<span>Subtotal:</span>
<span>{bill.subtotal.toFixed(2)}</span>
</div>
<div className="flex justify-between text-sm mb-2">
<span>Propina ({tipPercentage}%):</span>
<span>{calculateTip(bill.subtotal, tipPercentage).toFixed(2)}</span>
</div>
<Separator className="my-2" />
<div className="flex justify-between">
<span className="font-bold">Total:</span>
<span className="text-xl font-bold text-primary">
{(bill.subtotal + calculateTip(bill.subtotal, tipPercentage)).toFixed(2)}
</span>
</div>
</div>
<Button className="w-full" onClick={() => applyTip(bill.id)}>
Aplicar Propina
</Button>
</div>
</DialogContent>
</Dialog>
</div>
<Button
className="w-full gap-2"
onClick={() => closeBill(bill.id)}
>
<CreditCard className="h-4 w-4" />
Cerrar Cuenta
</Button>
</CardContent>
</Card>
))}
</div>
{bills.filter(b => b.status !== 'paid').length === 0 && (
<Card>
<CardContent className="py-12 text-center text-muted-foreground">
<Receipt className="h-12 w-12 mx-auto mb-4 opacity-50" />
<p>No hay cuentas abiertas</p>
</CardContent>
</Card>
)}
</div>
);
};
export default BillManagement;

View File

@@ -0,0 +1,213 @@
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent } from '@/components/ui/card';
import { QrCode, Plus, Search, Edit, Trash2, Eye } from 'lucide-react';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { toast } from 'sonner';
interface MenuItem {
id: string;
name: string;
description: string;
price: number;
category: string;
image?: string;
available: boolean;
allergens?: string[];
}
const DigitalMenu = () => {
const [searchTerm, setSearchTerm] = useState('');
const [selectedCategory, setSelectedCategory] = useState('all');
const [menuItems] = useState<MenuItem[]>([
{
id: '1',
name: 'Paella Valenciana',
description: 'Arroz tradicional con mariscos y pollo',
price: 18.50,
category: 'Platos Principales',
available: true,
allergens: ['mariscos', 'gluten']
},
{
id: '2',
name: 'Gazpacho Andaluz',
description: 'Sopa fría de tomate con verduras',
price: 6.50,
category: 'Entrantes',
available: true,
allergens: []
},
{
id: '3',
name: 'Tarta de Santiago',
description: 'Tarta de almendra tradicional gallega',
price: 5.50,
category: 'Postres',
available: true,
allergens: ['frutos secos', 'huevo']
},
{
id: '4',
name: 'Pulpo a la Gallega',
description: 'Pulpo cocido con pimentón y aceite de oliva',
price: 16.00,
category: 'Platos Principales',
available: false,
allergens: ['mariscos']
}
]);
const categories = ['all', 'Entrantes', 'Platos Principales', 'Postres', 'Bebidas'];
const filteredItems = menuItems.filter(item => {
const matchesSearch = item.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
item.description.toLowerCase().includes(searchTerm.toLowerCase());
const matchesCategory = selectedCategory === 'all' || item.category === selectedCategory;
return matchesSearch && matchesCategory;
});
const generateQR = (tableNumber: string) => {
toast.success(`Código QR generado para mesa ${tableNumber}`);
};
return (
<div className="space-y-6">
{/* QR Generation Section */}
<div className="flex flex-wrap gap-4 items-end">
<div className="flex-1 min-w-[200px]">
<Label htmlFor="table">Número de Mesa</Label>
<Input id="table" type="number" placeholder="Ej: 5" />
</div>
<Button onClick={() => generateQR('5')} className="gap-2">
<QrCode className="h-4 w-4" />
Generar QR
</Button>
<Dialog>
<DialogTrigger asChild>
<Button variant="outline" className="gap-2">
<Plus className="h-4 w-4" />
Nuevo Item
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Agregar Item al Menú</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div>
<Label htmlFor="item-name">Nombre del Plato</Label>
<Input id="item-name" placeholder="Ej: Paella Valenciana" />
</div>
<div>
<Label htmlFor="item-desc">Descripción</Label>
<Input id="item-desc" placeholder="Descripción del plato" />
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="item-price">Precio ()</Label>
<Input id="item-price" type="number" step="0.01" placeholder="18.50" />
</div>
<div>
<Label htmlFor="item-category">Categoría</Label>
<Select>
<SelectTrigger id="item-category">
<SelectValue placeholder="Seleccionar" />
</SelectTrigger>
<SelectContent>
{categories.slice(1).map(cat => (
<SelectItem key={cat} value={cat}>{cat}</SelectItem>
))}
</SelectContent>
</Select>
</div>
</div>
<Button className="w-full">Agregar Item</Button>
</div>
</DialogContent>
</Dialog>
</div>
{/* Search and Filter */}
<div className="flex flex-wrap gap-4">
<div className="flex-1 min-w-[200px] relative">
<Search className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
<Input
placeholder="Buscar platos..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="pl-10"
/>
</div>
<Select value={selectedCategory} onValueChange={setSelectedCategory}>
<SelectTrigger className="w-[200px]">
<SelectValue placeholder="Categoría" />
</SelectTrigger>
<SelectContent>
{categories.map(cat => (
<SelectItem key={cat} value={cat}>
{cat === 'all' ? 'Todas las categorías' : cat}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* Menu Items Grid */}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{filteredItems.map((item) => (
<Card key={item.id} className={!item.available ? 'opacity-60' : ''}>
<CardContent className="p-4">
<div className="flex justify-between items-start mb-2">
<div className="flex-1">
<h3 className="font-semibold text-lg">{item.name}</h3>
<p className="text-sm text-muted-foreground mt-1">{item.description}</p>
</div>
<Badge variant={item.available ? 'default' : 'secondary'}>
{item.available ? 'Disponible' : 'Agotado'}
</Badge>
</div>
{item.allergens && item.allergens.length > 0 && (
<div className="flex flex-wrap gap-1 my-2">
{item.allergens.map(allergen => (
<Badge key={allergen} variant="outline" className="text-xs">
{allergen}
</Badge>
))}
</div>
)}
<div className="flex justify-between items-center mt-4">
<span className="text-xl font-bold text-primary">{item.price.toFixed(2)}</span>
<div className="flex gap-2">
<Button size="icon" variant="ghost">
<Eye className="h-4 w-4" />
</Button>
<Button size="icon" variant="ghost">
<Edit className="h-4 w-4" />
</Button>
<Button size="icon" variant="ghost">
<Trash2 className="h-4 w-4" />
</Button>
</div>
</div>
</CardContent>
</Card>
))}
</div>
{filteredItems.length === 0 && (
<div className="text-center py-12 text-muted-foreground">
No se encontraron platos con los filtros seleccionados
</div>
)}
</div>
);
};
export default DigitalMenu;

View File

@@ -0,0 +1,212 @@
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Clock, AlertCircle, Check } from 'lucide-react';
import { toast } from 'sonner';
interface KitchenOrder {
id: string;
tableNumber: number;
items: KitchenItem[];
timestamp: Date;
priority: 'normal' | 'urgent';
status: 'preparing' | 'ready';
}
interface KitchenItem {
name: string;
quantity: number;
notes?: string;
station: string;
}
const KitchenDisplay = () => {
const [orders, setOrders] = useState<KitchenOrder[]>([
{
id: '1',
tableNumber: 5,
items: [
{ name: 'Paella Valenciana', quantity: 2, station: 'Caliente', notes: 'Extra mariscos' },
{ name: 'Gazpacho', quantity: 2, station: 'Frío' }
],
timestamp: new Date(Date.now() - 15 * 60000),
priority: 'normal',
status: 'preparing'
},
{
id: '2',
tableNumber: 3,
items: [
{ name: 'Pulpo a la Gallega', quantity: 1, station: 'Caliente', notes: 'Sin pimentón' }
],
timestamp: new Date(Date.now() - 25 * 60000),
priority: 'urgent',
status: 'preparing'
},
{
id: '3',
tableNumber: 8,
items: [
{ name: 'Tarta de Santiago', quantity: 3, station: 'Postres' }
],
timestamp: new Date(Date.now() - 5 * 60000),
priority: 'normal',
status: 'preparing'
}
]);
const getTimeSince = (date: Date) => {
const minutes = Math.floor((Date.now() - date.getTime()) / 60000);
return minutes;
};
const markAsReady = (orderId: string) => {
setOrders(orders.map(order =>
order.id === orderId ? { ...order, status: 'ready' } : order
));
toast.success('Pedido marcado como listo');
};
const getStationColor = (station: string) => {
switch (station) {
case 'Caliente': return 'bg-orange-500/10 text-orange-500';
case 'Frío': return 'bg-blue-500/10 text-blue-500';
case 'Postres': return 'bg-purple-500/10 text-purple-500';
default: return 'bg-gray-500/10 text-gray-500';
}
};
const preparingOrders = orders.filter(o => o.status === 'preparing');
const readyOrders = orders.filter(o => o.status === 'ready');
return (
<div className="space-y-6">
<div className="grid gap-6 lg:grid-cols-2">
{/* Preparing Orders */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold">En Preparación ({preparingOrders.length})</h3>
<Badge variant="secondary">{preparingOrders.length} pedidos</Badge>
</div>
<div className="space-y-3">
{preparingOrders.map((order) => {
const timeSince = getTimeSince(order.timestamp);
const isUrgent = timeSince > 20 || order.priority === 'urgent';
return (
<Card key={order.id} className={isUrgent ? 'border-orange-500' : ''}>
<CardHeader className="pb-3">
<div className="flex justify-between items-start">
<CardTitle className="text-lg flex items-center gap-2">
Mesa {order.tableNumber}
{isUrgent && (
<AlertCircle className="h-5 w-5 text-orange-500" />
)}
</CardTitle>
<div className="flex items-center gap-1 text-sm text-muted-foreground">
<Clock className="h-3 w-3" />
{timeSince} min
</div>
</div>
</CardHeader>
<CardContent className="space-y-3">
{order.items.map((item, idx) => (
<div key={idx} className="space-y-1">
<div className="flex justify-between items-start">
<div className="flex-1">
<div className="font-medium">
{item.quantity}x {item.name}
</div>
{item.notes && (
<div className="text-sm text-orange-500 font-medium mt-1">
{item.notes}
</div>
)}
</div>
<Badge className={getStationColor(item.station)} variant="secondary">
{item.station}
</Badge>
</div>
</div>
))}
<Button
className="w-full gap-2 mt-3"
onClick={() => markAsReady(order.id)}
>
<Check className="h-4 w-4" />
Marcar como Listo
</Button>
</CardContent>
</Card>
);
})}
{preparingOrders.length === 0 && (
<Card>
<CardContent className="py-12 text-center text-muted-foreground">
No hay pedidos en preparación
</CardContent>
</Card>
)}
</div>
</div>
{/* Ready Orders */}
<div className="space-y-4">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold">Listos para Servir ({readyOrders.length})</h3>
<Badge variant="default">{readyOrders.length} pedidos</Badge>
</div>
<div className="space-y-3">
{readyOrders.map((order) => {
const timeSince = getTimeSince(order.timestamp);
return (
<Card key={order.id} className="border-green-500 bg-green-500/5">
<CardHeader className="pb-3">
<div className="flex justify-between items-start">
<CardTitle className="text-lg flex items-center gap-2">
<Check className="h-5 w-5 text-green-500" />
Mesa {order.tableNumber}
</CardTitle>
<div className="flex items-center gap-1 text-sm text-muted-foreground">
<Clock className="h-3 w-3" />
{timeSince} min
</div>
</div>
</CardHeader>
<CardContent className="space-y-2">
{order.items.map((item, idx) => (
<div key={idx} className="flex justify-between">
<span className="font-medium">
{item.quantity}x {item.name}
</span>
<Badge className={getStationColor(item.station)} variant="secondary">
{item.station}
</Badge>
</div>
))}
</CardContent>
</Card>
);
})}
{readyOrders.length === 0 && (
<Card>
<CardContent className="py-12 text-center text-muted-foreground">
No hay pedidos listos
</CardContent>
</Card>
)}
</div>
</div>
</div>
</div>
);
};
export default KitchenDisplay;

View File

@@ -0,0 +1,223 @@
import { useState } from 'react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Clock, User, Plus, Check } from 'lucide-react';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Label } from '@/components/ui/label';
import { Input } from '@/components/ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { toast } from 'sonner';
interface Order {
id: string;
tableNumber: number;
items: OrderItem[];
status: 'pending' | 'preparing' | 'ready' | 'served';
timestamp: Date;
waiter: string;
total: number;
}
interface OrderItem {
name: string;
quantity: number;
price: number;
notes?: string;
}
const TableOrders = () => {
const [orders, setOrders] = useState<Order[]>([
{
id: '1',
tableNumber: 5,
items: [
{ name: 'Paella Valenciana', quantity: 2, price: 18.50 },
{ name: 'Gazpacho', quantity: 2, price: 6.50 }
],
status: 'preparing',
timestamp: new Date(Date.now() - 15 * 60000),
waiter: 'Carlos M.',
total: 50.00
},
{
id: '2',
tableNumber: 3,
items: [
{ name: 'Pulpo a la Gallega', quantity: 1, price: 16.00, notes: 'Sin pimentón' }
],
status: 'pending',
timestamp: new Date(Date.now() - 5 * 60000),
waiter: 'Ana L.',
total: 16.00
},
{
id: '3',
tableNumber: 8,
items: [
{ name: 'Tarta de Santiago', quantity: 3, price: 5.50 }
],
status: 'ready',
timestamp: new Date(Date.now() - 20 * 60000),
waiter: 'Carlos M.',
total: 16.50
}
]);
const getStatusColor = (status: Order['status']) => {
switch (status) {
case 'pending': return 'secondary';
case 'preparing': return 'default';
case 'ready': return 'default';
case 'served': return 'outline';
default: return 'secondary';
}
};
const getStatusLabel = (status: Order['status']) => {
switch (status) {
case 'pending': return 'Pendiente';
case 'preparing': return 'En Cocina';
case 'ready': return 'Listo';
case 'served': return 'Servido';
default: return status;
}
};
const updateOrderStatus = (orderId: string, newStatus: Order['status']) => {
setOrders(orders.map(order =>
order.id === orderId ? { ...order, status: newStatus } : order
));
toast.success('Estado actualizado correctamente');
};
const getTimeSince = (date: Date) => {
const minutes = Math.floor((Date.now() - date.getTime()) / 60000);
return `${minutes} min`;
};
return (
<div className="space-y-6">
<div className="flex justify-between items-center">
<div className="flex gap-2">
<Button variant="outline" size="sm">Todas</Button>
<Button variant="ghost" size="sm">Pendientes</Button>
<Button variant="ghost" size="sm">En Cocina</Button>
<Button variant="ghost" size="sm">Listas</Button>
</div>
<Dialog>
<DialogTrigger asChild>
<Button className="gap-2">
<Plus className="h-4 w-4" />
Nuevo Pedido
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Nuevo Pedido</DialogTitle>
</DialogHeader>
<div className="space-y-4">
<div>
<Label htmlFor="order-table">Mesa</Label>
<Input id="order-table" type="number" placeholder="Número de mesa" />
</div>
<div>
<Label htmlFor="order-waiter">Mesero</Label>
<Input id="order-waiter" placeholder="Nombre del mesero" />
</div>
<div>
<Label htmlFor="order-item">Plato</Label>
<Select>
<SelectTrigger id="order-item">
<SelectValue placeholder="Seleccionar plato" />
</SelectTrigger>
<SelectContent>
<SelectItem value="paella">Paella Valenciana - 18.50</SelectItem>
<SelectItem value="gazpacho">Gazpacho - 6.50</SelectItem>
<SelectItem value="pulpo">Pulpo a la Gallega - 16.00</SelectItem>
</SelectContent>
</Select>
</div>
<div>
<Label htmlFor="order-quantity">Cantidad</Label>
<Input id="order-quantity" type="number" min="1" defaultValue="1" />
</div>
<Button className="w-full">Crear Pedido</Button>
</div>
</DialogContent>
</Dialog>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{orders.map((order) => (
<Card key={order.id}>
<CardHeader className="pb-3">
<div className="flex justify-between items-start">
<CardTitle className="text-lg">Mesa {order.tableNumber}</CardTitle>
<Badge variant={getStatusColor(order.status)}>
{getStatusLabel(order.status)}
</Badge>
</div>
<div className="flex gap-4 text-sm text-muted-foreground mt-2">
<div className="flex items-center gap-1">
<User className="h-3 w-3" />
{order.waiter}
</div>
<div className="flex items-center gap-1">
<Clock className="h-3 w-3" />
{getTimeSince(order.timestamp)}
</div>
</div>
</CardHeader>
<CardContent className="space-y-3">
<div className="space-y-2">
{order.items.map((item, idx) => (
<div key={idx} className="flex justify-between text-sm">
<span>
{item.quantity}x {item.name}
{item.notes && (
<span className="text-xs text-muted-foreground block">
Nota: {item.notes}
</span>
)}
</span>
<span className="font-medium">{(item.quantity * item.price).toFixed(2)}</span>
</div>
))}
</div>
<div className="pt-2 border-t flex justify-between items-center">
<span className="font-bold">Total:</span>
<span className="font-bold text-lg">{order.total.toFixed(2)}</span>
</div>
<div className="flex gap-2 pt-2">
{order.status === 'pending' && (
<Button
size="sm"
className="flex-1"
onClick={() => updateOrderStatus(order.id, 'preparing')}
>
Enviar a Cocina
</Button>
)}
{order.status === 'ready' && (
<Button
size="sm"
className="flex-1 gap-2"
onClick={() => updateOrderStatus(order.id, 'served')}
>
<Check className="h-4 w-4" />
Marcar Servido
</Button>
)}
</div>
</CardContent>
</Card>
))}
</div>
</div>
);
};
export default TableOrders;