From 43a346665e4887714aca070ecb896f5778ed8982 Mon Sep 17 00:00:00 2001 From: Oriol Agost Batalla Date: Tue, 14 Nov 2023 20:50:39 +0100 Subject: [PATCH] feat: add user fetch for a night and a refuge --- .../refuge-detail/refuge-detail.page.html | 24 ++++---- .../refuge-detail/refuge-detail.page.ts | 40 +++++++++++++ .../reservations/reservation.service.spec.ts | 16 +++++ .../reservations/reservation.service.ts | 58 +++++++++++++++++++ .../reservations/get-reservations-schema.ts | 44 ++++++++++++++ app/src/schemas/reservations/night.ts | 12 ++++ app/src/schemas/reservations/reservation.ts | 14 +++++ 7 files changed, 196 insertions(+), 12 deletions(-) create mode 100644 app/src/app/services/reservations/reservation.service.spec.ts create mode 100644 app/src/app/services/reservations/reservation.service.ts create mode 100644 app/src/schemas/reservations/get-reservations-schema.ts create mode 100644 app/src/schemas/reservations/night.ts create mode 100644 app/src/schemas/reservations/reservation.ts diff --git a/app/src/app/pages/refuges/refuge-detail/refuge-detail.page.html b/app/src/app/pages/refuges/refuge-detail/refuge-detail.page.html index 4b3bec0..f1601ae 100644 --- a/app/src/app/pages/refuges/refuge-detail/refuge-detail.page.html +++ b/app/src/app/pages/refuges/refuge-detail/refuge-detail.page.html @@ -1,13 +1,13 @@ - - - refuge-detail - - - - - - - refuge-detail - - + + + + + + + + Search + + + + diff --git a/app/src/app/pages/refuges/refuge-detail/refuge-detail.page.ts b/app/src/app/pages/refuges/refuge-detail/refuge-detail.page.ts index 6f1c61b..ec85694 100644 --- a/app/src/app/pages/refuges/refuge-detail/refuge-detail.page.ts +++ b/app/src/app/pages/refuges/refuge-detail/refuge-detail.page.ts @@ -9,6 +9,9 @@ import { } from '../../../../schemas/refuge/get-refuge-schema'; import { match } from 'ts-pattern'; import { Refuge } from '../../../../schemas/refuge/refuge'; +import { Night } from '../../../../schemas/reservations/night'; +import { ReservationService } from '../../../services/reservations/reservation.service'; +import { GetReservationsResponse } from '../../../../schemas/reservations/get-reservations-schema'; @Component({ selector: 'app-refuge-detail', @@ -17,11 +20,14 @@ import { Refuge } from '../../../../schemas/refuge/refuge'; }) export class RefugeDetailPage implements OnInit { refuge?: Refuge; + pickedDate = ''; + userIds: string[] = []; constructor( private router: Router, private route: ActivatedRoute, private refugeService: RefugeService, + private reservationService: ReservationService, private alertController: AlertController, private loadingController: LoadingController, private translateService: TranslateService, @@ -143,4 +149,38 @@ export class RefugeDetailPage implements OnInit { await this.loadingController.dismiss().then(); await func(); } + + onSearch() { + console.log(this.pickedDate); + const date = this.getDateFromISOString(this.pickedDate); + const night = this.getNightFromDate(date); + if (night === null) return; + this.fetchUserIdsFromNight(night); + } + + private fetchUserIdsFromNight(night: Night) { + this.reservationService.getReservationsFrom(night).subscribe({ + next: (response: GetReservationsResponse) => + this.handleGetReservationsResponse(response), + error: () => this.handleClientError().then(), + }); + } + + private handleGetReservationsResponse(response: GetReservationsResponse) { + console.log(response); + } + + private getDateFromISOString(date: string): Date { + return new Date(date); + } + + private getNightFromDate(date: Date): Night | null { + if (this.refuge === undefined) return null; + return { + day: date.getDate(), + month: date.getMonth() + 1, + year: date.getFullYear(), + refugeId: this.refuge.id, + }; + } } diff --git a/app/src/app/services/reservations/reservation.service.spec.ts b/app/src/app/services/reservations/reservation.service.spec.ts new file mode 100644 index 0000000..ce19eac --- /dev/null +++ b/app/src/app/services/reservations/reservation.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ReservationService } from './reservation.service'; + +describe('ReservationService', () => { + let service: ReservationService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ReservationService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/app/src/app/services/reservations/reservation.service.ts b/app/src/app/services/reservations/reservation.service.ts new file mode 100644 index 0000000..44d3cde --- /dev/null +++ b/app/src/app/services/reservations/reservation.service.ts @@ -0,0 +1,58 @@ +import { Injectable } from '@angular/core'; +import { isValidNight, Night } from '../../../schemas/reservations/night'; +import { catchError, map, Observable, ObservableInput, of, retry } from 'rxjs'; +import { + GetReservationsErrors, + GetReservationsResponse, +} from '../../../schemas/reservations/get-reservations-schema'; +import { environment } from '../../../environments/environment'; +import { HttpClient, HttpErrorResponse } from '@angular/common/http'; +import { + Reservation, + ReservationPattern, +} from '../../../schemas/reservations/reservation'; +import { isMatching } from 'ts-pattern'; + +@Injectable({ + providedIn: 'root', +}) +export class ReservationService { + constructor(private http: HttpClient) {} + + getReservationsFrom(night: Night): Observable { + if (!isValidNight(night)) + return of({ + status: 'error', + error: GetReservationsErrors.CLIENT_SEND_DATA_ERROR, + }); + return this.getReservationsFromApi(night); + } + + getReservationsFromApi(night: Night): Observable { + const endpoint = this.getReservationEndpoint(night); + return this.http.get(endpoint).pipe( + map( + (reservations: Reservation[]) => { + if (isMatching(ReservationPattern, reservations.values())) + return { status: 'correct', data: reservations }; + return { + status: 'error', + error: GetReservationsErrors.SERVER_INCORRECT_DATA_FORMAT_ERROR, + }; + }, + ), + catchError>( + (err: HttpErrorResponse) => + of({ + status: 'error', + error: GetReservationsErrors.from(err), + }), + ), + retry(3), + ); + } + + private getReservationEndpoint(night: Night): string { + return `${environment.API}/reservations/refuge/${night.refugeId}/year/${night.year}/month/${night.month}/day/${night.day}/`; + } +} diff --git a/app/src/schemas/reservations/get-reservations-schema.ts b/app/src/schemas/reservations/get-reservations-schema.ts new file mode 100644 index 0000000..95ab2d3 --- /dev/null +++ b/app/src/schemas/reservations/get-reservations-schema.ts @@ -0,0 +1,44 @@ +import { Reservation } from './reservation'; +import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http'; +import { match } from 'ts-pattern'; + +export enum GetReservationsErrors { + UNAUTHORIZED = 'UNAUTHORIZED', + FORBIDDEN = 'FORBIDDEN', + NOT_FOUND = 'NOT_FOUND', + UNKNOWN_ERROR = 'UNKNOWN_ERROR', + SERVER_INCORRECT_DATA_FORMAT_ERROR = 'SERVER_INCORRECT_DATA_FORMAT_ERROR', + CLIENT_SEND_DATA_ERROR = 'CLIENT_SEND_DATA_ERROR', + PROGRAMMER_SEND_DATA_ERROR = 'PROGRAMMER_SEND_DATA_ERROR', +} + +export type GetReservationsResponse = + | { + status: 'correct'; + data: Reservation[]; + } + | { + status: 'error'; + error: GetReservationsErrors; + }; + +export namespace GetReservationsErrors { + export function from(err: HttpErrorResponse): GetReservationsErrors | never { + return match(err.status) + .returnType() + .with(0, () => { + throw new Error('You are offline or the server is down.'); + }) + .with( + HttpStatusCode.Unauthorized, + () => GetReservationsErrors.UNAUTHORIZED, + ) + .with(HttpStatusCode.Forbidden, () => GetReservationsErrors.FORBIDDEN) + .with(HttpStatusCode.NotFound, () => GetReservationsErrors.NOT_FOUND) + .with( + HttpStatusCode.UnprocessableEntity, + () => GetReservationsErrors.PROGRAMMER_SEND_DATA_ERROR, + ) + .otherwise(() => GetReservationsErrors.UNKNOWN_ERROR); + } +} diff --git a/app/src/schemas/reservations/night.ts b/app/src/schemas/reservations/night.ts new file mode 100644 index 0000000..d822471 --- /dev/null +++ b/app/src/schemas/reservations/night.ts @@ -0,0 +1,12 @@ +import { isValidId } from '../refuge/refuge'; + +export type Night = { + day: number; + month: number; + year: number; + refugeId: string; +}; + +export function isValidNight(night: Night): boolean { + return isValidId(night.refugeId); +} diff --git a/app/src/schemas/reservations/reservation.ts b/app/src/schemas/reservations/reservation.ts new file mode 100644 index 0000000..49d5ced --- /dev/null +++ b/app/src/schemas/reservations/reservation.ts @@ -0,0 +1,14 @@ +import { P } from 'ts-pattern'; + +export type Reservation = { + userId: string; + refugeId: string; + night: { + day: number; + month: number; + year: number; + }; + id: string; +}; + +export const ReservationPattern: P.Pattern = {};