From 17ff67da48e7215df4ec40d158f8cb3b01a93e94 Mon Sep 17 00:00:00 2001 From: arnaumarti Date: Thu, 28 Nov 2024 15:13:03 +0100 Subject: [PATCH 01/19] intial structure --- .../apartment-delete.component.css | 0 .../apartment-delete.component.html | 1 + .../apartment-delete.component.spec.ts | 23 ++++++++++++++++ .../apartment-delete.component.ts | 26 +++++++++++++++++++ 4 files changed, 50 insertions(+) create mode 100644 src/app/apartment/apartment-delete/apartment-delete.component.css create mode 100644 src/app/apartment/apartment-delete/apartment-delete.component.html create mode 100644 src/app/apartment/apartment-delete/apartment-delete.component.spec.ts create mode 100644 src/app/apartment/apartment-delete/apartment-delete.component.ts diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.css b/src/app/apartment/apartment-delete/apartment-delete.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.html b/src/app/apartment/apartment-delete/apartment-delete.component.html new file mode 100644 index 0000000..50a15ab --- /dev/null +++ b/src/app/apartment/apartment-delete/apartment-delete.component.html @@ -0,0 +1 @@ +

apartment-delete works!

diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.spec.ts b/src/app/apartment/apartment-delete/apartment-delete.component.spec.ts new file mode 100644 index 0000000..efcab46 --- /dev/null +++ b/src/app/apartment/apartment-delete/apartment-delete.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ApartmentDeleteComponent } from './apartment-delete.component'; + +describe('ApartmentDeleteComponent', () => { + let component: ApartmentDeleteComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ApartmentDeleteComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ApartmentDeleteComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.ts b/src/app/apartment/apartment-delete/apartment-delete.component.ts new file mode 100644 index 0000000..8a27b8b --- /dev/null +++ b/src/app/apartment/apartment-delete/apartment-delete.component.ts @@ -0,0 +1,26 @@ +import { Component, OnInit } from '@angular/core'; +import {Apartment} from '../apartment'; +import {ActivatedRoute} from '@angular/router'; +import {User} from '../../login-basic/user'; + +@Component({ + selector: 'app-apartment-delete', + standalone: true, + imports: [], + templateUrl: './apartment-delete.component.html', + styleUrl: './apartment-delete.component.css' +}) +export class ApartmentDeleteComponent implements OnInit { + public apartment: Apartment = new Apartment(); + public user: User = new User(); + public isAuthorized: boolean = false; + + constructor(private activatedApartment: ActivatedRoute, + ) { + } + + ngOnInit(): void { + this.user = this.authenticationService.getCurrentUser(); + this.isAuthorized = this.isAuthorised(); + } +} From 13b21b8a85eab12cf8f0eb3e545b91817e9ce063 Mon Sep 17 00:00:00 2001 From: arnaumarti Date: Thu, 28 Nov 2024 17:48:54 +0100 Subject: [PATCH 02/19] fixing some errors --- .../apartment-delete.component.ts | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.ts b/src/app/apartment/apartment-delete/apartment-delete.component.ts index 8a27b8b..3598ef5 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.ts +++ b/src/app/apartment/apartment-delete/apartment-delete.component.ts @@ -1,7 +1,8 @@ -import { Component, OnInit } from '@angular/core'; -import {Apartment} from '../apartment'; -import {ActivatedRoute} from '@angular/router'; -import {User} from '../../login-basic/user'; +import { Component } from '@angular/core'; +import { Router} from '@angular/router'; +import { User } from '../../login-basic/user'; +import { ApartmentService } from '../apartment.service'; +import { ErrorMessageService } from '../../error-handler/error-message.service'; @Component({ selector: 'app-apartment-delete', @@ -10,17 +11,17 @@ import {User} from '../../login-basic/user'; templateUrl: './apartment-delete.component.html', styleUrl: './apartment-delete.component.css' }) -export class ApartmentDeleteComponent implements OnInit { - public apartment: Apartment = new Apartment(); +export class ApartmentDeleteComponent { + public apartmentId: number | null = null; public user: User = new User(); - public isAuthorized: boolean = false; - constructor(private activatedApartment: ActivatedRoute, - ) { - } + constructor( + private router: Router, + private apartmentService: ApartmentService, + private errorMessageService: ErrorMessageService + ) {} + + + - ngOnInit(): void { - this.user = this.authenticationService.getCurrentUser(); - this.isAuthorized = this.isAuthorised(); - } } From b4b587e895e535e2ad1b35e934e845273b6ca0ab Mon Sep 17 00:00:00 2001 From: arnaumarti Date: Thu, 28 Nov 2024 17:54:27 +0100 Subject: [PATCH 03/19] implementation for deleting apartment --- .../apartment-delete.component.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.ts b/src/app/apartment/apartment-delete/apartment-delete.component.ts index 3598ef5..7c1c526 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.ts +++ b/src/app/apartment/apartment-delete/apartment-delete.component.ts @@ -21,7 +21,22 @@ export class ApartmentDeleteComponent { private errorMessageService: ErrorMessageService ) {} +onDelete(): void { + if (this.apartmentId === null) { + this.errorMessageService.showErrorMessage("No apartment selected for deletion."); + return; + } + this.apartmentService.deleteResource({id: this.apartmentId}).subscribe( + () => { + this.router.navigate(['/apartments']); + }, + (error) => { + console.error('Error deleting apartment', error); + this.errorMessageService.showErrorMessage('Failed to delete apartment. Please try again.'); + } + ); +} } From e28e68854f84b9e6a954632485a91d8f07dfd726 Mon Sep 17 00:00:00 2001 From: arnaumarti Date: Thu, 28 Nov 2024 18:38:29 +0100 Subject: [PATCH 04/19] fixing errors, implement load apartment to delete and implement cancel method --- .../apartment-delete.component.ts | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.ts b/src/app/apartment/apartment-delete/apartment-delete.component.ts index 7c1c526..ee4f771 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.ts +++ b/src/app/apartment/apartment-delete/apartment-delete.component.ts @@ -1,8 +1,9 @@ -import { Component } from '@angular/core'; +import {Component, OnInit} from '@angular/core'; import { Router} from '@angular/router'; import { User } from '../../login-basic/user'; import { ApartmentService } from '../apartment.service'; import { ErrorMessageService } from '../../error-handler/error-message.service'; +import {Apartment} from '../apartment'; @Component({ selector: 'app-apartment-delete', @@ -11,8 +12,9 @@ import { ErrorMessageService } from '../../error-handler/error-message.service'; templateUrl: './apartment-delete.component.html', styleUrl: './apartment-delete.component.css' }) -export class ApartmentDeleteComponent { +export class ApartmentDeleteComponent implements OnInit { public apartmentId: number | null = null; + public apartment: Apartment | null = null; public user: User = new User(); constructor( @@ -21,13 +23,38 @@ export class ApartmentDeleteComponent { private errorMessageService: ErrorMessageService ) {} -onDelete(): void { + ngOnInit(): void { + if (this.apartmentId !== null) { + this.loadApartment(); + } + } + + loadApartment(): void { // Busquem l'apartament per a poder eliminar-lo if (this.apartmentId === null) { + this.errorMessageService.showErrorMessage('No apartment selected for deletion.'); + return; + } + + this.apartmentService.getResource(this.apartmentId).subscribe( + (apartment) => { + this.apartment = apartment + }, + (error) => { + console.error('Error finding apartment:', error); + this.errorMessageService.showErrorMessage('Could not find apartment for deletion.'); + } + ); + } + + onDelete(): void { // Eliminem l'apartament anteriorment buscat + if (!this.apartmentId) { this.errorMessageService.showErrorMessage("No apartment selected for deletion."); return; } - this.apartmentService.deleteResource({id: this.apartmentId}).subscribe( + //const apartmentToDelete: Apartment = { id: this.apartmentId } as Apartment; + + this.apartmentService.deleteResource(this.apartment!).subscribe( () => { this.router.navigate(['/apartments']); }, @@ -36,7 +63,9 @@ onDelete(): void { this.errorMessageService.showErrorMessage('Failed to delete apartment. Please try again.'); } ); -} - + } + onCancel(): void { // Cancel·lem l'eliminació + this.router.navigate(['/apartments']); + } } From 427872e744ef0482904aed64875ca087f3aef3e2 Mon Sep 17 00:00:00 2001 From: arnaumarti Date: Wed, 4 Dec 2024 18:01:53 +0100 Subject: [PATCH 05/19] Html and css implementation and path creation for apartment-delete --- .../apartment-delete.component.css | 27 +++++++++++++++++++ .../apartment-delete.component.html | 12 ++++++++- src/app/app-routing.module.ts | 2 ++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.css b/src/app/apartment/apartment-delete/apartment-delete.component.css index e69de29..043f65f 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.css +++ b/src/app/apartment/apartment-delete/apartment-delete.component.css @@ -0,0 +1,27 @@ +.delete-container { + text-align: center; + padding: 20px; + background-color: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; + border-radius: 5px; +} +.buttons { + display: flex; + justify-content: center; + gap: 10px; +} +button { + padding: 10px 20px; + border: none; + border-radius: 5px; + cursor: pointer; +} +button:first-child { + background-color: #d9534f; + color: white; +} +button:last-child { + background-color: #6c757d; + color: white; +} diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.html b/src/app/apartment/apartment-delete/apartment-delete.component.html index 50a15ab..46f15f4 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.html +++ b/src/app/apartment/apartment-delete/apartment-delete.component.html @@ -1 +1,11 @@ -

apartment-delete works!

+
+

Confirm Apartment Deletion

+

Loading apartment details...

+
+

Are you sure you want to delete the apartment named {{ apartmentId }}?

+
+ + +
+
+
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 95e547f..590dee6 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -10,6 +10,7 @@ import { UserEditComponent } from './user/user-edit/user-edit.component'; import { UserDeleteComponent } from './user/user-delete/user-delete.component'; import {ApartmentListComponent} from './apartment/apartment-list/apartment-list.component'; import {ApartmentCreateComponent} from './apartment/apartment-create/apartment-create.component'; +import {ApartmentDeleteComponent} from './apartment/apartment-delete/apartment-delete.component'; const routes: Routes = [ { path: 'users/create', component: UserRegisterComponent}, @@ -20,6 +21,7 @@ const routes: Routes = [ { path: 'about', component: AboutComponent}, {path: 'apartments', component: ApartmentListComponent}, {path: 'apartment/create', component: ApartmentCreateComponent}, + {path: 'apartment/delete', component: ApartmentDeleteComponent}, { path: '404', component: NotFoundComponent}, { path: '', redirectTo: 'about', pathMatch: 'full'}, ]; From 5f07046543c32dd09097aa6d7db1ce2009af1a3e Mon Sep 17 00:00:00 2001 From: arnaumarti Date: Wed, 4 Dec 2024 18:40:19 +0100 Subject: [PATCH 06/19] fixing apartment-delete to have a deletion button i apartment view --- .../apartment-delete.component.css | 27 -------- .../apartment-delete.component.html | 11 ---- .../apartment-delete.component.ts | 62 ++++++++----------- src/app/app-routing.module.ts | 2 +- 4 files changed, 27 insertions(+), 75 deletions(-) diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.css b/src/app/apartment/apartment-delete/apartment-delete.component.css index 043f65f..e69de29 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.css +++ b/src/app/apartment/apartment-delete/apartment-delete.component.css @@ -1,27 +0,0 @@ -.delete-container { - text-align: center; - padding: 20px; - background-color: #f8d7da; - color: #721c24; - border: 1px solid #f5c6cb; - border-radius: 5px; -} -.buttons { - display: flex; - justify-content: center; - gap: 10px; -} -button { - padding: 10px 20px; - border: none; - border-radius: 5px; - cursor: pointer; -} -button:first-child { - background-color: #d9534f; - color: white; -} -button:last-child { - background-color: #6c757d; - color: white; -} diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.html b/src/app/apartment/apartment-delete/apartment-delete.component.html index 46f15f4..e69de29 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.html +++ b/src/app/apartment/apartment-delete/apartment-delete.component.html @@ -1,11 +0,0 @@ -
-

Confirm Apartment Deletion

-

Loading apartment details...

-
-

Are you sure you want to delete the apartment named {{ apartmentId }}?

-
- - -
-
-
diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.ts b/src/app/apartment/apartment-delete/apartment-delete.component.ts index ee4f771..5b3bfb6 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.ts +++ b/src/app/apartment/apartment-delete/apartment-delete.component.ts @@ -1,9 +1,8 @@ import {Component, OnInit} from '@angular/core'; -import { Router} from '@angular/router'; -import { User } from '../../login-basic/user'; +import {ActivatedRoute, Router} from '@angular/router'; import { ApartmentService } from '../apartment.service'; import { ErrorMessageService } from '../../error-handler/error-message.service'; -import {Apartment} from '../apartment'; +import {User} from '../../login-basic/user'; @Component({ selector: 'app-apartment-delete', @@ -13,59 +12,50 @@ import {Apartment} from '../apartment'; styleUrl: './apartment-delete.component.css' }) export class ApartmentDeleteComponent implements OnInit { - public apartmentId: number | null = null; - public apartment: Apartment | null = null; - public user: User = new User(); + public apartmentId: string; + public user: User; constructor( + private route: ActivatedRoute, private router: Router, private apartmentService: ApartmentService, private errorMessageService: ErrorMessageService ) {} ngOnInit(): void { - if (this.apartmentId !== null) { - this.loadApartment(); - } - } + this.apartmentId = this.route.snapshot.paramMap.get('id') || ''; + if (this.isAuthorised()) { + this.removeApartment(); - loadApartment(): void { // Busquem l'apartament per a poder eliminar-lo - if (this.apartmentId === null) { - this.errorMessageService.showErrorMessage('No apartment selected for deletion.'); - return; + } else { + this.onUnauthorised(); } + } + private removeApartment(): void { this.apartmentService.getResource(this.apartmentId).subscribe( (apartment) => { - this.apartment = apartment + this.apartmentService.deleteResource(apartment).subscribe( + () => { + this.router.navigate(['/apartments']); + }, + () => { + this.errorMessageService.showErrorMessage('Failed to delete apartment. Please try again.'); + } + ); }, - (error) => { - console.error('Error finding apartment:', error); - this.errorMessageService.showErrorMessage('Could not find apartment for deletion.'); + () => { + this.errorMessageService.showErrorMessage('Failed to load apartment for deletion.'); } ); } - onDelete(): void { // Eliminem l'apartament anteriorment buscat - if (!this.apartmentId) { - this.errorMessageService.showErrorMessage("No apartment selected for deletion."); - return; - } - - //const apartmentToDelete: Apartment = { id: this.apartmentId } as Apartment; - - this.apartmentService.deleteResource(this.apartment!).subscribe( - () => { - this.router.navigate(['/apartments']); - }, - (error) => { - console.error('Error deleting apartment', error); - this.errorMessageService.showErrorMessage('Failed to delete apartment. Please try again.'); - } - ); + private isAuthorised(): boolean { + return this.user.getRoles().includes('admin') || this.user.getRoles().includes('owner'); } - onCancel(): void { // Cancel·lem l'eliminació + onUnauthorised(): void { + this.errorMessageService.showErrorMessage('You are not authorized to create an apartment'); this.router.navigate(['/apartments']); } } diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 590dee6..82824eb 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -21,7 +21,7 @@ const routes: Routes = [ { path: 'about', component: AboutComponent}, {path: 'apartments', component: ApartmentListComponent}, {path: 'apartment/create', component: ApartmentCreateComponent}, - {path: 'apartment/delete', component: ApartmentDeleteComponent}, + {path: 'apartment/:id/delete', component: ApartmentDeleteComponent}, { path: '404', component: NotFoundComponent}, { path: '', redirectTo: 'about', pathMatch: 'full'}, ]; From 8adef003f32ba931bc4fe519e05b2e5729df353d Mon Sep 17 00:00:00 2001 From: arnaumarti Date: Thu, 5 Dec 2024 18:06:06 +0100 Subject: [PATCH 07/19] fixing some authorisation problems --- .../apartment-delete.component.ts | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/app/apartment/apartment-delete/apartment-delete.component.ts b/src/app/apartment/apartment-delete/apartment-delete.component.ts index 5b3bfb6..0396b24 100644 --- a/src/app/apartment/apartment-delete/apartment-delete.component.ts +++ b/src/app/apartment/apartment-delete/apartment-delete.component.ts @@ -3,6 +3,7 @@ import {ActivatedRoute, Router} from '@angular/router'; import { ApartmentService } from '../apartment.service'; import { ErrorMessageService } from '../../error-handler/error-message.service'; import {User} from '../../login-basic/user'; +import { AuthenticationBasicService } from '../../login-basic/authentication-basic.service'; @Component({ selector: 'app-apartment-delete', @@ -12,23 +13,41 @@ import {User} from '../../login-basic/user'; styleUrl: './apartment-delete.component.css' }) export class ApartmentDeleteComponent implements OnInit { - public apartmentId: string; - public user: User; + //public apartmentId: string; + public apartmentId: string = ''; + public user: User | null = null; + public isAuthorized: boolean = false; constructor( private route: ActivatedRoute, private router: Router, private apartmentService: ApartmentService, - private errorMessageService: ErrorMessageService - ) {} + private errorMessageService: ErrorMessageService, + private authenticationService: AuthenticationBasicService, +) {} ngOnInit(): void { this.apartmentId = this.route.snapshot.paramMap.get('id') || ''; - if (this.isAuthorised()) { - this.removeApartment(); + // Intentem obtenir l'usuari actual + try { + this.user = this.authenticationService.getCurrentUser(); - } else { - this.onUnauthorised(); + if (!this.user) { + throw new Error('No user found'); + } + + // Verifiquem si està autoritzat + this.isAuthorized = this.isAuthorised(); + + if (this.isAuthorized) { + this.removeApartment(); + } else { + this.onUnauthorised(); + } + } catch (error) { + console.error('Error during user authentication:', error); + this.errorMessageService.showErrorMessage('Authentication error. Please log in again.'); + this.router.navigate(['/login']); } } @@ -51,7 +70,10 @@ export class ApartmentDeleteComponent implements OnInit { } private isAuthorised(): boolean { - return this.user.getRoles().includes('admin') || this.user.getRoles().includes('owner'); + if (!this.user) { + return false; + } + return this.user && (this.user.getRoles().includes('admin') || this.user.getRoles().includes('owner')); } onUnauthorised(): void { From 4e6ab626598018132fa7335440c2a3abfd61239a Mon Sep 17 00:00:00 2001 From: albertm15 <155188920+albertm15@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:33:06 +0100 Subject: [PATCH 08/19] Update apartments working, but needs some little fixes --- src/app/app-routing.module.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 95e547f..a413ea9 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -10,6 +10,7 @@ import { UserEditComponent } from './user/user-edit/user-edit.component'; import { UserDeleteComponent } from './user/user-delete/user-delete.component'; import {ApartmentListComponent} from './apartment/apartment-list/apartment-list.component'; import {ApartmentCreateComponent} from './apartment/apartment-create/apartment-create.component'; +import {ApartmentUpdateComponent} from './apartment/apartment-update/apartment-update.component'; const routes: Routes = [ { path: 'users/create', component: UserRegisterComponent}, @@ -20,6 +21,7 @@ const routes: Routes = [ { path: 'about', component: AboutComponent}, {path: 'apartments', component: ApartmentListComponent}, {path: 'apartment/create', component: ApartmentCreateComponent}, + { path: 'apartment/:id/update', component: ApartmentUpdateComponent}, { path: '404', component: NotFoundComponent}, { path: '', redirectTo: 'about', pathMatch: 'full'}, ]; From d5ed2d01e485af3c7563b63dbe163681bc3205a3 Mon Sep 17 00:00:00 2001 From: albertm15 <155188920+albertm15@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:35:05 +0100 Subject: [PATCH 09/19] Update apartments working, but needs some little fixes v.1.1 --- .../apartment-update.component.css | 35 ++++ .../apartment-update.component.html | 97 +++++++++++ .../apartment-update.component.spec.ts | 23 +++ .../apartment-update.component.ts | 156 ++++++++++++++++++ 4 files changed, 311 insertions(+) create mode 100644 src/app/apartment/apartment-update/apartment-update.component.css create mode 100644 src/app/apartment/apartment-update/apartment-update.component.html create mode 100644 src/app/apartment/apartment-update/apartment-update.component.spec.ts create mode 100644 src/app/apartment/apartment-update/apartment-update.component.ts diff --git a/src/app/apartment/apartment-update/apartment-update.component.css b/src/app/apartment/apartment-update/apartment-update.component.css new file mode 100644 index 0000000..0bc345a --- /dev/null +++ b/src/app/apartment/apartment-update/apartment-update.component.css @@ -0,0 +1,35 @@ +.container { + background-color: #f8f9fa; + border-radius: 8px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} + +h1 { + font-size: 2rem; + font-weight: 600; + color: #343a40; +} + +.form-label { + font-weight: 500; + color: #495057; +} + +.form-control { + border-radius: 0.25rem; +} + +.btn-primary { + background-color: #007bff; + border-color: #007bff; +} + +.btn-secondary { + background-color: #6c757d; + border-color: #6c757d; +} + +.alert { + font-size: 1rem; + font-weight: 500; +} diff --git a/src/app/apartment/apartment-update/apartment-update.component.html b/src/app/apartment/apartment-update/apartment-update.component.html new file mode 100644 index 0000000..9917d6d --- /dev/null +++ b/src/app/apartment/apartment-update/apartment-update.component.html @@ -0,0 +1,97 @@ +
+ + @if (isLoading) { +
+
+ Loading... +
+
+ } + @else if (errorFetchMsg){ + + } + @else { +

Update Apartment

+ + +
+ + +
+
+ Selected image + +
+
+ +
+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ + +
+ + + +
+ + + +
+ +
+ + } +
+ + + + + + diff --git a/src/app/apartment/apartment-update/apartment-update.component.spec.ts b/src/app/apartment/apartment-update/apartment-update.component.spec.ts new file mode 100644 index 0000000..d44f9bc --- /dev/null +++ b/src/app/apartment/apartment-update/apartment-update.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ApartmentUpdateComponent } from './apartment-update.component'; + +describe('ApartmentUpdateComponent', () => { + let component: ApartmentUpdateComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ApartmentUpdateComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ApartmentUpdateComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/apartment/apartment-update/apartment-update.component.ts b/src/app/apartment/apartment-update/apartment-update.component.ts new file mode 100644 index 0000000..f2d267b --- /dev/null +++ b/src/app/apartment/apartment-update/apartment-update.component.ts @@ -0,0 +1,156 @@ +import { Component, OnInit } from '@angular/core'; +import { + FormBuilder, + FormControl, + FormGroup, FormsModule, ReactiveFormsModule, + Validators, +} from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ApartmentService } from '../apartment.service'; +import { Apartment } from '../apartment'; +import { catchError, of } from 'rxjs'; +import {CommonModule} from '@angular/common'; +import {User} from '../../login-basic/user'; +import { AuthenticationBasicService } from '../../login-basic/authentication-basic.service'; +import {ErrorMessageService} from '../../error-handler/error-message.service'; + +@Component({ + selector: 'app-apartment-update', + standalone: true, + imports: [FormsModule, CommonModule, ReactiveFormsModule], + templateUrl: './apartment-update.component.html', + styleUrls: ['./apartment-update.component.css'] +}) +export class ApartmentUpdateComponent implements OnInit { + public apartment: Apartment = new Apartment(); + public apartmentForm: FormGroup = new FormGroup({}); + public errorFetchMsg: string = ''; + public apartmentId: string = ''; + public isLoading: boolean = false; + public user: User = new User(); + public isAuthorized: boolean = false; + + + constructor( + private formBuilder: FormBuilder, + private apartmentService: ApartmentService, + private router: Router, + private activatedRoute: ActivatedRoute, + private errorMessageService: ErrorMessageService, + private authenticationService: AuthenticationBasicService, + ) {} + + ngOnInit(): void { + this.isLoading = true; + this.apartment = new Apartment(); + this.user = this.authenticationService.getCurrentUser(); + this.isAuthorized = this.isAuthorised(); + this.apartmentId = this.activatedRoute.snapshot.paramMap.get('id') || ''; + + + this.apartmentService + .getResource(this.apartmentId) + .pipe( + catchError((error) => { + this.errorFetchMsg = error.message; + return of(null); + }) + ) + .subscribe((_apartment) => { + if (_apartment) { + this.apartment = _apartment; + this.setUpForm(); + } + this.isLoading = false; + }); + + this.apartmentForm = this.formBuilder.group({ + name: new FormControl('', [Validators.required, Validators.minLength(3)]), + floor: new FormControl('', [Validators.required, Validators.min(0)]), + address: new FormControl('', [Validators.required]), + postalCode: new FormControl('', [Validators.required, Validators.pattern('^[0-9]{5}$')]), + city: new FormControl('', [Validators.required]), + country: new FormControl('', [Validators.required]), + description: new FormControl(''), + }); + + } + + + setUpForm(): void { + this.apartmentForm.setValue({ + name: this.apartment.name || '', + floor: this.apartment.floor || 0, + address: this.apartment.address || '', + postalCode: this.apartment.postalCode || '', + city: this.apartment.city || '', + country: this.apartment.country || '', + description: this.apartment.description || '', + }); + } + + private isAuthorised(): boolean { + return this.user.getRoles().includes('admin') || this.user.getRoles().includes('owner'); + } + + + onSubmit(): void { + this.apartment.id = this.apartmentId; + + if (!this.isAuthorized) { + this.onUnauthorised(); + return; + }/* + console.log(this.apartment.postalCode) + if (this.apartmentForm.invalid) { + for (const controlName in this.apartmentForm.controls) { + const control = this.apartmentForm.controls[controlName]; + if (control.invalid) { + console.log(`El campo ${controlName} no es válido.`); + console.log(control.errors); // Muestra los errores del campo + } + } + this.errorMessageService.showErrorMessage('Invalid form'); + + + return; + }*/ + + + this.apartmentService.updateResource(this.apartment) + .subscribe(() => { + this.router.navigate(['/apartments']) + }) + + } + + onUnauthorised(): void { + this.errorMessageService.showErrorMessage('You are not authorized to create an apartment'); + this.router.navigate(['/apartments']); + } + + + onCancel(): void { + this.router.navigate(['/about']); + } + + selectedImages: { file: File; url: string }[] = []; + + onFileChange(event: Event): void { + const input = event.target as HTMLInputElement; + if (input.files && input.files.length > 0) { + Array.from(input.files).forEach((file) => { + this.selectedImages.push({ + file, + url: URL.createObjectURL(file) + }); + }); + } + } + + removeImage(index: number): void { + URL.revokeObjectURL(this.selectedImages[index].url); + this.selectedImages.splice(index, 1); + } + +} From d5c4897b08a3dfe9ffc413d17a65c6b02bc7eff7 Mon Sep 17 00:00:00 2001 From: GiovanniMaerean Date: Fri, 6 Dec 2024 23:04:08 +0100 Subject: [PATCH 10/19] Only owner of the apartment or admin can edit --- .../apartment-update.component.ts | 19 ++++++++++++++- src/app/apartment/apartment.service.ts | 23 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/app/apartment/apartment-update/apartment-update.component.ts b/src/app/apartment/apartment-update/apartment-update.component.ts index f2d267b..027235a 100644 --- a/src/app/apartment/apartment-update/apartment-update.component.ts +++ b/src/app/apartment/apartment-update/apartment-update.component.ts @@ -13,6 +13,7 @@ import {CommonModule} from '@angular/common'; import {User} from '../../login-basic/user'; import { AuthenticationBasicService } from '../../login-basic/authentication-basic.service'; import {ErrorMessageService} from '../../error-handler/error-message.service'; +import {ResourceCollection} from '@lagoshny/ngx-hateoas-client'; @Component({ selector: 'app-apartment-update', @@ -47,6 +48,12 @@ export class ApartmentUpdateComponent implements OnInit { this.isAuthorized = this.isAuthorised(); this.apartmentId = this.activatedRoute.snapshot.paramMap.get('id') || ''; + if (!this.isAuthorized) { + this.onUnauthorised(); + return; + } + + this.apartmentService .getResource(this.apartmentId) @@ -58,6 +65,15 @@ export class ApartmentUpdateComponent implements OnInit { ) .subscribe((_apartment) => { if (_apartment) { + if(!this.user.getRoles().includes('admin')) { + this.apartmentService.isApartmentOwnedByUser(this.user, _apartment).subscribe((isOwned) => { + if (!isOwned) { + this.onUnauthorised(); + return; + } + }); + } + this.apartment = _apartment; this.setUpForm(); } @@ -125,7 +141,7 @@ export class ApartmentUpdateComponent implements OnInit { } onUnauthorised(): void { - this.errorMessageService.showErrorMessage('You are not authorized to create an apartment'); + this.errorMessageService.showErrorMessage('You are not authorized'); this.router.navigate(['/apartments']); } @@ -153,4 +169,5 @@ export class ApartmentUpdateComponent implements OnInit { this.selectedImages.splice(index, 1); } + } diff --git a/src/app/apartment/apartment.service.ts b/src/app/apartment/apartment.service.ts index 40b1bd5..ff5ddf1 100644 --- a/src/app/apartment/apartment.service.ts +++ b/src/app/apartment/apartment.service.ts @@ -34,4 +34,27 @@ export class ApartmentService extends HateoasResourceOperation { public findByAddress(address: string): Observable> { return this.searchCollection("findByAddress", { params: { address: address } }); } + + public isApartmentOwnedByUser(owner: User, userApartment: Apartment): Observable { + return new Observable((observer) => { + this.findByOwner(owner).subscribe({ + next: (resourceCollection: ResourceCollection) => { + const apartments = Object.values(resourceCollection).flat(); + + const isOwned = apartments.some((apartment: Apartment) => + apartment.id === userApartment.id + ); + + observer.next(isOwned); + observer.complete(); + }, + error: (err) => { + console.error('Error checking ownership:', err); + observer.next(false); + observer.complete(); + }, + }); + }); + } + } From 9e8a074a810128eb3846e4555fc4088080e7027a Mon Sep 17 00:00:00 2001 From: GiovanniMaerean Date: Sat, 7 Dec 2024 02:23:23 +0100 Subject: [PATCH 11/19] Fix apartment has no id for comparison --- .../apartment-update.component.html | 17 +++++----- .../apartment-update.component.ts | 26 +++++++-------- src/app/apartment/apartment.service.ts | 32 +++++++++++-------- src/app/apartment/apartment.ts | 8 +++++ 4 files changed, 48 insertions(+), 35 deletions(-) diff --git a/src/app/apartment/apartment-update/apartment-update.component.html b/src/app/apartment/apartment-update/apartment-update.component.html index 9917d6d..b0091db 100644 --- a/src/app/apartment/apartment-update/apartment-update.component.html +++ b/src/app/apartment/apartment-update/apartment-update.component.html @@ -30,40 +30,41 @@

Update Apartment

-
+
- +
- +
- + +
- +
- +
- +
- +
diff --git a/src/app/apartment/apartment-update/apartment-update.component.ts b/src/app/apartment/apartment-update/apartment-update.component.ts index 027235a..7f6e7d5 100644 --- a/src/app/apartment/apartment-update/apartment-update.component.ts +++ b/src/app/apartment/apartment-update/apartment-update.component.ts @@ -13,7 +13,6 @@ import {CommonModule} from '@angular/common'; import {User} from '../../login-basic/user'; import { AuthenticationBasicService } from '../../login-basic/authentication-basic.service'; import {ErrorMessageService} from '../../error-handler/error-message.service'; -import {ResourceCollection} from '@lagoshny/ngx-hateoas-client'; @Component({ selector: 'app-apartment-update', @@ -65,6 +64,7 @@ export class ApartmentUpdateComponent implements OnInit { ) .subscribe((_apartment) => { if (_apartment) { + _apartment.id = _apartment.getIdFromLinks() if(!this.user.getRoles().includes('admin')) { this.apartmentService.isApartmentOwnedByUser(this.user, _apartment).subscribe((isOwned) => { if (!isOwned) { @@ -81,12 +81,12 @@ export class ApartmentUpdateComponent implements OnInit { }); this.apartmentForm = this.formBuilder.group({ - name: new FormControl('', [Validators.required, Validators.minLength(3)]), - floor: new FormControl('', [Validators.required, Validators.min(0)]), - address: new FormControl('', [Validators.required]), - postalCode: new FormControl('', [Validators.required, Validators.pattern('^[0-9]{5}$')]), - city: new FormControl('', [Validators.required]), - country: new FormControl('', [Validators.required]), + name: new FormControl('', { validators: [Validators.required, Validators.minLength(3)]}), + floor: new FormControl('', { validators: [Validators.required, Validators.min(0)]}), + address: new FormControl('',{ validators: [Validators.required]}), + postalCode: new FormControl('', { validators: [Validators.required, Validators.pattern('^[0-9]{5}$')]}), + city: new FormControl('',{ validators: [Validators.required]}), + country: new FormControl('', { validators: [Validators.required]}), description: new FormControl(''), }); @@ -116,21 +116,19 @@ export class ApartmentUpdateComponent implements OnInit { if (!this.isAuthorized) { this.onUnauthorised(); return; - }/* - console.log(this.apartment.postalCode) + } if (this.apartmentForm.invalid) { for (const controlName in this.apartmentForm.controls) { const control = this.apartmentForm.controls[controlName]; if (control.invalid) { - console.log(`El campo ${controlName} no es válido.`); - console.log(control.errors); // Muestra los errores del campo + console.log(`Field ${controlName} is not valid.`); + console.log(control.errors); } } this.errorMessageService.showErrorMessage('Invalid form'); - return; - }*/ + } this.apartmentService.updateResource(this.apartment) @@ -147,7 +145,7 @@ export class ApartmentUpdateComponent implements OnInit { onCancel(): void { - this.router.navigate(['/about']); + this.router.navigate(['/apartments']); } selectedImages: { file: File; url: string }[] = []; diff --git a/src/app/apartment/apartment.service.ts b/src/app/apartment/apartment.service.ts index ff5ddf1..819f704 100644 --- a/src/app/apartment/apartment.service.ts +++ b/src/app/apartment/apartment.service.ts @@ -12,39 +12,46 @@ export class ApartmentService extends HateoasResourceOperation { } public findByOwner(owner: User): Observable> { - return this.searchCollection("findByOwner", { params: { owner: owner } }); + return this.searchCollection("findByOwner", {params: {owner: owner}}); } public findByCity(city: string): Observable> { - return this.searchCollection("findByCity", { params: { city: city } }); + return this.searchCollection("findByCity", {params: {city: city}}); } public findByPostalCode(postalCode: string): Observable> { - return this.searchCollection("findByPostalCode", { params: { postalCode: postalCode } }); + return this.searchCollection("findByPostalCode", {params: {postalCode: postalCode}}); } public findByCountry(country: string): Observable> { - return this.searchCollection("findByCountry", { params: { country: country } }); + return this.searchCollection("findByCountry", {params: {country: country}}); } public findByName(name: string): Observable> { - return this.searchCollection("findByName", { params: { name: name } }); + return this.searchCollection("findByName", {params: {name: name}}); } public findByAddress(address: string): Observable> { - return this.searchCollection("findByAddress", { params: { address: address } }); + return this.searchCollection("findByAddress", {params: {address: address}}); } public isApartmentOwnedByUser(owner: User, userApartment: Apartment): Observable { return new Observable((observer) => { + let isOwned = false; + this.findByOwner(owner).subscribe({ - next: (resourceCollection: ResourceCollection) => { - const apartments = Object.values(resourceCollection).flat(); + next: (apartments: ResourceCollection) => { + if (apartments && Array.isArray(apartments.resources)) { + + for (let i = 0; i < apartments.resources.length; i++) { - const isOwned = apartments.some((apartment: Apartment) => - apartment.id === userApartment.id - ); + if (apartments.resources[i].getIdFromLinks() === userApartment.id) { + isOwned = true; + break; + } + } + } observer.next(isOwned); observer.complete(); }, @@ -52,9 +59,8 @@ export class ApartmentService extends HateoasResourceOperation { console.error('Error checking ownership:', err); observer.next(false); observer.complete(); - }, + } }); }); } - } diff --git a/src/app/apartment/apartment.ts b/src/app/apartment/apartment.ts index 648cd52..5439e71 100644 --- a/src/app/apartment/apartment.ts +++ b/src/app/apartment/apartment.ts @@ -20,4 +20,12 @@ export class Apartment extends Resource { super(); Object.assign(this, values); } + + getIdFromLinks(): string { + if (this._links?.self?.href) { + return this._links.self.href.split('/').pop() || ''; + } + return this.id; + } + } From 4e2f13b9cfc715d9370c0135d80aa25d67bb53aa Mon Sep 17 00:00:00 2001 From: albertm15 <155188920+albertm15@users.noreply.github.com> Date: Sat, 7 Dec 2024 22:45:39 +0100 Subject: [PATCH 12/19] Little updates in update apartment form, adding specific error messages for each input --- .../apartment-update.component.ts | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/app/apartment/apartment-update/apartment-update.component.ts b/src/app/apartment/apartment-update/apartment-update.component.ts index 7f6e7d5..0726fc8 100644 --- a/src/app/apartment/apartment-update/apartment-update.component.ts +++ b/src/app/apartment/apartment-update/apartment-update.component.ts @@ -118,14 +118,34 @@ export class ApartmentUpdateComponent implements OnInit { return; } if (this.apartmentForm.invalid) { + this.errorMessageService.showErrorMessage('Invalid form'); + for (const controlName in this.apartmentForm.controls) { const control = this.apartmentForm.controls[controlName]; if (control.invalid) { + this.errorMessageService.showErrorMessage(`Invalid form: field ${controlName} is not valid.`); + + for(const errorType in control.errors){ + if(errorType == "required"){ + this.errorMessageService.showErrorMessage(`Invalid form: field ${controlName} is required.`); + } + else if(errorType == "minlength"){ + this.errorMessageService.showErrorMessage(`Invalid form: field ${controlName} requires a minimum length of 3.`); + } + else if(errorType == "min"){ + this.errorMessageService.showErrorMessage(`Invalid form: field ${controlName} requires a value equals or grater than 0.`); + } + else if(errorType == "pattern"){ + this.errorMessageService.showErrorMessage(`Invalid form: field ${controlName} requires a 5 digit number.`); + } + } console.log(`Field ${controlName} is not valid.`); console.log(control.errors); } } +/* this.errorMessageService.showErrorMessage('Invalid form'); +*/ return; } From a6b97a6ffc6283b2f5950f7d7812417b8a77b426 Mon Sep 17 00:00:00 2001 From: Aniol Date: Wed, 11 Dec 2024 18:06:10 +0100 Subject: [PATCH 13/19] fix: create apartments on adding reference of apartment details --- .../apartment-create.component.html | 4 ---- .../apartment-create.component.ts | 4 ++-- src/app/apartment/apartment-details.ts | 24 +++++++++++++++++++ src/app/apartment/apartment.ts | 2 ++ 4 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 src/app/apartment/apartment-details.ts diff --git a/src/app/apartment/apartment-create/apartment-create.component.html b/src/app/apartment/apartment-create/apartment-create.component.html index 2aaac53..0f0dfe1 100644 --- a/src/app/apartment/apartment-create/apartment-create.component.html +++ b/src/app/apartment/apartment-create/apartment-create.component.html @@ -47,10 +47,6 @@

Create Apartment

-
- - -
diff --git a/src/app/apartment/apartment-create/apartment-create.component.ts b/src/app/apartment/apartment-create/apartment-create.component.ts index 3fd61a8..b8be4e4 100644 --- a/src/app/apartment/apartment-create/apartment-create.component.ts +++ b/src/app/apartment/apartment-create/apartment-create.component.ts @@ -7,6 +7,7 @@ import { FormsModule } from '@angular/forms'; import { ErrorMessageService } from '../../error-handler/error-message.service'; import { CommonModule } from '@angular/common'; import { ApartmentService } from '../apartment.service'; +import { ApartmentDetails } from '../apartment-details'; @Component({ selector: 'app-apartment-create', @@ -40,6 +41,7 @@ export class ApartmentCreateComponent implements OnInit { this.apartment.owner = this.user; this.apartment.registrationDate = new Date(); + this.apartment.apartmentDetails = new ApartmentDetails(); this.apartmentService.createResource({ body: this.apartment }).subscribe(() => { this.router.navigate(['/apartment' + this.apartment.id]); @@ -78,6 +80,4 @@ export class ApartmentCreateComponent implements OnInit { URL.revokeObjectURL(this.selectedImages[index].url); this.selectedImages.splice(index, 1); } - - } diff --git a/src/app/apartment/apartment-details.ts b/src/app/apartment/apartment-details.ts new file mode 100644 index 0000000..3ce92ed --- /dev/null +++ b/src/app/apartment/apartment-details.ts @@ -0,0 +1,24 @@ +import { HateoasResource, Resource } from '@lagoshny/ngx-hateoas-client'; + +@HateoasResource('apartments') +export class ApartmentDetails extends Resource { + id: number = 0; + square: number = 0; + numBathrooms: number = 0; + numBedrooms: number = 0; + hasAc: boolean = false; + hasElevator: boolean = false; + + constructor(values: object = {}) { + super(); + Object.assign(this, values); + } + + getIdFromLinks(): string { + if (this._links?.self?.href) { + return this._links.self.href.split('/').pop() || ''; + } + return this.id.toString(); + } + +} diff --git a/src/app/apartment/apartment.ts b/src/app/apartment/apartment.ts index 5439e71..0a65281 100644 --- a/src/app/apartment/apartment.ts +++ b/src/app/apartment/apartment.ts @@ -1,5 +1,6 @@ import { HateoasResource, Resource } from '@lagoshny/ngx-hateoas-client'; import { User } from '../login-basic/user'; +import { ApartmentDetails } from './apartment-details'; @HateoasResource('apartments') export class Apartment extends Resource { @@ -15,6 +16,7 @@ export class Apartment extends Resource { detail: string = ''; note?: string = ''; registrationDate?: Date = new Date(); + apartmentDetails: ApartmentDetails = new ApartmentDetails(); constructor(values: object = {}) { super(); From d9677b12a5c255bf945a109ac4697f8f3a866690 Mon Sep 17 00:00:00 2001 From: PauBarahona22 Date: Wed, 11 Dec 2024 22:17:46 +0100 Subject: [PATCH 14/19] Visit status --- src/app/app-routing.module.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 62024c9..dd5f235 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -12,6 +12,8 @@ import {ApartmentListComponent} from './apartment/apartment-list/apartment-list. import {ApartmentCreateComponent} from './apartment/apartment-create/apartment-create.component'; import {ApartmentUpdateComponent} from './apartment/apartment-update/apartment-update.component'; import {ApartmentDeleteComponent} from './apartment/apartment-delete/apartment-delete.component'; +import {VisitStatusComponent} from './visit/visit-status/visit-status.component'; + const routes: Routes = [ { path: 'users/create', component: UserRegisterComponent}, @@ -24,6 +26,7 @@ const routes: Routes = [ { path: 'apartment/create', component: ApartmentCreateComponent}, { path: 'apartment/:id/update', component: ApartmentUpdateComponent}, { path: 'apartment/:id/delete', component: ApartmentDeleteComponent}, + { path: 'visit/:id/status', component: VisitStatusComponent}, { path: '404', component: NotFoundComponent}, { path: '', redirectTo: 'about', pathMatch: 'full'}, ]; From 865f5b3cad8aeb0ba4123030334189e4ff95f71a Mon Sep 17 00:00:00 2001 From: PauBarahona22 Date: Wed, 11 Dec 2024 22:42:05 +0100 Subject: [PATCH 15/19] Visit status2.0 --- .../visit-status/visit-status.component.css | 71 +++++++++++++++++++ .../visit-status/visit-status.component.html | 18 +++++ .../visit-status.component.spec.ts | 23 ++++++ .../visit-status/visit-status.component.ts | 58 +++++++++++++++ src/app/visit/visit.service.ts | 11 +++ src/app/visit/visit.ts | 24 +++++++ 6 files changed, 205 insertions(+) create mode 100644 src/app/visit/visit-status/visit-status.component.css create mode 100644 src/app/visit/visit-status/visit-status.component.html create mode 100644 src/app/visit/visit-status/visit-status.component.spec.ts create mode 100644 src/app/visit/visit-status/visit-status.component.ts create mode 100644 src/app/visit/visit.service.ts create mode 100644 src/app/visit/visit.ts diff --git a/src/app/visit/visit-status/visit-status.component.css b/src/app/visit/visit-status/visit-status.component.css new file mode 100644 index 0000000..877f53e --- /dev/null +++ b/src/app/visit/visit-status/visit-status.component.css @@ -0,0 +1,71 @@ +h1 { + text-align: center; + color: #2c3e50; + font-family: 'Arial', sans-serif; + margin-bottom: 20px; +} + +.status-table { + width: 80%; + margin: 0 auto; + border-collapse: collapse; + font-family: 'Arial', sans-serif; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + background-color: #f9f9f9; +} + +.status-table th, .status-table td { + padding: 12px 15px; + text-align: center; +} + +.status-table th { + background-color: #49565a; + color: white; + text-transform: uppercase; + font-size: 14px; + letter-spacing: 1px; +} + +.status-table tr:nth-child(even) { + background-color: #f2f2f2; +} + +.status-table tr:hover { + background-color: #eaf3fc; +} + +.status-table td { + font-size: 14px; + color: #2c3e50; +} +/* Estilo para el status */ +.status { + display: flex; + align-items: center; + font-weight: bold; + text-transform: capitalize; + justify-content: center; +} + +.status::before { + content: ''; + display: inline-block; + width: 10px; + height: 10px; + border-radius: 50%; + margin-right: 8px; +} + +/* Colores según el estado */ +.status.pending::before { + background-color: #f1c40f; /* Amarillo */ +} + +.status.rejected::before { + background-color: #e74c3c; /* Rojo */ +} + +.status.accepted::before { + background-color: #2ecc71; /* Verde */ +} diff --git a/src/app/visit/visit-status/visit-status.component.html b/src/app/visit/visit-status/visit-status.component.html new file mode 100644 index 0000000..d302825 --- /dev/null +++ b/src/app/visit/visit-status/visit-status.component.html @@ -0,0 +1,18 @@ +

VISIT STATUS

+ + + + + + + + + + + + {{ visit.status }} + + + + +
StatusDate & Time
{{ visit.visitDate}}
diff --git a/src/app/visit/visit-status/visit-status.component.spec.ts b/src/app/visit/visit-status/visit-status.component.spec.ts new file mode 100644 index 0000000..7173321 --- /dev/null +++ b/src/app/visit/visit-status/visit-status.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { VisitStatusComponent } from './visit-status.component'; + +describe('VisitStatusComponent', () => { + let component: VisitStatusComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [VisitStatusComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(VisitStatusComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/visit/visit-status/visit-status.component.ts b/src/app/visit/visit-status/visit-status.component.ts new file mode 100644 index 0000000..d02099b --- /dev/null +++ b/src/app/visit/visit-status/visit-status.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import {Visit} from '../visit'; +import {User} from '../../login-basic/user'; +import {ActivatedRoute, Router} from '@angular/router'; +import {ErrorMessageService} from '../../error-handler/error-message.service'; +import {AuthenticationBasicService} from '../../login-basic/authentication-basic.service'; +import { VisitService } from '../visit.service'; +import {catchError, of} from 'rxjs'; +@Component({ + selector: 'app-visit-status', + standalone: true, + imports: [CommonModule], + templateUrl: './visit-status.component.html', + styleUrl: './visit-status.component.css' +}) +export class VisitStatusComponent implements OnInit { + public visit: Visit = new Visit() + public user: User = new User(); + public visitId: string = ''; + public errorFetchMsg: string = ''; + + + + constructor( + private router: Router, + private visitService: VisitService = new VisitService(), + private activatedRoute: ActivatedRoute, + private errorMessageService: ErrorMessageService, + private authenticationService: AuthenticationBasicService + ) {} + + ngOnInit(): void { + this.visit = new Visit(); + this.visitId = this.activatedRoute.snapshot.paramMap.get('id') || ''; + this.user = this.authenticationService.getCurrentUser(); + + + + this.visitService + .getResource(this.visitId) + .pipe( + catchError((error) => { + this.errorFetchMsg = error.message; + return of(null); + }) + ) + .subscribe((_visit) => { + if (_visit) { + this.visit = _visit; + this.visit.id = this.visit.getIdFromLinks(); + console.log(this.visit); + + } + }); + + } +} diff --git a/src/app/visit/visit.service.ts b/src/app/visit/visit.service.ts new file mode 100644 index 0000000..a1d35d1 --- /dev/null +++ b/src/app/visit/visit.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from "@angular/core"; +import { HateoasResourceOperation } from "@lagoshny/ngx-hateoas-client"; +import { Visit } from "./visit"; + +@Injectable({ providedIn: "root" }) +export class VisitService extends HateoasResourceOperation { + + constructor() { + super(Visit); + } +} diff --git a/src/app/visit/visit.ts b/src/app/visit/visit.ts new file mode 100644 index 0000000..f444974 --- /dev/null +++ b/src/app/visit/visit.ts @@ -0,0 +1,24 @@ +import { HateoasResource, Resource } from '@lagoshny/ngx-hateoas-client'; +import {User} from '../login-basic/user'; + +@HateoasResource('visits') +export class Visit extends Resource { + id: string = ''; + visitDate: Date = new Date(); + user: User = new User(); + status: string = ''; + + + constructor(values: object = {}) { + super(); + Object.assign(this, values); + } + + + getIdFromLinks(): string { + if (this._links?.self?.href) { + return this._links.self.href.split('/').pop() || ''; + } + return this.id; + } +} From 9527bffaddc29f189b39ef35fdc87cdf370b25b0 Mon Sep 17 00:00:00 2001 From: Aniol0012 Date: Thu, 12 Dec 2024 16:38:14 +0100 Subject: [PATCH 16/19] feat: add apartment to navbar --- src/app/navbar/navbar.component.html | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index 2ee8525..166b4f0 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -10,6 +10,17 @@ + + + + + + +