Refactor dashboard sidebar

This commit is contained in:
gpt-engineer-app[bot]
2025-10-10 23:36:05 +00:00
parent b1030222f6
commit 4ff9ca94b3
17 changed files with 619 additions and 426 deletions

View File

@@ -35,6 +35,21 @@ import InvoiceDetail from "./pages/dashboard/InvoiceDetail";
import HotelManagement from "./pages/dashboard/HotelManagement"; import HotelManagement from "./pages/dashboard/HotelManagement";
import RestaurantPOS from "./pages/dashboard/RestaurantPOS"; import RestaurantPOS from "./pages/dashboard/RestaurantPOS";
import Personalization from "./pages/dashboard/Personalization"; import Personalization from "./pages/dashboard/Personalization";
// Hotel pages
import HotelRooms from "./pages/dashboard/hotel/Rooms";
import HotelCheckIn from "./pages/dashboard/hotel/CheckIn";
import HotelRoomService from "./pages/dashboard/hotel/RoomServicePage";
import HotelKeyless from "./pages/dashboard/hotel/KeylessAccess";
import HotelStaff from "./pages/dashboard/hotel/Staff";
// Restaurant pages
import RestaurantPOS_Terminal from "./pages/dashboard/restaurant/POSPage";
import RestaurantOrders from "./pages/dashboard/restaurant/Orders";
import RestaurantKitchen from "./pages/dashboard/restaurant/Kitchen";
import RestaurantBills from "./pages/dashboard/restaurant/Bills";
import RestaurantTables from "./pages/dashboard/restaurant/Tables";
import RestaurantMenu from "./pages/dashboard/restaurant/Menu";
import RestaurantInventory from "./pages/dashboard/restaurant/Inventory";
import RestaurantStaff from "./pages/dashboard/restaurant/Staff";
import NotFound from "./pages/NotFound"; import NotFound from "./pages/NotFound";
const queryClient = new QueryClient(); const queryClient = new QueryClient();
@@ -249,6 +264,48 @@ const AppRouter = () => (
</DashboardLayout> </DashboardLayout>
</ProtectedRoute> </ProtectedRoute>
} /> } />
<Route path="/dashboard/hotel" element={
<ProtectedRoute>
<DashboardLayout>
<HotelManagement />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/hotel/rooms" element={
<ProtectedRoute>
<DashboardLayout>
<HotelRooms />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/hotel/checkin" element={
<ProtectedRoute>
<DashboardLayout>
<HotelCheckIn />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/hotel/room-service" element={
<ProtectedRoute>
<DashboardLayout>
<HotelRoomService />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/hotel/keyless" element={
<ProtectedRoute>
<DashboardLayout>
<HotelKeyless />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/hotel/staff" element={
<ProtectedRoute>
<DashboardLayout>
<HotelStaff />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant-pos" element={ <Route path="/dashboard/restaurant-pos" element={
<ProtectedRoute> <ProtectedRoute>
<DashboardLayout> <DashboardLayout>
@@ -256,6 +313,69 @@ const AppRouter = () => (
</DashboardLayout> </DashboardLayout>
</ProtectedRoute> </ProtectedRoute>
} /> } />
<Route path="/dashboard/restaurant" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantPOS />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant/pos" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantPOS_Terminal />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant/orders" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantOrders />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant/kitchen" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantKitchen />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant/bills" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantBills />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant/tables" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantTables />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant/menu" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantMenu />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant/inventory" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantInventory />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/restaurant/staff" element={
<ProtectedRoute>
<DashboardLayout>
<RestaurantStaff />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/personalization" element={ <Route path="/dashboard/personalization" element={
<ProtectedRoute> <ProtectedRoute>
<DashboardLayout> <DashboardLayout>

View File

@@ -39,7 +39,14 @@ import {
ChevronRight, ChevronRight,
Hotel, Hotel,
UtensilsCrossed, UtensilsCrossed,
Brain Brain,
DoorOpen,
BellRing,
Key,
Receipt,
ChefHat,
Grid3x3,
Package
} from 'lucide-react'; } from 'lucide-react';
const DashboardLayout = ({ children }: { children: React.ReactNode }) => { const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
@@ -60,10 +67,35 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
const menuItems = [ const menuItems = [
{ icon: Home, label: 'Dashboard', path: '/dashboard' }, { icon: Home, label: 'Dashboard', path: '/dashboard' },
{ icon: Settings, label: 'Admin Panel', path: '/dashboard/admin' }, { icon: Settings, label: 'Admin Panel', path: '/dashboard/admin', hasSubmenu: true },
{ icon: Plus, label: 'Channel Manager', path: '/dashboard/channel-manager' }, { icon: Plus, label: 'Channel Manager', path: '/dashboard/channel-manager', hasSubmenu: true },
{ icon: Hotel, label: 'Hotel Management', path: '/dashboard/hotel-management' }, {
{ icon: UtensilsCrossed, label: 'Restaurant POS', path: '/dashboard/restaurant-pos' }, icon: Hotel,
label: 'Hotel Management',
path: '/dashboard/hotel',
subItems: [
{ icon: Home, label: 'Habitaciones', path: '/dashboard/hotel/rooms' },
{ icon: DoorOpen, label: 'Check-in', path: '/dashboard/hotel/checkin' },
{ icon: BellRing, label: 'Room Service', path: '/dashboard/hotel/room-service' },
{ icon: Key, label: 'Acceso', path: '/dashboard/hotel/keyless' },
{ icon: Users, label: 'Personal', path: '/dashboard/hotel/staff' }
]
},
{
icon: UtensilsCrossed,
label: 'Restaurant POS',
path: '/dashboard/restaurant',
subItems: [
{ icon: CreditCard, label: 'POS Terminal', path: '/dashboard/restaurant/pos' },
{ icon: Receipt, label: 'Pedidos', path: '/dashboard/restaurant/orders' },
{ icon: ChefHat, label: 'Cocina', path: '/dashboard/restaurant/kitchen' },
{ icon: Receipt, label: 'Cuentas', path: '/dashboard/restaurant/bills' },
{ icon: Grid3x3, label: 'Mesas', path: '/dashboard/restaurant/tables' },
{ icon: UtensilsCrossed, label: 'Menú', path: '/dashboard/restaurant/menu' },
{ icon: Package, label: 'Inventario', path: '/dashboard/restaurant/inventory' },
{ icon: Users, label: 'Personal', path: '/dashboard/restaurant/staff' }
]
},
{ icon: Brain, label: 'Personalization', path: '/dashboard/personalization' }, { icon: Brain, label: 'Personalization', path: '/dashboard/personalization' },
{ icon: Wallet, label: 'Wallet', path: '/dashboard/wallet' }, { icon: Wallet, label: 'Wallet', path: '/dashboard/wallet' },
{ icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' }, { icon: MessageSquare, label: 'Message', path: '/dashboard/messages', badge: '2' },
@@ -168,15 +200,18 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
<div className="space-y-1 pr-8"> <div className="space-y-1 pr-8">
{menuItems.map((item) => { {menuItems.map((item) => {
const Icon = item.icon; const Icon = item.icon;
const isActive = location.pathname === item.path; const isActive = location.pathname === item.path || location.pathname.startsWith(item.path + '/');
const isAdminPanel = item.path === '/dashboard/admin'; const isAdminPanel = item.path === '/dashboard/admin';
const isChannelManager = item.path === '/dashboard/channel-manager'; const isChannelManager = item.path === '/dashboard/channel-manager';
const hasDirectSubItems = item.subItems && item.subItems.length > 0;
const isExpanded = expandedItems[item.path] || (hasDirectSubItems && item.subItems.some(sub => location.pathname === sub.path));
return ( return (
<div key={item.path}> <div key={item.path}>
<div className={`flex items-center justify-between ${sidebarCollapsed ? '' : 'pr-2'}`}>
<Link <Link
to={item.path} to={item.path}
className={`flex items-center space-x-3 px-7 py-2.5 rounded-none transition-all border-l-4 ${ className={`flex items-center space-x-3 px-7 py-2.5 rounded-none transition-all border-l-4 flex-1 ${
isActive isActive
? 'text-white border-l-4 rounded-r-full' ? 'text-white border-l-4 rounded-r-full'
: 'text-gray-700 hover:text-red-500 border-transparent rounded-r-full' : 'text-gray-700 hover:text-red-500 border-transparent rounded-r-full'
@@ -199,6 +234,40 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
</div> </div>
)} )}
</Link> </Link>
{!sidebarCollapsed && hasDirectSubItems && (
<button
onClick={() => toggleExpanded(item.path)}
className="p-1 hover:bg-gray-200 rounded mr-2"
>
{isExpanded ? (
<ChevronDown className="w-3 h-3" />
) : (
<ChevronRight className="w-3 h-3" />
)}
</button>
)}
</div>
{/* Direct sub-items (Hotel & Restaurant) */}
{!sidebarCollapsed && hasDirectSubItems && isExpanded && (
<div className="mt-1 ml-10 space-y-1">
{item.subItems.map((sub) => {
const SubIcon = sub.icon;
const activeSubPath = location.pathname === sub.path;
return (
<Link
key={sub.path}
to={sub.path}
className={`flex items-center space-x-2 px-3 py-2 rounded-md text-sm ${activeSubPath ? 'bg-orange-50 text-orange-800' : 'text-gray-600 hover:text-orange-600 hover:bg-gray-50'}`}
>
<SubIcon className="w-4 h-4" />
<span>{sub.label}</span>
</Link>
);
})}
</div>
)}
{/* Channel Manager submenus */} {/* Channel Manager submenus */}
{!sidebarCollapsed && isChannelManager && location.pathname.startsWith('/dashboard/channel-manager') && ( {!sidebarCollapsed && isChannelManager && location.pathname.startsWith('/dashboard/channel-manager') && (

View File

@@ -1,8 +1,6 @@
import React, { useState } from 'react'; import { Link } from 'react-router-dom';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Card, CardContent } from '@/components/ui/card';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { import {
Hotel, Hotel,
DoorOpen, DoorOpen,
@@ -10,24 +8,12 @@ import {
QrCode, QrCode,
Users, Users,
Bed, Bed,
Calendar,
Clock,
CheckCircle,
AlertCircle,
Sparkles, Sparkles,
UtensilsCrossed, ArrowRight,
Key Key
} from 'lucide-react'; } from 'lucide-react';
import RoomManagement from '@/components/hotel/RoomManagement';
import CheckInSystem from '@/components/hotel/CheckInSystem';
import RoomService from '@/components/hotel/RoomService';
import KeylessEntry from '@/components/hotel/KeylessEntry';
import StaffManagement from '@/components/hotel/StaffManagement';
const HotelManagement = () => { const HotelManagement = () => {
const [activeTab, setActiveTab] = useState('overview');
// Stats de ejemplo
const stats = { const stats = {
totalRooms: 120, totalRooms: 120,
occupied: 85, occupied: 85,
@@ -41,8 +27,46 @@ const HotelManagement = () => {
const occupancyRate = ((stats.occupied / stats.totalRooms) * 100).toFixed(1); const occupancyRate = ((stats.occupied / stats.totalRooms) * 100).toFixed(1);
const sections = [
{
title: 'Gestión de Habitaciones',
description: 'Administra el estado y disponibilidad de habitaciones',
icon: Bed,
path: '/dashboard/hotel/rooms',
color: 'blue'
},
{
title: 'Check-in Digital',
description: 'Sistema de check-in automático sin contacto',
icon: DoorOpen,
path: '/dashboard/hotel/checkin',
color: 'green'
},
{
title: 'Room Service',
description: 'Gestión de pedidos de servicio a habitación',
icon: BellRing,
path: '/dashboard/hotel/room-service',
color: 'purple'
},
{
title: 'Acceso sin Llave',
description: 'Códigos QR y PINs para acceso a habitaciones',
icon: Key,
path: '/dashboard/hotel/keyless',
color: 'orange'
},
{
title: 'Gestión de Personal',
description: 'Administra el equipo del hotel por departamentos',
icon: Users,
path: '/dashboard/hotel/staff',
color: 'indigo'
}
];
return ( return (
<div className="min-h-screen bg-gradient-to-br from-blue-50 via-white to-purple-50 p-6"> <div className="container mx-auto p-6 space-y-6">
{/* Header */} {/* Header */}
<div className="mb-8"> <div className="mb-8">
<div className="flex items-center gap-3 mb-2"> <div className="flex items-center gap-3 mb-2">
@@ -50,22 +74,21 @@ const HotelManagement = () => {
<Hotel className="w-6 h-6 text-white" /> <Hotel className="w-6 h-6 text-white" />
</div> </div>
<div> <div>
<h1 className="text-3xl font-bold text-gray-900">Hotel Management</h1> <h1 className="text-3xl font-bold">Hotel Management</h1>
<p className="text-gray-600">Sistema integral de gestión hotelera</p> <p className="text-muted-foreground">Sistema integral de gestión hotelera</p>
</div> </div>
</div> </div>
</div> </div>
{/* Overview Stats */} {/* Overview Stats */}
{activeTab === 'overview' && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<Card className="border-l-4 border-l-blue-500"> <Card className="border-l-4 border-l-blue-500">
<CardContent className="p-6"> <CardContent className="p-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<p className="text-sm text-gray-600 mb-1">Ocupación</p> <p className="text-sm text-muted-foreground mb-1">Ocupación</p>
<p className="text-2xl font-bold text-gray-900">{occupancyRate}%</p> <p className="text-2xl font-bold">{occupancyRate}%</p>
<p className="text-xs text-gray-500">{stats.occupied}/{stats.totalRooms} habitaciones</p> <p className="text-xs text-muted-foreground">{stats.occupied}/{stats.totalRooms} habitaciones</p>
</div> </div>
<div className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center"> <div className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center">
<Bed className="w-6 h-6 text-blue-600" /> <Bed className="w-6 h-6 text-blue-600" />
@@ -78,9 +101,9 @@ const HotelManagement = () => {
<CardContent className="p-6"> <CardContent className="p-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<p className="text-sm text-gray-600 mb-1">Check-ins Hoy</p> <p className="text-sm text-muted-foreground mb-1">Check-ins Hoy</p>
<p className="text-2xl font-bold text-gray-900">{stats.checkInsToday}</p> <p className="text-2xl font-bold">{stats.checkInsToday}</p>
<p className="text-xs text-gray-500">{stats.checkOutsToday} check-outs</p> <p className="text-xs text-muted-foreground">{stats.checkOutsToday} check-outs</p>
</div> </div>
<div className="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center"> <div className="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center">
<DoorOpen className="w-6 h-6 text-green-600" /> <DoorOpen className="w-6 h-6 text-green-600" />
@@ -93,9 +116,9 @@ const HotelManagement = () => {
<CardContent className="p-6"> <CardContent className="p-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<p className="text-sm text-gray-600 mb-1">Room Service</p> <p className="text-sm text-muted-foreground mb-1">Room Service</p>
<p className="text-2xl font-bold text-gray-900">{stats.roomServiceOrders}</p> <p className="text-2xl font-bold">{stats.roomServiceOrders}</p>
<p className="text-xs text-gray-500">Pedidos activos</p> <p className="text-xs text-muted-foreground">Pedidos activos</p>
</div> </div>
<div className="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center"> <div className="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center">
<BellRing className="w-6 h-6 text-purple-600" /> <BellRing className="w-6 h-6 text-purple-600" />
@@ -108,8 +131,8 @@ const HotelManagement = () => {
<CardContent className="p-6"> <CardContent className="p-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<p className="text-sm text-gray-600 mb-1">Ingresos Hoy</p> <p className="text-sm text-muted-foreground mb-1">Ingresos Hoy</p>
<p className="text-2xl font-bold text-gray-900">${stats.revenue.toLocaleString()}</p> <p className="text-2xl font-bold">${stats.revenue.toLocaleString()}</p>
<p className="text-xs text-green-600">+12% vs ayer</p> <p className="text-xs text-green-600">+12% vs ayer</p>
</div> </div>
<div className="w-12 h-12 rounded-full bg-orange-100 flex items-center justify-center"> <div className="w-12 h-12 rounded-full bg-orange-100 flex items-center justify-center">
@@ -119,168 +142,32 @@ const HotelManagement = () => {
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
)}
{/* Main Content Tabs */} {/* Sections Grid */}
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
<TabsList className="grid w-full grid-cols-6 lg:w-auto lg:inline-grid">
<TabsTrigger value="overview" className="flex items-center gap-2">
<Hotel className="w-4 h-4" />
<span className="hidden sm:inline">Resumen</span>
</TabsTrigger>
<TabsTrigger value="rooms" className="flex items-center gap-2">
<Bed className="w-4 h-4" />
<span className="hidden sm:inline">Habitaciones</span>
</TabsTrigger>
<TabsTrigger value="checkin" className="flex items-center gap-2">
<QrCode className="w-4 h-4" />
<span className="hidden sm:inline">Check-in</span>
</TabsTrigger>
<TabsTrigger value="roomservice" className="flex items-center gap-2">
<UtensilsCrossed className="w-4 h-4" />
<span className="hidden sm:inline">Room Service</span>
</TabsTrigger>
<TabsTrigger value="keyless" className="flex items-center gap-2">
<Key className="w-4 h-4" />
<span className="hidden sm:inline">Acceso</span>
</TabsTrigger>
<TabsTrigger value="staff" className="flex items-center gap-2">
<Users className="w-4 h-4" />
<span className="hidden sm:inline">Personal</span>
</TabsTrigger>
</TabsList>
<TabsContent value="overview" className="space-y-6">
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Habitaciones por Estado */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Bed className="w-5 h-5" />
Estado de Habitaciones
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div className="flex items-center justify-between p-3 bg-green-50 rounded-lg">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rounded-full bg-green-500"></div>
<span className="font-medium">Disponibles</span>
</div>
<Badge variant="secondary">{stats.available}</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-blue-50 rounded-lg">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rounded-full bg-blue-500"></div>
<span className="font-medium">Ocupadas</span>
</div>
<Badge variant="secondary">{stats.occupied}</Badge>
</div>
<div className="flex items-center justify-between p-3 bg-orange-50 rounded-lg">
<div className="flex items-center gap-3">
<div className="w-3 h-3 rounded-full bg-orange-500"></div>
<span className="font-medium">Mantenimiento</span>
</div>
<Badge variant="secondary">{stats.maintenance}</Badge>
</div>
</div>
</CardContent>
</Card>
{/* Check-ins Pendientes */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Calendar className="w-5 h-5" />
Check-ins de Hoy
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{[1, 2, 3].map((i) => (
<div key={i} className="flex items-center justify-between p-3 border rounded-lg hover:bg-gray-50 transition-colors">
<div> <div>
<p className="font-medium">Habitación {100 + i}</p> <h2 className="text-xl font-semibold mb-4">Módulos del Sistema</h2>
<p className="text-sm text-gray-600">Reserva #{1234 + i} - 2 huéspedes</p> <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{sections.map((section) => {
const Icon = section.icon;
return (
<Link key={section.path} to={section.path}>
<Card className="hover:shadow-lg transition-shadow cursor-pointer h-full">
<CardContent className="p-6">
<div className="flex items-start justify-between mb-4">
<div className={`w-12 h-12 rounded-lg bg-${section.color}-100 flex items-center justify-center`}>
<Icon className={`w-6 h-6 text-${section.color}-600`} />
</div> </div>
<div className="text-right"> <ArrowRight className="w-5 h-5 text-muted-foreground" />
<p className="text-sm font-medium">14:00</p>
<Badge variant="outline" className="mt-1">Pendiente</Badge>
</div> </div>
</div> <h3 className="font-semibold text-lg mb-2">{section.title}</h3>
))} <p className="text-sm text-muted-foreground">{section.description}</p>
</div>
<Button className="w-full mt-4" variant="outline">
Ver Todos los Check-ins
</Button>
</CardContent> </CardContent>
</Card> </Card>
</Link>
);
})}
</div> </div>
{/* Quick Actions */}
<Card>
<CardHeader>
<CardTitle>Acciones Rápidas</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<Button
variant="outline"
className="h-24 flex-col gap-2"
onClick={() => setActiveTab('checkin')}
>
<QrCode className="w-6 h-6" />
<span>Nuevo Check-in</span>
</Button>
<Button
variant="outline"
className="h-24 flex-col gap-2"
onClick={() => setActiveTab('rooms')}
>
<Bed className="w-6 h-6" />
<span>Gestionar Habitaciones</span>
</Button>
<Button
variant="outline"
className="h-24 flex-col gap-2"
onClick={() => setActiveTab('roomservice')}
>
<UtensilsCrossed className="w-6 h-6" />
<span>Room Service</span>
</Button>
<Button
variant="outline"
className="h-24 flex-col gap-2"
onClick={() => setActiveTab('keyless')}
>
<Key className="w-6 h-6" />
<span>Acceso Digital</span>
</Button>
</div> </div>
</CardContent>
</Card>
</TabsContent>
<TabsContent value="rooms">
<RoomManagement />
</TabsContent>
<TabsContent value="checkin">
<CheckInSystem />
</TabsContent>
<TabsContent value="roomservice">
<RoomService />
</TabsContent>
<TabsContent value="keyless">
<KeylessEntry />
</TabsContent>
<TabsContent value="staff">
<StaffManagement />
</TabsContent>
</Tabs>
</div> </div>
); );
}; };

View File

@@ -1,20 +1,70 @@
import { useState } from 'react'; import { Link } from 'react-router-dom';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Card, CardContent } from '@/components/ui/card';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { UtensilsCrossed, QrCode, ChefHat, Receipt, CreditCard, Package, Users as UsersIcon, ArrowRight } from 'lucide-react';
import { UtensilsCrossed, QrCode, ChefHat, Receipt } from 'lucide-react';
import DigitalMenu from '@/components/restaurant/DigitalMenu';
import TableOrders from '@/components/restaurant/TableOrders';
import KitchenDisplay from '@/components/restaurant/KitchenDisplay';
import BillManagement from '@/components/restaurant/BillManagement';
import TableConfiguration from '@/components/restaurant/TableConfiguration';
import InventoryManagement from '@/components/restaurant/InventoryManagement';
import POSTerminal from '@/components/restaurant/POSTerminal';
import StaffManagement from '@/components/restaurant/StaffManagement';
const RestaurantPOS = () => { const RestaurantPOS = () => {
const [activeOrders] = useState(12); const activeOrders = 12;
const [pendingKitchen] = useState(8); const pendingKitchen = 8;
const [dailyRevenue] = useState(4280); const dailyRevenue = 4280;
const sections = [
{
title: 'Terminal POS',
description: 'Sistema de punto de venta completo',
icon: CreditCard,
path: '/dashboard/restaurant/pos',
color: 'green'
},
{
title: 'Pedidos en Mesa',
description: 'Gestiona pedidos de todas las mesas',
icon: Receipt,
path: '/dashboard/restaurant/orders',
color: 'blue'
},
{
title: 'Display de Cocina',
description: 'Vista de pedidos para el equipo de cocina',
icon: ChefHat,
path: '/dashboard/restaurant/kitchen',
color: 'orange'
},
{
title: 'Gestión de Cuentas',
description: 'Split bill, propinas y cierre de cuentas',
icon: Receipt,
path: '/dashboard/restaurant/bills',
color: 'purple'
},
{
title: 'Configuración de Mesas',
description: 'Gestiona el layout y estado de las mesas',
icon: QrCode,
path: '/dashboard/restaurant/tables',
color: 'indigo'
},
{
title: 'Menú Digital',
description: 'Gestiona platos y genera códigos QR',
icon: UtensilsCrossed,
path: '/dashboard/restaurant/menu',
color: 'red'
},
{
title: 'Inventario',
description: 'Control de stock y reposición de productos',
icon: Package,
path: '/dashboard/restaurant/inventory',
color: 'yellow'
},
{
title: 'Personal del Restaurante',
description: 'Administra tu equipo de trabajo',
icon: UsersIcon,
path: '/dashboard/restaurant/staff',
color: 'teal'
}
];
return ( return (
<div className="container mx-auto p-6 space-y-6"> <div className="container mx-auto p-6 space-y-6">
@@ -33,164 +83,76 @@ const RestaurantPOS = () => {
{/* Stats Overview */} {/* Stats Overview */}
<div className="grid gap-4 md:grid-cols-3"> <div className="grid gap-4 md:grid-cols-3">
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardContent className="p-6">
<CardTitle className="text-sm font-medium">Pedidos Activos</CardTitle> <div className="flex items-center justify-between">
<Receipt className="h-4 w-4 text-muted-foreground" /> <div>
</CardHeader> <p className="text-sm text-muted-foreground mb-1">Pedidos Activos</p>
<CardContent> <p className="text-2xl font-bold">{activeOrders}</p>
<div className="text-2xl font-bold">{activeOrders}</div>
<p className="text-xs text-muted-foreground">En proceso ahora</p> <p className="text-xs text-muted-foreground">En proceso ahora</p>
</div>
<div className="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center">
<Receipt className="w-6 h-6 text-blue-600" />
</div>
</div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardContent className="p-6">
<CardTitle className="text-sm font-medium">En Cocina</CardTitle> <div className="flex items-center justify-between">
<ChefHat className="h-4 w-4 text-muted-foreground" /> <div>
</CardHeader> <p className="text-sm text-muted-foreground mb-1">En Cocina</p>
<CardContent> <p className="text-2xl font-bold">{pendingKitchen}</p>
<div className="text-2xl font-bold">{pendingKitchen}</div>
<p className="text-xs text-muted-foreground">Preparando</p> <p className="text-xs text-muted-foreground">Preparando</p>
</div>
<div className="w-12 h-12 rounded-full bg-orange-100 flex items-center justify-center">
<ChefHat className="w-6 h-6 text-orange-600" />
</div>
</div>
</CardContent> </CardContent>
</Card> </Card>
<Card> <Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardContent className="p-6">
<CardTitle className="text-sm font-medium">Ventas del Día</CardTitle> <div className="flex items-center justify-between">
<QrCode className="h-4 w-4 text-muted-foreground" /> <div>
</CardHeader> <p className="text-sm text-muted-foreground mb-1">Ventas del Día</p>
<CardContent> <p className="text-2xl font-bold">${dailyRevenue.toLocaleString()}</p>
<div className="text-2xl font-bold">${dailyRevenue.toLocaleString()}</div> <p className="text-xs text-green-600">+12% vs ayer</p>
<p className="text-xs text-muted-foreground">+12% vs ayer</p> </div>
<div className="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center">
<QrCode className="w-6 h-6 text-green-600" />
</div>
</div>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
{/* Main Content */} {/* Sections Grid */}
<Tabs defaultValue="pos" className="space-y-4"> <div>
<TabsList className="grid w-full grid-cols-8"> <h2 className="text-xl font-semibold mb-4">Módulos del Sistema</h2>
<TabsTrigger value="pos">POS</TabsTrigger> <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
<TabsTrigger value="orders">Pedidos</TabsTrigger> {sections.map((section) => {
<TabsTrigger value="kitchen">Cocina</TabsTrigger> const Icon = section.icon;
<TabsTrigger value="bills">Cuentas</TabsTrigger> return (
<TabsTrigger value="tables">Mesas</TabsTrigger> <Link key={section.path} to={section.path}>
<TabsTrigger value="menu">Menú</TabsTrigger> <Card className="hover:shadow-lg transition-shadow cursor-pointer h-full">
<TabsTrigger value="inventory">Inventario</TabsTrigger> <CardContent className="p-6">
<TabsTrigger value="staff">Personal</TabsTrigger> <div className="flex items-start justify-between mb-4">
</TabsList> <div className={`w-12 h-12 rounded-lg bg-${section.color}-100 flex items-center justify-center`}>
<Icon className={`w-6 h-6 text-${section.color}-600`} />
<TabsContent value="pos" className="space-y-4"> </div>
<Card> <ArrowRight className="w-5 h-5 text-muted-foreground" />
<CardHeader> </div>
<CardTitle>Terminal Punto de Venta</CardTitle> <h3 className="font-semibold mb-2">{section.title}</h3>
<CardDescription> <p className="text-sm text-muted-foreground">{section.description}</p>
Sistema POS completo conectado con inventario
</CardDescription>
</CardHeader>
<CardContent>
<POSTerminal />
</CardContent> </CardContent>
</Card> </Card>
</TabsContent> </Link>
);
<TabsContent value="menu" className="space-y-4"> })}
<Card> </div>
<CardHeader> </div>
<CardTitle>Gestión de Menú y Platos</CardTitle>
<CardDescription>
Configura tu menú y genera códigos QR para las mesas
</CardDescription>
</CardHeader>
<CardContent>
<DigitalMenu />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="orders" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Sistema de Pedidos en Mesa</CardTitle>
<CardDescription>
Gestiona pedidos de todas las mesas en tiempo real
</CardDescription>
</CardHeader>
<CardContent>
<TableOrders />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="kitchen" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Display de Cocina</CardTitle>
<CardDescription>
Vista de pedidos para el equipo de cocina
</CardDescription>
</CardHeader>
<CardContent>
<KitchenDisplay />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="bills" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Gestión de Cuentas</CardTitle>
<CardDescription>
Split bill, propinas y cierre de cuentas
</CardDescription>
</CardHeader>
<CardContent>
<BillManagement />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="tables" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Configuración de Mesas</CardTitle>
<CardDescription>
Gestiona el layout y estado de las mesas del restaurante
</CardDescription>
</CardHeader>
<CardContent>
<TableConfiguration />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="inventory" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Gestión de Inventario</CardTitle>
<CardDescription>
Control de stock, alertas y reposición de productos
</CardDescription>
</CardHeader>
<CardContent>
<InventoryManagement />
</CardContent>
</Card>
</TabsContent>
<TabsContent value="staff" className="space-y-4">
<Card>
<CardHeader>
<CardTitle>Gestión de Personal</CardTitle>
<CardDescription>
Administra tu equipo de restaurante
</CardDescription>
</CardHeader>
<CardContent>
<StaffManagement />
</CardContent>
</Card>
</TabsContent>
</Tabs>
</div> </div>
); );
}; };

View File

@@ -0,0 +1,12 @@
import CheckInSystem from '@/components/hotel/CheckInSystem';
const CheckIn = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Check-in Digital</h1>
<CheckInSystem />
</div>
);
};
export default CheckIn;

View File

@@ -0,0 +1,12 @@
import KeylessEntry from '@/components/hotel/KeylessEntry';
const KeylessAccess = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Acceso sin Llave</h1>
<KeylessEntry />
</div>
);
};
export default KeylessAccess;

View File

@@ -0,0 +1,12 @@
import RoomService from '@/components/hotel/RoomService';
const RoomServicePage = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Room Service</h1>
<RoomService />
</div>
);
};
export default RoomServicePage;

View File

@@ -0,0 +1,11 @@
import RoomManagement from '@/components/hotel/RoomManagement';
const Rooms = () => {
return (
<div className="container mx-auto p-6">
<RoomManagement />
</div>
);
};
export default Rooms;

View File

@@ -0,0 +1,12 @@
import StaffManagement from '@/components/hotel/StaffManagement';
const Staff = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Personal del Hotel</h1>
<StaffManagement />
</div>
);
};
export default Staff;

View File

@@ -0,0 +1,12 @@
import BillManagement from '@/components/restaurant/BillManagement';
const Bills = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Gestión de Cuentas</h1>
<BillManagement />
</div>
);
};
export default Bills;

View File

@@ -0,0 +1,12 @@
import InventoryManagement from '@/components/restaurant/InventoryManagement';
const Inventory = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Gestión de Inventario</h1>
<InventoryManagement />
</div>
);
};
export default Inventory;

View File

@@ -0,0 +1,12 @@
import KitchenDisplay from '@/components/restaurant/KitchenDisplay';
const Kitchen = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Display de Cocina</h1>
<KitchenDisplay />
</div>
);
};
export default Kitchen;

View File

@@ -0,0 +1,12 @@
import DigitalMenu from '@/components/restaurant/DigitalMenu';
const Menu = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Menú Digital</h1>
<DigitalMenu />
</div>
);
};
export default Menu;

View File

@@ -0,0 +1,12 @@
import TableOrders from '@/components/restaurant/TableOrders';
const Orders = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Pedidos en Mesa</h1>
<TableOrders />
</div>
);
};
export default Orders;

View File

@@ -0,0 +1,12 @@
import POSTerminal from '@/components/restaurant/POSTerminal';
const POSPage = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Terminal POS</h1>
<POSTerminal />
</div>
);
};
export default POSPage;

View File

@@ -0,0 +1,12 @@
import StaffManagement from '@/components/restaurant/StaffManagement';
const Staff = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Personal del Restaurante</h1>
<StaffManagement />
</div>
);
};
export default Staff;

View File

@@ -0,0 +1,12 @@
import TableConfiguration from '@/components/restaurant/TableConfiguration';
const Tables = () => {
return (
<div className="container mx-auto p-6">
<h1 className="text-3xl font-bold mb-6">Configuración de Mesas</h1>
<TableConfiguration />
</div>
);
};
export default Tables;