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