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

main
Last change on this file was e48199a, checked in by Aleksandar Panovski <apano77@…>, 10 days ago

Final version for DB

  • Property mode set to 100644
File size: 10.5 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 setCheckInTime(response.data.reservationDateTime);
33 setFormData(response.data);
34
35 setRestaurantId(response.data.restaurantId);
36 const restaurantResponse = await axios.get(`http://localhost:8081/api/restaurants/${response.data.restaurantId}`);
37 setRestaurant(restaurantResponse.data);
38
39 setTableNumber(response.data.tableNumber);
40 const tableResponse = await axios.get(`http://localhost:8081/api/tables/${response.data.tableNumber}`);
41 setTable(tableResponse.data)
42
43 setIsLoading(false);
44 } catch (error) {
45 console.error('Error fetching reservation:', error);
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 useEffect(() => {
68 if (table?.restaurant?.operatingHours && selectedDate) {
69 const options = generateTimeOptions(table.restaurant.operatingHours);
70 setTimeOptions(options);
71 }
72 }, [table, selectedDate]);
73
74
75 const handleInputChange = (e) => {
76 const { name, value } = e.target;
77
78 if (name === 'partySize') {
79 const valueAsNumber = Math.min(value, table?.capacity);
80 setFormData(prevState => ({
81 ...prevState,
82 [name]: valueAsNumber
83 }));
84 } else {
85 setFormData(prevState => ({
86 ...prevState,
87 [name]: value
88 }));
89 }
90 };
91
92
93 const handleSubmit = async (e) => {
94 e.preventDefault();
95
96 try {
97 const token = localStorage.getItem("token");
98 if (!token) {
99 console.error("No token found");
100 return;
101 }
102
103 const decodedToken = jwtDecode(token);
104 const userId = decodedToken.iss;
105
106 const updatedReservationData = {
107 ...formData,
108 reservationDateTime: `${selectedDate}T${selectedTime}`,
109 checkInTime: checkInTime,
110 reservationID: reservationId,
111 };
112 await axios.post(
113 `http://localhost:8081/api/reservations/${reservationId}/${userId}`,
114 updatedReservationData,
115 {
116 headers: {
117 'Content-Type': 'application/json',
118 }
119 }
120 );
121 console.log(updatedReservationData)
122
123 navigate(`/reservations`);
124 } catch (error) {
125 console.error('Error updating reservation:', error);
126 }
127 };
128
129 const formatTimeSlot = (timeSlot) => {
130 const date = new Date(timeSlot);
131 const formattedDate = date.toLocaleDateString();
132 const formattedTime = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
133 return `${formattedDate} - ${formattedTime}`;
134 };
135
136 const today = new Date();
137 const year = today.getFullYear();
138 const month = String(today.getMonth() + 1).padStart(2, '0');
139 const day = String(today.getDate()).padStart(2, '0');
140 const formattedDate = `${year}-${month}-${day}`;
141
142 const generateTimeOptions = (operatingHours) => {
143 const now = new Date();
144 const selectedDateObj = new Date(selectedDate);
145 const isToday = selectedDateObj.toDateString() === now.toDateString();
146
147 let options = [];
148 for (const hours of operatingHours.split(',')) {
149 const [start, end] = hours.trim().split('-');
150 const startTime = new Date(selectedDateObj);
151 const endTime = new Date(selectedDateObj);
152 const [startHour, startMinute] = start.split(':').map(Number);
153 const [endHour, endMinute] = end.split(':').map(Number);
154 startTime.setHours(startHour, startMinute, 0);
155 endTime.setHours(endHour, endMinute, 0);
156
157 if (isToday && startTime < now) {
158 startTime.setTime(roundToNext15Minutes(now).getTime());
159 }
160
161 if (endTime <= now) {
162 setNoAvailableMessage('No available time due to closing.');
163 continue;
164 }
165
166 while (startTime <= endTime) {
167 options.push(startTime.toTimeString().slice(0, 5));
168 startTime.setMinutes(startTime.getMinutes() + 15);
169 }
170 }
171
172 return options.length ? options : ['No available time'];
173 };
174
175 const roundToNext15Minutes = (date) => {
176 const ms = 1000 * 60 * 15;
177 const roundedTime = new Date(Math.ceil(date.getTime() / ms) * ms);
178
179 if (roundedTime.getTime() === date.getTime()) {
180 roundedTime.setMinutes(roundedTime.getMinutes() + 15);
181 }
182
183 return roundedTime;
184 };
185
186 useEffect(() => {
187 if (restaurant?.operatingHours && selectedDate) {
188 const options = generateTimeOptions(restaurant.operatingHours);
189 setTimeOptions(options);
190 }
191 }, [restaurant, selectedDate]);
192
193
194 return (
195 <div className="container">
196 {isLoading ? (
197 <p>Loading...</p>
198 ) : (
199 <>
200 <h1>Edit Reservation</h1>
201 <div className="card-body">
202 <h2 className="card-title">
203 {restaurant?.name}
204 <StarRating key={restaurant?.id} rating={restaurant?.rating || 0}/>
205 </h2>
206 <p className="card-text">Operating Hours: {restaurant?.operatingHours}</p>
207 <p className="card-text">Address: Ul. {restaurant?.address}</p>
208 <br/>
209 </div>
210 <form onSubmit={handleSubmit}>
211 <div className="mb-3">
212 <label>Select Date:</label>
213 <input
214 type="date"
215 className="form-control mt-2"
216 onChange={(event) => setSelectedDate(event.target.value)}
217 value={selectedDate}
218 min={formattedDate}
219 />
220
221 <label>Select Time:</label>
222 <select
223 className="form-select mt-2"
224 onChange={(event) => setSelectedTime(event.target.value)}
225 value={selectedTime}
226 disabled={!selectedDate}
227 >
228 <option value="">Select Time</option>
229 {timeOptions.map((time, index) => (
230 <option key={index} value={time}>
231 {time}
232 </option>
233 ))}
234 </select>
235 <label className="text-danger">
236 Current check-in time: {formatTimeSlot(checkInTime)}
237 </label>
238 </div>
239 <div className="mb-3">
240 <label htmlFor="partySize" className="form-label">Party Size</label>
241 <input
242 type="number"
243 className="form-control"
244 id="partySize"
245 name="partySize"
246 max={table?.capacity}
247 min={1}
248 value={formData.partySize || ''}
249 onChange={handleInputChange}
250 />
251 <label className="text-danger">
252 Table capacity: {table?.capacity}
253 </label>
254 </div>
255 <div className="mb-3">
256 <label htmlFor="specialRequests" className="form-label">Special Requests</label>
257 <input
258 type="text"
259 className="form-control"
260 id="specialRequests"
261 name="specialRequests"
262 value={formData.specialRequests || ''}
263 onChange={handleInputChange}
264 />
265 </div>
266 <button type="submit" className="btn btn-primary">Submit</button>
267 </form>
268 </>
269 )}
270 </div>
271 );
272};
273
274export default ReservationEdit;
Note: See TracBrowser for help on using the repository browser.