Implement Hotel Management module
This commit is contained in:
279
src/pages/dashboard/HotelManagement.tsx
Normal file
279
src/pages/dashboard/HotelManagement.tsx
Normal file
@@ -0,0 +1,279 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Hotel,
|
||||
DoorOpen,
|
||||
BellRing,
|
||||
QrCode,
|
||||
Users,
|
||||
Bed,
|
||||
Calendar,
|
||||
Clock,
|
||||
CheckCircle,
|
||||
AlertCircle,
|
||||
Sparkles,
|
||||
UtensilsCrossed,
|
||||
Key
|
||||
} 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';
|
||||
|
||||
const HotelManagement = () => {
|
||||
const [activeTab, setActiveTab] = useState('overview');
|
||||
|
||||
// Stats de ejemplo
|
||||
const stats = {
|
||||
totalRooms: 120,
|
||||
occupied: 85,
|
||||
available: 25,
|
||||
maintenance: 10,
|
||||
checkInsToday: 15,
|
||||
checkOutsToday: 12,
|
||||
roomServiceOrders: 8,
|
||||
revenue: 45600
|
||||
};
|
||||
|
||||
const occupancyRate = ((stats.occupied / stats.totalRooms) * 100).toFixed(1);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-blue-50 via-white to-purple-50 p-6">
|
||||
{/* Header */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-blue-500 to-purple-500 flex items-center justify-center">
|
||||
<Hotel className="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-gray-900">Hotel Management</h1>
|
||||
<p className="text-gray-600">Sistema integral de gestión hotelera</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Overview Stats */}
|
||||
{activeTab === 'overview' && (
|
||||
<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">
|
||||
<CardContent className="p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-600 mb-1">Ocupación</p>
|
||||
<p className="text-2xl font-bold text-gray-900">{occupancyRate}%</p>
|
||||
<p className="text-xs text-gray-500">{stats.occupied}/{stats.totalRooms} habitaciones</p>
|
||||
</div>
|
||||
<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" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-l-4 border-l-green-500">
|
||||
<CardContent className="p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-600 mb-1">Check-ins Hoy</p>
|
||||
<p className="text-2xl font-bold text-gray-900">{stats.checkInsToday}</p>
|
||||
<p className="text-xs text-gray-500">{stats.checkOutsToday} check-outs</p>
|
||||
</div>
|
||||
<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" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-l-4 border-l-purple-500">
|
||||
<CardContent className="p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-600 mb-1">Room Service</p>
|
||||
<p className="text-2xl font-bold text-gray-900">{stats.roomServiceOrders}</p>
|
||||
<p className="text-xs text-gray-500">Pedidos activos</p>
|
||||
</div>
|
||||
<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" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="border-l-4 border-l-orange-500">
|
||||
<CardContent className="p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-sm text-gray-600 mb-1">Ingresos Hoy</p>
|
||||
<p className="text-2xl font-bold text-gray-900">${stats.revenue.toLocaleString()}</p>
|
||||
<p className="text-xs text-green-600">+12% vs ayer</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 rounded-full bg-orange-100 flex items-center justify-center">
|
||||
<Sparkles className="w-6 h-6 text-orange-600" />
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Main Content Tabs */}
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
|
||||
<TabsList className="grid w-full grid-cols-5 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>
|
||||
</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>
|
||||
<p className="font-medium">Habitación {100 + i}</p>
|
||||
<p className="text-sm text-gray-600">Reserva #{1234 + i} - 2 huéspedes</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-sm font-medium">14:00</p>
|
||||
<Badge variant="outline" className="mt-1">Pendiente</Badge>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Button className="w-full mt-4" variant="outline">
|
||||
Ver Todos los Check-ins
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</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>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="rooms">
|
||||
<RoomManagement />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="checkin">
|
||||
<CheckInSystem />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="roomservice">
|
||||
<RoomService />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="keyless">
|
||||
<KeylessEntry />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HotelManagement;
|
||||
Reference in New Issue
Block a user