diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 99aa932..a4616a2 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -15,6 +15,7 @@ import {AdoptionDetailComponent} from './adoptions/adoption-detail/adoption-deta
import {AdoptionDeleteComponent} from './adoptions/adoption-delete/adoption-delete.component';
import {AdoptionCreateComponent} from "./adoptions/adoption-create/adoption-create.component";
import { ShelterListComponent } from './shelter/shelter-list/shelter-list.component'
+import {ShelterCreateComponent} from "./shelter/shelter-create/shelter-create.component";
const routes: Routes = [
{ path: 'users/create', component: UserRegisterComponent},
@@ -32,6 +33,7 @@ const routes: Routes = [
{ path: 'adoptions/detail', component: AdoptionDetailComponent },
{ path: 'adoptions/search', component: AdoptionSearchComponent },
{ path: 'shelters', component: ShelterListComponent},
+ { path: 'shelters/create', component: ShelterCreateComponent},
];
@NgModule({
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 8a7c555..11f2d3b 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -30,6 +30,10 @@ import {AdoptionDetailComponent} from './adoptions/adoption-detail/adoption-deta
import {AdoptionDeleteComponent} from './adoptions/adoption-delete/adoption-delete.component';
import {AdoptionCreateComponent} from "./adoptions/adoption-create/adoption-create.component";
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
+import {ShelterService} from "./shelter/shelter.service";
+import {ShelterListComponent} from "./shelter/shelter-list/shelter-list.component";
+import {ShelterCreateComponent} from "./shelter/shelter-create/shelter-create.component";
+import {ShelterDetailComponent} from "./shelter/shelter-detail/shelter-detail.component";
@NgModule({
declarations: [
@@ -49,6 +53,9 @@ import { provideAnimationsAsync } from '@angular/platform-browser/animations/asy
AdoptionDetailComponent,
AdoptionEditComponent,
AdoptionListComponent
+ ShelterListComponent,
+ ShelterCreateComponent,
+ ShelterDetailComponent
],
imports: [
BrowserModule,
@@ -62,12 +69,12 @@ import { provideAnimationsAsync } from '@angular/platform-browser/animations/asy
LoginBasicModule,
ErrorHandlerModule,
NgbModule,
- ReactiveFormsModule,
+ ReactiveFormsModule
],
providers: [
{ provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
{ provide: HTTP_INTERCEPTORS, useClass: HttpErrorInterceptor, multi: true },
- AuthenticationBasicService, LoggedInGuard, UserService, provideAnimationsAsync()
+ AuthenticationBasicService, LoggedInGuard, UserService, ShelterService, provideAnimationsAsync()
],
bootstrap: [AppComponent]
})
diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html
index 55e04f2..418ef19 100644
--- a/src/app/navbar/navbar.component.html
+++ b/src/app/navbar/navbar.component.html
@@ -18,6 +18,16 @@
[routerLink]="['/users']"> List
+
+ Shelters
+
+
diff --git a/src/app/shelter/shelter-create/shelter-create.component.html b/src/app/shelter/shelter-create/shelter-create.component.html
new file mode 100644
index 0000000..0d81e0b
--- /dev/null
+++ b/src/app/shelter/shelter-create/shelter-create.component.html
@@ -0,0 +1,97 @@
+
diff --git a/src/app/shelter/shelter-create/shelter-create.component.ts b/src/app/shelter/shelter-create/shelter-create.component.ts
new file mode 100644
index 0000000..9a88928
--- /dev/null
+++ b/src/app/shelter/shelter-create/shelter-create.component.ts
@@ -0,0 +1,129 @@
+import {Component, OnInit} from '@angular/core';
+import {Router} from "@angular/router";
+import {ShelterService} from "../shelter.service";
+import {Shelter} from "../shelter";
+import {AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators} from "@angular/forms";
+import {ModalDismissReasons, NgbModal} from "@ng-bootstrap/ng-bootstrap";
+import {PagedResourceCollection} from "@lagoshny/ngx-hateoas-client";
+import {formatDate} from "@angular/common";
+
+@Component({
+ selector: 'app-shelter-create',
+ templateUrl: './shelter-create.component.html',
+})
+export class ShelterCreateComponent implements OnInit{
+
+ closeResult = '';
+ public isModalSaved: boolean = false;
+ public shelters: Shelter[] = [];
+ public shelter: Shelter;
+ public commonNameInput: string = '';
+ public commonEmailsList: any = [];
+ public shelterForm: FormGroup;
+
+ constructor(
+ private router: Router,
+ private shelterService: ShelterService,
+ private modalService: NgbModal
+ ) {}
+
+ ngOnInit(): void {
+ this.shelter = new Shelter();
+ this.shelterForm = new FormGroup({
+ name: new FormControl(this.shelter.name, [
+ Validators.required,
+ ]),
+ email: new FormControl(this.shelter.email, [
+ Validators.required,
+ this.emailValidator(),
+ ]),
+ mobile: new FormControl(this.shelter.mobile, [
+ Validators.required,
+ this.mobileValidator(),
+ ]),
+ });
+ this.loadShelterList();
+ }
+
+ loadShelterList() {
+ this.shelterService
+ .getPage({
+ sort: { name: 'ASC' },
+ })
+ .subscribe((shelters: PagedResourceCollection) => {
+ this.shelters = shelters.resources.sort((a, b) =>
+ a.name.localeCompare(b.name)
+ );
+ });
+ }
+
+ open(content) {
+ this.modalService
+ .open(content, { ariaLabelledBy: 'modal-basic-title' })
+ .result.then(
+ (result) => {
+ this.closeResult = `Closed with: ${result}`;
+ },
+ (reason) => {
+ this.closeResult = `Dismissed ${this.getDismissReason(reason)}`;
+ }
+ );
+ }
+
+ private getDismissReason(reason: any): string {
+ if (reason === ModalDismissReasons.ESC) {
+ return 'by pressing ESC';
+ } else if (reason === ModalDismissReasons.BACKDROP_CLICK) {
+ return 'by clicking on a backdrop';
+ } else {
+ return `with: ${reason}`;
+ }
+ }
+
+ saveAndClose(modal: any) {
+ this.isModalSaved = true;
+ modal.close('Save click');
+ }
+
+ emailValidator(): ValidatorFn {
+ const nameRe: RegExp = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;
+ return (control: AbstractControl): ValidationErrors | null => {
+ const invalid = !nameRe.test(control.value);
+ return invalid ? { invalidName: { value: control.value } } : null;
+ };
+ }
+
+ mobileValidator(): ValidatorFn {
+ const nameRe: RegExp = /^$|[0-9]{11}/;
+ return (control: AbstractControl): ValidationErrors | null => {
+ const invalid = !nameRe.test(control.value);
+ return invalid ? { invalidName: { value: control.value } } : null;
+ };
+
+ }
+
+ get name() {
+ return this.shelterForm.get('name');
+ }
+
+ get email() {
+ return this.shelterForm.get('email');
+ }
+
+ get mobile() {
+ return this.shelterForm.get('mobile');
+ }
+
+ onSubmit(): void {
+ this.shelter.createdAt = new Date();
+ this.shelter.updatedAt = new Date();
+ this.shelterService
+ .createResource({ body: this.shelter })
+ .subscribe((shelter: Shelter) => {
+ console.log(shelter);
+ const uri = (shelter as any).uri;
+ this.router.navigate([uri]).then();
+ });
+ }
+
+}
diff --git a/src/app/shelter/shelter-delete/shelter-delete.component.html b/src/app/shelter/shelter-delete/shelter-delete.component.html
new file mode 100644
index 0000000..7725f68
--- /dev/null
+++ b/src/app/shelter/shelter-delete/shelter-delete.component.html
@@ -0,0 +1,25 @@
+
+
+
Please, confirm deletion:
+
+
+
+
+
+
+
+
diff --git a/src/app/shelter/shelter-delete/shelter-delete.component.ts b/src/app/shelter/shelter-delete/shelter-delete.component.ts
new file mode 100644
index 0000000..a26d8af
--- /dev/null
+++ b/src/app/shelter/shelter-delete/shelter-delete.component.ts
@@ -0,0 +1,37 @@
+import {Component, OnInit} from '@angular/core';
+import {ActivatedRoute, Router} from "@angular/router";
+import {Shelter} from "../shelter";
+import {ShelterService} from "../shelter.service";
+
+@Component({
+ selector: 'app-shelter-delete',
+ templateUrl: './shelter-delete.component.html',
+})
+export class ShelterDeleteComponent implements OnInit {
+ idShelter: string;
+ shelter: Shelter;
+ constructor(
+ private router: Router,
+ private shelterService: ShelterService,
+ private route: ActivatedRoute
+ ) {}
+ ngOnInit(): void {
+ this.idShelter = this.route.snapshot.paramMap.get('id');
+ }
+ delete() {
+ this.shelterService.getResource(this.idShelter).subscribe((shelter: Shelter) => {
+ this.shelter = shelter;
+ this.shelterService
+ .patchResource(this.shelter)
+ .subscribe((patchedShelter: Shelter) => {
+ this.shelterService.deleteResourceById(patchedShelter.id).subscribe({
+ next: (e) => {
+ this.router.navigateByUrl('/shelters');
+ },
+ error: (err) => {
+ },
+ });
+ });
+ });
+ }
+}
diff --git a/src/app/shelter/shelter-detail/shelter-detail.component.html b/src/app/shelter/shelter-detail/shelter-detail.component.html
new file mode 100644
index 0000000..13250a5
--- /dev/null
+++ b/src/app/shelter/shelter-detail/shelter-detail.component.html
@@ -0,0 +1,45 @@
+
+
+
Shelter {{ shelterDetail.id }}
+
+
+
Name
+
+ {{ shelterDetail.name }}
+
+
+
+
Email
+
{{ shelterDetail.email }}
+
+
+
+
+
diff --git a/src/app/shelter/shelter-detail/shelter-detail.component.ts b/src/app/shelter/shelter-detail/shelter-detail.component.ts
new file mode 100644
index 0000000..8eaf462
--- /dev/null
+++ b/src/app/shelter/shelter-detail/shelter-detail.component.ts
@@ -0,0 +1,29 @@
+import {Component, OnInit} from '@angular/core';
+import {Shelter} from "../shelter";
+import {ActivatedRoute} from "@angular/router";
+import {AuthenticationBasicService} from "../../login-basic/authentication-basic.service";
+import {ShelterService} from "../shelter.service";
+
+@Component({
+ selector: 'app-shelter-detail',
+ templateUrl: './shelter-detail.component.html',
+})
+export class ShelterDetailComponent implements OnInit{
+ shelterDetail: Shelter;
+ constructor(
+ private route: ActivatedRoute,
+ private shelterService: ShelterService,
+ private authenticationService: AuthenticationBasicService
+ ) {}
+
+ ngOnInit(): void {
+ const id = this.route.snapshot.paramMap.get('id');
+ this.shelterService.getResource(id).subscribe((shelter: Shelter) => {
+ this.shelterDetail = shelter;
+ });
+ }
+
+ isRole(role: string): boolean {
+ return this.authenticationService.isRole(role);
+ }
+}
diff --git a/src/app/shelter/shelter-list/shelter-list.component.html b/src/app/shelter/shelter-list/shelter-list.component.html
index 31ee882..a5b98f8 100644
--- a/src/app/shelter/shelter-list/shelter-list.component.html
+++ b/src/app/shelter/shelter-list/shelter-list.component.html
@@ -1 +1,21 @@
-
+
+
+
+
+
+
E-mail
+
{{shelter.email}}
+
+
+
+
+
+
+
+
+
diff --git a/src/app/shelter/shelter-list/shelter-list.component.ts b/src/app/shelter/shelter-list/shelter-list.component.ts
index f5943c6..30c8add 100644
--- a/src/app/shelter/shelter-list/shelter-list.component.ts
+++ b/src/app/shelter/shelter-list/shelter-list.component.ts
@@ -1,11 +1,44 @@
-import { Component } from '@angular/core';
+import {Component, OnInit} from '@angular/core';
+import {Shelter} from "../shelter";
+import {Router} from "@angular/router";
+import {ShelterService} from "../shelter.service";
+import {PagedResourceCollection} from "@lagoshny/ngx-hateoas-client";
@Component({
selector: 'app-shelter-list',
- standalone: true,
- imports: [],
templateUrl: './shelter-list.component.html',
})
-export class ShelterListComponent {
+export class ShelterListComponent implements OnInit {
+ public shelters: Shelter[] = [];
+ public pageSize = 5;
+ public page = 1;
+ public totalShelters = 0;
+ constructor(
+ public router: Router,
+ private shelterService: ShelterService,
+ ) {}
+
+ ngOnInit(): void {
+ this.shelterService
+ .getPage({
+ pageParams: { size: this.pageSize },
+ sort: { name: 'ASC' },
+ })
+ .subscribe((page: PagedResourceCollection) => {
+ this.shelters = page.resources;
+ console.log(this.shelters);
+ this.totalShelters = page.totalElements;
+ });
+ }
+ changePage(): void {
+ this.shelterService
+ .getPage({
+ pageParams: { page: this.page - 1, size: this.pageSize },
+ sort: { name: 'ASC' },
+ })
+ .subscribe(
+ (page: PagedResourceCollection) => (this.shelters = page.resources)
+ );
+ }
}
diff --git a/src/app/shelter/shelter.service.ts b/src/app/shelter/shelter.service.ts
new file mode 100644
index 0000000..6df3803
--- /dev/null
+++ b/src/app/shelter/shelter.service.ts
@@ -0,0 +1,16 @@
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { HateoasResourceOperation, ResourceCollection } from '@lagoshny/ngx-hateoas-client';
+import {Shelter} from "./shelter";
+
+@Injectable({providedIn: 'root'})
+export class ShelterService extends HateoasResourceOperation {
+
+ constructor() {
+ super(Shelter);
+ }
+
+ public findByName(query: string): Observable> {
+ return this.searchCollection('findByName', { params: { text: query } });
+ }
+}
diff --git a/src/app/shelter/shelter.ts b/src/app/shelter/shelter.ts
new file mode 100644
index 0000000..368a723
--- /dev/null
+++ b/src/app/shelter/shelter.ts
@@ -0,0 +1,22 @@
+import { HateoasResource, Resource } from '@lagoshny/ngx-hateoas-client';
+
+@HateoasResource('shelters')
+export class Shelter extends Resource {
+ uri: string;
+ name: string;
+ email: string;
+ mobile: string;
+ createdAt: Date;
+ updatedAt: Date;
+ isActive: boolean;
+
+ constructor(values: object = {}) {
+ super();
+ Object.assign(this as any, values);
+ }
+
+ public get id(): string {
+ let uriArray = this.uri.split('/');
+ return uriArray.pop();
+ }
+}