From 66cd364e7c21f39e7c27a0620df9c02167046a21 Mon Sep 17 00:00:00 2001 From: Kipchumba Bett Date: Thu, 5 Oct 2023 14:56:41 +0300 Subject: [PATCH] [prep]: Initial prep monthly report (#1626) * prep: Initial prep monthly report * Add prep monthly report patient list * WIP * Reset variables & rm dead code * Delete src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.css * Delete src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.css --------- Co-authored-by: Drizzentic --- .prettierrc | 6 + .../hiv/data-analytics-hiv.module.ts | 2 + .../hiv/data-analytics-hiv.routes.ts | 16 ++ ...ata-analytics-monthly-reports.component.ts | 8 +- .../prep-monthly-report.component.ts | 94 ++++++++++++ .../prep-monthly-resource.service.spec.ts | 35 +++++ .../etl-api/prep-monthly-resource.service.ts | 57 +++++++ src/app/hiv-care-lib/hiv-care-lib.module.ts | 9 ++ .../prep-monthly-base.component.css | 0 .../prep-monthly-base.component.html | 53 +++++++ .../prep-monthly-base.component.spec.ts | 23 +++ .../prep-monthly-base.component.ts | 131 ++++++++++++++++ ...-monthly-report-patient-list.component.css | 0 ...monthly-report-patient-list.component.html | 35 +++++ ...thly-report-patient-list.component.spec.ts | 44 ++++++ ...p-monthly-report-patient-list.component.ts | 108 ++++++++++++++ .../prep-monthly-report-view.component.css | 97 ++++++++++++ .../prep-monthly-report-view.component.html | 112 ++++++++++++++ ...prep-monthly-report-view.component.spec.ts | 26 ++++ .../prep-monthly-report-view.component.ts | 140 ++++++++++++++++++ 20 files changed, 995 insertions(+), 1 deletion(-) create mode 100644 .prettierrc create mode 100644 src/app/data-analytics-dashboard/hiv/prep-report/prep-monthly-report.component.ts create mode 100644 src/app/etl-api/prep-monthly-resource.service.spec.ts create mode 100644 src/app/etl-api/prep-monthly-resource.service.ts create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.css create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.html create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.spec.ts create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.ts create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.css create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.html create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.spec.ts create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.ts create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.css create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.html create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.spec.ts create mode 100644 src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.ts diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..1387fd027 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "trailingComma": "none", + "tabWidth": 2, + "semi": true, + "singleQuote": true +} diff --git a/src/app/data-analytics-dashboard/hiv/data-analytics-hiv.module.ts b/src/app/data-analytics-dashboard/hiv/data-analytics-hiv.module.ts index 1fd600fe9..a883ee4df 100644 --- a/src/app/data-analytics-dashboard/hiv/data-analytics-hiv.module.ts +++ b/src/app/data-analytics-dashboard/hiv/data-analytics-hiv.module.ts @@ -35,6 +35,7 @@ import { DataAnalyticsMonthlyReportComponent } from './monthly-reports-dashboard import { DataAnalyticsHivGainsAndLossesComponent } from './hiv-monthly-gains-and-losses/data-analytics-hiv-gains-and-losses.component'; import { ContactTestingComponent } from './contact-testing/contact-testing/contact-testing.component'; import { DialogModule } from 'primeng/primeng'; +import { PrepMonthlyReportPatientListComponent } from 'src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component'; import { TxReportsDashboardComponent } from './tx-reports-dashboard/tx-reports-dashboard.component'; import { TxMlReportComponent } from './tx-ml-report/tx-ml-report.component'; import { TxNewReportComponent } from './datim-reports/tx-new-report/tx-new-report.component'; @@ -80,6 +81,7 @@ import { TxRttReportComponent } from './datim-reports/tx-rtt-report.component'; HivSummaryMonthlyIndicatorsComponent, SurgeReportComponent, PrepReportComponent, + PrepMonthlyReportPatientListComponent, MOH412HIVDataAnalyticsComponent, MOH412HIVDataAnalyticsPatientListComponent, IPTReportComponent, diff --git a/src/app/data-analytics-dashboard/hiv/data-analytics-hiv.routes.ts b/src/app/data-analytics-dashboard/hiv/data-analytics-hiv.routes.ts index 3a14b6dcc..024380fd5 100644 --- a/src/app/data-analytics-dashboard/hiv/data-analytics-hiv.routes.ts +++ b/src/app/data-analytics-dashboard/hiv/data-analytics-hiv.routes.ts @@ -40,6 +40,8 @@ import { ContactTestingComponent } from './contact-testing/contact-testing/conta import { FamilyTestingContactComponent } from 'src/app/hiv-care-lib/family-testing/family-testing-contact-list.component'; import { AddContactTraceComponent } from 'src/app/hiv-care-lib/family-testing/contact-trace/add-contact-trace.component'; import { EditContactTraceComponent } from 'src/app/hiv-care-lib/family-testing/contact-trace/edit-contact-trace.component'; +import { PrepMonthlyReportComponent } from './prep-report/prep-monthly-report.component'; +import { PrepMonthlyReportPatientListComponent } from 'src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component'; import { TxReportsDashboardComponent } from './tx-reports-dashboard/tx-reports-dashboard.component'; import { TxMlReportComponent } from './tx-ml-report/tx-ml-report.component'; import { TxMlReportPatientListComponent } from 'src/app/hiv-care-lib/tx-ml-report/tx-ml-report-patient-list/tx-ml-report-patient-list.component'; @@ -51,6 +53,7 @@ import { TxMmdReportPatientListComponent } from 'src/app/hiv-care-lib/tx-mmd-rep import { TxMmdReportComponent } from './datim-reports/tx-mmd-report.component'; import { TxRttReportComponent } from './datim-reports/tx-rtt-report.component'; import { TxRttReportPatientListComponent } from 'src/app/hiv-care-lib/tx-rtt-report/tx-rtt-report-patient-list/tx-rtt-report-patient-list.component'; + const routes: Routes = [ { path: 'clinic-flow', @@ -198,6 +201,19 @@ const routes: Routes = [ } ] }, + { + path: 'prep-monthly-report', + children: [ + { + path: '', + component: PrepMonthlyReportComponent + }, + { + path: 'patient-list', + component: PrepMonthlyReportPatientListComponent + } + ] + }, { path: 'moh-412-report', children: [ diff --git a/src/app/data-analytics-dashboard/hiv/monthly-reports-dashboard/data-analytics-monthly-reports.component.ts b/src/app/data-analytics-dashboard/hiv/monthly-reports-dashboard/data-analytics-monthly-reports.component.ts index 7415c9709..92fde7865 100644 --- a/src/app/data-analytics-dashboard/hiv/monthly-reports-dashboard/data-analytics-monthly-reports.component.ts +++ b/src/app/data-analytics-dashboard/hiv/monthly-reports-dashboard/data-analytics-monthly-reports.component.ts @@ -16,11 +16,17 @@ export class DataAnalyticsMonthlyReportComponent implements OnInit { ngOnInit() { this.dashboards = [ { - title: 'PrEP Monthly Report', + title: 'PrEP Monthly Report (deprecated)', description: '', url: 'prep-report', icon: 'fa' }, + { + title: 'New PrEP Monthly Report', + description: '', + url: 'prep-monthly-report', + icon: 'fa' + }, { title: 'TB Treatment Therapy report', description: '', diff --git a/src/app/data-analytics-dashboard/hiv/prep-report/prep-monthly-report.component.ts b/src/app/data-analytics-dashboard/hiv/prep-report/prep-monthly-report.component.ts new file mode 100644 index 000000000..8c67491e6 --- /dev/null +++ b/src/app/data-analytics-dashboard/hiv/prep-report/prep-monthly-report.component.ts @@ -0,0 +1,94 @@ +import { Router, ActivatedRoute } from '@angular/router'; +import { Component, OnInit } from '@angular/core'; +import { Location } from '@angular/common'; +import { take } from 'rxjs/operators'; +import * as rison from 'rison-node'; +import * as Moment from 'moment'; + +import { DataAnalyticsDashboardService } from '../../services/data-analytics-dashboard.services'; +import { PrepMonthlyReportBaseComponent } from 'src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component'; +import { PrepMonthlyResourceService } from 'src/app/etl-api/prep-monthly-resource.service'; + +@Component({ + selector: 'prep-monthly-report-base', + templateUrl: + './../../../hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.html' +}) +export class PrepMonthlyReportComponent + extends PrepMonthlyReportBaseComponent + implements OnInit { + public enabledControls = 'monthControl,locationControl'; + + constructor( + public router: Router, + public route: ActivatedRoute, + public prepMonthlyResourceService: PrepMonthlyResourceService, + private dataAnalyticsDashboardService: DataAnalyticsDashboardService, + private location: Location + ) { + super(router, route, prepMonthlyResourceService); + } + + public ngOnInit() { + this.loadReportParamsFromUrl(); + } + + public generateReport() { + this.setSelectedLocation(); + this.storeParamsInUrl(); + + if (Array.isArray(this._locationUuids) && this._locationUuids.length > 0) { + this.params = { + locationUuids: this.getSelectedLocations(this._locationUuids), + month: Moment(this._month).endOf('month').format('YYYY-MM-DD') + }; + super.getPrepMonthlyAggReport(this.params); + super.showDraftReportAlert(this._month); + } else { + this.errorMessage = 'Locations are required!'; + } + } + + public storeParamsInUrl() { + const state = { + locationUuids: this.getSelectedLocations(this._locationUuids), + month: Moment(this._month).endOf('month').format('YYYY-MM-DD') + }; + const stateUrl = rison.encode(state); + const path = this.router.parseUrl(this.location.path()); + path.queryParams = { + state: stateUrl + }; + + this.location.replaceState(path.toString()); + } + + public loadReportParamsFromUrl() { + const path = this.router.parseUrl(this.location.path()); + + if (path.queryParams['state']) { + const state = rison.decode(path.queryParams['state']); + this.month = state.month; + this.locationUuids = state.locations; + } + + if (path.queryParams['state']) { + this.generateReport(); + } + } + + public setSelectedLocation() { + this.dataAnalyticsDashboardService + .getSelectedLocations() + .pipe(take(1)) + .subscribe((data) => { + if (data) { + this.locationUuids = data.locations; + } + }); + } + + private getSelectedLocations(locationUuids: Array): string { + return locationUuids.map((location) => location.value).join(','); + } +} diff --git a/src/app/etl-api/prep-monthly-resource.service.spec.ts b/src/app/etl-api/prep-monthly-resource.service.spec.ts new file mode 100644 index 000000000..81fcd3410 --- /dev/null +++ b/src/app/etl-api/prep-monthly-resource.service.spec.ts @@ -0,0 +1,35 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { RouterTestingModule } from '@angular/router/testing'; +import { routes } from '../clinic-dashboard/clinic-dashboard.routes'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ClinicDashboardComponent } from '../clinic-dashboard/clinic-dashboard.component'; +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { AppSettingsService } from '../app-settings/app-settings.service'; +import { LocalStorageService } from '../utils/local-storage.service'; +import { PrepMonthlyResourceService } from './prep-monthly-resource.service'; + +describe('PrepMonthlyResourceService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + PrepMonthlyResourceService, + AppSettingsService, + LocalStorageService + ], + declarations: [ClinicDashboardComponent], + imports: [ + RouterTestingModule.withRoutes(routes), + HttpClientTestingModule + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }); + }); + + it('should be created', inject( + [PrepMonthlyResourceService], + (service: PrepMonthlyResourceService) => { + expect(service).toBeTruthy(); + } + )); +}); diff --git a/src/app/etl-api/prep-monthly-resource.service.ts b/src/app/etl-api/prep-monthly-resource.service.ts new file mode 100644 index 000000000..8ec9515fb --- /dev/null +++ b/src/app/etl-api/prep-monthly-resource.service.ts @@ -0,0 +1,57 @@ +import { Injectable } from '@angular/core'; +import { AppSettingsService } from '../app-settings/app-settings.service'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { catchError, map } from 'rxjs/operators'; +@Injectable({ + providedIn: 'root' +}) +export class PrepMonthlyResourceService { + public get url(): string { + return this.appSettingsService.getEtlRestbaseurl().trim(); + } + constructor( + public http: HttpClient, + public appSettingsService: AppSettingsService + ) {} + public getPrepMonthlyAggReport(params: any): Observable { + // tslint:disable-next-line: max-line-length + return this.http + .get( + `${this.url}prep-monthly-report?endDate=${params.month}&locationUuids=${params.locationUuids}` + ) + .pipe( + catchError((err: any) => { + const error: any = err; + const errorObj = { + error: error.status, + message: error.statusText + }; + return Observable.of(errorObj); + }), + map((response: Response) => { + return response; + }) + ); + } + public getPrepMonthlyPatientList(params: any): Observable { + // tslint:disable-next-line: max-line-length + return this.http + .get( + `${this.url}prep-monthly-report-patient-list?&endDate=${params.month}&locationUuids=${params.locationUuids}&indicators=${params.indicators}` + ) + .pipe( + catchError((err: any) => { + const error: any = err; + const errorObj = { + error: error.status, + message: error.statusText + }; + return Observable.of(errorObj); + }), + map((response: Response) => { + return response; + }) + ); + } +} diff --git a/src/app/hiv-care-lib/hiv-care-lib.module.ts b/src/app/hiv-care-lib/hiv-care-lib.module.ts index b580110e4..4459838ef 100644 --- a/src/app/hiv-care-lib/hiv-care-lib.module.ts +++ b/src/app/hiv-care-lib/hiv-care-lib.module.ts @@ -122,6 +122,10 @@ import { Covid19ReportComponent } from './covid-19-report/covid-19-report.compon import { Covid19ReportFiltersComponent } from './covid-19-report/covid-19-report-filters/covid-19-report-filters.component'; import { Covid19ReportPatientListComponent } from './covid-19-report/covid-19-report-patient-list/covid-19-report-patient-list.component'; import { Covid19TabularViewComponent } from './covid-19-report/covid-19-tabular-view/covid-19-tabular-view.component'; +import { PrepMonthlyResourceService } from '../etl-api/prep-monthly-resource.service'; +import { PrepMonthlyReportComponent } from '../data-analytics-dashboard/hiv/prep-report/prep-monthly-report.component'; +import { PrepMonthlyReportBaseComponent } from './prep-report/monthly/prep-monthly-base/prep-monthly-base.component'; +import { PrepMonthlyReportViewComponent } from './prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component'; import { TxMlReportBaseComponent } from './tx-ml-report/tx-ml-report-base/tx-ml-report-base.component'; import { TxMlReportPatientListComponent } from './tx-ml-report/tx-ml-report-patient-list/tx-ml-report-patient-list.component'; import { TxMlReportViewComponent } from './tx-ml-report/tx-ml-report-view/tx-ml-report-view.component'; @@ -228,6 +232,7 @@ import { TxRttReportPatientListComponent } from './tx-rtt-report/tx-rtt-report-p Covid19ReportFiltersComponent, Covid19ReportPatientListComponent, Covid19TabularViewComponent, + PrepMonthlyReportViewComponent, TxMlReportViewComponent ], declarations: [ @@ -301,6 +306,9 @@ import { TxRttReportPatientListComponent } from './tx-rtt-report/tx-rtt-report-p Covid19ReportFiltersComponent, Covid19ReportPatientListComponent, Covid19TabularViewComponent, + PrepMonthlyReportComponent, + PrepMonthlyReportBaseComponent, + PrepMonthlyReportViewComponent, TxMlReportBaseComponent, TxMlReportPatientListComponent, TxMlReportViewComponent, @@ -315,6 +323,7 @@ import { TxRttReportPatientListComponent } from './tx-rtt-report/tx-rtt-report-p ], providers: [ MOHReportService, + PrepMonthlyResourceService, LocationResourceService, ClinicalSummaryVisualizationService, RetentionReportResourceService, diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.css b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.html b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.html new file mode 100644 index 000000000..661965aa1 --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.html @@ -0,0 +1,53 @@ +

+ PrEP Monthly Report +

+ +
+ Loading... +
+ + +
+ + + + +
+
+ +
+ × +

+ An + error occurred while trying to load the report. Please try again. +

+

+ {{ errorMessage }} +

+
+
+ Viewing a Draft Version of the Report for the chosen month. + This report is likely to change without warning. +
+
+ + + + + +
diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.spec.ts b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.spec.ts new file mode 100644 index 000000000..e6805689a --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.spec.ts @@ -0,0 +1,23 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { PrepMonthlyReportBaseComponent } from './prep-monthly-base.component'; + +describe('PrepMonthlyReportBaseComponent', () => { + let component: PrepMonthlyReportBaseComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [PrepMonthlyReportBaseComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PrepMonthlyReportBaseComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.ts b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.ts new file mode 100644 index 000000000..12a1bc66f --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-base/prep-monthly-base.component.ts @@ -0,0 +1,131 @@ +import { Component, OnInit, Output } from '@angular/core'; +import { Router, ActivatedRoute } from '@angular/router'; +import * as _ from 'lodash'; +import * as Moment from 'moment'; +import { PrepMonthlyResourceService } from 'src/app/etl-api/prep-monthly-resource.service'; + +@Component({ + selector: 'prep-monthly-report-base', + templateUrl: './prep-monthly-base.component.html', + styleUrls: ['./prep-monthly-base.component.css'] +}) +export class PrepMonthlyReportBaseComponent implements OnInit { + @Output() + public params: any; + + public indicators: string; + public selectedIndicators = []; + public prepReportSummaryData: any = []; + public columnDefs: any = []; + public reportName = 'PrEP Monthly Report'; + public currentView = 'monthly'; + public currentViewBelow = 'pdf'; + public month: string; + + public statusError = false; + public errorMessage = ''; + public showInfoMessage = false; + public isLoading = false; + public reportHead: any; + public pinnedBottomRowData: any = []; + public enabledControls = 'monthControl'; + public _month: string; + public isReleased = true; + + public _locationUuids: any = []; + + public get locationUuids(): Array { + return this._locationUuids; + } + + public set locationUuids(v: Array) { + const locationUuids = []; + _.each(v, (location: any) => { + if (location.value) { + locationUuids.push(location); + } + }); + this._locationUuids = locationUuids; + } + + constructor( + public router: Router, + public route: ActivatedRoute, + public prepReport: PrepMonthlyResourceService + ) { + this.route.queryParams.subscribe((params: any) => { + if (params) { + params.month === undefined + ? (this._month = Moment() + .subtract(1, 'M') + .endOf('month') + .format('YYYY-MM-DD')) + : (this._month = params.month); + } + this.showDraftReportAlert(this._month); + }); + } + + ngOnInit() {} + + public generateReport() {} + + public onMonthChange(value): any { + this._month = Moment(value).endOf('month').format('YYYY-MM-DD'); + } + + public storeParamsInUrl(params: any) { + this.router.navigate([], { + relativeTo: this.route, + queryParams: params + }); + } + + public getPrepMonthlyAggReport(params: any) { + this.columnDefs = []; + this.prepReportSummaryData = []; + + this.storeParamsInUrl(params); + this.isLoading = true; + this.prepReport.getPrepMonthlyAggReport(params).subscribe((data) => { + if (data.error) { + this.showInfoMessage = true; + this.errorMessage = `There has been an error while loading the report, please retry again`; + this.isLoading = false; + } else { + this.showInfoMessage = false; + this.columnDefs = data.sectionDefinitions; + this.prepReportSummaryData = data.result; + this.isLoading = false; + this.showDraftReportAlert(this._month); + } + }); + } + + public indicatorSelected($event: any) { + this.router.navigate(['patient-list'], { + relativeTo: this.route, + queryParams: { + indicators: $event.indicator, + indicatorHeader: $event.indicatorHeader, + month: $event.month, + locationUuids: $event.locationUuids + } + }); + } + + public setParams() { + this.params = { + locationUuids: this._locationUuids, + month: Moment(this._month).format('YYYY-MM-DD') + }; + } + + public showDraftReportAlert(date) { + if (date != null && date >= Moment().endOf('month').format('YYYY-MM-DD')) { + this.isReleased = false; + } else { + this.isReleased = true; + } + } +} diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.css b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.html b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.html new file mode 100644 index 000000000..f25f06295 --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.html @@ -0,0 +1,35 @@ +
+ +
+
+ Loading... +
+

+ {{ selectedIndicator }} patient list for the month of + {{ selectedMonth }} +

+
+ + +
+

+ + All records loaded {{ '[ ' + patientData.length + ' ]' }} +

+ +

+
+ +
+

Error loading patient list.

+
diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.spec.ts b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.spec.ts new file mode 100644 index 000000000..200982753 --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.spec.ts @@ -0,0 +1,44 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { AppSettingsService } from 'src/app/app-settings/app-settings.service'; +import { LocalStorageService } from 'src/app/utils/local-storage.service'; +import { RouterTestingModule } from '@angular/router/testing'; +import { routes } from 'src/app/clinic-dashboard/clinic-dashboard.routes'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { ClinicDashboardComponent } from 'src/app/clinic-dashboard/clinic-dashboard.component'; +import { PrepMonthlyReportPatientListComponent } from './prep-monthly-report-patient-list.component'; + +describe('PrepMonthlyReportPatientListComponent', () => { + let component: PrepMonthlyReportPatientListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ + PrepMonthlyReportPatientListComponent, + ClinicDashboardComponent + ], + providers: [ + // { provide: PrepResourceService, useClass: PrepResouceServiceMock }, + AppSettingsService, + LocalStorageService + ], + imports: [ + RouterTestingModule.withRoutes(routes), + HttpClientTestingModule + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PrepMonthlyReportPatientListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.ts b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.ts new file mode 100644 index 000000000..494a747ed --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-patient-list/prep-monthly-report-patient-list.component.ts @@ -0,0 +1,108 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Location } from '@angular/common'; +import * as Moment from 'moment'; +import { PrepMonthlyResourceService } from 'src/app/etl-api/prep-monthly-resource.service'; +@Component({ + selector: 'app-prep-monthly-report-patient-list', + templateUrl: './prep-monthly-report-patient-list.component.html', + styleUrls: ['./prep-monthly-report-patient-list.component.css'] +}) +export class PrepMonthlyReportPatientListComponent implements OnInit { + public params: any; + public patientData: any = []; + public extraColumns: Array = []; + public isLoading = true; + public overrideColumns: Array = []; + public selectedIndicator: string; + public hasLoadedAll = false; + public hasError = false; + public selectedMonth: String; + + constructor( + private router: Router, + private route: ActivatedRoute, + private _location: Location, + public prepResource: PrepMonthlyResourceService + ) {} + + ngOnInit() { + this.addExtraColumns(); + this.route.queryParams.subscribe( + (params) => { + if (params && params.month) { + this.params = params; + this.selectedIndicator = params.indicatorHeader; + this.selectedMonth = params.month; + this.getPatientList(params); + } + }, + (error) => { + console.error('Error', error); + } + ); + } + + private getPatientList(params: any) { + this.patientData = []; + this.prepResource.getPrepMonthlyPatientList(params).subscribe((data) => { + this.isLoading = false; + if (data && data.result) { + this.patientData = data.result; + this.hasLoadedAll = true; + } + }); + } + + public addExtraColumns() { + const extraColumns = { + phone_number: 'Phone', + enrollment_date: 'Date Enrolled', + last_appointment: 'Last Appointment', + prev_rtc_date: 'Previous RTC Date', + latest_rtc_date: 'RTC Date', + days_since_rtc_date: 'Days missed since RTC', + cur_prep_meds_names: 'Current prEp Regimen', + hiv_rapid_test: 'HIV Rapid test result', + rapid_test_date: 'HIV Rapid test date', + population_type: 'Population Type', + ovcid_id: 'OVCID', + population_type_category: 'Population Type Category', + nearest_center: 'Estate/Nearest Center' + }; + + for (const indicator in extraColumns) { + if (indicator) { + this.extraColumns.push({ + headerName: extraColumns[indicator], + field: indicator + }); + } + } + + this.overrideColumns.push( + { + field: 'identifiers', + cellRenderer: (column) => { + return ( + '' + + column.value + + '' + ); + } + }, + { + field: 'last_appointment', + width: 200 + }, + { + field: 'cur_prep_meds_names', + width: 160 + } + ); + } + + public goBack() { + this._location.back(); + } +} diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.css b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.css new file mode 100644 index 000000000..fa50fcb37 --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.css @@ -0,0 +1,97 @@ +table { + width: 100%; + table-layout: auto; + white-space: nowrap; + border-collapse: separate; + margin: 5px; +} + +.header { + background-color: #337ab7; + color: white; + font-weight: bold; +} + +td { + padding: 10px; + border: 1px solid #090909; + text-align: centre; + font-size: auto; +} +th { + padding: 10px; + border: 1px solid #090909; + text-align: left; + font-size: 11px; +} +.first { + padding: 10px; + position: absolute; + border: 1px solid #090909; + text-align: left; + font-size: 18px; +} +.labels tr td { + background-color: #2cc16a; + font-weight: bold; + color: #fff; +} + +.label tr td label { + display: block; +} +caption { + padding-top: inherit; + padding-bottom: 8px; + color: #ffffff; + background: #3498db; + font-size: medium; + font-weight: bold; + text-align: center; +} + +[data-toggle='toggle'] { + display: none; +} +.value { + cursor: pointer; +} +.value:hover { + background-color: #337ab7a8; + color: white; +} +.padding { + margin: 2.5px; +} + +td, +th { + margin: 0; + border: 1px solid grey; + white-space: pre-line; + border-top-width: 0px; +} + +.headcol { + position: absolute; + width: 2em; + left: 0; + top: auto; + border-top-width: 1px; + /*only relevant for first row*/ + margin-top: -1px; + /*compensate for top border*/ +} +.table-content-class { + overflow-x: scroll; +} + +.bg-black { + background-color: black; +} + +.total { + font-size: medium; + font-weight: bold; + text-align: center; +} diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.html b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.html new file mode 100644 index 000000000..d916352db --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.html @@ -0,0 +1,112 @@ +
+
+
+ + + {{ reportDetails.reportName }} +
+ +
+
+
+
+
+
+ +
+ + +
+
+
+
+
+ + + +
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {{ hmd.label }} + {{ hmd.value }}
Age Disaggregation + {{ ag }} +
Gender Disaggregation + {{ gg }} + + Total +
+ {{ data.sectionTitle }} +
+ {{ row.rowTitle }} + + {{ cell.value }} +
+
+
+
+
+
diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.spec.ts b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.spec.ts new file mode 100644 index 000000000..b4cd9c5b8 --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.spec.ts @@ -0,0 +1,26 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { DomSanitizer } from '@angular/platform-browser'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { MultiSelectModule } from 'primeng/primeng'; +import { PrepMonthlyReportViewComponent } from './prep-monthly-report-view.component'; + +describe('ReportViewCompoent', () => { + let component: PrepMonthlyReportViewComponent; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [HttpClientTestingModule], + imports: [DomSanitizer, MultiSelectModule] + }) + .compileComponents() + .then(() => { + fixture = TestBed.createComponent(PrepMonthlyReportViewComponent); + component = fixture.componentInstance; + }); + }); + + it('should be created', () => { + pending(); + }); +}); diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.ts b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.ts new file mode 100644 index 000000000..50c8a85d7 --- /dev/null +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.ts @@ -0,0 +1,140 @@ +import { + Component, + OnInit, + Input, + Output, + EventEmitter, + OnChanges, + SimpleChanges +} from '@angular/core'; + +import * as _ from 'lodash'; + +@Component({ + selector: 'app-prep-monthly-report-view', + templateUrl: './prep-monthly-report-view.component.html', + styleUrls: ['./prep-monthly-report-view.component.css'] +}) +export class PrepMonthlyReportViewComponent implements OnInit, OnChanges { + @Input() SummaryData = []; + @Input() sectionDefs: any; + @Input() reportDetails: any; + + @Output() + public indicatorSelected = new EventEmitter(); + + public tableSectionIndicators = []; + public tableSectionData: any[] = []; + public headerMetaData = []; + public ageGroups = []; + public genderGroups = []; + public tableData = []; + + constructor() {} + + ngOnInit() {} + + public ngOnChanges(changes: SimpleChanges) { + // reset variables + this.tableSectionIndicators = []; + this.tableSectionData = []; + if (changes.SummaryData) { + this.tableSectionIndicators = this.sectionDefs; + this.tableSectionData = this.SummaryData; + this.buildTableBody(); + } + } + + public setOnCellClicked(whichCell) { + const payload = { + indicator: [...whichCell.indicators], + indicatorHeader: whichCell.cell, + month: this.reportDetails.month, + locationUuids: this.reportDetails.locationUuids + }; + this.indicatorSelected.emit(payload); + } + + public buildTableBody() { + this.tableSectionData = this.SummaryData; + this.tableSectionIndicators = this.sectionDefs; + + this.resetTableVariables(); + + const resultsMap = this.mapPrepMonthlyReportResults(); + + if ( + this.tableSectionIndicators.length > 0 && + this.tableSectionData.length > 0 + ) { + this.tableSectionIndicators[0].indicators.forEach((indicator) => { + this.headerMetaData.push({ + label: indicator.label, + value: resultsMap.get(indicator.indicator) + }); + }); + + // Age distribution + this.tableSectionIndicators[1].indicators[0].indicators.forEach( + (indicator) => { + this.ageGroups.push(indicator); + } + ); + + // Gender distribution + this.tableSectionIndicators[1].indicators[1].indicators.forEach( + (indicator) => { + this.genderGroups.push(indicator); + } + ); + + // Table data + // Remove the first two sections + const allData = this.tableSectionIndicators.slice(2); + + allData.forEach((section) => { + this.tableData.push({ + sectionTitle: section.sectionTitle, + sectionData: section.indicators.map((sect) => { + return { + rowTitle: sect.label, + rowData: sect.indicators.map((val) => { + if (val.indicator.startsWith('total_')) { + return { + cell: val.label, + indicators: [val.indicator], + value: resultsMap.get(val.indicator) || 0 + }; + } else { + return { + cell: val.label, + indicators: [val.indicator], + value: resultsMap.get(val.indicator) || 0 + }; + } + }) + }; + }) + }); + }); + } + } + + private resetTableVariables() { + this.headerMetaData = []; + this.ageGroups = []; + this.genderGroups = []; + this.tableData = []; + } + + private mapPrepMonthlyReportResults() { + return this.tableSectionData.reduce((map, result) => { + for (const key in result) { + if (result.hasOwnProperty(key)) { + map.set(key, result[key]); + } + } + return map; + }, new Map()); + } +}