From 0ba462f7858e15974f8079084e418b77c675e8c7 Mon Sep 17 00:00:00 2001 From: migudel <miguel.moras@estudiantes.uva.es> Date: Sun, 3 Nov 2024 12:45:44 +0100 Subject: [PATCH] Agregado vista de reservas de usuario --- .../bookings/booking/booking.component.ts | 18 +++++-- .../user/main-page/main-page.component.html | 14 ++++-- .../user/main-page/main-page.component.ts | 3 +- .../user-booking-list.component.html | 25 +++++++++- .../user-booking-list.component.ts | 48 ++++++++++++++++++- .../app/shared/cliente-api-rest.service.ts | 22 ++++++++- angular/RestClient/src/types/Booking.d.ts | 4 +- angular/RestClient/src/types/User.d.ts | 7 ++- angular/package-lock.json | 6 --- .../Controllers/UserController.java | 29 +++++++---- .../Repositories/BookingRepository.java | 3 -- 11 files changed, 144 insertions(+), 35 deletions(-) delete mode 100644 angular/package-lock.json 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 803417a..caa8887 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 35ecb31..0685752 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 4d31d5f..e1f7201 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 75ada56..2df122e 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 568e58c..76220e6 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 6cfa26d..31c4590 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 aac08c6..797c8aa 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 ac99f9d..09a0ec8 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 2e8ea37..0000000 --- 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 a2e8961..a336822 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 d988f40..a010a3a 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); -- GitLab