From f0ba8e3cfa936ab3a67a0c1c3b6a2c96aa3436e9 Mon Sep 17 00:00:00 2001 From: Nadeesha Jayamanne Date: Thu, 23 Oct 2025 00:47:52 +0530 Subject: [PATCH 1/3] fix: update Navbar brand link to point to the parent directory --- src/components/Layout/Navbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Layout/Navbar.js b/src/components/Layout/Navbar.js index 0125cfe..2bfcb39 100644 --- a/src/components/Layout/Navbar.js +++ b/src/components/Layout/Navbar.js @@ -52,7 +52,7 @@ const Navbar = () => { return ( - + SkyNest Hotels From 4b24222b847183bfeceb103865f90bb4f86878dc Mon Sep 17 00:00:00 2001 From: Nadeesha Jayamanne Date: Thu, 23 Oct 2025 01:17:15 +0530 Subject: [PATCH 2/3] feat: Add pre-bookings functionality with confirmation feature and tabbed interface --- src/pages/Bookings.js | 223 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 197 insertions(+), 26 deletions(-) diff --git a/src/pages/Bookings.js b/src/pages/Bookings.js index f348dca..21ca901 100644 --- a/src/pages/Bookings.js +++ b/src/pages/Bookings.js @@ -1,22 +1,25 @@ import React, { useState, useEffect } from 'react'; -import { Container, Row, Col, Card, Button, Table, Badge, Modal, Form, Alert, Spinner } from 'react-bootstrap'; -import { FaCalendarCheck, FaPlus, FaEdit, FaEye, FaSearch, FaFilter } from 'react-icons/fa'; +import { Container, Row, Col, Card, Button, Table, Badge, Modal, Form, Alert, Spinner, Tabs, Tab } from 'react-bootstrap'; +import { FaCalendarCheck, FaPlus, FaEdit, FaEye, FaSearch, FaFilter, FaCheckCircle, FaClock } from 'react-icons/fa'; import { apiUrl } from '../utils/api'; import { useBranch } from '../context/BranchContext'; const Bookings = () => { const { selectedBranchId } = useBranch(); const [bookings, setBookings] = useState([]); + const [preBookings, setPreBookings] = useState([]); const [showModal, setShowModal] = useState(false); const [selectedBooking, setSelectedBooking] = useState(null); const [modalType, setModalType] = useState('add'); const [filterStatus, setFilterStatus] = useState('All'); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); + const [activeTab, setActiveTab] = useState('bookings'); - // Fetch bookings from backend + // Fetch bookings and pre-bookings from backend useEffect(() => { fetchBookings(); + fetchPreBookings(); }, [filterStatus, selectedBranchId]); const fetchBookings = async () => { @@ -76,6 +79,79 @@ const Bookings = () => { } }; + const fetchPreBookings = async () => { + try { + setError(''); + + let url = '/api/bookings/pre-bookings?'; + if (selectedBranchId !== 'All') { + url += `branch_id=${selectedBranchId}`; + } + + const response = await fetch(apiUrl(url)); + const data = await response.json(); + + if (data.success && data.data && data.data.preBookings) { + const transformedPreBookings = data.data.preBookings.map(pb => ({ + id: `PB${String(pb.pre_booking_id).padStart(3, '0')}`, + preBookingId: pb.pre_booking_id, + guestName: pb.guest_name, + guestEmail: pb.guest_email, + guestPhone: pb.guest_phone, + hotelBranch: `SkyNest ${pb.branch_name}`, + roomNumber: pb.room_number, + roomType: pb.room_type, + checkInDate: pb.expected_check_in?.split('T')[0], + checkOutDate: pb.expected_check_out?.split('T')[0], + capacity: parseInt(pb.capacity) || 2, + method: pb.prebooking_method, + pricePerNight: parseFloat(pb.price_per_night) || 0, + createdAt: pb.created_at?.split('T')[0] + })); + + setPreBookings(transformedPreBookings); + } + } catch (err) { + console.error('Error fetching pre-bookings:', err); + } + }; + + const handleConfirmPreBooking = async (preBooking) => { + if (!window.confirm(`Confirm pre-booking ${preBooking.id} and convert it to a confirmed booking?`)) { + return; + } + + try { + const user = JSON.parse(localStorage.getItem('skyNestUser')); + const response = await fetch(apiUrl(`/api/bookings/pre-booking/${preBooking.preBookingId}/confirm`), { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${user?.token}` + }, + body: JSON.stringify({ + num_adults: preBooking.capacity, + num_children: 0, + special_requests: '' + }) + }); + + const data = await response.json(); + + if (data.success) { + alert(`✅ ${data.message}`); + // Refresh both lists + fetchBookings(); + fetchPreBookings(); + } else { + alert(`❌ ${data.error || 'Failed to confirm pre-booking'}`); + } + } catch (err) { + console.error('Error confirming pre-booking:', err); + alert('❌ Failed to confirm pre-booking'); + } + }; + const handleCreateBooking = async (newBookingData) => { try { const res = await fetch(`${API_URL}/confirmed`, { @@ -224,32 +300,43 @@ const Bookings = () => { - {/* Filters */} - - - - - Filter by Status - - setFilterStatus(e.target.value)} - > - - - - - - - - - - - - {/* Bookings Table */} + {/* Tabs for Bookings and Pre-Bookings */} + + setActiveTab(k)} + className="mb-3" + > + Confirmed Bookings ({bookings.length}) + }> + {/* Filters */} + + + + + Filter by Status + + setFilterStatus(e.target.value)} + > + + + + + + + + + + + + {/* Bookings Table */} +
Bookings List ({filteredBookings.length}) @@ -337,6 +424,90 @@ const Bookings = () => { + + + + Pre-Bookings ({preBookings.length}) + }> + {/* Pre-Bookings Table */} + + +
+ Pending Pre-Bookings ({preBookings.length}) +
+
+ +
+ + + + + + + + + + + + + + + + {preBookings.length === 0 ? ( + + + + ) : ( + preBookings.map((preBooking) => ( + + + + + + + + + + + + )) + )} + +
Pre-Booking IDGuest NameHotel/RoomExpected Check-inExpected Check-outCapacityMethodCreatedActions
+

No pending pre-bookings

+
+ {preBooking.id} + +
+ {preBooking.guestName} +
+ {preBooking.guestEmail} +
+
+
+ {preBooking.hotelBranch} +
+ Room {preBooking.roomNumber} ({preBooking.roomType}) +
+
{new Date(preBooking.checkInDate).toLocaleDateString()}{new Date(preBooking.checkOutDate).toLocaleDateString()}{preBooking.capacity} guests + {preBooking.method} + {new Date(preBooking.createdAt).toLocaleDateString()} + +
+
+
+
+
+ + From 11578e0ee5bb19e12e3051ce575c7de471e9f4b2 Mon Sep 17 00:00:00 2001 From: Nadeesha Jayamanne Date: Thu, 23 Oct 2025 01:19:38 +0530 Subject: [PATCH 3/3] refactor: Remove action buttons from Employees table for cleaner UI --- src/pages/Employees.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/pages/Employees.js b/src/pages/Employees.js index 67c4a00..4801eee 100644 --- a/src/pages/Employees.js +++ b/src/pages/Employees.js @@ -290,7 +290,6 @@ const Employees = () => { Phone Branch Role - Actions @@ -310,23 +309,6 @@ const Employees = () => { {employee.role || 'Staff'} - - - - ))}