Skip to content
Snippets Groups Projects
Commit 0ba462f7 authored by migudel's avatar migudel :speech_balloon:
Browse files

Agregado vista de reservas de usuario

parent abf85c79
Branches master
No related tags found
1 merge request!10Add ts types and json mocks, remove poblate scripts and fix the cascade...
Showing
with 144 additions and 35 deletions
...@@ -7,7 +7,7 @@ import { ...@@ -7,7 +7,7 @@ import {
} from '@angular/forms'; } from '@angular/forms';
import { BookingService } from '../../../../shared/booking.service'; // Asegúrate de que el servicio exista 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'; import { Booking } from '../../../../../types';
@Component({ @Component({
...@@ -22,6 +22,7 @@ export class BookingComponent implements OnInit { ...@@ -22,6 +22,7 @@ export class BookingComponent implements OnInit {
roomId: number = 0; roomId: number = 0;
constructor( constructor(
private router: Router,
private route: ActivatedRoute, private route: ActivatedRoute,
private fb: FormBuilder, private fb: FormBuilder,
private bookingService: BookingService private bookingService: BookingService
...@@ -45,9 +46,10 @@ export class BookingComponent implements OnInit { ...@@ -45,9 +46,10 @@ export class BookingComponent implements OnInit {
submitBooking() { submitBooking() {
if (this.bookingForm.valid) { if (this.bookingForm.valid) {
const formValue = this.bookingForm.value; const formValue = this.bookingForm.value;
const { userId } = formValue;
const bookingRequest: Booking = { const bookingRequest: Booking = {
...formValue, ...formValue,
userId: { id: formValue.userId }, userId: { id: userId },
roomId: { id: formValue.roomId }, roomId: { id: formValue.roomId },
}; };
console.warn(bookingRequest); console.warn(bookingRequest);
...@@ -56,8 +58,16 @@ export class BookingComponent implements OnInit { ...@@ -56,8 +58,16 @@ export class BookingComponent implements OnInit {
this.bookingService.createBooking(bookingRequest).subscribe( this.bookingService.createBooking(bookingRequest).subscribe(
(response) => { (response) => {
console.log('Reserva creada con éxito', response); console.log('Reserva creada con éxito', response);
// Aquí puedes redirigir al usuario o mostrar un mensaje de éxito // Llama al servicio para actualizar el estado del usuario
this.bookingForm.reset(); // Opcional: resetea el formulario después de una reserva exitosa 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) => { (error) => {
console.error('Error al crear la reserva', error); console.error('Error al crear la reserva', error);
......
...@@ -12,10 +12,14 @@ ...@@ -12,10 +12,14 @@
</div> </div>
<ul class="user-list"> <ul class="user-list">
<li *ngFor="let user of filteredUsers" class="user-item"> @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-name">{{ user.name }}</span>
<span class="user-email">{{ user.email }}</span> <span class="user-email">{{ user.email }}</span>
<span class="user-status">{{ user.status }}</span> <span class="user-status">{{ user.status }}</span>
</li> </li>
</a>
}
</ul> </ul>
</div> </div>
...@@ -5,9 +5,10 @@ import { User } from '../../../../../types'; ...@@ -5,9 +5,10 @@ import { User } from '../../../../../types';
import { FormsModule } from '@angular/forms'; import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import users from '../../../../../mocks/users.json'; import users from '../../../../../mocks/users.json';
import { RouterModule } from '@angular/router';
@Component({ @Component({
standalone: true, standalone: true,
imports: [FormsModule, CommonModule], imports: [FormsModule, CommonModule, RouterModule],
selector: 'app-main-page', selector: 'app-main-page',
templateUrl: './main-page.component.html', templateUrl: './main-page.component.html',
styleUrls: ['./main-page.component.css'], styleUrls: ['./main-page.component.css'],
......
<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>
import { Component } from '@angular/core'; 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({ @Component({
selector: 'app-user-booking-list', selector: 'app-user-booking-list',
standalone: true, standalone: true,
imports: [], imports: [FormsModule, CommonModule, RouterModule],
templateUrl: './user-booking-list.component.html', templateUrl: './user-booking-list.component.html',
styleUrl: './user-booking-list.component.css' styleUrl: './user-booking-list.component.css',
}) })
export class UserBookingListComponent { 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';
}
} }
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { Hotel, Booking, Room } from '../../types'; import { Hotel, Booking, Room, UserState } from '../../types';
import { Observable } from 'rxjs';
import { User } from '../../types'; import { User } from '../../types';
@Injectable({ @Injectable({
...@@ -69,4 +68,23 @@ export class ClienteApiRestService { ...@@ -69,4 +68,23 @@ export class ClienteApiRestService {
observe: 'body', 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',
}
);
}
} }
...@@ -5,6 +5,6 @@ export interface Booking { ...@@ -5,6 +5,6 @@ export interface Booking {
id: number; id: number;
startDate: Date; startDate: Date;
endDate: Date; endDate: Date;
user: User; userId: User;
room: Room; roomId: Room;
} }
...@@ -3,5 +3,10 @@ export interface User { ...@@ -3,5 +3,10 @@ export interface User {
name: string; name: string;
email: String; email: String;
// status: "noBookings" | "withActiveBookings" | "withInactiveBookings"; // 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';
{
"name": "angular",
"lockfileVersion": 3,
"requires": true,
"packages": {}
}
package com.uva.roomBooking.Controllers; package com.uva.roomBooking.Controllers;
import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -17,7 +18,6 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -17,7 +18,6 @@ import org.springframework.web.bind.annotation.RestController;
import com.uva.roomBooking.Models.UserStatus; import com.uva.roomBooking.Models.UserStatus;
import com.uva.roomBooking.Models.Booking; import com.uva.roomBooking.Models.Booking;
import com.uva.roomBooking.Models.User; import com.uva.roomBooking.Models.User;
import com.uva.roomBooking.Repositories.BookingRepository;
import com.uva.roomBooking.Repositories.UserRepository; import com.uva.roomBooking.Repositories.UserRepository;
@RestController @RestController
...@@ -25,11 +25,9 @@ import com.uva.roomBooking.Repositories.UserRepository; ...@@ -25,11 +25,9 @@ import com.uva.roomBooking.Repositories.UserRepository;
@CrossOrigin(origins = "*") @CrossOrigin(origins = "*")
public class UserController { public class UserController {
private final UserRepository userRepository; private final UserRepository userRepository;
private final BookingRepository bookingRepository;
public UserController(UserRepository userRepository, BookingRepository bookingRepository) { public UserController(UserRepository userRepository) {
this.userRepository = userRepository; this.userRepository = userRepository;
this.bookingRepository = bookingRepository;
} }
@GetMapping @GetMapping
...@@ -71,17 +69,32 @@ public class UserController { ...@@ -71,17 +69,32 @@ public class UserController {
throw new RuntimeException("Missing required fields"); throw new RuntimeException("Missing required fields");
} }
UserStatus userStatus = UserStatus.valueOf(strStatus); 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) { switch (userStatus) {
// TODO Buscar como validar las (in)active bookings // TODO Buscar como validar las (in)active bookings
case NO_BOOKINGS: case NO_BOOKINGS:
if (!target.getBookings().isEmpty()) 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: case WITH_ACTIVE_BOOKINGS:
if (target.getBookings().isEmpty()) 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: case WITH_INACTIVE_BOOKINGS:
if (target.getBookings().isEmpty()) 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: default:
break; break;
} }
...@@ -101,6 +114,6 @@ public class UserController { ...@@ -101,6 +114,6 @@ public class UserController {
@GetMapping("/{id}/bookings") @GetMapping("/{id}/bookings")
public List<Booking> getUserBookingsById(@PathVariable int id) { public List<Booking> getUserBookingsById(@PathVariable int id) {
User user = userRepository.findById(id).orElseThrow(); User user = userRepository.findById(id).orElseThrow();
return bookingRepository.findByUserId(user); return user.getBookings();
} }
} }
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
package com.uva.roomBooking.Repositories; package com.uva.roomBooking.Repositories;
import com.uva.roomBooking.Models.Booking; import com.uva.roomBooking.Models.Booking;
import com.uva.roomBooking.Models.User;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
...@@ -13,8 +12,6 @@ import org.springframework.data.repository.query.Param; ...@@ -13,8 +12,6 @@ import org.springframework.data.repository.query.Param;
public interface BookingRepository extends JpaRepository<Booking, Integer> { 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") @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, List<Booking> findByRoomIdAndDateRange(@Param("roomId") int roomId, @Param("startDate") LocalDate startDate,
@Param("endDate") LocalDate endDate); @Param("endDate") LocalDate endDate);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment