Skip to content

Commit

Permalink
feat: add user fetch for a night and a refuge
Browse files Browse the repository at this point in the history
  • Loading branch information
oriolagobat committed Nov 14, 2023
1 parent 97e3f23 commit 43a3466
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 12 deletions.
24 changes: 12 additions & 12 deletions app/src/app/pages/refuges/refuge-detail/refuge-detail.page.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<ion-header [translucent]="true">
<ion-toolbar>
<ion-title>refuge-detail</ion-title>
</ion-toolbar>
</ion-header>

<ion-content [fullscreen]="true">
<ion-header collapse="condense">
<ion-toolbar>
<ion-title size="large">refuge-detail</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-grid>
<ion-col>
<ion-datetime presentation="date" [(ngModel)]="pickedDate"></ion-datetime>
</ion-col>
<ion-col>
<ion-button (click)="onSearch()" style="margin-left: 5%">
Search
<ion-icon style="margin-left: 5%" name="folder"></ion-icon>
</ion-button>
</ion-col>
</ion-grid>
</ion-content>
40 changes: 40 additions & 0 deletions app/src/app/pages/refuges/refuge-detail/refuge-detail.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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,
Expand Down Expand Up @@ -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,
};
}
}
16 changes: 16 additions & 0 deletions app/src/app/services/reservations/reservation.service.spec.ts
Original file line number Diff line number Diff line change
@@ -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();
});
});
58 changes: 58 additions & 0 deletions app/src/app/services/reservations/reservation.service.ts
Original file line number Diff line number Diff line change
@@ -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<GetReservationsResponse> {
if (!isValidNight(night))
return of({
status: 'error',
error: GetReservationsErrors.CLIENT_SEND_DATA_ERROR,
});
return this.getReservationsFromApi(night);
}

getReservationsFromApi(night: Night): Observable<GetReservationsResponse> {
const endpoint = this.getReservationEndpoint(night);
return this.http.get<Reservation[]>(endpoint).pipe(
map<Reservation[], GetReservationsResponse | Error>(
(reservations: Reservation[]) => {
if (isMatching(ReservationPattern, reservations.values()))
return { status: 'correct', data: reservations };
return {
status: 'error',
error: GetReservationsErrors.SERVER_INCORRECT_DATA_FORMAT_ERROR,
};
},
),
catchError<GetReservationsResponse | Error, ObservableInput<any>>(
(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}/`;
}
}
44 changes: 44 additions & 0 deletions app/src/schemas/reservations/get-reservations-schema.ts
Original file line number Diff line number Diff line change
@@ -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<GetReservationsErrors>()
.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);
}
}
12 changes: 12 additions & 0 deletions app/src/schemas/reservations/night.ts
Original file line number Diff line number Diff line change
@@ -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);
}
14 changes: 14 additions & 0 deletions app/src/schemas/reservations/reservation.ts
Original file line number Diff line number Diff line change
@@ -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<Reservation> = {};

0 comments on commit 43a3466

Please sign in to comment.