diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6a007ee..3c0cbd6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -16,6 +16,7 @@ "jwt-decode": "^4.0.0", "leaflet": "^1.9.4", "react": "^18.3.1", + "react-datepicker": "^7.4.0", "react-dom": "^18.3.1", "react-icons": "^5.3.0", "react-leaflet": "^4.2.1", @@ -2177,6 +2178,14 @@ "node": ">=0.8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "engines": { + "node": ">=6" + } + }, "node_modules/code-block-writer": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", @@ -2362,6 +2371,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", @@ -5239,6 +5257,47 @@ "node": ">=0.10.0" } }, + "node_modules/react-datepicker": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-7.4.0.tgz", + "integrity": "sha512-vSSok4DTZ9/Os8O4HjZLxh4SZVFU6dQvoCX6mfbNdBqMsBBdzftrvMz0Nb4UUVVbgj9o8PfX84K3/31oPrTqmg==", + "dependencies": { + "@floating-ui/react": "^0.26.23", + "clsx": "^2.1.1", + "date-fns": "^3.6.0", + "prop-types": "^15.8.1" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17 || ^18", + "react-dom": "^16.9.0 || ^17 || ^18" + } + }, + "node_modules/react-datepicker/node_modules/@floating-ui/react": { + "version": "0.26.24", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.24.tgz", + "integrity": "sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw==", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-datepicker/node_modules/@floating-ui/react-dom": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", + "integrity": "sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==", + "dependencies": { + "@floating-ui/dom": "^1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index 9b32f06..0907ab9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,6 +19,7 @@ "jwt-decode": "^4.0.0", "leaflet": "^1.9.4", "react": "^18.3.1", + "react-datepicker": "^7.4.0", "react-dom": "^18.3.1", "react-icons": "^5.3.0", "react-leaflet": "^4.2.1", diff --git a/frontend/src/Pages/booking.jsx b/frontend/src/Pages/booking.jsx index 07dbc73..08bf9bb 100644 --- a/frontend/src/Pages/booking.jsx +++ b/frontend/src/Pages/booking.jsx @@ -2,200 +2,205 @@ import React, { useState, useEffect } from 'react'; import { IoCalendarOutline, IoArrowBack } from 'react-icons/io5'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; - +import DatePicker from 'react-datepicker'; // Import DatePicker +import 'react-datepicker/dist/react-datepicker.css'; // Import default styles const BookingPage = () => { - const [station, setStation] = useState(''); // Holds the typed input - const [selectedStation, setSelectedStation] = useState(null); // Holds the selected station - const [date, setDate] = useState(''); - const [services, setServices] = useState([ - { id: 'cloak', name: 'Cloak Room Booking', availability: 0 }, - { id: 'wheelchair', name: 'Wheelchair Booking', availability: 0 }, - { id: 'coolie', name: 'Coolie Booking', availability: 0 } - ]); - const [stationSuggestions, setStationSuggestions] = useState([]); // Holds station suggestions - const [loading, setLoading] = useState(false); - const [error, setError] = useState(''); // Track errors - const [noResults, setNoResults] = useState(false); // Track if no stations are found - const navigate = useNavigate(); - - // Fetch stations suggestions as the user types - const fetchStationSuggestions = async (query) => { - try { - const response = await axios.get(`http://localhost:3000/station/`); - - if (response.data.length > 0) { - setStationSuggestions(response.data); // The response should include station _id and name - setNoResults(false); // Reset no results flag - } else { - setStationSuggestions([]); - setNoResults(true); // Set flag if no matching stations are found - } - } catch (err) { - setError("Error fetching station suggestions. Please try again."); - setNoResults(false); // Clear no results if there’s an error - } - }; - - - // Function to fetch service availability data from the backend - const fetchServiceData = async (stationId) => { - try { - setLoading(true); - const response = await axios.get(`http://localhost:3000/station/${stationId}/bookings`); - const { coolieBookings, wheelchairBookings, cloakroomBookings } = response.data; - - // Update the availability in the services array - setServices([ - { id: 'cloak', name: 'Cloak Room Booking', availability: cloakroomBookings.length }, - { id: 'wheelchair', name: 'Wheelchair Booking', availability: wheelchairBookings.length }, - { id: 'coolie', name: 'Coolie Booking', availability: coolieBookings.length } - ]); - - setLoading(false); - } catch (err) { - setError('Error fetching service data. Please try again.'); - setLoading(false); - } - }; - - // Fetch service availability when the selected station is updated - useEffect(() => { - if (selectedStation) { - fetchServiceData(selectedStation._id); // Assuming station ID is _id - } - }, [selectedStation]); - - // Handle station input change - const handleStationInputChange = (e) => { - const value = e.target.value; - setStation(value); - setError(''); // Clear error message on input change - - if (value.length > 2) { - // Fetch station suggestions when input has more than 2 characters - fetchStationSuggestions(value); + useEffect(() => { + document.title = 'Station Saarthi | Booking'; + }, []); + + const [station, setStation] = useState(''); // Holds the typed input + const [selectedStation, setSelectedStation] = useState(null); // Holds the selected station + const [date, setDate] = useState(null); // Initial date state for DatePicker + const [services, setServices] = useState([ + { id: 'cloak', name: 'Cloak Room Booking', availability: 0 }, + { id: 'wheelchair', name: 'Wheelchair Booking', availability: 0 }, + { id: 'coolie', name: 'Coolie Booking', availability: 0 } + ]); + const [stationSuggestions, setStationSuggestions] = useState([]); // Holds station suggestions + const [loading, setLoading] = useState(false); + const [error, setError] = useState(''); // Track errors + const [noResults, setNoResults] = useState(false); // Track if no stations are found + const navigate = useNavigate(); + + // Fetch stations suggestions as the user types + const fetchStationSuggestions = async (query) => { + try { + const response = await axios.get(`http://localhost:3000/station/`); + + if (response.data.length > 0) { + setStationSuggestions(response.data); // The response should include station _id and name + setNoResults(false); // Reset no results flag } else { - setStationSuggestions([]); // Clear suggestions if input is too short - setNoResults(false); // Clear no results if input is too short + setStationSuggestions([]); + setNoResults(true); // Set flag if no matching stations are found } - }; - - // Handle station selection from suggestions - const handleStationSelect = (station) => { - setSelectedStation(station); // Set the selected station - setStation(station.name); // Update the input value with the selected station's name - setStationSuggestions([]); // Clear the suggestions after selection - setError(''); // Clear any previous errors - }; - - return ( -
No stations found matching your search.
+ )} + + {/* Handle errors */} + {error && ( +{error}
+ )}No stations found matching your search.
- )} - - {/* Handle errors */} - {error && ( -{error}
- )} -Loading services...
- ) : error && !stationSuggestions.length ? ( -{error}
- ) : ( -Loading services...
+ ) : ( +