diff --git a/.gitignore b/.gitignore index 73cfdb62c0d09ddc5671811621d994cd2271da64..7498efe6d462c0f40b2634da5fbb926432f1eeab 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,9 @@ taller *.pdf **/target/ -**/.vscode \ No newline at end of file +**/.vscode + +**/tmp +**/*.tmp +**/target +**/*.ln \ No newline at end of file diff --git a/angular/RestClient/src/app/app.routes.ts b/angular/RestClient/src/app/app.routes.ts index 1ce26aedf31b469cb240caedf2e61b0fee4ff3e9..51aacbb7f9be2b3f9af5d3a7d4eaafb164c5ba26 100644 --- a/angular/RestClient/src/app/app.routes.ts +++ b/angular/RestClient/src/app/app.routes.ts @@ -5,7 +5,7 @@ import { HotelRegisterComponent } from './core/features/hotel/hotel-register/hot import { MainPageComponent } from './core/features/user/main-page/main-page.component'; import { BookingListComponent } from './core/features/bookings/booking-list/booking-list.component'; import { UserBookingListComponent } from './core/features/user/user-booking-list/user-booking-list.component'; -import { UserFormComponent} from './core/features/user/user-form/user-form.component'; +import { UserFormComponent } from './core/features/user/user-form/user-form.component'; export const routes: Routes = [ { @@ -40,6 +40,10 @@ export const routes: Routes = [ path: 'users/:id', component: UserFormComponent, }, + { + path: 'register', + component: UserFormComponent, + }, { path: '**', redirectTo: '', 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 468ec54164998e93265193162e34e7526131036d..c3506bbd37ebb81f35189e481d64e9875bac28b3 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 @@ -1,10 +1,10 @@ import { Component, OnInit } from '@angular/core'; -import { User, UserStateFilter } from '../../../../../types'; +import { Client, User, UserStateFilter } from '../../../../../types'; import { FormsModule } from '@angular/forms'; import { CommonModule } from '@angular/common'; import { RouterModule } from '@angular/router'; import { UserClientService } from '../../../../shared/user-client.service'; -import mockUsers from '../../../../../mocks/users.json'; // Renombrado para claridad +import { users } from '../../../../../mocks/users'; // Renombrado para claridad @Component({ standalone: true, @@ -14,21 +14,22 @@ import mockUsers from '../../../../../mocks/users.json'; // Renombrado para clar styleUrls: ['./main-page.component.css'], }) export class MainPageComponent implements OnInit { - users: User[] = []; - filteredUsers: User[] = []; + users: Client[] = []; + filteredUsers: Client[] = []; selectedStatus: UserStateFilter = 'All'; constructor(private userClient: UserClientService) {} ngOnInit(): void { // Validar que el mock sea del tipo correcto - const isValidMock = Array.isArray(mockUsers) && mockUsers.every(user => 'id' in user && 'name' in user && 'status' in user); - this.users = isValidMock ? (mockUsers as User[]) : []; + // const isValidMock = Array.isArray(mockUsers) && mockUsers.every(user => 'id' in user && 'name' in user && 'status' in user); + // this.users = isValidMock ? (mockUsers as User[]) : []; + this.users = users; this.filteredUsers = [...this.users]; // Sobrescribir con datos reales si están disponibles this.userClient.getAllUsers().subscribe({ - next: (data: User[]) => { + next: (data: Client[]) => { this.users = data; this.filteredUsers = [...data]; }, @@ -46,7 +47,7 @@ export class MainPageComponent implements OnInit { } } - getState(user: User): string { + getState(user: Client): string { switch (user.status) { case 'NO_BOOKINGS': return 'SIN RESERVAS'; diff --git a/angular/RestClient/src/app/core/features/user/user-form/user-form.component.html b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.html index 92bcb7c97d45e220d97213eb0379111b70d550d3..d68f32bfd2d6a14846503422e0273bc04effd127 100644 --- a/angular/RestClient/src/app/core/features/user/user-form/user-form.component.html +++ b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.html @@ -25,8 +25,9 @@ /> </div> + @if (isEditing) { <!-- Campo Contraseña Actual (solo en edición) --> - <div class="form-group" *ngIf="isEditing"> + <div class="form-group"> <label for="currentPassword">Contraseña actual:</label> <input id="currentPassword" @@ -38,7 +39,7 @@ </div> <!-- Campo Nueva Contraseña (solo en edición) --> - <div class="form-group" *ngIf="isEditing"> + <div class="form-group"> <label for="newPassword">Nueva contraseña:</label> <input id="newPassword" @@ -48,35 +49,27 @@ placeholder="Introduce tu nueva contraseña" /> </div> + } <!-- Grupo de Botones --> <div class="button-group"> - <button - *ngIf="!isEditing" - type="button" - class="btn btn-primary" - (click)="toggleEdit()" - > + @if (!isEditing) { + <button type="button" class="btn btn-primary" (click)="toggleEdit()"> Editar </button> - - <button - *ngIf="isEditing" - type="button" - class="btn btn-secondary" - (click)="cancelEdit()" - > + } @else { + <button type="button" class="btn btn-secondary" (click)="cancelEdit()"> Cancelar </button> <button - *ngIf="isEditing" type="submit" class="btn btn-success" [disabled]="!userForm.valid" > Guardar </button> + } </div> </form> </div> diff --git a/angular/RestClient/src/app/core/features/user/user-form/user-form.component.ts b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.ts index 9627686755f1d00d3886e3a15385f42b662370f0..558e1c58a73e3d7ef1eaf852bce1a989a40bc42b 100644 --- a/angular/RestClient/src/app/core/features/user/user-form/user-form.component.ts +++ b/angular/RestClient/src/app/core/features/user/user-form/user-form.component.ts @@ -1,6 +1,14 @@ import { Component, OnInit } from '@angular/core'; -import { FormBuilder, FormGroup, Validators, ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { + FormBuilder, + FormGroup, + Validators, + ReactiveFormsModule, + FormsModule, +} from '@angular/forms'; import { UserClientService } from '../../../../shared/user-client.service'; +import { users } from '../../../../../mocks/users'; +import { ActivatedRoute } from '@angular/router'; @Component({ standalone: true, @@ -12,30 +20,52 @@ import { UserClientService } from '../../../../shared/user-client.service'; export class UserFormComponent implements OnInit { userForm!: FormGroup; isEditing = false; + id = 0; - constructor(private fb: FormBuilder, private userService: UserClientService) {} + constructor( + private fb: FormBuilder, + private userService: UserClientService, + private route: ActivatedRoute + ) {} ngOnInit(): void { this.initializeForm(); - // this.loadUserData(); + this.route.paramMap.subscribe({ + next: (params) => { + const id = Number(params.get('id')); + if (id) { + this.id = id; + this.isEditing = true; + this.loadUserData(); + } + }, + }); } private initializeForm(): void { this.userForm = this.fb.group({ name: [{ value: '', disabled: true }, Validators.required], - email: [{ value: '', disabled: true }, [Validators.required, Validators.email]], + email: [ + { value: '', disabled: true }, + [Validators.required, Validators.email], + ], currentPassword: [''], // Solo habilitado en modo edición newPassword: [''], // Solo habilitado en modo edición }); } private loadUserData(): void { - this.userService.getCurrentUser().subscribe((user) => { - this.userForm.patchValue({ - name: user.name, - email: user.email, + // this.userService.getCurrentUser().subscribe((user) => { + console.log({ id: this.id }); + users + .filter((u) => u.id == this.id) + .slice(0) + .map((user) => { + this.userForm.patchValue({ + name: user.name, + email: user.email, + }); }); - }); } toggleEdit(): void { diff --git a/angular/RestClient/src/app/core/navigation/navigation.component.html b/angular/RestClient/src/app/core/navigation/navigation.component.html index 63615464cbbf7aec69cbd99e5e33ea9d1e5e08d8..6ba3f139cd79d2fdfae6deb883b6a91e995ce6fd 100644 --- a/angular/RestClient/src/app/core/navigation/navigation.component.html +++ b/angular/RestClient/src/app/core/navigation/navigation.component.html @@ -8,5 +8,63 @@ <li> <a class="btn" [routerLink]="['/bookings', 'search']">Nueva Reserva</a> </li> + <li class="ml-auto"> + @if (isLogged){ + <!-- Dropdown para usuario registrado --> + <div class="relative ml-6"> + <button + (click)="toggleDropdown()" + class="flex items-center space-x-2 p-2 bg-blue-500 text-white rounded hover:bg-blue-600 focus:outline-none" + > + <span>{{ userName }}</span> + <svg + xmlns="http://www.w3.org/2000/svg" + class="h-5 w-5" + viewBox="0 0 20 20" + fill="currentColor" + > + <path + fill-rule="evenodd" + d="M5.23 7.21a.75.75 0 011.06.02L10 10.94l3.71-3.71a.75.75 0 111.06 1.06l-4 4a.75.75 0 01-1.06 0l-4-4a.75.75 0 01.02-1.06z" + clip-rule="evenodd" + /> + </svg> + </button> + + <!-- Menú desplegable --> + @if (dropdownOpen) { + <div + class="absolute right-0 mt-2 w-48 bg-slate-700 border border-gray-500 rounded shadow-lg" + > + <ul> + <li> + <a + class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" + [routerLink]="['/bookings']" + > + Mis Reservas + </a> + </li> + <li> + <a + class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100" + > + <!-- (click)="logout()" --> + Cerrar Sesión + </a> + </li> + </ul> + </div> + } + </div> + + } @else { + <a + class="btn bg-blue-500 text-white ml-6 hover:bg-blue-600" + [routerLink]="['/login']" + >Login</a + > + } + </li> </ul> </nav> diff --git a/angular/RestClient/src/app/core/navigation/navigation.component.ts b/angular/RestClient/src/app/core/navigation/navigation.component.ts index ccdab77b49379e3ed27abd65ada67e693882939a..69efb6ad2307d3ac4f6865450372e280ec639519 100644 --- a/angular/RestClient/src/app/core/navigation/navigation.component.ts +++ b/angular/RestClient/src/app/core/navigation/navigation.component.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; import { Router, RouterModule } from '@angular/router'; +import { AuthClientService } from '../../shared/auth-client.service'; @Component({ selector: 'app-navigation', standalone: true, @@ -7,4 +8,24 @@ import { Router, RouterModule } from '@angular/router'; templateUrl: './navigation.component.html', styleUrl: './navigation.component.css', }) -export class NavigationComponent {} +export class NavigationComponent { + isLogged = true; + userName = 'User'; + dropdownOpen = false; + + constructor(private authClient: AuthClientService) {} + + toggleDropdown() { + this.dropdownOpen = !this.dropdownOpen; + this.authClient.login('migudel@dev.com', 'NQSASorry').subscribe({ + next: (response) => { + console.log(response); + alert('OKEY! You are logged'); + }, + error: (error) => { + console.error(error); + alert('Error! You are not logged'); + }, + }); + } +} diff --git a/angular/RestClient/src/app/shared/auth-client.service.ts b/angular/RestClient/src/app/shared/auth-client.service.ts index 61bf7a25a37f8e8208b30e789aa1086e72c6ba32..931fc7dbacbec3db5e5d048722fa5980017355e7 100644 --- a/angular/RestClient/src/app/shared/auth-client.service.ts +++ b/angular/RestClient/src/app/shared/auth-client.service.ts @@ -13,17 +13,17 @@ export class AuthClientService { login(email: String, password: String) { return this.http.post( `${this.URI}/login`, - { email, password }, - { - headers: { - 'Content-Type': 'application/json', - 'Access-Control-Allow-Origin': '*', - 'Access-Control-Allow-Methods': - 'GET, POST, OPTIONS, PUT, PATCH, DELETE', - 'Access-Control-Allow-Headers': 'X-Requested-With,content-type', - 'Access-Control-Allow-Credentials': 'true', - }, - } + { email, password } + // { + // headers: { + // 'Content-Type': 'application/json', + // 'Access-Control-Allow-Origin': '*', + // 'Access-Control-Allow-Methods': + // 'GET, POST, OPTIONS, PUT, PATCH, DELETE', + // 'Access-Control-Allow-Headers': 'X-Requested-With,content-type', + // 'Access-Control-Allow-Credentials': 'true', + // }, + // } ); } diff --git a/angular/RestClient/src/app/shared/user-client.service.ts b/angular/RestClient/src/app/shared/user-client.service.ts index 3e42700ffab602cc1bb5b219a8b8bec5d8a6f4a1..7383a72b9aefd100bc87ebba38ef287e27eff3dd 100644 --- a/angular/RestClient/src/app/shared/user-client.service.ts +++ b/angular/RestClient/src/app/shared/user-client.service.ts @@ -1,7 +1,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { environment } from '../../../environments/environment'; -import { User, UserState } from '../../types'; +import { Client, User, UserState } from '../../types'; @Injectable({ providedIn: 'root', @@ -18,7 +18,7 @@ export class UserClientService { // Obtener todos los usuarios getAllUsers() { - return this.http.get<User[]>(this.URI, { + return this.http.get<Client[]>(this.URI, { observe: 'body', }); } diff --git a/angular/RestClient/src/mocks/users.json b/angular/RestClient/src/mocks/users.json deleted file mode 100644 index 79c155fa54e09974615ea2fab044e4b19e31f161..0000000000000000000000000000000000000000 --- a/angular/RestClient/src/mocks/users.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "id": 1, - "name": "John Doe", - "email": "jon@com", - "status": "NO_BOOKINGS" - }, - { - "id": 2, - "name": "Jane Smith", - "status": "WITH_ACTIVE_BOOKINGS" - } - ] - \ No newline at end of file diff --git a/angular/RestClient/src/mocks/users.ts b/angular/RestClient/src/mocks/users.ts new file mode 100644 index 0000000000000000000000000000000000000000..ffdf8f23af07980429bbb8cbf6a1e351bb555958 --- /dev/null +++ b/angular/RestClient/src/mocks/users.ts @@ -0,0 +1,18 @@ +import { Client, User } from '../types'; + +export const users: Client[] = [ + { + id: 1, + name: 'John Doe', + email: 'jon@com', + rol: 'CLIENT', + status: 'NO_BOOKINGS', + }, + { + id: 2, + name: 'Angela Doe', + email: 'angle@com', + rol: 'CLIENT', + status: 'NO_BOOKINGS', + }, +]; diff --git a/angular/RestClient/src/types/User.d.ts b/angular/RestClient/src/types/User.d.ts index 1ecc3d7512e7ff0b644e5555d290c48e88518219..277f806a74fb1b2f854d733cc10acca67f18b840 100644 --- a/angular/RestClient/src/types/User.d.ts +++ b/angular/RestClient/src/types/User.d.ts @@ -2,10 +2,20 @@ export interface User { id: number; name: string; email: String; - // status: "noBookings" | "withActiveBookings" | "withInactiveBookings"; + rol: UserRol; +} + +export interface Client extends User { status: UserState; + // bookings: number[] // Booking[] } +export interface HotelAdmin extends User { + // hotels: number[] // Hotel[] +} + +export type UserRol = 'ADMIN' | 'CLIENT' | 'HOTEL_ADMIN'; + export type UserStateFilter = 'All' | UserState; export type UserState = diff --git a/java/services/auth/src/main/java/com/uva/authentication/controllers/AuthController.java b/java/services/auth/src/main/java/com/uva/authentication/controllers/AuthController.java index 08ad46a807354a557e2bd5f6f6f9d5fc94a79949..a877bb7cc097de413913191e46c26c7b1d66b8c7 100644 --- a/java/services/auth/src/main/java/com/uva/authentication/controllers/AuthController.java +++ b/java/services/auth/src/main/java/com/uva/authentication/controllers/AuthController.java @@ -9,6 +9,7 @@ import com.uva.authentication.models.*; import com.uva.authentication.services.AuthService; @RestController +@CrossOrigin(origins = "*") public class AuthController { @Autowired