diff --git a/angular/RestClient/src/app/core/features/bookings/booking/booking.component.ts b/angular/RestClient/src/app/core/features/bookings/booking/booking.component.ts index 803417af352f0c52d9bcd2025d664bd380b2f65b..caa88872745a726998ab3347fa4db32e7c822153 100644 --- a/angular/RestClient/src/app/core/features/bookings/booking/booking.component.ts +++ b/angular/RestClient/src/app/core/features/bookings/booking/booking.component.ts @@ -7,7 +7,7 @@ import { } from '@angular/forms'; import { BookingService } from '../../../../shared/booking.service'; // Asegúrate de que el servicio exista -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { Booking } from '../../../../../types'; @Component({ @@ -22,6 +22,7 @@ export class BookingComponent implements OnInit { roomId: number = 0; constructor( + private router: Router, private route: ActivatedRoute, private fb: FormBuilder, private bookingService: BookingService @@ -45,9 +46,10 @@ export class BookingComponent implements OnInit { submitBooking() { if (this.bookingForm.valid) { const formValue = this.bookingForm.value; + const { userId } = formValue; const bookingRequest: Booking = { ...formValue, - userId: { id: formValue.userId }, + userId: { id: userId }, roomId: { id: formValue.roomId }, }; console.warn(bookingRequest); @@ -56,8 +58,16 @@ export class BookingComponent implements OnInit { this.bookingService.createBooking(bookingRequest).subscribe( (response) => { console.log('Reserva creada con éxito', response); - // Aquí puedes redirigir al usuario o mostrar un mensaje de éxito - this.bookingForm.reset(); // Opcional: resetea el formulario después de una reserva exitosa + // Llama al servicio para actualizar el estado del usuario + this.bookingService.createBooking(bookingRequest).subscribe({ + next: (response) => { + console.log('Reserva creada con éxito', response); + }, + error: (error) => { + console.error('Error al crear la reserva', error); + }, + }); + this.router.navigate(['/user', userId, 'bookings']); }, (error) => { console.error('Error al crear la reserva', error); diff --git a/angular/RestClient/src/app/core/features/user/main-page/main-page.component.html b/angular/RestClient/src/app/core/features/user/main-page/main-page.component.html index 35ecb3160c1f96b219142bfb1a673dae651b2679..06857529f8bf00a6937bb6b02d36bd32879458d5 100644 --- a/angular/RestClient/src/app/core/features/user/main-page/main-page.component.html +++ b/angular/RestClient/src/app/core/features/user/main-page/main-page.component.html @@ -12,10 +12,14 @@ </div> <ul class="user-list"> - <li *ngFor="let user of filteredUsers" class="user-item"> - <span class="user-name">{{ user.name }}</span> - <span class="user-email">{{ user.email }}</span> - <span class="user-status">{{ user.status }}</span> - </li> + @for (user of filteredUsers; track user.id) { + <a [routerLink]="['/users', user.id, 'bookings']"> + <li class="user-item"> + <span class="user-name">{{ user.name }}</span> + <span class="user-email">{{ user.email }}</span> + <span class="user-status">{{ user.status }}</span> + </li> + </a> + } </ul> </div> diff --git a/angular/RestClient/src/app/core/features/user/main-page/main-page.component.ts b/angular/RestClient/src/app/core/features/user/main-page/main-page.component.ts index 4d31d5fb5e02714ff027f7294df31d403cdeef86..e1f720168b60365a0753522e0333b8c14e771fc7 100644 --- a/angular/RestClient/src/app/core/features/user/main-page/main-page.component.ts +++ b/angular/RestClient/src/app/core/features/user/main-page/main-page.component.ts @@ -5,9 +5,10 @@ import { User } from '../../../../../types'; import { FormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; import users from '../../../../../mocks/users.json'; +import { RouterModule } from '@angular/router'; @Component({ standalone: true, - imports: [FormsModule, CommonModule], + imports: [FormsModule, CommonModule, RouterModule], selector: 'app-main-page', templateUrl: './main-page.component.html', styleUrls: ['./main-page.component.css'], diff --git a/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.html b/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.html index 75ada56bb00e07afa3eb45f457f137df9c5b24c3..2df122e3a62fe1e0bf61b6211fea87a22fcf43d6 100644 --- a/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.html +++ b/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.html @@ -1 +1,24 @@ -<p>user-booking-list works!</p> +<div class="booking-container"> + <h1>Listado de Reservas</h1> + + <div class="filter-container"> + <label for="filter">Filtrar por estado:</label> + <select id="filter" [(ngModel)]="selectedState" (change)="updateBookings()"> + <option value="all">Todas</option> + <option value="active">Reservas activas</option> + <option value="inactive">Reservas inactivas</option> + </select> + </div> + + <ul class="booking-list"> + @for( booking of bookings; track booking.id) { + <li class="booking-item"> + <span class="booking-id">Reserva #{{ booking.id }}</span> + <span class="booking-dates" + >{{ booking.startDate }} - {{ booking.endDate }}</span + > + <span class="booking-status">{{ genBookingState(booking) }}</span> + </li> + } + </ul> +</div> diff --git a/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.ts b/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.ts index 568e58c4db9eff3e0cbfe3cd59a570b6d6d49db3..76220e6fc852a710d72b9086cce6f3763f6b74e5 100644 --- a/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.ts +++ b/angular/RestClient/src/app/core/features/user/user-booking-list/user-booking-list.component.ts @@ -1,12 +1,56 @@ import { Component } from '@angular/core'; +import { ClienteApiRestService } from '../../../../shared/cliente-api-rest.service'; +import { Booking } from '../../../../../types'; +import { ActivatedRoute, RouterModule } from '@angular/router'; +import { MatSelectModule } from '@angular/material/select'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +type state = 'all' | 'active' | 'inactive'; @Component({ selector: 'app-user-booking-list', standalone: true, - imports: [], + imports: [FormsModule, CommonModule, RouterModule], templateUrl: './user-booking-list.component.html', - styleUrl: './user-booking-list.component.css' + styleUrl: './user-booking-list.component.css', }) export class UserBookingListComponent { + selectedState: state = 'all'; + bookings: Booking[] = []; + userId: number = 0; + + constructor( + private client: ClienteApiRestService, + private route: ActivatedRoute + ) { + this.route.paramMap.subscribe({ + next: (params) => { + this.userId = Number(params.get('id')); + this.updateBookings(); + }, + }); + } + + ngOnInit() { + this.updateBookings(); + } + + updateBookings() { + this.client.getUserBookings(this.userId).subscribe({ + next: (bookings) => { + this.bookings = bookings; + console.log({ bookings }); + }, + error: (error) => { + console.error(error); + }, + }); + } + genBookingState(booking: Booking) { + return new Date(booking.endDate).getTime() < Date.now() + ? 'Reserva inactiva' + : 'Reserva activa'; + } } diff --git a/angular/RestClient/src/app/shared/cliente-api-rest.service.ts b/angular/RestClient/src/app/shared/cliente-api-rest.service.ts index 6cfa26dd890aa8b7ddc91ee5376ad4fc2c328b4f..31c4590202a9dd1795b196ccaf4e7a3d0782778b 100644 --- a/angular/RestClient/src/app/shared/cliente-api-rest.service.ts +++ b/angular/RestClient/src/app/shared/cliente-api-rest.service.ts @@ -1,7 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { Hotel, Booking, Room } from '../../types'; -import { Observable } from 'rxjs'; +import { Hotel, Booking, Room, UserState } from '../../types'; import { User } from '../../types'; @Injectable({ @@ -69,4 +68,23 @@ export class ClienteApiRestService { observe: 'body', }); } + + getUserBookings(userId: number) { + return this.http.get<Booking[]>( + `${ClienteApiRestService.BASE_URI}/users/${userId}/bookings` + ); + } + + alterUserStatus(status: UserState) { + return this.http.patch( + `${ClienteApiRestService.BASE_URI}/users`, + { + status, + }, + { + observe: 'response', + responseType: 'text', + } + ); + } } diff --git a/angular/RestClient/src/types/Booking.d.ts b/angular/RestClient/src/types/Booking.d.ts index aac08c692615398dce13a8ad0dc8c1866027d36f..797c8aafb11b15aff5ac7cb9a3f4b510d7628284 100644 --- a/angular/RestClient/src/types/Booking.d.ts +++ b/angular/RestClient/src/types/Booking.d.ts @@ -5,6 +5,6 @@ export interface Booking { id: number; startDate: Date; endDate: Date; - user: User; - room: Room; + userId: User; + roomId: Room; } diff --git a/angular/RestClient/src/types/User.d.ts b/angular/RestClient/src/types/User.d.ts index ac99f9de94fd9bfc0c839f8c35fca5b1a45d9783..09a0ec82f1aa9dab3f0a946cca718206297c8c13 100644 --- a/angular/RestClient/src/types/User.d.ts +++ b/angular/RestClient/src/types/User.d.ts @@ -3,5 +3,10 @@ export interface User { name: string; email: String; // status: "noBookings" | "withActiveBookings" | "withInactiveBookings"; - status: 'NO_BOOKINGS' | 'WITH_ACTIVE_BOOKINGS' | 'WITH_INACTIVE_BOOKINGS'; + status: UserState; } + +export type UserState = + | 'NO_BOOKINGS' + | 'WITH_ACTIVE_BOOKINGS' + | 'WITH_INACTIVE_BOOKINGS'; diff --git a/angular/package-lock.json b/angular/package-lock.json deleted file mode 100644 index 2e8ea3773995634d5992101777fe05f484f55b9e..0000000000000000000000000000000000000000 --- a/angular/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "angular", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/UserController.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/UserController.java index a2e8961252f4df18b75b92d18ee42b5e7d05fd36..a336822dccd7f7a597356a4b68f3ff51c177c22e 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/UserController.java +++ b/java/roomBooking/src/main/java/com/uva/roomBooking/Controllers/UserController.java @@ -1,5 +1,6 @@ package com.uva.roomBooking.Controllers; +import java.time.LocalDate; import java.util.List; import java.util.Map; @@ -17,7 +18,6 @@ import org.springframework.web.bind.annotation.RestController; import com.uva.roomBooking.Models.UserStatus; import com.uva.roomBooking.Models.Booking; import com.uva.roomBooking.Models.User; -import com.uva.roomBooking.Repositories.BookingRepository; import com.uva.roomBooking.Repositories.UserRepository; @RestController @@ -25,11 +25,9 @@ import com.uva.roomBooking.Repositories.UserRepository; @CrossOrigin(origins = "*") public class UserController { private final UserRepository userRepository; - private final BookingRepository bookingRepository; - public UserController(UserRepository userRepository, BookingRepository bookingRepository) { + public UserController(UserRepository userRepository) { this.userRepository = userRepository; - this.bookingRepository = bookingRepository; } @GetMapping @@ -71,17 +69,32 @@ public class UserController { throw new RuntimeException("Missing required fields"); } UserStatus userStatus = UserStatus.valueOf(strStatus); + + // TODO decicir cual va a ser nuestra politica + boolean activeBookings = target.getBookings().stream() + .anyMatch(booking -> booking.getEndDate().isAfter(LocalDate.now())); // reserva > ahora + // boolean activeBookings = target.getBookings().stream().anyMatch(booking -> + // !booking.getEndDate().isBefore(LocalDate.now())); // reserva >= ahora + boolean inactiveBookings = target.getBookings().stream() + .anyMatch(booking -> booking.getStartDate().isBefore(LocalDate.now())); // reserva < ahora + // boolean inactiveBookings = target.getBookings().stream().anyMatch(booking -> + // !booking.getStartDate().isAfter(LocalDate.now())); // reserva <= ahora + switch (userStatus) { // TODO Buscar como validar las (in)active bookings case NO_BOOKINGS: if (!target.getBookings().isEmpty()) - throw new IllegalArgumentException("Invalid State: The user have at least one booking"); + throw new IllegalArgumentException("Invalid State: The user has at least one booking"); case WITH_ACTIVE_BOOKINGS: if (target.getBookings().isEmpty()) - throw new IllegalArgumentException("Invalid State: The user don't have bookings"); + throw new IllegalArgumentException("Invalid State: The user don't has bookings"); + if (!activeBookings) + throw new IllegalArgumentException("Invalid State: The user don't has active bookings"); case WITH_INACTIVE_BOOKINGS: if (target.getBookings().isEmpty()) - throw new IllegalArgumentException("Invalid State: The user don't have bookings"); + throw new IllegalArgumentException("Invalid State: The user don't has bookings"); + if (!inactiveBookings) + throw new IllegalArgumentException("Invalid State: The user don't has inactive bookings"); default: break; } @@ -101,6 +114,6 @@ public class UserController { @GetMapping("/{id}/bookings") public List<Booking> getUserBookingsById(@PathVariable int id) { User user = userRepository.findById(id).orElseThrow(); - return bookingRepository.findByUserId(user); + return user.getBookings(); } } diff --git a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java b/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java index d988f40a668af629bf64a142737f4f5f70bc432b..a010a3a19ccfbb0fafd588c4fb7a52cb530897d9 100644 --- a/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java +++ b/java/roomBooking/src/main/java/com/uva/roomBooking/Repositories/BookingRepository.java @@ -2,7 +2,6 @@ package com.uva.roomBooking.Repositories; import com.uva.roomBooking.Models.Booking; -import com.uva.roomBooking.Models.User; import java.time.LocalDate; import java.util.List; @@ -13,8 +12,6 @@ import org.springframework.data.repository.query.Param; public interface BookingRepository extends JpaRepository<Booking, Integer> { - List<Booking> findByUserId(User userId); - @Query("SELECT b FROM Booking b WHERE b.roomId.id = ?1 AND b.startDate < ?2 AND b.endDate > ?3") List<Booking> findByRoomIdAndDateRange(@Param("roomId") int roomId, @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate);