Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/app/data-analytics-dashboard/hiv/data-analytics-hiv.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import { AhdReportComponent } from './ahd-report/ahd-report.component';
import { AhdMonthlyReportPatientlistComponent } from 'src/app/hiv-care-lib/ahd-monthly-report/ahd-monthly-report-patientlist/ahd-monthly-report-patientlist.component';
import { PlhivNcdV2ReportPatientListComponent } from 'src/app/hiv-care-lib/plhiv-ncd-v2-report/plhiv-ncd-v2-report-patient-list/plhiv-ncd-v2-report-patient-list.component';
import { PlhivNcdV2ReportComponent } from './plhiv-ncd-v2-report/plhiv-ncd-v2-report.component';
import { CaseSurveillanceBaseComponent } from 'src/app/hiv-care-lib/dqa-reports/case-surveillance/case-surveillance-base/case-surveillance-base.component';
import { CaseSurveillancePatientListComponent } from 'src/app/hiv-care-lib/dqa-reports/case-surveillance/case-surveillance-patient-list/case-surveillance-patient-list.component';

const routes: Routes = [
{
Expand Down Expand Up @@ -375,6 +377,19 @@ const routes: Routes = [
}
]
},
{
path: 'case-surveillance',
children: [
{
path: '',
component: CaseSurveillanceBaseComponent
},
{
path: 'cs-report-patientlist',
component: CaseSurveillancePatientListComponent
}
]
},
{
path: '',
component: DqaReportsComponent,
Expand Down
18 changes: 18 additions & 0 deletions src/app/etl-api/case-surveillance.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { TestBed, inject } from '@angular/core/testing';

import { CaseSurveillanceService } from './case-surveillance.service';

describe('CaseSurveillanceService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [CaseSurveillanceService]
});
});

it('should be created', inject(
[CaseSurveillanceService],
(service: CaseSurveillanceService) => {
expect(service).toBeTruthy();
}
));
});
58 changes: 58 additions & 0 deletions src/app/etl-api/case-surveillance.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Injectable } from '@angular/core';
import { AppSettingsService } from '../app-settings/app-settings.service';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import * as Moment from 'moment';
import { catchError, map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class CaseSurveillanceService {
public get url(): string {
return this.appSettingsService.getEtlRestbaseurl().trim();
}
constructor(
public http: HttpClient,
public appSettingsService: AppSettingsService
) {}
public getCaseSurveillanceReport(params: any): Observable<any> {
// tslint:disable-next-line: max-line-length
return this.http
.get(
`${this.url}cs-case-surveillance?startDate=${params.startDate}&endDate=${params.endDate}&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 getCaseSurveillancePatientList(params: any): Observable<any> {
// tslint:disable-next-line: max-line-length
return this.http
.get(
`${this.url}cs-case-surveillance-patient-list?startDate=${params.startDate}&endDate=${params.endDate}&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;
})
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<h4 class="component-title text-success">
<span class="fa fa-pie-chart"></span>Case Surveillance
</h4>

<report-filters
[enabledControls]="enabledControls"
[(startDate)]="startDate"
[(endDate)]="endDate"
(generateReport)="generateReport()"
>
</report-filters>

<div class="alert alert-danger fade in" *ngIf="showInfoMessage">
<a href="#" class="close" data-dismiss="alert">&times;</a>
<h4 *ngIf="!statusError">
<strong><span class="glyphicon glyphicon-warning-sign"></span> </strong> An
error occurred while trying to load the report. Please try again.
</h4>
<p>
<small>{{ errorMessage }}</small>
</p>
</div>
<div *ngIf="showPatientList">
<app-facility-dashboard
[facilityName]="facilityName"
[SummaryData]="csSummaryData"
[sectionDefs]="columnDefs"
(CellSelection)="onIndicatorSelected($event)"
[reportDetails]="params"
></app-facility-dashboard>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { CaseSurveillanceBaseComponent } from './case-surveillance-base.component';

describe('CaseSurveillanceBaseComponent', () => {
let component: CaseSurveillanceBaseComponent;
let fixture: ComponentFixture<CaseSurveillanceBaseComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [CaseSurveillanceBaseComponent]
}).compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(CaseSurveillanceBaseComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';

import * as Moment from 'moment';
import * as _ from 'lodash';
import { take } from 'rxjs/operators';
import { DataAnalyticsDashboardService } from 'src/app/data-analytics-dashboard/services/data-analytics-dashboard.services';
import { CaseSurveillanceService } from 'src/app/etl-api/case-surveillance.service';

@Component({
selector: 'app-case-surveillance-base',
templateUrl: './case-surveillance-base.component.html',
styleUrls: ['./case-surveillance-base.component.css']
})
export class CaseSurveillanceBaseComponent implements OnInit {
public enabledControls = 'locationControl,datesControl,';
public _locationUuids: any = [];
public params: any = [];
public showPatientList = false;
public showInfoMessage = false;
public facilityName = '';
public csSummaryData: any = [];
private _startDate: Date = Moment().subtract(1, 'month').toDate();
isLoading: boolean;
columnDefs: any;
errorMessage: string;
pinnedBottomRowData: any[];
private _sDate: any;
private _eDate: any;
public get startDate(): Date {
return this._startDate;
}

public set startDate(v: Date) {
this._startDate = v;
}

private _endDate: Date = new Date();
public get endDate(): Date {
return this._endDate;
}

public set endDate(v: Date) {
this._endDate = v;
}
public get locationUuids(): Array<string> {
return this._locationUuids;
}

public set locationUuids(v: Array<string>) {
const locationUuids = [];
_.each(v, (location: any) => {
if (location.value) {
locationUuids.push(location);
}
});
this._locationUuids = locationUuids;
}
constructor(
private router: Router,
private dataAnalyticsDashboardService: DataAnalyticsDashboardService,
private route: ActivatedRoute,
public caseSurveillanceService: CaseSurveillanceService
) {}

ngOnInit() {}

// ✅ Proper reusable function to build query params
private buildQueryParams(selectedLocations: any) {
return (this.params = {
locationUuids: this.getSelectedLocations(selectedLocations),
startDate: Moment(this.startDate).format('YYYY-MM-DD'),
endDate: Moment(this.endDate).format('YYYY-MM-DD')
});
}

public getCaseSurveillanceReport(params: any) {
this.isLoading = true;
this.caseSurveillanceService
.getCaseSurveillanceReport(params)
.subscribe((data) => {
try {
if (data.error) {
this.showInfoMessage = true;
this.errorMessage = `There has been an error while loading the report, please retry again`;
this.isLoading = false;
return;
}

this.showInfoMessage = false;

// Extract all results from queriesAndSchemas
let allResults: any[] = [];
if (Array.isArray(data.queriesAndSchemas)) {
data.queriesAndSchemas.forEach((reportItem) => {
if (reportItem.results && reportItem.results.results) {
allResults = allResults.concat(reportItem.results.results);
}
});
}

this.csSummaryData = allResults;
this.columnDefs = data.sectionDefinitions || [];

this.calculateTotalSummary();
} catch (err) {
console.error('Error processing report', err);
this.showInfoMessage = true;
this.errorMessage = 'There was an error processing the report.';
} finally {
this.isLoading = false;
}
});
}

public calculateTotalSummary() {
const totalsRow = [];
const totalObj: any = { location: 'Totals' };

if (this.csSummaryData && this.csSummaryData.length > 0) {
this.csSummaryData.forEach((item) => {
if (item.results && Array.isArray(item.results)) {
item.results.forEach((row) => {
Object.keys(row).forEach((key) => {
if (typeof row[key] === 'number') {
// Add numeric values
if (totalObj[key]) {
totalObj[key] += row[key];
} else {
totalObj[key] = row[key];
}
} else {
// Ensure non-numeric fields exist
if (!totalObj[key]) {
totalObj[key] = null;
}
}
});
});
}
});
totalsRow.push(totalObj);
this.pinnedBottomRowData = totalsRow;
}
}

public calculateTotalSummary1() {
const totalsRow = [];
if (this.csSummaryData.length > 0) {
const totalObj = {
location: 'Totals'
};
_.each(this.csSummaryData, (row) => {
Object.keys(row).map((key) => {
if (Number.isInteger(row[key]) === true) {
if (totalObj[key]) {
totalObj[key] = row[key] + totalObj[key];
} else {
totalObj[key] = row[key];
}
} else {
if (Number.isNaN(totalObj[key])) {
totalObj[key] = 0;
}
if (totalObj[key] === null) {
totalObj[key] = 0;
}
totalObj[key] = 0 + totalObj[key];
}
});
});
totalObj.location = 'Totals';
totalsRow.push(totalObj);
this.pinnedBottomRowData = totalsRow;
}
}

public onIndicatorSelected(value) {
this.router.navigate(['patient-list'], {
relativeTo: this.route,
queryParams: {
indicators: value.field,
indicatorHeader: value.headerName,
indicatorGender: value.gender,
sDate: this._sDate,
eDate: this._eDate,
locationUuids: value.location
}
});
}

// ✅ Generate report and navigate
public generateReport() {
this.dataAnalyticsDashboardService
.getSelectedLocations()
.pipe(take(1))
.subscribe((data) => {
if (data) {
const queryParams = this.buildQueryParams(data.locations);

this.router.navigate([], {
relativeTo: this.route,
queryParams
});

this.facilityName = data.facility
? data.facility
: data.locations.length > 0
? data.locations[0].label
: '';

this.getCaseSurveillanceReport(this.params);

this.showPatientList = true;
}
});
}

// Convert location objects → CSV string
private getSelectedLocations(locationUuids: Array<any>): string {
return locationUuids.map((location) => location.value).join(',');
}
}
Loading