Skip to content

Commit

Permalink
feat: add async get refuges list
Browse files Browse the repository at this point in the history
  • Loading branch information
Pablito2020 committed Oct 24, 2023
1 parent 6406049 commit 9c1697d
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 106 deletions.
10 changes: 5 additions & 5 deletions app/src/app/pages/refuges/refuge-list/refuges-list.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<ion-row>
<ion-col
routerLink="/refuges/{{refuge.id}}"
*ngFor="let refuge of refuges"
*ngFor="let refuge of refuges | async"
size-lg="6"
size-md="6"
size-sm="12"
Expand Down Expand Up @@ -54,17 +54,17 @@
>
<div class="refuge-name">{{refuge.name}}</div>
<p>
Regió: <br />
Regió: <br/>
<strong> {{refuge.region}} </strong>
</p>
<p>
Altitud: <br />
Altitud: <br/>
<strong> {{refuge.altitude}}m </strong>
</p>
<p>
Capacitat:
<br />
<strong>- Hivern: {{refuge.capacity.winter}} </strong> <br />
<br/>
<strong>- Hivern: {{refuge.capacity.winter}} </strong> <br/>
<strong>- Estiu: {{refuge.capacity.summer}} </strong>
</p>
</ion-col>
Expand Down
90 changes: 45 additions & 45 deletions app/src/app/pages/refuges/refuge-list/refuges-list.page.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,70 @@
import { Component, OnInit } from '@angular/core';
import { RefugeService } from '../../../services/refuge/refuge.service';
import { AlertController } from '@ionic/angular';
import { match } from 'ts-pattern';
import { Refuge } from '../../../schemas/refuge/refuge';
import {Component, OnInit} from '@angular/core';
import {RefugeService} from '../../../services/refuge/refuge.service';
import {AlertController} from '@ionic/angular';
import {isMatching, match} from 'ts-pattern';
import {Refuge} from '../../../schemas/refuge/refuge';
import {
CorrectGetRefuges,
CorrectGetRefugesPattern,
ErrorGetRefuges,
ErrorGetRefugesPattern,
GetAllRefugesErrors,
GetAllRefugesResponse,
} from '../../../schemas/refuge/get-all-refuges-schema';
import { Router } from '@angular/router';
import {Router} from '@angular/router';
import {BehaviorSubject, combineLatest, filter, map, Observable, Subject} from "rxjs";

