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

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

Final version for DB

  • Property mode set to 100644
File size: 10.5 KB
RevLine 
[d24f17c]1import React, { useState, useEffect } from 'react';
2import axios from 'axios';
3import {useNavigate, useParams} from 'react-router-dom';
4import StarRating from "./StarRating";
[8ca35dc]5import {jwtDecode} from "jwt-decode";
[d24f17c]6
7const ReservationEdit = () => {
8 const navigate = useNavigate();
[f5b256e]9 const { reservationId } = useParams();
[d24f17c]10 const [isLoading, setIsLoading] = useState(true);
11 const [formData, setFormData] = useState({});
[f5b256e]12 const [tableNumber, setTableNumber] = useState({});
[d24f17c]13 const [table, setTable] = useState({});
14 const [restaurant, setRestaurant] = useState({});
[f5b256e]15 const [restaurantId, setRestaurantId] = useState({});
[d24f17c]16 const [timeSlots, setTimeSlots] = useState([]);
17 const [filteredTimeSlots, setFilteredTimeSlots] = useState([]);
[8ca35dc]18 const [checkInTime, setCheckInTime] = useState([]);
[f5b256e]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([]);
[d24f17c]26
27 useEffect(() => {
28 const fetchReservation = async () => {
29 try {
30 setIsLoading(true);
[8ca35dc]31 const response = await axios.get(`http://localhost:8081/api/reservations/${reservationId}`);
[f5b256e]32 setCheckInTime(response.data.reservationDateTime);
[8ca35dc]33 setFormData(response.data);
[e48199a]34
[f5b256e]35 setRestaurantId(response.data.restaurantId);
[e48199a]36 const restaurantResponse = await axios.get(`http://localhost:8081/api/restaurants/${response.data.restaurantId}`);
37 setRestaurant(restaurantResponse.data);
[f5b256e]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
[d24f17c]43 setIsLoading(false);
44 } catch (error) {
45 console.error('Error fetching reservation:', error);
46 }
47 };
48 fetchReservation();
49 }, [reservationId]);
50
51 useEffect(() => {
[f5b256e]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
[e15e8d9]67 useEffect(() => {
68 if (table?.restaurant?.operatingHours && selectedDate) {
69 const options = generateTimeOptions(table.restaurant.operatingHours);
70 setTimeOptions(options);
71 }
72 }, [table, selectedDate]);
[d24f17c]73
74
75 const handleInputChange = (e) => {
76 const { name, value } = e.target;
77
[f5b256e]78 if (name === 'partySize') {
79 const valueAsNumber = Math.min(value, table?.capacity);
80 setFormData(prevState => ({
81 ...prevState,
82 [name]: valueAsNumber
83 }));
[d24f17c]84 } else {
[f5b256e]85 setFormData(prevState => ({
86 ...prevState,
87 [name]: value
88 }));
[d24f17c]89 }
90 };
91
[f5b256e]92
[d24f17c]93 const handleSubmit = async (e) => {
94 e.preventDefault();
[8ca35dc]95
[d24f17c]96 try {
[8ca35dc]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
[f5b256e]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)
[8ca35dc]122
[f5b256e]123 navigate(`/reservations`);
[d24f17c]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
[f5b256e]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
[e48199a]142 const generateTimeOptions = (operatingHours) => {
143 const now = new Date();
144 const selectedDateObj = new Date(selectedDate);
145 const isToday = selectedDateObj.toDateString() === now.toDateString();
[e15e8d9]146
[e48199a]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 }
[e15e8d9]160
[e48199a]161 if (endTime <= now) {
162 setNoAvailableMessage('No available time due to closing.');
163 continue;
164 }
[e15e8d9]165
[e48199a]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 }
[e15e8d9]182
[e48199a]183 return roundedTime;
[8ca35dc]184 };
185
[f5b256e]186 useEffect(() => {
[e48199a]187 if (restaurant?.operatingHours && selectedDate) {
188 const options = generateTimeOptions(restaurant.operatingHours);
[f5b256e]189 setTimeOptions(options);
190 }
191 }, [restaurant, selectedDate]);
192
193
[d24f17c]194 return (
195 <div className="container">
[f5b256e]196 {isLoading ? (
[d24f17c]197 <p>Loading...</p>
198 ) : (
199 <>
200 <h1>Edit Reservation</h1>
201 <div className="card-body">
[f5b256e]202 <h2 className="card-title">
[e48199a]203 {restaurant?.name}
204 <StarRating key={restaurant?.id} rating={restaurant?.rating || 0}/>
[d24f17c]205 </h2>
[e48199a]206 <p className="card-text">Operating Hours: {restaurant?.operatingHours}</p>
207 <p className="card-text">Address: Ul. {restaurant?.address}</p>
208 <br/>
[d24f17c]209 </div>
210 <form onSubmit={handleSubmit}>
211 <div className="mb-3">
[f5b256e]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>
[d24f17c]233 ))}
234 </select>
[f5b256e]235 <label className="text-danger">
236 Current check-in time: {formatTimeSlot(checkInTime)}
237 </label>
[d24f17c]238 </div>
239 <div className="mb-3">
240 <label htmlFor="partySize" className="form-label">Party Size</label>
[f5b256e]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>
[d24f17c]254 </div>
255 <div className="mb-3">
[f5b256e]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 />
[d24f17c]265 </div>
266 <button type="submit" className="btn btn-primary">Submit</button>
267 </form>
268 </>
269 )}
270 </div>
271 );
272};
273
[f5b256e]274export default ReservationEdit;
Note: See TracBrowser for help on using the repository browser.