diff --git a/backend/src/test/kotlin/blue/mild/covid/vaxx/requests/http-client.env.json b/backend/src/test/kotlin/blue/mild/covid/vaxx/requests/http-client.env.json index 8ec138f7..2a808b64 100644 --- a/backend/src/test/kotlin/blue/mild/covid/vaxx/requests/http-client.env.json +++ b/backend/src/test/kotlin/blue/mild/covid/vaxx/requests/http-client.env.json @@ -1,6 +1,8 @@ { "local": { - "url": "http://localhost:8080/api" + "url": "http://localhost:8080/api", + "email": "vaxx@mild.blue", + "password": "bluemild" }, "staging": { "url": "https://covid-vaxx.stg.mild.blue/api", diff --git a/backend/src/test/kotlin/blue/mild/covid/vaxx/requests/test-staging.http b/backend/src/test/kotlin/blue/mild/covid/vaxx/requests/test-staging.http index 3d75699c..768125d4 100644 --- a/backend/src/test/kotlin/blue/mild/covid/vaxx/requests/test-staging.http +++ b/backend/src/test/kotlin/blue/mild/covid/vaxx/requests/test-staging.http @@ -3,7 +3,7 @@ Content-Type: application/json { "credentials": { - "email": "{{user}}", + "email": "{{email}}", "password": "{{password}}" }, "vaccineSerialNumber": "test", diff --git a/frontend/src/app/app.component.ts b/frontend/src/app/app.component.ts index fc635acd..3a6c3b1e 100644 --- a/frontend/src/app/app.component.ts +++ b/frontend/src/app/app.component.ts @@ -1,6 +1,7 @@ import { Component, OnInit } from '@angular/core'; import { QuestionService } from '@app/services/question/question.service'; import { AlertService } from '@app/services/alert/alert.service'; +import { StatisticsService } from '@app/services/statistics/statistics.service'; @Component({ selector: 'app-root', @@ -10,12 +11,14 @@ import { AlertService } from '@app/services/alert/alert.service'; export class AppComponent implements OnInit { constructor(private _questionService: QuestionService, + private _statisticsService: StatisticsService, private _alertService: AlertService) { } async ngOnInit(): Promise { // Reload questions from BE on every app load (page refresh as well) await this._initQuestions(); + await this._initStatistics(); } private async _initQuestions(): Promise { @@ -25,4 +28,12 @@ export class AppComponent implements OnInit { this._alertService.error(e.message); } } + + private async _initStatistics(): Promise { + try { + await this._statisticsService.loadStatistics(); + } catch (e) { + this._alertService.error(e.message); + } + } } diff --git a/frontend/src/app/generated/api/default.service.ts b/frontend/src/app/generated/api/default.service.ts index 6be1c0db..d49094d1 100644 --- a/frontend/src/app/generated/api/default.service.ts +++ b/frontend/src/app/generated/api/default.service.ts @@ -948,66 +948,6 @@ export class DefaultService { ); } - /** - * @param from Date FROM which should system provide statistics. - * @param to Date TO which should system provide statistics. - * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. - * @param reportProgress flag to report request and response progress. - */ - public apiAdminStatisticsGet(from?: string, to?: string, observe?: 'body', reportProgress?: boolean, options?: { httpHeaderAccept?: 'application/json' }): Observable; - public apiAdminStatisticsGet(from?: string, to?: string, observe?: 'response', reportProgress?: boolean, options?: { httpHeaderAccept?: 'application/json' }): Observable>; - public apiAdminStatisticsGet(from?: string, to?: string, observe?: 'events', reportProgress?: boolean, options?: { httpHeaderAccept?: 'application/json' }): Observable>; - public apiAdminStatisticsGet(from?: string, to?: string, observe: any = 'body', reportProgress: boolean = false, options?: { httpHeaderAccept?: 'application/json' }): Observable { - - let queryParameters = new HttpParams({ encoder: this.encoder }); - if (from !== undefined && from !== null) { - queryParameters = this.addToHttpParams(queryParameters, - from, 'from'); - } - if (to !== undefined && to !== null) { - queryParameters = this.addToHttpParams(queryParameters, - to, 'to'); - } - - let headers = this.defaultHeaders; - - let credential: string | undefined; - // authentication (jwtAuth) required - credential = this.configuration.lookupCredential('jwtAuth'); - if (credential) { - headers = headers.set('Authorization', 'Bearer ' + credential); - } - - let httpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; - if (httpHeaderAcceptSelected === undefined) { - // to determine the Accept header - const httpHeaderAccepts: string[] = [ - 'application/json' - ]; - httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); - } - if (httpHeaderAcceptSelected !== undefined) { - headers = headers.set('Accept', httpHeaderAcceptSelected); - } - - - let responseType: 'text' | 'json' = 'json'; - if (httpHeaderAcceptSelected && httpHeaderAcceptSelected.startsWith('text')) { - responseType = 'text'; - } - - return this.httpClient.get(`${this.configuration.basePath}/api/admin/statistics`, - { - params: queryParameters, - responseType: responseType, - withCredentials: this.configuration.withCredentials, - headers: headers, - observe: observe, - reportProgress: reportProgress - } - ); - } - /** * Get vaccination detail for given patient ID. * @param id Patients ID @@ -1549,6 +1489,59 @@ export class DefaultService { ); } + /** + * @param from Date FROM which should system provide statistics. + * @param to Date TO which should system provide statistics. + * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. + * @param reportProgress flag to report request and response progress. + */ + public apiStatisticsGet(from?: string, to?: string, observe?: 'body', reportProgress?: boolean, options?: { httpHeaderAccept?: 'application/json' }): Observable; + public apiStatisticsGet(from?: string, to?: string, observe?: 'response', reportProgress?: boolean, options?: { httpHeaderAccept?: 'application/json' }): Observable>; + public apiStatisticsGet(from?: string, to?: string, observe?: 'events', reportProgress?: boolean, options?: { httpHeaderAccept?: 'application/json' }): Observable>; + public apiStatisticsGet(from?: string, to?: string, observe: any = 'body', reportProgress: boolean = false, options?: { httpHeaderAccept?: 'application/json' }): Observable { + + let queryParameters = new HttpParams({ encoder: this.encoder }); + if (from !== undefined && from !== null) { + queryParameters = this.addToHttpParams(queryParameters, + from, 'from'); + } + if (to !== undefined && to !== null) { + queryParameters = this.addToHttpParams(queryParameters, + to, 'to'); + } + + let headers = this.defaultHeaders; + + let httpHeaderAcceptSelected: string | undefined = options && options.httpHeaderAccept; + if (httpHeaderAcceptSelected === undefined) { + // to determine the Accept header + const httpHeaderAccepts: string[] = [ + 'application/json' + ]; + httpHeaderAcceptSelected = this.configuration.selectHeaderAccept(httpHeaderAccepts); + } + if (httpHeaderAcceptSelected !== undefined) { + headers = headers.set('Accept', httpHeaderAcceptSelected); + } + + + let responseType: 'text' | 'json' = 'json'; + if (httpHeaderAcceptSelected && httpHeaderAcceptSelected.startsWith('text')) { + responseType = 'text'; + } + + return this.httpClient.get(`${this.configuration.basePath}/api/statistics`, + { + params: queryParameters, + responseType: responseType, + withCredentials: this.configuration.withCredentials, + headers: headers, + observe: observe, + reportProgress: reportProgress + } + ); + } + /** * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. diff --git a/frontend/src/app/model/Statistics.ts b/frontend/src/app/model/Statistics.ts new file mode 100644 index 00000000..5f73af3b --- /dev/null +++ b/frontend/src/app/model/Statistics.ts @@ -0,0 +1,8 @@ +export interface Statistics { + availableSlots: number; + bookedSlots: number; + emailsSentCount: number; + patientsDataVerifiedCount: number; + registrationsCount: number; + vaccinatedPatientsCount: number; +} diff --git a/frontend/src/app/pages/info/info.component.html b/frontend/src/app/pages/info/info.component.html index 970b1ade..a0e875de 100644 --- a/frontend/src/app/pages/info/info.component.html +++ b/frontend/src/app/pages/info/info.component.html @@ -8,7 +8,16 @@ Vaccine icon

Sedmička a Poliklinika Prahy 7 pro vás zajistily možnost očkování proti nemoci COVID-19 vakcínou Comirnaty od společnosti - Pfizer/BioNTech. + Pfizer/BioNTech.
+ + + + Zbývá {{statistics.availableSlots}} volných termínů. + + + Bohužel už není žádný volný termín. + +

@@ -58,10 +67,20 @@

favorite_border

- + + + + + + + + + diff --git a/frontend/src/app/pages/info/info.component.ts b/frontend/src/app/pages/info/info.component.ts index eccb4c4f..335a583f 100644 --- a/frontend/src/app/pages/info/info.component.ts +++ b/frontend/src/app/pages/info/info.component.ts @@ -1,4 +1,6 @@ import { Component } from '@angular/core'; +import { StatisticsService } from '@app/services/statistics/statistics.service'; +import { Statistics } from '@app/model/Statistics'; @Component({ selector: 'app-info', @@ -6,8 +8,12 @@ import { Component } from '@angular/core'; styleUrls: ['./info.component.scss'] }) export class InfoComponent { + public statistics?: Statistics; - constructor() { + constructor(private _statisticsService: StatisticsService) { + this._statisticsService.statistics.subscribe(statistics => { + this.statistics = statistics; + }); } } diff --git a/frontend/src/app/parsers/statistics.parser.ts b/frontend/src/app/parsers/statistics.parser.ts new file mode 100644 index 00000000..bf81eb00 --- /dev/null +++ b/frontend/src/app/parsers/statistics.parser.ts @@ -0,0 +1,8 @@ +import { SystemStatisticsDtoOut } from '@app/generated'; +import { Statistics } from '@app/model/Statistics'; + +export const parseStatistics = (data: SystemStatisticsDtoOut): Statistics => { + return { + ...data + }; +}; diff --git a/frontend/src/app/services/statistics/statistics.service.spec.ts b/frontend/src/app/services/statistics/statistics.service.spec.ts new file mode 100644 index 00000000..2df0af37 --- /dev/null +++ b/frontend/src/app/services/statistics/statistics.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { StatisticsService } from './statistics.service'; + +describe('StatisticsService', () => { + let service: StatisticsService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(StatisticsService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/services/statistics/statistics.service.ts b/frontend/src/app/services/statistics/statistics.service.ts new file mode 100644 index 00000000..9f20b605 --- /dev/null +++ b/frontend/src/app/services/statistics/statistics.service.ts @@ -0,0 +1,43 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { SystemStatisticsDtoOut } from '@app/generated'; +import { environment } from '@environments/environment'; +import { map } from 'rxjs/operators'; +import { Statistics } from '@app/model/Statistics'; +import { parseStatistics } from '@app/parsers/statistics.parser'; +import { BehaviorSubject, Observable } from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class StatisticsService { + + private _statisticsnKey = 'questions'; + private _statisticsSubject: BehaviorSubject = new BehaviorSubject(undefined); + public statistics: Observable = this._statisticsSubject.asObservable(); + + constructor(private _http: HttpClient) { + this._initStatistics(); + } + + public async loadStatistics(): Promise { + return this._http.get( + `${environment.apiUrl}/statistics` + ).pipe( + map(response => { + const statistics = parseStatistics(response); + + this._statisticsSubject.next(statistics); + localStorage.setItem(this._statisticsnKey, JSON.stringify(statistics)); + + return statistics; + }) + ).toPromise(); + } + + private _initStatistics(): void { + const value = localStorage.getItem(this._statisticsnKey); + const savedStatistics = value ? JSON.parse(value) : undefined; + this._statisticsSubject.next(savedStatistics); + } +}