From 6fde01f2f74301455c8e56ff25eb9b9268092b09 Mon Sep 17 00:00:00 2001 From: Nasirucode Date: Tue, 3 Feb 2026 20:31:11 +0100 Subject: [PATCH 1/5] Fix: Added direct room booking --- .../src/components/HomePage/RoomsModal.jsx | 161 ++++++++++++++++++ dashboard/src/lib/utils.js | 19 +++ dashboard/src/pages/Home.jsx | 36 +++- dashboard/src/stores/useCartStore.js | 1 + 4 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 dashboard/src/components/HomePage/RoomsModal.jsx diff --git a/dashboard/src/components/HomePage/RoomsModal.jsx b/dashboard/src/components/HomePage/RoomsModal.jsx new file mode 100644 index 0000000..d2ee1d8 --- /dev/null +++ b/dashboard/src/components/HomePage/RoomsModal.jsx @@ -0,0 +1,161 @@ +import { useEffect, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { Badge } from "@/components/ui/badge"; +import { call } from "@/lib/frappeClient"; +import { useCartStore } from "@/stores/useCartStore"; +import Loader from "@/components/Loader"; + +const RoomsModal = ({ open, onOpenChange }) => { + const [rooms, setRooms] = useState([]); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const navigate = useNavigate(); + const { startNewTakeAwayOrder, setCustomer, setCustomerName } = useCartStore(); + + useEffect(() => { + if (open) { + fetchRooms(); + } else { + // Reset state when modal closes + setRooms([]); + setError(null); + } + }, [open]); + + const fetchRooms = async () => { + setLoading(true); + setError(null); + try { + const response = await call.get("havano_restaurant_pos.api.get_booked_rooms"); + if (response.message && response.message.success) { + setRooms(response.message.rooms || []); + } else { + setError(response.message?.message || "Failed to fetch rooms"); + } + } catch (err) { + console.error("Error fetching rooms:", err); + setError(err?.message || "Failed to fetch rooms"); + } finally { + setLoading(false); + } + }; + + const handleRoomSelect = (room) => { + if (!room.customer) { + setError(`Room ${room.room_number} does not have a customer assigned. Please ensure the guest has a customer linked.`); + return; + } + + // Set customer from room guest + setCustomer(room.customer); + setCustomerName(room.customer_name || room.customer); + + // Start a new take away order with room customer + startNewTakeAwayOrder(); + + // Close modal and navigate to menu + onOpenChange(false); + navigate("/menu"); + }; + + return ( + + + + Select Room + + Choose a room to bill for the guest. The order will be billed under the customer/guest in the occupied room. + + + + {loading && ( +
+ +
+ )} + + {error && !loading && ( +
+ {error} +
+ )} + + {!loading && !error && rooms.length === 0 && ( +
+ No booked rooms available at the moment. +
+ )} + + {!loading && !error && rooms.length > 0 && ( +
+ {rooms.map((room) => ( +
room.customer && handleRoomSelect(room)} + > +
+
+

Room {room.room_number}

+ {room.room_name && room.room_name !== room.room_number && ( +

{room.room_name}

+ )} +
+ + {room.status} + +
+ + {room.room_type && ( +

+ Type: {room.room_type} +

+ )} + + {room.floor && ( +

+ Floor: {room.floor} +

+ )} + + {room.guest_name && ( +

+ Guest: {room.guest_name} +

+ )} + + {room.customer_name && ( +

+ Customer: {room.customer_name} +

+ )} + + {!room.customer && ( +

+ No customer assigned +

+ )} +
+ ))} +
+ )} +
+
+ ); +}; + +export default RoomsModal; diff --git a/dashboard/src/lib/utils.js b/dashboard/src/lib/utils.js index 7ef5441..5b92720 100644 --- a/dashboard/src/lib/utils.js +++ b/dashboard/src/lib/utils.js @@ -362,6 +362,25 @@ export async function isRestaurantMode() { } +export async function isRoomDirectBookingsEnabled() { + try { + const { message } = await db.getSingleValue( + "HA POS Settings", + "enable_room_direct_bookings" + ); + if (message && typeof message === "object") { + return Boolean(message.enable_room_direct_bookings); + } + if (typeof message === "string") { + return Boolean(Number(message)); + } + return Boolean(message); + } catch (err) { + console.error("Error fetching HA POS Settings.enable_room_direct_bookings:", err); + return false; + } +} + /** * Get user transaction type mappings from HA POS Setting * Returns array of transaction types available for the current user diff --git a/dashboard/src/pages/Home.jsx b/dashboard/src/pages/Home.jsx index 5a3e306..bc23641 100644 --- a/dashboard/src/pages/Home.jsx +++ b/dashboard/src/pages/Home.jsx @@ -3,6 +3,7 @@ import { useNavigate } from "react-router-dom"; import Clock from "@/components/HomePage/Clock"; import OrdersList from "@/components/HomePage/OrdersList"; +import RoomsModal from "@/components/HomePage/RoomsModal"; import Container from "@/components/Shared/Container"; import { Button } from "@/components/ui/button"; import { @@ -17,6 +18,7 @@ import { getCurrentUserFullName, getNumberOfOrders, isRestaurantMode, + isRoomDirectBookingsEnabled, } from "@/lib/utils"; import { useCartStore } from "@/stores/useCartStore"; import { useMenuStore } from "@/stores/useMenuStore"; @@ -28,6 +30,8 @@ const Home = () => { const [userName, setUserName] = useState(null); const [popularItems, setPopularItems] = useState([]); const [restModeEnabled, setRestModeEnabled] = useState(false); + const [roomBookingsEnabled, setRoomBookingsEnabled] = useState(false); + const [showRoomsModal, setShowRoomsModal] = useState(false); useEffect(() => { @@ -67,6 +71,23 @@ const Home = () => { }; }, []); + useEffect(() => { + let cancelled = false; + const loadRoomBookings = async () => { + try { + const enabled = await isRoomDirectBookingsEnabled(); + if (!cancelled) setRoomBookingsEnabled(Boolean(enabled)); + } catch (err) { + console.error("Failed to load Room Direct Bookings:", err); + if (!cancelled) setRoomBookingsEnabled(false); + } + }; + loadRoomBookings(); + return () => { + cancelled = true; + }; + }, []); + useEffect(() => { if (!menuItems || menuItems.length === 0) { setPopularItems([]); @@ -163,8 +184,20 @@ const Home = () => { } className={!restModeEnabled ? "opacity-50 cursor-not-allowed" : ""} > - DINE IN + TABLES + {roomBookingsEnabled && ( + + )} - {roomBookingsEnabled && ( - - )}