source: my-react-app/src/components/ReservationEdit.js@ f5b256e

main
Last change on this file since f5b256e was f5b256e, checked in by Aleksandar Panovski <apano77@…>, 3 weeks ago

Big change done works with handle_reservation_update() trigger

  • Property mode set to 100644
File size: 11.2 KB
Line 
1import React, { useState, useEffect } from 'react';
2import axios from 'axios';
3import {useNavigate, useParams} from 'react-router-dom';
4import StarRating from "./StarRating";
5import {jwtDecode} from "jwt-decode";
6
7const ReservationEdit = () => {
8 const navigate = useNavigate();
9 const { reservationId } = useParams();
10 const [isLoading, setIsLoading] = useState(true);
11 const [formData, setFormData] = useState({});
12 const [tableNumber, setTableNumber] = useState({});
13 const [table, setTable] = useState({});
14 const [restaurant, setRestaurant] = useState({});
15 const [restaurantId, setRestaurantId] = useState({});
16 const [timeSlots, setTimeSlots] = useState([]);
17 const [filteredTimeSlots, setFilteredTimeSlots] = useState([]);
18 const [checkInTime, setCheckInTime] = useState([]);
19 const [tableReservations, setTableReservations] = useState([]);
20
21 const timeSlotInterval = 15;
22
23 const [selectedDate, setSelectedDate] = useState('');
24 const [selectedTime, setSelectedTime] = useState('');
25 const [timeOptions, setTimeOptions] = useState([]);
26
27 useEffect(() => {
28 const fetchReservation = async () => {
29 try {
30 setIsLoading(true);
31 const response = await axios.get(`http://localhost:8081/api/reservations/${reservationId}`);
32 console.log(response)
33 setCheckInTime(response.data.reservationDateTime);
34 setFormData(response.data);
35 setRestaurant(response.data.restaurantName);
36 setRestaurantId(response.data.restaurantId);
37
38 setTableNumber(response.data.tableNumber);
39 const tableResponse = await axios.get(`http://localhost:8081/api/tables/${response.data.tableNumber}`);
40 setTable(tableResponse.data)
41
42 setIsLoading(false);
43 } catch (error) {
44 console.error('Error fetching reservation:', error);
45 }
46 };
47
48 fetchReservation();
49 }, [reservationId]);
50
51 useEffect(() => {
52 const fetchTableReservations = async () => {
53 try {
54 const response = await axios.get(`http://localhost:8081/api/table-reservations/${table.tableId}`);
55 setTableReservations(response.data);
56 setIsLoading(false);
57 } catch (error) {
58 console.error('Error fetching table reservations:', error);
59 }
60 };
61
62 if (table?.tableId) {
63 fetchTableReservations();
64 }
65 }, [table]);
66
67 const generateTimeSlots = (operatingHours, interval) => {
68 const slots = [];
69 const [startTimeStr, endTimeStr] = operatingHours.split('-');
70 const [startHours, startMinutes] = startTimeStr.split(':').map(Number);
71 const [endHours, endMinutes] = endTimeStr.split(':').map(Number);
72
73 const startTime = new Date();
74 startTime.setHours(startHours, startMinutes, 0, 0);
75
76 const endTime = new Date();
77 endTime.setHours(endHours, endMinutes, 0, 0);
78
79 let currentTime = startTime;
80 while (currentTime <= endTime) {
81 slots.push(new Date(currentTime).toISOString());
82 currentTime = new Date(currentTime.getTime() + interval * 60000);
83 }
84
85 return slots;
86 };
87
88 const generateTimeOptions = (operatingHours) => {
89 const { startTime, endTime } = parseOperatingHours(operatingHours);
90 const now = new Date();
91
92 const selectedDateObj = new Date(selectedDate);
93 const isToday = selectedDateObj.toDateString() === now.toDateString();
94 const isTomorrow = selectedDateObj > now && selectedDateObj.getDate() === now.getDate() + 1;
95
96 let currentTime;
97
98 if (isToday) {
99 currentTime = roundToNext15Minutes(new Date());
100 } else {
101 currentTime = new Date(startTime);
102 }
103
104 const options = [];
105 while (currentTime <= endTime) {
106 options.push(currentTime.toTimeString().slice(0, 5));
107 currentTime = new Date(currentTime.getTime() + 15 * 60 * 1000);
108 }
109
110 return options;
111 };
112
113 useEffect(() => {
114 const operatingHours = table?.restaurant?.operatingHours || "09:00-00:00";
115 const allTimeSlots = generateTimeSlots(operatingHours, timeSlotInterval);
116
117 const availableSlots = allTimeSlots.filter((slot) =>
118 !tableReservations.includes(slot)
119 );
120
121 setFilteredTimeSlots(availableSlots);
122 }, [tableReservations, table]);
123
124 const handleInputChange = (e) => {
125 const { name, value } = e.target;
126
127 if (name === 'partySize') {
128 const valueAsNumber = Math.min(value, table?.capacity);
129 setFormData(prevState => ({
130 ...prevState,
131 [name]: valueAsNumber
132 }));
133 } else {
134 setFormData(prevState => ({
135 ...prevState,
136 [name]: value
137 }));
138 }
139 };
140
141
142 const handleSubmit = async (e) => {
143 e.preventDefault();
144
145 try {
146 const token = localStorage.getItem("token");
147 if (!token) {
148 console.error("No token found");
149 return;
150 }
151
152 const decodedToken = jwtDecode(token);
153 const userId = decodedToken.iss;
154
155 const updatedReservationData = {
156 ...formData,
157 reservationDateTime: `${selectedDate}T${selectedTime}`,
158 checkInTime: checkInTime,
159 reservationID: reservationId,
160 };
161 await axios.post(
162 `http://localhost:8081/api/reservations/${reservationId}/${userId}`,
163 updatedReservationData,
164 {
165 headers: {
166 'Content-Type': 'application/json',
167 }
168 }
169 );
170 console.log(updatedReservationData)
171
172 navigate(`/reservations`);
173 } catch (error) {
174 console.error('Error updating reservation:', error);
175 }
176 };
177
178 const formatTimeSlot = (timeSlot) => {
179 const date = new Date(timeSlot);
180 const formattedDate = date.toLocaleDateString();
181 const formattedTime = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
182 return `${formattedDate} - ${formattedTime}`;
183 };
184
185 const today = new Date();
186 const year = today.getFullYear();
187 const month = String(today.getMonth() + 1).padStart(2, '0');
188 const day = String(today.getDate()).padStart(2, '0');
189 const formattedDate = `${year}-${month}-${day}`;
190
191 const parseOperatingHours = (operatingHours) => {
192 const [start, end] = operatingHours.split('-');
193 return {
194 startTime: new Date(`1970-01-01T${start}:00`),
195 endTime: new Date(`1970-01-01T${end}:00`)
196 };
197 };
198
199 useEffect(() => {
200 if (formData?.restaurant?.operatingHours && selectedDate) {
201 const options = generateTimeOptions(formData.restaurant.operatingHours);
202 setTimeOptions(options);
203 }
204 }, [restaurant, selectedDate]);
205
206 // useEffect(() => {
207 // if (checkInTime) {
208 // const checkInDateObj = new Date(checkInTime);
209 // setSelectedDate(checkInDateObj.toISOString().split("T")[0]);
210 // setSelectedTime(checkInDateObj.toTimeString().slice(0, 5));
211 // }
212 // }, [checkInTime]);
213
214 return (
215 <div className="container">
216 {isLoading ? (
217 <p>Loading...</p>
218 ) : (
219 <>
220 <h1>Edit Reservation</h1>
221 <div className="card-body">
222 <h2 className="card-title">
223 {formData.restaurant.name} <StarRating key={formData.restaurant.id} rating={formData.restaurant.rating} />
224 </h2>
225 <p className="card-text">{formData.restaurant.name}</p>
226 <p className="card-text">{formData.restaurant.operatingHours}</p>
227 <p className="card-text">Ul. {formData.restaurant.address}</p>
228 <br />
229 </div>
230 <form onSubmit={handleSubmit}>
231 <div className="mb-3">
232 <label>Select Date:</label>
233 <input
234 type="date"
235 className="form-control mt-2"
236 onChange={(event) => setSelectedDate(event.target.value)}
237 value={selectedDate}
238 min={formattedDate}
239 />
240
241 <label>Select Time:</label>
242 <select
243 className="form-select mt-2"
244 onChange={(event) => setSelectedTime(event.target.value)}
245 value={selectedTime}
246 disabled={!selectedDate}
247 >
248 <option value="">Select Time</option>
249 {timeOptions.map((time, index) => (
250 <option key={index} value={time}>
251 {time}
252 </option>
253 ))}
254 </select>
255 <label className="text-danger">
256 Current check-in time: {formatTimeSlot(checkInTime)}
257 </label>
258 </div>
259 <div className="mb-3">
260 <label htmlFor="partySize" className="form-label">Party Size</label>
261 <input
262 type="number"
263 className="form-control"
264 id="partySize"
265 name="partySize"
266 max={table?.capacity}
267 min={1}
268 value={formData.partySize || ''}
269 onChange={handleInputChange}
270 />
271 <label className="text-danger">
272 Table capacity: {table?.capacity}
273 </label>
274 </div>
275 <div className="mb-3">
276 <label htmlFor="specialRequests" className="form-label">Special Requests</label>
277 <input
278 type="text"
279 className="form-control"
280 id="specialRequests"
281 name="specialRequests"
282 value={formData.specialRequests || ''}
283 onChange={handleInputChange}
284 />
285 </div>
286 <button type="submit" className="btn btn-primary">Submit</button>
287 </form>
288 </>
289 )}
290 </div>
291 );
292};
293
294export default ReservationEdit;
Note: See TracBrowser for help on using the repository browser.