- Timestamp:
- 02/17/25 01:39:28 (4 months ago)
- Branches:
- master
- Children:
- de83113
- Parents:
- a70b5a4
- git-author:
- ste08 <sjovanoska@…> (02/17/25 01:39:02)
- git-committer:
- ste08 <sjovanoska@…> (02/17/25 01:39:28)
- Location:
- src/main
- Files:
-
- 4 added
- 1 deleted
- 10 edited
- 3 moved
Legend:
- Unmodified
- Added
- Removed
-
src/main/java/com/example/skychasemk/controller/ApplicationUserController.java
ra70b5a4 r9868304 2 2 3 3 import com.example.skychasemk.dto.ApplicationUserDTO; 4 import com.example.skychasemk.dto.ApplicationUserLoginDTO; 4 5 import com.example.skychasemk.model.ApplicationUser; 5 6 import com.example.skychasemk.services.ApplicationUserService; … … 8 9 import org.springframework.http.ResponseEntity; 9 10 import org.springframework.web.bind.annotation.*; 11 12 import java.util.HashMap; 13 import java.util.Map; 10 14 11 15 @RestController … … 22 26 return ResponseEntity.ok("User saved successfully"); 23 27 } 24 28 @PostMapping("/login") 29 public ResponseEntity<Map<String,Long>> loginUser(@Valid @RequestBody ApplicationUserLoginDTO userDTO) { 30 ApplicationUser loginUser = userService.findByEmail(userDTO); 31 Map<String,Long> response = new HashMap<>(); 32 response.put("userId",loginUser.getUserid()); 33 return ResponseEntity.ok(response); 34 } 25 35 } -
src/main/java/com/example/skychasemk/dto/ApplicationUserDTO.java
ra70b5a4 r9868304 22 22 private String password; 23 23 24 private String phoneNumber; 24 private String phone_number; 25 26 public String getPhone_number() { 27 return phone_number; 28 } 29 30 public void setPhone_number(String phone_number) { 31 this.phone_number = phone_number; 32 } 25 33 } -
src/main/java/com/example/skychasemk/model/ApplicationUser.java
ra70b5a4 r9868304 31 31 @Column(name = "phone_number") 32 32 33 private String phone Number;33 private String phone_number; 34 34 35 35 @Column(name = "date_joined") … … 41 41 } 42 42 43 public void setPhoneNumber(String phoneNumber) { 44 this.phone_number = phoneNumber; 45 } 43 46 } -
src/main/java/com/example/skychasemk/repository/ApplicationUserRepository.java
ra70b5a4 r9868304 11 11 @Repository 12 12 public interface ApplicationUserRepository extends JpaRepository<ApplicationUser, Long> { 13 Optional<ApplicationUser> findByEmail(String email);14 13 @Query("SELECT u FROM ApplicationUser u WHERE u.userid = :id") 15 14 Optional<ApplicationUser> getUserById(@Param("id") Long userid); 15 @Query("SELECT u FROM ApplicationUser u WHERE u.email=:email") 16 Optional<ApplicationUser> findByEmail(@Param("email") String email); 16 17 } -
src/main/java/com/example/skychasemk/services/ApplicationUserService.java
ra70b5a4 r9868304 2 2 3 3 import com.example.skychasemk.dto.ApplicationUserDTO; 4 import com.example.skychasemk.dto.ApplicationUserLoginDTO; 4 5 import com.example.skychasemk.model.ApplicationUser; 5 6 import com.example.skychasemk.repository.ApplicationUserRepository; 6 7 import jakarta.transaction.Transactional; 8 import jakarta.validation.Valid; 7 9 import org.springframework.beans.factory.annotation.Autowired; 8 10 import org.springframework.stereotype.Service; 9 11 10 import java.time.Instant; 11 import java.time.LocalDate; 12 import java.util.Optional; 12 13 //import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 13 14 … … 32 33 user.setEmail(userDTO.getEmail()); 33 34 user.setPassword(userDTO.getPassword()); 34 user.setPhoneNumber(userDTO.getPhone Number());35 user.setPhoneNumber(userDTO.getPhone_number()); 35 36 ApplicationUser savedUser = userRepository.save(user); 36 37 userRepository.flush(); 37 38 return savedUser; 38 39 } 40 41 public ApplicationUser findByEmail(@Valid ApplicationUserLoginDTO userDTO) { 42 if (userRepository.findByEmail(userDTO.getEmail()).isEmpty()) { 43 throw new RuntimeException("User not registered"); 44 } else { 45 Optional<ApplicationUser> userId = userRepository.findByEmail(userDTO.getEmail()); 46 return userId.get(); 47 } 48 } 39 49 } -
src/main/resources/static/FlightSearch.html
ra70b5a4 r9868304 8 8 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> 9 9 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> 10 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css"> 11 <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.0-2/css/all.min.css'> 12 <style> 13 body { 14 background: url('images/flight.jpg') no-repeat center center fixed; 15 background-size: cover; 16 display: flex; 17 flex-direction: column; 18 align-items: center; 19 justify-content: center; 20 height: 100vh; 21 margin: 0; 22 font-family: Arial, sans-serif; 23 } 24 25 .header { 26 position: absolute; 27 top: 0; 28 left: 0; 29 display: flex; 30 align-items: center; 31 background-color: rebeccapurple; 32 padding: 10px; 33 width: 100%; 34 z-index: 10; 35 } 36 .header img { 37 width: 40px; 38 height: 40px; 39 margin-right: 20px; 40 } 41 42 .header h1 { 43 color: white; 44 margin: 0; 45 font-size: 15px; 46 padding-right: 50px; 47 } 48 49 .header button { 50 background-color: transparent; 51 border: none; 52 color: white; 53 font-size: 14px; 54 } 55 56 .header button:hover { 57 background-color: transparent; 58 cursor: pointer; 59 } 60 61 .split { 62 height: 100%; 63 width: 50%; 64 position: fixed; 65 z-index: 1; 66 top: 0; 67 overflow-x: hidden; 68 padding-top: 20px; 69 } 70 71 .left { 72 left: 0; 73 padding:50px; 74 } 75 76 .right { 77 right: 0; 78 padding:10px; 79 } 80 select { 81 -webkit-appearance: none; 82 -moz-appearance: none; 83 appearance: none; 84 border: 0; 85 outline: 0; 86 font: inherit; 87 width: 20em; 88 height: 3em; 89 padding: 0 4em 0 1em; 90 background: url(https://upload.wikimedia.org/wikipedia/commons/9/9d/Caret_down_font_awesome_whitevariation.svg) no-repeat right 0.8em center/1.4em, linear-gradient(to left, rgba(255, 255, 255, 0.3) 3em, rgba(255, 255, 255, 0.2) 3em); 91 color: white; 92 border-radius: 0.25em; 93 box-shadow: 0 0 1em 0 rgba(0, 0, 0, 0.2); 94 cursor: pointer; 95 } 96 select option { 97 color: inherit; 98 background-color: #320a28; 99 } 100 select:focus { 101 outline: none; 102 } 103 select::-ms-expand { 104 display: none; 105 } 106 107 .search-form-container h2 { 108 color: white; 109 padding-top: 110px; 110 } 111 112 .search-form { 113 padding: 10px; 114 color:white; 115 font-family: Cambria; 116 } 117 .search { 118 background-color: rebeccapurple; 119 color: white; 120 width: 20em; 121 height: 3em; 122 } 123 124 .book { 125 background-color: darkblue; 126 color: white; 127 width: 20em; 128 height: 3em; 129 } 130 131 .search:hover { 132 background-color: mediumpurple; 133 } 134 135 .flights-list-container { 136 color: white; 137 } 138 139 .flights-list-container h2{ 140 padding-top: 110px; 141 } 142 .flights-list .flight-item { 143 margin-bottom: 15px; 144 } 145 146 .flights-list .flight-item span { 147 margin-right: 15px; 148 } 149 .flight-item { 150 display: flex; 151 align-items: center; 152 justify-content: space-between; 153 padding: 15px; 154 background: url(https://upload.wikimedia.org/wikipedia/commons/9/9d/Caret_down_font_awesome_whitevariation.svg) no-repeat right 0.8em center/1.4em, linear-gradient(to left, rgba(255, 255, 255, 0.3) 3em, rgba(255, 255, 255, 0.2) 3em); 155 border-radius: 8px; 156 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); 157 transition: transform 0.3s ease, background-color 0.3s ease; 158 width: 70%; 159 height: 15px; 160 } 161 162 .popup-overlay { 163 position: fixed; 164 top: 0; 165 left: 0; 166 width: 100%; 167 height: 100%; 168 background: rgba(0, 0, 0, 0.7); 169 display: flex; 170 align-items: center; 171 justify-content: center; 172 } 173 174 .popup { 175 background-color: white; 176 padding: 20px; 177 width: 300px; 178 border-radius: 10px; 179 } 180 181 .popup button { 182 margin-top: 10px; 183 background-color: rebeccapurple; 184 color: white; 185 border: none; 186 padding: 5px; 187 cursor: pointer; 188 } 189 190 .popup button:hover { 191 background-color: mediumpurple; 192 } 193 194 .calendar { 195 background-color: transparent; 196 border-radius: 2px; 197 border-color: white; 198 width: 18.6em; 199 height: 2.5em; 200 color:white; 201 } 202 </style> 10 203 </head> 11 204 <body> 12 205 13 206 <div id="app" class="flight-search"> 14 <header class="app-header"> 15 <button class="report-issue-btn" @click="showReportPopup">Report Issue</button> 16 <button class="report-issue-btn" @click="goToWishlistPage">🤍</button> 17 <button class="logout-btn" @click="logout">Log Out</button> 207 <header class="header"> 208 <button @click="home"><img src="/images/home.png" alt="Home Icon"></button> 209 <button @click="showReportPopup">Report Issue</button> 210 <button @click="goToWishlistPage">🤍</button> 211 <button @click="home">Log Out</button> 18 212 </header> 19 213 20 <div class="main-content"> 21 <!-- Left side: Flight Search Form --> 214 <div class="split left"> 22 215 <div class="search-form-container"> 23 <h 1>Flight Search</h1>216 <h2>Search flights</h2> 24 217 25 218 <div class="search-form"> 26 219 <label for="departure-city">Departure From</label> 220 <br> 27 221 <select v-model="departureCity" id="departure-city"> 28 222 <option value="" disabled selected>Select a departure city</option> … … 31 225 32 226 <label for="destination">Destination</label> 227 <br> 33 228 <select v-model="destination" id="destination"> 34 229 <option value="" disabled selected>Select a destination</option> … … 37 232 38 233 <label for="departure-date">Departure Date</label> 39 <input type="date" v-model="departureDate" id="departureDate" /> 40 234 <br> 235 <input class="calendar" type="date" v-model="departureDate" id="departureDate" /> 236 <br> 41 237 <div class="toggle-wrapper"> 42 <label for="return-date-toggle">Include Return Date</label> 43 <input type="checkbox" v-model="showReturnDate" id="return-date-toggle" /> 238 <label for="return-date-toggle">Include Return Date<input type="checkbox" v-model="showReturnDate" id="return-date-toggle" /></label> 44 239 </div> 45 240 <br> 46 241 <div v-if="showReturnDate"> 47 242 <label for="return-date">Return Date</label> 48 <input type="date" v-model="returnDate" id="returnDate" />243 <input class="calendar" type="date" v-model="returnDate" id="returnDate" /> 49 244 </div> 50 51 <button @click="searchFlights">Search Flights</button>245 <br> 246 <button class="search" @click="searchFlights">Search Flights</button> 52 247 </div> 53 248 </div> 54 55 <!-- Right side: Available Flights List -->56 <div class="flights-list-container" v- if="flights.length">249 </div> 250 <div class="split right"> 251 <div class="flights-list-container" v-show="isContainerVisible" v-if="flights.length"> 57 252 <h2>Available Flights</h2> 58 253 <div class="flights-list"> 59 254 <div class="flight-item" v-for="flight in flights" :key="flight.flightId"> 60 255 <input type="checkbox" v-model="flight.selected" /> 61 <span>{{flight.departureTime}} | {{flight.arrivalTime}} | ${{ flight.price }} | {{flight.availableSeats}}</span> 62 63 <!-- Heart icon for Wishlist --> 256 <span>{{ flight.departureTime }} | {{ flight.arrivalTime }} | ${{ flight.price }} | {{ flight.availableSeats }}</span> 257 64 258 <span class="wishlist-heart" @click="toggleWishlist(flight)"> 65 259 {{ flight.wishlisted ? '❤️' : '🤍' }} … … 68 262 </div> 69 263 70 <!-- Book Button (Only appears if at least one flight is selected) --> 71 <button v-if="selectedFlights.length" @click="bookFlights" class="book-btn"> 264 <button v-if="selectedFlights.length" @click="bookFlights" class="book"> 72 265 Book 73 266 </button> 74 75 267 </div> 76 268 </div> 77 269 78 <!-- Popup Modal for Reporting an Issue -->79 270 <div v-if="showPopup" class="popup-overlay"> 80 271 <div class="popup"> … … 93 284 el: '#app', 94 285 data: { 286 isContainerVisible:false, 95 287 departureCity: '', 96 288 destination: '', … … 112 304 methods: { 113 305 async searchFlights() { 114 console.log("button clicked"); 115 306 this.isContainerVisible = !this.isContainerVisible; 116 307 if (this.departureCity && this.destination && this.departureDate) { 117 console.log("Search parameters are valid.");118 119 308 try { 120 // Log the params being sent121 console.log("Params being sent:", {122 departureCity: this.departureCity,123 destination: this.destination,124 departureDate: this.departureDate,125 returnDate: this.showReturnDate ? this.returnDate : null126 });127 128 309 const response = await axios.get('/api/flights/flight-search', { 129 310 params: { … … 135 316 }); 136 317 137 console.log("Response received:", response.data);138 139 // Handle no results140 318 if (response.data && response.data.length > 0) { 141 319 this.flights = response.data; 142 console.log("Flights found:", this.flights);143 320 } else { 144 321 this.flights = []; 145 322 alert("No flights found for the given criteria."); 146 323 } 147 148 324 } catch (error) { 149 325 console.error("Error fetching flights", error); 150 326 } 151 327 } else { 152 alert("Please select departure city, destination, and date ");328 alert("Please select departure city, destination, and date."); 153 329 this.flights = []; 154 330 } 155 } 156 , 331 }, 157 332 bookFlights() { 158 333 if (!this.selectedFlights.length) { … … 160 335 return; 161 336 } 337 162 338 const flight = this.selectedFlights[0]; 163 console.log(this.selectedFlights[0]);164 339 const totalCost = flight.price; 165 const bookingDate = new Date().toISOString().split('T')[0];166 167 168 340 const bookingData = { 169 flightId: flight.flightI D,170 bookingDate: bookingDate,341 flightId: flight.flightId, 342 bookingDate: new Date().toISOString().split('T')[0], 171 343 status: 'PENDING', 172 344 totalCost: totalCost 173 345 }; 174 console.log("Booking Data",bookingData); 346 175 347 axios.post('/api/bookings', bookingData) 176 348 .then(response => { 177 349 const bookingID = response.data.bookingID; 178 350 alert("Booked successfully!"); 179 window.location.href = `/transaction?amount=${encodeURIComponent(totalCost)}&bookingId=${encodeURIComponent(bookingID)}&flightId=${encodeURIComponent(flight.flightI D)}`;351 window.location.href = `/transaction?amount=${encodeURIComponent(totalCost)}&bookingId=${encodeURIComponent(bookingID)}&flightId=${encodeURIComponent(flight.flightId)}`; 180 352 }) 181 353 .catch(error => { … … 184 356 }); 185 357 }, 186 logout() {187 window.location.href = '/ login';358 home() { 359 window.location.href = '/'; 188 360 }, 189 361 async toggleWishlist(flight) { 190 362 flight.wishlisted = !flight.wishlisted; 191 192 363 const wishlistData = { 193 targetId: flight.flightI D,364 targetId: flight.flightId, 194 365 wishlisted: flight.wishlisted 195 366 }; 196 367 try { 197 const response = await axios.post('/api/wishlists', wishlistData); 198 console.log("Wishlist updated"); 368 await axios.post('/api/wishlists', wishlistData); 199 369 } catch (error) { 200 console.error("Error updating wishlist:", error .response ? error.response.data : error.message);370 console.error("Error updating wishlist:", error); 201 371 } 202 372 }, 203 373 goToWishlistPage() { 204 window.location.href = '/ wishlist';374 window.location.href = '/api/wishlists'; 205 375 }, 206 376 showReportPopup() { … … 211 381 }, 212 382 submitIssue() { 213 const flight = this.selectedFlights[0];214 383 if (this.issueDescription.trim()) { 215 384 const reviewData = { 216 385 userID: 1, 217 subject: this.subject,386 subject: "Issue Report", 218 387 description: this.issueDescription 219 388 }; … … 225 394 }) 226 395 .catch(error => { 227 console.error("Error submitting issue:", error .response ? error.response.data : error.message);396 console.error("Error submitting issue:", error); 228 397 alert("There was an error submitting your issue. Please try again."); 229 398 }); … … 232 401 } 233 402 }, 234 leaveReview() {235 const flight = this.selectedFlights[0];236 if (this.issueDescription.trim()) {237 const reviewData = {238 userID: 1,239 targetID: flight.flightId,240 reviewComment: this.issueDescription,241 rating: 5,242 date: new Date().toISOString().split('T')[0]243 };244 245 axios.post('/api/support-tickets', reviewData)246 .then(response => {247 alert("Issue reported successfully!");248 this.closePopup();249 })250 .catch(error => {251 console.error("Error submitting issue:", error.response ? error.response.data : error.message);252 alert("There was an error submitting your issue. Please try again.");253 });254 } else {255 alert("Please enter a description for the issue.");256 }257 },258 403 async fetchFlights() { 259 404 try { 260 405 const response = await axios.get('/api/destinations'); 261 262 406 this.cities = response.data.map(departureCity => departureCity.name); 263 407 this.places = response.data.map(destination => destination.name); … … 276 420 console.error("Error fetching flights", error); 277 421 }); 278 axios.get('api/bookings/getAll/${flight.flightId}')279 .then(response => {280 console.log(response.data);281 this.bookings = response.data;282 })283 .catch(error => {284 console.error("Error fetching flights", error);285 })286 422 } 287 423 }); -
src/main/resources/static/TransactionPage.html
ra70b5a4 r9868304 8 8 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> 9 9 </head> 10 <style> 11 @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800;900&display=swap'); 12 13 14 * { 15 margin: 0; 16 padding: 0; 17 box-sizing: border-box; 18 font-family: 'Poppins', sans-serif 19 } 20 21 .container { 22 margin: 10px auto; 23 padding: 150px; 24 padding-top:10px; 25 } 26 27 .container .card { 28 width: 100%; 29 box-shadow: rgba(0, 0, 0, 0.24) 0px 3px 8px; 30 background: #fff; 31 border-radius: 0px; 32 } 33 34 body { 35 background: #eee 36 } 37 38 39 .container .card .img-box { 40 width: 80px; 41 height: 50px; 42 } 43 44 .container .card img { 45 width: 100%; 46 object-fit: fill; 47 } 48 49 .container .card .number { 50 font-size: 24px; 51 } 52 53 .container .card-body .btn.btn-primary .fab.fa-cc-paypal { 54 font-size: 32px; 55 color: #3333f7; 56 } 57 58 .fab.fa-cc-amex { 59 color: #1c6acf; 60 font-size: 32px; 61 } 62 63 .fab.fa-cc-mastercard { 64 font-size: 32px; 65 color: red; 66 } 67 68 .fab.fa-cc-discover { 69 font-size: 32px; 70 color: orange; 71 } 72 73 .c-green { 74 color: green; 75 } 76 77 .box { 78 height: 40px; 79 width: 50px; 80 display: flex; 81 align-items: center; 82 justify-content: center; 83 background-color: #ddd; 84 } 85 86 .btn.btn-primary.payment { 87 background-color: #1c6acf; 88 color: white; 89 border-radius: 0px; 90 height: 50px; 91 display: flex; 92 align-items: center; 93 justify-content: center; 94 margin-top: 24px; 95 } 96 97 98 .form__div { 99 height: 50px; 100 position: relative; 101 margin-bottom: 24px; 102 } 103 104 .form-control { 105 width: 100%; 106 height: 45px; 107 font-size: 14px; 108 border: 1px solid #DADCE0; 109 border-radius: 0; 110 outline: none; 111 padding: 2px; 112 background: none; 113 z-index: 1; 114 box-shadow: none; 115 } 116 117 .form__label { 118 position: absolute; 119 left: 16px; 120 top: 10px; 121 background-color: #fff; 122 color: #80868B; 123 font-size: 16px; 124 transition: .3s; 125 text-transform: uppercase; 126 } 127 128 .form-control:focus+.form__label { 129 top: -8px; 130 left: 12px; 131 color: #1A73E8; 132 font-size: 12px; 133 font-weight: 500; 134 z-index: 10; 135 } 136 137 .form-control:not(:placeholder-shown).form-control:not(:focus)+.form__label { 138 top: -8px; 139 left: 12px; 140 font-size: 12px; 141 font-weight: 500; 142 z-index: 10; 143 } 144 .input-group{ 145 align-content: center; 146 padding-left: 500px; 147 padding-top:10px; 148 } 149 .button-group{ 150 display:flex; 151 gap:10px; 152 } 153 .pay-btn, 154 .cancel-btn { 155 padding: 10px 20px; 156 font-size: 16px; 157 cursor: pointer; 158 border: none; 159 border-radius: 5px; 160 } 161 162 .pay-btn { 163 background-color: #4CAF50; /* Green background for the pay button */ 164 color: white; 165 } 166 167 .cancel-btn { 168 background-color: #f44336; /* Red background for the cancel button */ 169 color: white; 170 } 171 </style> 10 172 <body> 11 173 12 <div id="app" class="transaction-container"> 13 <div class="transaction-box"> 14 <h2>Complete Your Payment</h2> 15 16 <form @submit.prevent="processPayment"> 17 <div class="input-group"> 18 <label for="cardholder">Cardholder Name</label> 19 <input type="text" id="cardholder" v-model="cardholder" placeholder="John Doe" required /> 174 <div id="app" class="container"> 175 <div class="row"> 176 <div class="col-lg-4 mb-lg-0 mb-3"> 177 <div class="card p-3"> 178 <div class="img-box"> 179 <img src="https://www.freepnglogos.com/uploads/visa-logo-download-png-21.png" alt=""> 180 </div> 181 <div class="number"> 182 <label class="fw-bold" for="">**** **** **** 1060</label> 183 </div> 184 <div class="d-flex align-items-center justify-content-between"> 185 <small><span class="fw-bold">Expiry date:</span><span>10/16</span></small> 186 <small><span class="fw-bold">Name:</span><span>Kumar</span></small> 187 </div> 188 </div> 189 </div> 190 <div class="col-lg-4 mb-lg-0 mb-3"> 191 <div class="card p-3"> 192 <div class="img-box"> 193 <img src="https://www.freepnglogos.com/uploads/mastercard-png/file-mastercard-logo-svg-wikimedia-commons-4.png" 194 alt=""> 195 </div> 196 <div class="number"> 197 <label class="fw-bold">**** **** **** 1060</label> 198 </div> 199 <div class="d-flex align-items-center justify-content-between"> 200 <small><span class="fw-bold">Expiry date:</span><span>10/16</span></small> 201 <small><span class="fw-bold">Name:</span><span>Kumar</span></small> 202 </div> 203 </div> 204 </div> 205 <div class="col-lg-4 mb-lg-0 mb-3"> 206 <div class="card p-3"> 207 <div class="img-box"> 208 <img src="https://www.freepnglogos.com/uploads/discover-png-logo/credit-cards-discover-png-logo-4.png" 209 alt=""> 210 </div> 211 <div class="number"> 212 <label class="fw-bold">**** **** **** 1060</label> 213 </div> 214 <div class="d-flex align-items-center justify-content-between"> 215 <small><span class="fw-bold">Expiry date:</span><span>10/16</span></small> 216 <small><span class="fw-bold">Name:</span><span>Kumar</span></small> 217 </div> 218 </div> 219 </div> 220 <div class="col-12 mt-4"> 221 <div class="card p-3"> 222 <p class="mb-0 fw-bold h4">Payment Methods</p> 223 </div> 224 </div> 20 225 </div> 21 22 <div class="input-group"> 23 <label for="cardNumber">Card Number</label> 24 <input type="text" 25 id="cardNumber" 26 v-model="cardNumber" 27 maxlength="16" 28 placeholder="1234 5678 9012 3456" 29 required /> 30 </div> 31 32 <div class="input-group"> 33 <label for="expiration">Expiration Date</label> 34 <input type="month" id="expiration" v-model="expiration" required /> 35 </div> 36 37 <div class="button-group"> 38 <button type="submit" class="pay-btn">Pay</button> 39 <button type="button" class="cancel-btn" @click="cancelPayment">Cancel</button> 40 </div> 41 </form> 42 43 <div v-if="paymentSuccess" class="success-message"> 44 ✅ Payment successful! Redirecting... 226 <form class="submit" @submit.prevent="processPayment"> 227 <div class="input-group"> 228 <label for="cardholder">Cardholder Name</label> 229 <input type="text" id="cardholder" v-model="cardholder" placeholder="John Doe" required /> 230 </div> 231 232 <div class="input-group"> 233 <label for="cardNumber">Card Number</label> 234 <input type="text" 235 id="cardNumber" 236 v-model="cardNumber" 237 maxlength="16" 238 placeholder="1234 5678 9012 3456" 239 required /> 240 </div> 241 242 <div class="input-group"> 243 <label for="expiration">Expiration Date</label> 244 <input type="month" id="expiration" v-model="expiration" required /> 245 </div> 246 247 <div class="button-group"> 248 <button type="submit" class="pay-btn">Pay</button> 249 <button type="button" class="cancel-btn" @click="cancelPayment">Cancel</button> 250 </div> 251 </form> 45 252 </div> 46 </div>47 </div>48 253 49 254 <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> -
src/main/resources/static/UserLogin.html
ra70b5a4 r9868304 35 35 data: { 36 36 email: '', 37 password: '' 37 password: '', 38 userId:'' 38 39 }, 39 40 methods: { 40 loginUser() {41 async loginUser() { 41 42 if (this.email && this.password) { 42 window.location.href = '/flights'; 43 try{ 44 const response = await fetch('/api/user/login', { 45 method:'POST', 46 headers: { 47 'Content-Type':'application/json' 48 }, 49 body: JSON.stringify({ 50 email:this.email, 51 password:this.password 52 }) 53 }); 54 if(!response.ok){ 55 throw new Error('Login failed'); 56 } 57 const data = await response.json(); 58 console.log(data); 59 if(data.userId){ 60 console.log('Success'); 61 window.location.href = `/flights?userId=${encodeURIComponent(data.userId)}`; 62 }else { 63 alert('Invalid login credentials'); 64 } 65 } catch (error){ 66 console.error(error); 67 alert('Login failed. Please try again.'); 68 } 43 69 } 44 70 } -
src/main/resources/static/css/main.css
ra70b5a4 r9868304 1 1 .signup-container { 2 background-image: url('../ ../images/registration.jpg');2 background-image: url('../images/registration.jpg'); 3 3 background-size: cover; 4 4 background-position: center; -
src/main/resources/static/index.html
ra70b5a4 r9868304 4 4 <meta charset="UTF-8"> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>Support Tickets</title> 7 <link rel="stylesheet" href="/css/main.css"> 8 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> 6 <title>SkyChase-mk</title> 7 <style> 8 body { 9 background: url('images/homepage.jpg') no-repeat center center fixed; 10 background-size: cover; 11 display: flex; 12 flex-direction: column; 13 align-items: center; 14 justify-content: center; 15 height: 100vh; 16 margin: 0; 17 font-family: Arial, sans-serif; 18 } 19 20 .header { 21 position: absolute; 22 top: 0; 23 left: 0; 24 display: flex; 25 align-items: center; 26 background-color:rebeccapurple; 27 padding: 10px; 28 width: 100%; 29 } 30 31 .header img { 32 width: 40px; 33 height: 40px; 34 margin-right: 10px; 35 } 36 37 .header h1 { 38 color: white; 39 margin: 0; 40 font-size: 15px; 41 padding-right: 50px; 42 } 43 44 .buttons { 45 text-align: center; 46 } 47 48 .buttons button { 49 padding: 15px 30px; 50 margin: 10px; 51 font-size: 18px; 52 border: none; 53 border-radius: 5px; 54 cursor: pointer; 55 transition: 0.3s; 56 } 57 58 .signup { 59 background-color: rebeccapurple; 60 color: white; 61 } 62 63 .signup:hover { 64 background-color: mediumpurple; 65 } 66 67 .login { 68 background-color: #007bff; 69 color: white; 70 } 71 72 .login:hover { 73 background-color: #0056b3; 74 } 75 .adminlogin { 76 top:0; 77 right: 0; 78 background-color: rebeccapurple; 79 border:0; 80 color:white; 81 padding: 0 1200px; 82 } 83 </style> 9 84 </head> 10 85 <body> 11 12 <div id="app" class="support-ticket-container"> 13 <h1>Support Tickets</h1> 14 <div class="ticket-layout"> 15 <!-- Left side: Ticket list --> 16 <div class="ticket-list"> 17 <div class="ticket-item" 18 v-for="ticket in tickets" 19 :key="ticket.id" 20 @click="selectTicket(ticket)" 21 :class="{'active': selectedTicket && selectedTicket.id === ticket.id}"> 22 <div class="ticket-info"> 23 <p><strong>Subject:</strong> {{ ticket.subject }}</p> 24 <p><strong>Date:</strong> {{ ticket.date }}</p> 25 </div> 26 <div class="ticket-actions"> 27 <button @click.stop="resolveTicket(ticket.id)">Resolve</button> 28 </div> 29 </div> 30 </div> 31 32 <!-- Right side: Ticket details --> 33 <div class="ticket-details" v-if="selectedTicket"> 34 <h2>Ticket Details</h2> 35 <p><strong>Subject:</strong> {{ selectedTicket.subject }}</p> 36 <p><strong>Description:</strong> {{ selectedTicket.description }}</p> 37 <p><strong>Date:</strong> {{ selectedTicket.date }}</p> 38 <button @click="resolveTicket(selectedTicket.id)">Resolve</button> 39 </div> 40 </div> 86 <div class="header"> 87 <img src="/images/home.png" alt="Home Icon"> 88 <h1>SkyChase</h1> 89 <button class="adminlogin" onclick="location.href='/admin'">Admin?</button> 41 90 </div> 42 91 43 <script> 44 new Vue({ 45 el: '#app', 46 data: { 47 tickets: [ 48 { id: 1, subject: 'Flight booking issue', description: 'Customer could not book a flight.', date: '2025-02-01' }, 49 { id: 2, subject: 'Payment failure', description: 'Payment was not processed during checkout.', date: '2025-02-02' } 50 ], 51 selectedTicket: null 52 }, 53 methods: { 54 resolveTicket(id) { 55 alert(`Ticket ${id} resolved.`); 56 // Optionally, you can update the ticket's status or remove it 57 }, 58 selectTicket(ticket) { 59 this.selectedTicket = ticket; 60 } 61 } 62 }); 63 </script> 64 92 <div class="buttons"> 93 <button class="signup" onclick="location.href='/signup'">Sign Up</button> 94 <button class="login" onclick="location.href='/login'">Login</button> 95 </div> 65 96 </body> 66 97 </html>
Note:
See TracChangeset
for help on using the changeset viewer.