diff --git a/backend/hotel_hacienda/src/app.js b/backend/hotel_hacienda/src/app.js
index 96f2e8d..e140b56 100644
--- a/backend/hotel_hacienda/src/app.js
+++ b/backend/hotel_hacienda/src/app.js
@@ -34,6 +34,8 @@ const exchangeRoutes = require('./routes/exchange.routes');
const hotelRoutes = require('./routes/hotelpl.routes');
const restaurantRoutes = require('./routes/restaurantpl.routes');
const incomehrxRoutes = require('./routes/incomehrx.routes');
+const roomsRoutes = require('./routes/rooms.routes');
+const dashboardRoutes = require('./routes/dashboard.routes');
//Prefijo - Auth routes are public (no middleware)
app.use('/api/auth', authRoutes);
@@ -54,5 +56,7 @@ app.use('/api/purchases', authMiddleware, purchaseRoutes);
app.use('/api/exchange', authMiddleware, exchangeRoutes);
app.use('/api/hotelpl', authMiddleware, hotelRoutes);
app.use('/api/restaurantpl', authMiddleware, restaurantRoutes);
+app.use('/api/rooms', authMiddleware, roomsRoutes);
+app.use('/api/dashboard', authMiddleware, dashboardRoutes);
module.exports = app;
diff --git a/backend/hotel_hacienda/src/controllers/dashboard.controller.js b/backend/hotel_hacienda/src/controllers/dashboard.controller.js
new file mode 100644
index 0000000..1357c8c
--- /dev/null
+++ b/backend/hotel_hacienda/src/controllers/dashboard.controller.js
@@ -0,0 +1,65 @@
+const pool = require('../db/connection');
+
+const getKPIs = async (req, res) => {
+ try {
+ const today = new Date().toISOString().split('T')[0];
+
+ const [totalRooms, availableRooms, checkIns, checkOuts] = await Promise.all([
+ pool.query('SELECT COUNT(*) as count FROM rooms'),
+ pool.query("SELECT COUNT(*) as count FROM rooms WHERE status = 'available'"),
+ pool.query("SELECT COUNT(*) as count FROM reservations WHERE check_in = $1 AND status IN ('confirmed', 'checked_in')", [today]),
+ pool.query("SELECT COUNT(*) as count FROM reservations WHERE check_out = $1 AND status = 'checked_in'", [today]),
+ ]);
+
+ const total = parseInt(totalRooms.rows[0].count);
+ const available = parseInt(availableRooms.rows[0].count);
+ const occupancy = total > 0 ? Math.round(((total - available) / total) * 100) : 0;
+
+ res.json({
+ occupancy,
+ availableRooms: available,
+ totalRooms: total,
+ todayCheckIns: parseInt(checkIns.rows[0].count),
+ todayCheckOuts: parseInt(checkOuts.rows[0].count),
+ });
+ } catch (error) {
+ console.error(error);
+ res.status(500).json({ message: 'Error al obtener KPIs' });
+ }
+};
+
+const getWeeklyRevenue = async (req, res) => {
+ try {
+ const result = await pool.query(`
+ SELECT DATE(check_out) as day, COALESCE(SUM(total_amount), 0) as revenue
+ FROM reservations
+ WHERE check_out >= CURRENT_DATE - INTERVAL '7 days' AND status = 'checked_out'
+ GROUP BY DATE(check_out) ORDER BY day
+ `);
+ res.json({ weeklyRevenue: result.rows });
+ } catch (error) {
+ console.error(error);
+ res.status(500).json({ message: 'Error al obtener ingresos semanales' });
+ }
+};
+
+const getTodayArrivals = async (req, res) => {
+ try {
+ const today = new Date().toISOString().split('T')[0];
+ const result = await pool.query(`
+ SELECT r.id, r.check_in, r.check_out, r.room_id, r.status,
+ g.first_name, g.last_name, g.phone
+ FROM reservations r
+ JOIN guests g ON g.id = r.guest_id
+ WHERE (r.check_in = $1 OR r.check_out = $1)
+ AND r.status IN ('confirmed', 'checked_in')
+ ORDER BY r.check_in
+ `, [today]);
+ res.json({ arrivals: result.rows });
+ } catch (error) {
+ console.error(error);
+ res.status(500).json({ message: 'Error al obtener llegadas' });
+ }
+};
+
+module.exports = { getKPIs, getWeeklyRevenue, getTodayArrivals };
diff --git a/backend/hotel_hacienda/src/controllers/rooms.controller.js b/backend/hotel_hacienda/src/controllers/rooms.controller.js
new file mode 100644
index 0000000..ff04633
--- /dev/null
+++ b/backend/hotel_hacienda/src/controllers/rooms.controller.js
@@ -0,0 +1,62 @@
+const pool = require('../db/connection');
+
+const getRoomsWithStatus = async (req, res) => {
+ try {
+ const result = await pool.query(`
+ SELECT r.*,
+ res.id as reservation_id,
+ g.first_name || ' ' || g.last_name as guest_name,
+ g.phone as guest_phone,
+ res.check_in,
+ res.check_out
+ FROM rooms r
+ LEFT JOIN reservations res ON res.room_id = r.id_room AND res.status = 'checked_in'
+ LEFT JOIN guests g ON g.id = res.guest_id
+ ORDER BY r.floor, r.name_room
+ `);
+ res.json({ rooms: result.rows });
+ } catch (error) {
+ console.error(error);
+ res.status(500).json({ message: 'Error al obtener estado de habitaciones' });
+ }
+};
+
+const updateRoomStatus = async (req, res) => {
+ try {
+ const { id } = req.params;
+ const { status } = req.body;
+ const userId = req.user?.user_id;
+
+ const validStatuses = ['available', 'occupied', 'cleaning', 'maintenance'];
+ if (!validStatuses.includes(status)) {
+ return res.status(400).json({ message: 'Estado invalido' });
+ }
+
+ const current = await pool.query('SELECT status FROM rooms WHERE id_room = $1', [id]);
+ if (current.rows.length === 0) {
+ return res.status(404).json({ message: 'Habitacion no encontrada' });
+ }
+ const previousStatus = current.rows[0].status;
+
+ await pool.query('UPDATE rooms SET status = $1 WHERE id_room = $2', [status, id]);
+
+ await pool.query(
+ 'INSERT INTO room_status_log (room_id, previous_status, new_status, changed_by) VALUES ($1, $2, $3, $4)',
+ [id, previousStatus, status, userId]
+ );
+
+ if (status === 'cleaning') {
+ await pool.query(
+ `INSERT INTO housekeeping_tasks (room_id, priority, type, status) VALUES ($1, 'high', 'checkout', 'pending')`,
+ [id]
+ );
+ }
+
+ res.json({ message: 'Estado actualizado correctamente' });
+ } catch (error) {
+ console.error(error);
+ res.status(500).json({ message: 'Error al actualizar estado' });
+ }
+};
+
+module.exports = { getRoomsWithStatus, updateRoomStatus };
diff --git a/backend/hotel_hacienda/src/routes/dashboard.routes.js b/backend/hotel_hacienda/src/routes/dashboard.routes.js
new file mode 100644
index 0000000..91b2d54
--- /dev/null
+++ b/backend/hotel_hacienda/src/routes/dashboard.routes.js
@@ -0,0 +1,9 @@
+const express = require('express');
+const router = express.Router();
+const dashboardController = require('../controllers/dashboard.controller');
+
+router.get('/kpis', dashboardController.getKPIs);
+router.get('/weekly-revenue', dashboardController.getWeeklyRevenue);
+router.get('/today-arrivals', dashboardController.getTodayArrivals);
+
+module.exports = router;
diff --git a/backend/hotel_hacienda/src/routes/rooms.routes.js b/backend/hotel_hacienda/src/routes/rooms.routes.js
new file mode 100644
index 0000000..15f6d21
--- /dev/null
+++ b/backend/hotel_hacienda/src/routes/rooms.routes.js
@@ -0,0 +1,8 @@
+const express = require('express');
+const router = express.Router();
+const roomsController = require('../controllers/rooms.controller');
+
+router.get('/status', roomsController.getRoomsWithStatus);
+router.put('/:id/status', roomsController.updateRoomStatus);
+
+module.exports = router;
diff --git a/frontend/Frontend-Hotel/src/App.jsx b/frontend/Frontend-Hotel/src/App.jsx
index 0587c53..e55cc78 100644
--- a/frontend/Frontend-Hotel/src/App.jsx
+++ b/frontend/Frontend-Hotel/src/App.jsx
@@ -39,6 +39,7 @@ import InventoryReport from "./pages/Inventory/InventoryReport.jsx";
import NewMonthlyPayment from "./pages/Expenses/NewMonthlyPayment.jsx";
import Outcomes from "./pages/Inventory/Outcomes.jsx";
import HousekeeperOutcomes from "./pages/Inventory/HousekeeperOutcomes.jsx";
+import RoomDashboard from "./pages/RoomDashboard/RoomDashboard.jsx";
import "./styles/global.css";
//SubmenĂș de Hotel
@@ -131,6 +132,7 @@ export default function App() {
{t('common.loading')}
+ {room.bed_type} +
++ {room.floor} +
++ {t("common.name")}: {room.guest_name} +
+ {room.guest_phone && ( ++ {t("common.phone")}: {room.guest_phone} +
+ )} + {room.check_in && ( ++ {t("reservations.checkIn")}:{" "} + {new Date(room.check_in).toLocaleDateString()} +
+ )} + {room.check_out && ( ++ {t("reservations.checkOut")}:{" "} + {new Date(room.check_out).toLocaleDateString()} +
+ )} ++ ${room.cost_per_nigth} +
+