source: my-react-app/src/components/ReservationHistory.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: 8.7 KB
Line 
1import React, { useEffect, useState } from "react";
2import {jwtDecode} from "jwt-decode";
3import axios from "axios";
4
5const ReservationHistory = () => {
6 const [reservations, setReservations] = useState([]);
7 const [filteredReservations, setFilteredReservations] = useState([]);
8 const [loading, setLoading] = useState(true);
9 const [error, setError] = useState(null);
10
11 const [restaurantFilter, setRestaurantFilter] = useState("");
12 const [tableFilter, setTableFilter] = useState("");
13 const [partySizeFilter, setPartySizeFilter] = useState("");
14 const [statusFilter, setStatusFilter] = useState("");
15 const [cancellationReasonFilter, setCancellationReasonFilter] = useState("");
16
17 const [startDate, setStartDate] = useState("");
18 const [endDate, setEndDate] = useState("");
19
20 useEffect(() => {
21 const fetchReservations = async () => {
22 try {
23 const token = localStorage.getItem("token");
24 if (!token) {
25 setError("User not authenticated.");
26 setLoading(false);
27 return;
28 }
29
30 const decodedToken = jwtDecode(token);
31 const userId = decodedToken.iss;
32
33 const response = await axios.get(
34 `http://localhost:8081/api/past-reservations/${userId}`,
35 {
36 headers: { Authorization: `Bearer ${token}` },
37 }
38 );
39
40 setReservations(response.data);
41 setFilteredReservations(response.data);
42 } catch (err) {
43 setError("Failed to fetch reservations.");
44 } finally {
45 setLoading(false);
46 }
47 };
48
49 fetchReservations();
50 }, []);
51
52 useEffect(() => {
53 let tempReservations = reservations;
54
55 if (restaurantFilter) {
56 tempReservations = tempReservations.filter(res =>
57 res.restaurant?.name.toLowerCase().includes(restaurantFilter.toLowerCase())
58 );
59 }
60 if (tableFilter) {
61 tempReservations = tempReservations.filter(res =>
62 res.table?.id?.toString() === tableFilter
63 );
64 }
65 if (partySizeFilter) {
66 tempReservations = tempReservations.filter(res =>
67 res.partySize?.toString() === partySizeFilter
68 );
69 }
70 if (statusFilter) {
71 tempReservations = tempReservations.filter(res =>
72 res.status.toLowerCase().includes(statusFilter.toLowerCase())
73 );
74 }
75 if (cancellationReasonFilter) {
76 tempReservations = tempReservations.filter(res =>
77 (res.cancellationReason || "None").toLowerCase().includes(cancellationReasonFilter.toLowerCase())
78 );
79 }
80 if (startDate && endDate) {
81 const start = new Date(startDate);
82 const end = new Date(endDate);
83
84 tempReservations = tempReservations.filter(res => {
85 const reservationDate = new Date(res.reservationDateTime);
86 return reservationDate >= start && reservationDate <= end;
87 });
88 }
89
90 setFilteredReservations(tempReservations);
91 }, [
92 restaurantFilter,
93 tableFilter,
94 partySizeFilter,
95 statusFilter,
96 cancellationReasonFilter,
97 startDate,
98 endDate,
99 reservations
100 ]);
101
102 const resetFilters = () => {
103 setRestaurantFilter("");
104 setTableFilter("");
105 setPartySizeFilter("");
106 setStatusFilter("");
107 setCancellationReasonFilter("");
108 setStartDate("");
109 setEndDate("");
110 };
111
112 if (loading) return <div>Loading...</div>;
113 if (error) return <div className="alert alert-danger">{error}</div>;
114
115 return (
116 <div className="container mt-5">
117 <h3 className="mb-4 text-center">Past Reservations</h3>
118
119 <div className="row mb-4 align-items-end">
120 <div className="col-md-2">
121 <input
122 type="text"
123 className="form-control"
124 placeholder="Filter by Restaurant"
125 value={restaurantFilter}
126 onChange={(e) => setRestaurantFilter(e.target.value)}
127 />
128 </div>
129 <div className="col-md-2">
130 <input
131 type="number"
132 className="form-control"
133 placeholder="Filter by Table ID"
134 value={tableFilter}
135 onChange={(e) => setTableFilter(e.target.value)}
136 />
137 </div>
138 <div className="col-md-4 d-flex gap-2">
139 <input
140 type="date"
141 className="form-control"
142 placeholder="Start date"
143 value={startDate}
144 onChange={(e) => setStartDate(e.target.value)}
145 />
146 <input
147 type="date"
148 className="form-control"
149 placeholder="End date"
150 value={endDate}
151 onChange={(e) => setEndDate(e.target.value)}
152 />
153 </div>
154 <div className="col-md-2">
155 <input
156 type="number"
157 className="form-control"
158 placeholder="Filter by Party Size"
159 value={partySizeFilter}
160 onChange={(e) => setPartySizeFilter(e.target.value)}
161 />
162 </div>
163 <div className="col-md-2">
164 <select
165 value={statusFilter}
166 onChange={(e) => setStatusFilter(e.target.value)}
167 className="form-control"
168 >
169 <option value="">Filter by status</option>
170 <option value="successful">Successful</option>
171 <option value="canceled">Canceled</option>
172 </select>
173 </div>
174 <div className="col-md-2 mt-2">
175 <input
176 type="text"
177 className="form-control"
178 placeholder="Filter by Cancellation Reason"
179 value={cancellationReasonFilter}
180 onChange={(e) => setCancellationReasonFilter(e.target.value)}
181 />
182 </div>
183 <div className="col-md-2 mt-2">
184 <button
185 onClick={resetFilters}
186 className="btn btn-outline-secondary w-100"
187 >
188 Reset Filters
189 </button>
190 </div>
191 </div>
192
193 <div className="table-responsive">
194 <table className="table table-striped table-hover table-bordered align-middle">
195 <thead className="table-dark text-center">
196 <tr>
197 <th>#</th>
198 <th>Restaurant</th>
199 <th>Table</th>
200 <th>Date & Time</th>
201 <th>Party Size</th>
202 <th>Special Requests</th>
203 <th>Status</th>
204 <th>Cancellation Reason</th>
205 </tr>
206 </thead>
207 <tbody>
208 {filteredReservations.length > 0 ? (
209 filteredReservations.map((res, index) => (
210 <tr key={res.id}>
211 <td>{index + 1}</td>
212 <td>{res.restaurant?.name || "N/A"}</td>
213 <td>{res.table?.id || "N/A"}</td>
214 <td>{new Date(res.reservationDateTime).toLocaleString()}</td>
215 <td>{res.partySize}</td>
216 <td>{res.specialRequests || "None"}</td>
217 <td>{res.status}</td>
218 <td>{res.cancellationReason || "None"}</td>
219 </tr>
220 ))
221 ) : (
222 <tr>
223 <td colSpan="8" className="text-center">No reservations found.</td>
224 </tr>
225 )}
226 </tbody>
227 </table>
228 </div>
229 </div>
230 );
231};
232
233export default ReservationHistory;
Note: See TracBrowser for help on using the repository browser.