@Component({
selector: 'app-refuges',
templateUrl: './refuges-list.page.html',
styleUrls: ['./refuges-list.page.scss'],
})
export class RefugesListPage implements OnInit {
refuges: Refuge[] = [];
searchTerm: string = '';
allRefuges: Refuge[] = [];
refuges: Observable<Refuge[]>
errors: Observable<GetAllRefugesErrors>
private search: Subject<String>

constructor(
private router: Router,
private refugeService: RefugeService,
private alertController: AlertController,
) {
this.getRefuges();
this.errors = this.refugeService.getRefuges().pipe(
filter((response): response is ErrorGetRefuges => !isMatching(ErrorGetRefugesPattern, response)),
map((response: ErrorGetRefuges) => response.error)
);
this.search = new BehaviorSubject<String>("");
const searchInput = this.search.asObservable();
const allRefuges = this.refugeService.getRefuges().pipe(
filter((response): response is CorrectGetRefuges => isMatching(CorrectGetRefugesPattern, response)),
map((response: CorrectGetRefuges) => response.data),
);
this.refuges = combineLatest([searchInput, allRefuges]).pipe(
map(([searchTerm, refuges]) => {
if (searchTerm === "") return refuges;
return refuges.filter((refuge: Refuge) => refuge.name.toLowerCase().includes(searchTerm.toLowerCase()))
}),
)
}

ngOnInit() {}

getRefuges() {
return this.refugeService.getRefuges().subscribe({
next: (response: any) => this.handleGetAllRefugesResponse(response),
ngOnInit() {
this.errors.subscribe({
next: (error: GetAllRefugesErrors) => this.handleError(error),
error: () => this.handleClientError().then(),
});
})
}

private handleGetAllRefugesResponse(response: GetAllRefugesResponse) {
match(response)
.with({ status: 'correct' }, (response) => {
this.allRefuges = response.data;
this.refuges = this.allRefuges;
})
.with({ status: 'error' }, (response) => {
this.handleError(response.error);
})
.exhaustive();

getImageUrlFor(refuge: Refuge): string {
return this.refugeService.getImageUrlFor(refuge);
}

searchByName() {
this.search.next(this.searchTerm);
}

createRefuge() {
console.log('create refuge');
}

private handleError(error: GetAllRefugesErrors) {
Expand All @@ -68,7 +87,6 @@ export class RefugesListPage implements OnInit {
text: 'OK',
handler: () => {
this.alertController.dismiss().then();
this.getRefuges();
},
},
],
Expand All @@ -91,22 +109,4 @@ export class RefugesListPage implements OnInit {
})
.then();
}

getImageUrlFor(refuge: Refuge): string {
return this.refugeService.getImageUrlFor(refuge);
}

searchByName() {
if (this.searchTerm === '') {
this.refuges = this.allRefuges;
return;
}
this.refuges = this.allRefuges.filter((refuge: Refuge) =>
refuge.name.toLowerCase().includes(this.searchTerm.toLowerCase()),
);
}

createRefuge() {
console.log('create refuge');
}
}
29 changes: 18 additions & 11 deletions app/src/app/schemas/refuge/get-all-refuges-schema.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
import { Refuge } from './refuge';
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { match } from 'ts-pattern';
import {Refuge} from './refuge';
import {HttpErrorResponse} from '@angular/common/http';
import {match, P} from 'ts-pattern';

export enum GetAllRefugesErrors {
UNKNOWN_ERROR = 'UNKNOWN_ERROR',
SERVER_INCORRECT_DATA_FORMAT_ERROR = 'SERVER_INCORRECT_DATA_FORMAT_ERROR',
}

export type CorrectGetRefuges = {
status: 'correct';
data: Refuge[];
}

export type ErrorGetRefuges = {
status: 'error';
error: GetAllRefugesErrors;
};

export type GetAllRefugesResponse =
| {
status: 'correct';
data: Refuge[];
}
| {
status: 'error';
error: GetAllRefugesErrors;
};
| CorrectGetRefuges
| ErrorGetRefuges;

export const CorrectGetRefugesPattern: P.Pattern<CorrectGetRefuges> = {};
export const ErrorGetRefugesPattern: P.Pattern<ErrorGetRefuges> = {};

