[cfc16a3] | 1 | import React, {useState, useEffect, useContext} from 'react';
|
---|
[d24f17c] | 2 | import 'bootstrap/dist/css/bootstrap.min.css';
|
---|
| 3 | import StarRating from './StarRating';
|
---|
| 4 | import { useNavigate } from 'react-router-dom';
|
---|
[cfc16a3] | 5 | import {RestaurantContext} from "./RestaurantContext";
|
---|
[f5b256e] | 6 | import {Alert} from "bootstrap";
|
---|
| 7 |
|
---|
| 8 | const parseTime = (timeString) => {
|
---|
| 9 | const [hours, minutes] = timeString.trim().split(':').map(Number);
|
---|
| 10 | return new Date().setHours(hours, minutes, 0, 0);
|
---|
| 11 | };
|
---|
| 12 |
|
---|
| 13 | const roundToNextQuarter = (date) => {
|
---|
| 14 | const minutes = date.getMinutes();
|
---|
| 15 | const roundedMinutes = Math.floor(minutes / 15) * 15;
|
---|
| 16 | date.setMinutes(roundedMinutes, 0, 0);
|
---|
| 17 | return date;
|
---|
| 18 | };
|
---|
| 19 |
|
---|
| 20 | const shouldMoveToNextDay = (currentTime, endTime) => {
|
---|
| 21 | return (endTime - currentTime) <= 2 * 60 * 60 * 1000;
|
---|
| 22 | };
|
---|
[d24f17c] | 23 |
|
---|
| 24 | const Restaurants = () => {
|
---|
| 25 | const [restaurants, setRestaurants] = useState([]);
|
---|
| 26 | const navigate = useNavigate();
|
---|
[cfc16a3] | 27 | const restaurantContext = useContext(RestaurantContext);
|
---|
[2518b3a] | 28 | console.log(restaurantContext)
|
---|
[d24f17c] | 29 |
|
---|
| 30 | useEffect(() => {
|
---|
[cfc16a3] | 31 | setRestaurants(restaurantContext.restaurants);
|
---|
| 32 | }, [restaurantContext]);
|
---|
[d24f17c] | 33 |
|
---|
[f5b256e] | 34 |
|
---|
| 35 | const generateTimeSlots = (operatingHours) => {
|
---|
| 36 | const timeSlots = [];
|
---|
| 37 | const [startTimeStr, endTimeStr] = operatingHours.split('-').map((time) => time.trim());
|
---|
| 38 |
|
---|
| 39 | const startTime = parseTime(startTimeStr);
|
---|
| 40 | let endTime = parseTime(endTimeStr);
|
---|
| 41 |
|
---|
| 42 | const currentTime = new Date().getTime();
|
---|
| 43 | if (shouldMoveToNextDay(currentTime, endTime)) {
|
---|
| 44 | endTime += 24 * 60 * 60 * 1000;
|
---|
| 45 | }
|
---|
| 46 |
|
---|
| 47 | let currentTimeSlot = new Date(startTime);
|
---|
| 48 | currentTimeSlot = roundToNextQuarter(currentTimeSlot);
|
---|
| 49 |
|
---|
| 50 | while (currentTimeSlot.getTime() < endTime) {
|
---|
| 51 | timeSlots.push(currentTimeSlot.toISOString());
|
---|
| 52 | currentTimeSlot.setMinutes(currentTimeSlot.getMinutes() + 15);
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | return timeSlots;
|
---|
| 56 | };
|
---|
| 57 |
|
---|
[d24f17c] | 58 | const handleDetailClick = (restaurantId) => {
|
---|
| 59 | navigate(`/restaurants/${restaurantId}`);
|
---|
[f5b256e] | 60 | };
|
---|
[d24f17c] | 61 |
|
---|
| 62 | const handleTimeSlotClick = (table, timeSlot, restaurant) => {
|
---|
| 63 | const tableNumber = table.id;
|
---|
| 64 | const formattedTimeSlot = timeSlot;
|
---|
| 65 | const restaurantId = restaurant.restaurantId;
|
---|
| 66 |
|
---|
[f5b256e] | 67 | const encodedTableNumber = encodeURIComponent(tableNumber);
|
---|
[d24f17c] | 68 | const encodedTimeSlot = encodeURIComponent(formattedTimeSlot);
|
---|
| 69 | const encodedRestaurantId = encodeURIComponent(restaurantId);
|
---|
| 70 |
|
---|
| 71 | navigate(`/reservationConfirmation/${encodedTableNumber}/${encodedTimeSlot}/${encodedRestaurantId}`);
|
---|
[f5b256e] | 72 | };
|
---|
[d24f17c] | 73 |
|
---|
| 74 | const renderTimeSlots = (tablesList, restaurant) => {
|
---|
| 75 | const currentTime = new Date().getTime();
|
---|
[f5b256e] | 76 | let renderedTimeSlots = {};
|
---|
| 77 |
|
---|
| 78 | if (tablesList.length === 0) {
|
---|
| 79 | return <p>No tables available for reservations at this restaurant.</p>;
|
---|
| 80 | }
|
---|
| 81 |
|
---|
| 82 | return tablesList.flatMap((table) => {
|
---|
| 83 | const tableTimeSlots = generateTimeSlots(restaurant.operatingHours);
|
---|
[d24f17c] | 84 |
|
---|
| 85 | if (!renderedTimeSlots[table.capacity]) {
|
---|
| 86 | renderedTimeSlots[table.capacity] = 0;
|
---|
| 87 | return (
|
---|
| 88 | <div key={table.capacity}>
|
---|
[f5b256e] | 89 | <h3>Table for {table.capacity} guests</h3>
|
---|
| 90 | {tableTimeSlots.map((timeSlot, index) => {
|
---|
[d24f17c] | 91 | const timeSlotTime = new Date(timeSlot).getTime();
|
---|
| 92 |
|
---|
[f5b256e] | 93 | if (timeSlotTime > currentTime && renderedTimeSlots[table.capacity] < 3) {
|
---|
| 94 | renderedTimeSlots[table.capacity]++;
|
---|
[d24f17c] | 95 | const timeSlotDateTime = new Date(timeSlot);
|
---|
[f5b256e] | 96 | const formattedTime = timeSlotDateTime.toLocaleTimeString([], {
|
---|
| 97 | hour: '2-digit',
|
---|
| 98 | minute: '2-digit'
|
---|
| 99 | });
|
---|
[d24f17c] | 100 |
|
---|
| 101 | return (
|
---|
[f5b256e] | 102 | <button
|
---|
| 103 | key={index}
|
---|
| 104 | className="btn btn-primary me-2 mb-2"
|
---|
| 105 | onClick={() => handleTimeSlotClick(table, timeSlot, restaurant)}
|
---|
| 106 | >
|
---|
| 107 | {formattedTime} {}
|
---|
[d24f17c] | 108 | </button>
|
---|
| 109 | );
|
---|
| 110 | } else {
|
---|
[f5b256e] | 111 | return null;
|
---|
[d24f17c] | 112 | }
|
---|
| 113 | })}
|
---|
| 114 | </div>
|
---|
| 115 | );
|
---|
| 116 | } else {
|
---|
| 117 | return null;
|
---|
| 118 | }
|
---|
| 119 | });
|
---|
[f5b256e] | 120 | };
|
---|
[d24f17c] | 121 |
|
---|
| 122 | return (
|
---|
| 123 | <div className="container">
|
---|
| 124 | <h2>Restaurants</h2>
|
---|
| 125 | <div className="row">
|
---|
| 126 | {restaurants.map((restaurant) => (
|
---|
[f5b256e] | 127 | <div key={restaurant.restaurantId} className="col-md-4 mb-4">
|
---|
[d24f17c] | 128 | <div className="card">
|
---|
| 129 | <div className="card-body">
|
---|
| 130 | <h5 className="card-title">
|
---|
[f5b256e] | 131 | {restaurant.name}
|
---|
[d24f17c] | 132 | </h5>
|
---|
| 133 | <p className="card-text">{restaurant.cuisineType}</p>
|
---|
| 134 | <p className="card-text">{restaurant.operatingHours}</p>
|
---|
| 135 | <p className="card-text">Ul. {restaurant.address}</p>
|
---|
[f5b256e] | 136 |
|
---|
| 137 | {restaurant.tablesList && restaurant.tablesList.length > 0 ? (
|
---|
| 138 | <div className="d-flex flex-wrap">
|
---|
| 139 | {renderTimeSlots(restaurant.tablesList, restaurant)}
|
---|
| 140 | </div>
|
---|
| 141 | ) : (
|
---|
| 142 | <p>No tables available for reservations at this restaurant.</p>
|
---|
| 143 | )}
|
---|
[d24f17c] | 144 | </div>
|
---|
[f5b256e] | 145 | <button onClick={() => handleDetailClick(restaurant.restaurantId)} className="btn btn-primary">
|
---|
| 146 | View Details
|
---|
[cfc16a3] | 147 | </button>
|
---|
[d24f17c] | 148 | </div>
|
---|
| 149 | </div>
|
---|
| 150 | ))}
|
---|
| 151 | </div>
|
---|
| 152 | </div>
|
---|
| 153 | );
|
---|
| 154 | };
|
---|
| 155 |
|
---|
[f5b256e] | 156 | export default Restaurants;
|
---|