export namespace GetAllRefugesErrors {
export function from(err: HttpErrorResponse): GetAllRefugesErrors | never {
Expand Down
88 changes: 43 additions & 45 deletions app/src/app/services/refuge/refuge.service.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,58 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { catchError, map, Observable, ObservableInput, of, retry } from 'rxjs';
import {
GetAllRefugesErrors,
GetAllRefugesResponse,
} from '../../schemas/refuge/get-all-refuges-schema';
import { environment } from '../../../environments/environment';
import { isValidId, Refuge, RefugePattern } from '../../schemas/refuge/refuge';
import { isMatching } from 'ts-pattern';
import {
GetRefugeFromIdErrors,
GetRefugeResponse,
} from '../../schemas/refuge/get-refuge-schema';
import {
DeleteRefugeFromIdErrors,
DeleteRefugeResponse,
} from '../../schemas/refuge/delete-refuge-schema';
import {Injectable} from '@angular/core';
import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {catchError, distinctUntilChanged, map, mergeMap, Observable, ObservableInput, of, retry, timer} from 'rxjs';
import {GetAllRefugesErrors, GetAllRefugesResponse,} from '../../schemas/refuge/get-all-refuges-schema';
import {environment} from '../../../environments/environment';
import {isValidId, Refuge, RefugePattern} from '../../schemas/refuge/refuge';
import {isMatching} from 'ts-pattern';
import {GetRefugeFromIdErrors, GetRefugeResponse,} from '../../schemas/refuge/get-refuge-schema';
import {DeleteRefugeFromIdErrors, DeleteRefugeResponse,} from '../../schemas/refuge/delete-refuge-schema';

@Injectable({
providedIn: 'root',
})
export class RefugeService {
constructor(private http: HttpClient) {}
constructor(private http: HttpClient) {
}

/**
* @description get refuges from the API every 3 seconds
*/
getRefuges(): Observable<GetAllRefugesResponse> {
return this.getAllRefugesFromApi();
return timer(0, 3000).pipe(
mergeMap(() => this.getAllRefugesFromApi()),
distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b))
);
}

getRefugeFrom(id: string): Observable<GetRefugeResponse> {
if (!isValidId(id))
return of({
status: 'error',
error: GetRefugeFromIdErrors.CLIENT_SEND_DATA_ERROR,
});
return this.getRefugeFromApi(id);
}

getImageUrlFor(refuge: Refuge): string {
return `${environment.API}/static/images/refuges/${refuge.image}`;
}

deleteRefuge(id: string): Observable<DeleteRefugeResponse> {
if (!isValidId(id))
return of({
status: 'error',
error: DeleteRefugeFromIdErrors.CLIENT_SEND_DATA_ERROR,
});
return this.deleteRefugeFromApi(id);
}

private getAllRefugesFromApi(): Observable<GetAllRefugesResponse> {
const endpoint = this.getAllRefugesEndpoint();
return this.http.get<Refuge[]>(endpoint).pipe(
map<Refuge[], GetAllRefugesResponse | Error>((refuges: Refuge[]) => {
if (isMatching(RefugePattern, refuges.values()))
return { status: 'correct', data: refuges };
return {status: 'correct', data: refuges};
return {
status: 'error',
error: GetAllRefugesErrors.SERVER_INCORRECT_DATA_FORMAT_ERROR,
Expand All @@ -53,21 +73,12 @@ export class RefugeService {
return `${environment.API}/refuges/`;
}

getRefugeFrom(id: string): Observable<GetRefugeResponse> {
if (!isValidId(id))
return of({
status: 'error',
error: GetRefugeFromIdErrors.CLIENT_SEND_DATA_ERROR,
});
return this.getRefugeFromApi(id);
}

private getRefugeFromApi(id: string): Observable<GetRefugeResponse> {
const endpoint = this.getRefugeFromIdEndpoint(id);
return this.http.get<Refuge>(endpoint).pipe(
map<Refuge, GetRefugeResponse | Error>((refuge: Refuge) => {
if (isMatching(RefugePattern, refuge))
return { status: 'correct', data: refuge };
return {status: 'correct', data: refuge};
return {
status: 'error',
error: GetRefugeFromIdErrors.SERVER_INCORRECT_DATA_FORMAT_ERROR,
Expand All @@ -88,25 +99,12 @@ export class RefugeService {
return `${environment.API}/refuges/${id}/`;
}

getImageUrlFor(refuge: Refuge): string {
return `${environment.API}/static/images/refuges/${refuge.image}`;
}

deleteRefuge(id: string): Observable<DeleteRefugeResponse> {
if (!isValidId(id))
return of({
status: 'error',
error: DeleteRefugeFromIdErrors.CLIENT_SEND_DATA_ERROR,
});
return this.deleteRefugeFromApi(id);
}

private deleteRefugeFromApi(id: string): Observable<DeleteRefugeResponse> {
const endpoint = this.deleteRefugeFromIdEndpoint(id);
return this.http.delete<Refuge>(endpoint).pipe(
map<Refuge, DeleteRefugeResponse | Error>((refuge: Refuge) => {
if (isMatching(RefugePattern, refuge))
return { status: 'correct', data: refuge };
return {status: 'correct', data: refuge};
return {
status: 'error',
error: DeleteRefugeFromIdErrors.SERVER_INCORRECT_DATA_FORMAT_ERROR,
Expand Down

0 comments on commit 9c1697d

Please sign in to comment.