Skip to content

Commit 30ae97d

Browse files
committed
feat(#9231): enable place filter aggregate targets for users with multiple facility_ids (#9232)
1 parent d0e4330 commit 30ae97d

9 files changed

+501
-107
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,59 @@
11
<section class="sidebar-filter">
2-
<div
3-
class="sidebar-backdrop"
4-
[ngClass]="{ hidden: !isOpen }"
5-
(click)="toggleSidebarFilter()"
6-
(keydown.escape)="toggleSidebarFilter()">
2+
<div class="sidebar-backdrop" [ngClass]="{ hidden: !isOpen }"
3+
(click)="toggleSidebarFilter()" (keydown.escape)="toggleSidebarFilter()">
74
</div>
85

96
<div class="sidebar-main" [ngClass]="{ hidden: !isOpen }">
107
<div class="sidebar-header">
11-
<p class="sidebar-title">{{ 'reports.sidebar.filter.title' | translate }}</p>
8+
<p class="sidebar-title">{{ 'reports.sidebar.filter.title' | translate }}
9+
</p>
1210
<a class="sidebar-close fa fa-times" (click)="toggleSidebarFilter()"></a>
1311
</div>
1412

1513
<div class="sidebar-body">
1614
<mat-accordion multi>
15+
<!-- Facility -->
16+
<div class="filter-options-container" *ngIf="userFacilities.length > 1">
17+
<span class="filter-options-title"> {{ facilityFilterLabel | translate
18+
}} </span>
19+
<ng-container *ngFor="let facility of userFacilities">
20+
<div class="filter-radio-option">
21+
<label class="filter-option-wrapper">
22+
<input type="radio" name="facility" [value]="facility"
23+
class="filter-option-radio"
24+
[checked]="facility._id === selectedFacility._id"
25+
(change)="fetchAggregateTargetsByFacility(facility)">
26+
<span class="filter-option-label">{{ facility.name }}</span>
27+
</label>
28+
</div>
29+
</ng-container>
30+
</div>
31+
</mat-accordion>
32+
33+
<mat-accordion multi>
34+
<!-- Reporting Period -->
1735
<div class="filter-options-container">
18-
<span class="filter-options-title"> {{ facilityFilterLabel | translate }} </span>
19-
<ng-container *ngFor="let facility of userFacilities">
20-
<div class="filter-option-place">
21-
<label class="filter-option-wrapper">
22-
<input
23-
type="radio"
24-
name="facility"
25-
[value]="facility"
26-
class="filter-option-radio"
27-
[checked]="facility._id === selectedFacility._id"
28-
(click)="fetchAggregateTargets(facility)">
29-
<span class="filter-option-label">{{ facility.name }}</span>
30-
</label>
31-
</div>
32-
</ng-container>
36+
<span class="filter-options-title">{{
37+
'analytics.target.aggregates.reporting_period' | translate }}</span>
38+
<div class="filter-radio-option"
39+
*ngFor="let period of reportingPeriods">
40+
<label class="filter-option-wrapper">
41+
<input type="radio" name="reporting-period"
42+
class="filter-option-radio" [value]="period.value"
43+
[(ngModel)]="selectedReportingPeriod"
44+
(change)="fetchAggregateTargetsByReportingPeriod()">
45+
<span class="filter-option-label">{{ period.label | translate
46+
}}</span>
47+
</label>
48+
</div>
3349
</div>
3450
</mat-accordion>
3551
</div>
3652

3753
<div class="sidebar-footer">
38-
<button type="button" class="btn btn-primary" (click)="toggleSidebarFilter()">{{ 'reports.sidebar.filter.submit' | translate }}</button>
54+
<button type="button" class="btn btn-primary"
55+
(click)="toggleSidebarFilter()">{{ 'reports.sidebar.filter.submit' |
56+
translate }}</button>
3957
</div>
4058
</div>
4159
</section>

webapp/src/ts/modules/analytics/analytics-target-aggregates-sidebar-filter.component.ts

+23-3
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,18 @@ import { SettingsService } from '@mm-services/settings.service';
1414
export class AnalyticsTargetAggregatesSidebarFilterComponent implements OnInit, OnDestroy {
1515

1616
@Input() userFacilities;
17-
@Output() facilitySelected = new EventEmitter<string>();
17+
@Output() facilitySelectionChanged = new EventEmitter<string>();
18+
@Output() reportingPeriodSelectionChanged = new EventEmitter<string>();
1819
private globalActions;
20+
readonly reportingPeriods = [
21+
{ value: ReportingPeriod.CURRENT, label: ReportingPeriod.CURRENT },
22+
{ value: ReportingPeriod.PREVIOUS, label: ReportingPeriod.PREVIOUS }
23+
];
24+
1925
DEFAULT_FACILITY_LABEL = 'Facility';
2026
subscriptions: Subscription = new Subscription();
2127
isOpen = false;
28+
selectedReportingPeriod;
2229
selectedFacility;
2330
facilityFilterLabel;
2431

@@ -47,6 +54,10 @@ export class AnalyticsTargetAggregatesSidebarFilterComponent implements OnInit,
4754
if (!this.selectedFacility && filterState?.defaultFilters?.facility) {
4855
this.selectedFacility = filterState.defaultFilters.facility;
4956
}
57+
58+
if (!this.selectedReportingPeriod && filterState?.defaultFilters?.reportingPeriod) {
59+
this.selectedReportingPeriod = filterState.defaultFilters.reportingPeriod;
60+
}
5061
});
5162

5263
this.subscriptions.add(subscription);
@@ -74,8 +85,17 @@ export class AnalyticsTargetAggregatesSidebarFilterComponent implements OnInit,
7485
}
7586
}
7687

77-
fetchAggregateTargets(facility) {
88+
fetchAggregateTargetsByFacility(facility) {
7889
this.selectedFacility = facility;
79-
this.facilitySelected.emit(this.selectedFacility);
90+
this.facilitySelectionChanged.emit(this.selectedFacility);
8091
}
92+
93+
fetchAggregateTargetsByReportingPeriod() {
94+
this.reportingPeriodSelectionChanged.emit(this.selectedReportingPeriod);
95+
}
96+
}
97+
98+
export enum ReportingPeriod {
99+
CURRENT = 'targets.this_month.subtitle',
100+
PREVIOUS = 'targets.last_month.subtitle'
81101
}

webapp/src/ts/modules/analytics/analytics-target-aggregates.component.html

+16-18
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,38 @@
11
<div class="page" *ngIf="!enabled || loading">
2-
<div class="item-content empty-selection disabled" *ngIf="!loading; else loaderTpl">
2+
<div class="item-content empty-selection disabled"
3+
*ngIf="!loading; else loaderTpl">
34
<div>{{'analytics.target.aggregates.disabled' | translate}}</div>
45
</div>
56
</div>
67

7-
<div
8-
class="inbox page target-aggregates"
9-
*ngIf="enabled && !loading"
8+
<div class="inbox page target-aggregates" *ngIf="enabled && !loading"
109
[ngClass]="{'sidebar-open': !!sidebarFilter.isOpen, 'sidebar-closed': !sidebarFilter.isOpen}">
11-
<div
12-
id="target-aggregates-list"
13-
class="inbox-items left-pane"
10+
<div id="target-aggregates-list" class="inbox-items left-pane"
1411
[ngClass]="{ 'col-sm-3': !!sidebarFilter.isOpen, 'col-sm-4': !sidebarFilter.isOpen }">
1512
<ul>
16-
<mm-content-row *ngFor="let aggregate of aggregates"
17-
[id]="aggregate.id"
13+
<mm-content-row *ngFor="let aggregate of aggregates" [id]="aggregate.id"
1814
[route]="['/', 'analytics', 'target-aggregates', aggregate.id]"
19-
[selected]="aggregate.selected"
20-
[icon]="aggregate.icon"
15+
[selected]="aggregate.selected" [icon]="aggregate.icon"
2116
[heading]="aggregate.heading"
22-
[lineage]="aggregate.facility"
17+
[lineage]="aggregate.filtersToDisplay?.length ? aggregate.filtersToDisplay : null"
2318
[aggregate]="aggregate.aggregateValue">
2419
</mm-content-row>
2520
</ul>
26-
<p *ngIf="error && !aggregates?.length" class="alert alert-danger" role="alert">{{'analytics.target.aggregates.error' | translate}}</p>
27-
<p class="loading-status" *ngIf="!error && !aggregates?.length">{{'analytics.target.aggregates.no.targets' | translate}}</p>
21+
<p *ngIf="error && !aggregates?.length" class="alert alert-danger"
22+
role="alert">{{'analytics.target.aggregates.error' | translate}}</p>
23+
<p class="loading-status" *ngIf="!error && !aggregates?.length">
24+
{{'analytics.target.aggregates.no.targets' | translate}}</p>
2825
</div>
2926

3027
<div class="content-pane right-pane">
31-
<div class="item-content" [ngClass]="{ 'col-sm-6': !!sidebarFilter.isOpen, 'col-sm-8': !sidebarFilter.isOpen }">
28+
<div class="item-content"
29+
[ngClass]="{ 'col-sm-6': !!sidebarFilter.isOpen, 'col-sm-8': !sidebarFilter.isOpen }">
3230
<router-outlet></router-outlet>
3331
</div>
3432
<mm-analytics-target-aggregates-sidebar-filter
35-
class="col-sm-3 sidebar-filter-wrapper"
36-
[userFacilities]="userFacilities"
37-
(facilitySelected)="getTargetAggregates($event)">
33+
class="col-sm-3 sidebar-filter-wrapper" [userFacilities]="userFacilities"
34+
(facilitySelectionChanged)="getTargetAggregates($event, reportingPeriodFilter)"
35+
(reportingPeriodSelectionChanged)="getTargetAggregates(facilityFilter, $event)">
3836
</mm-analytics-target-aggregates-sidebar-filter>
3937
</div>
4038
</div>

webapp/src/ts/modules/analytics/analytics-target-aggregates.component.ts

+41-8
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { combineLatest, Subscription } from 'rxjs';
44

55
import { Selectors } from '@mm-selectors/index';
66
import { TargetAggregatesActions } from '@mm-actions/target-aggregates';
7-
import { TargetAggregatesService } from '@mm-services/target-aggregates.service';
7+
import { AggregateTarget, TargetAggregatesService } from '@mm-services/target-aggregates.service';
88
import { PerformanceService } from '@mm-services/performance.service';
99
import { GlobalActions } from '@mm-actions/global';
1010
import { UserSettingsService } from '@mm-services/user-settings.service';
11+
import { ReportingPeriod } from '@mm-modules/analytics/analytics-target-aggregates-sidebar-filter.component';
1112

1213
@Component({
1314
selector: 'analytics-target-aggregates',
@@ -19,13 +20,15 @@ export class AnalyticsTargetAggregatesComponent implements OnInit, OnDestroy {
1920
private globalActions: GlobalActions;
2021
private trackPerformance;
2122
subscriptions: Subscription = new Subscription();
22-
userFacilities;
2323
loading = true;
2424
enabled = false;
2525
aggregates: any = null;
2626
selected = null;
2727
error = null;
28+
userFacilities;
2829
sidebarFilter;
30+
reportingPeriodFilter;
31+
facilityFilter;
2932

3033
constructor(
3134
private store: Store,
@@ -78,12 +81,22 @@ export class AnalyticsTargetAggregatesComponent implements OnInit, OnDestroy {
7881
this.subscriptions.add(selectorsSubscription);
7982
}
8083

81-
async getTargetAggregates(userFacility) {
84+
async getTargetAggregates(userFacility, reportingPeriod) {
8285
try {
83-
const aggregates = this.enabled ? await this.targetAggregatesService.getAggregates(userFacility?._id) : [];
84-
if (this.userFacilities.length > 1) {
85-
aggregates.forEach((aggregate) => aggregate.facility = userFacility?.name);
86+
let aggregates: AggregateTarget[] = [];
87+
if (this.enabled) {
88+
this.facilityFilter = userFacility;
89+
this.reportingPeriodFilter = reportingPeriod;
90+
aggregates = await this.targetAggregatesService.getAggregates(
91+
this.facilityFilter?._id, this.reportingPeriodFilter
92+
);
8693
}
94+
95+
const reportingMonth = await this.targetAggregatesService.getReportingMonth(reportingPeriod);
96+
97+
aggregates = aggregates
98+
.map(aggregate => this.formatAggregate(aggregate, userFacility, reportingPeriod, reportingMonth));
99+
87100
this.targetAggregatesActions.setTargetAggregates(aggregates);
88101
this.targetAggregatesActions.setTargetAggregatesLoaded(true);
89102

@@ -93,18 +106,38 @@ export class AnalyticsTargetAggregatesComponent implements OnInit, OnDestroy {
93106
} finally {
94107
this.loading = false;
95108
this.trackPerformance?.stop({
96-
name: [ 'analytics', 'target_aggregates', 'load' ].join(':'),
109+
name: ['analytics', 'target_aggregates', 'load'].join(':'),
97110
recordApdex: true,
98111
});
99112
}
100113
}
101114

115+
private formatAggregate(aggregate, userFacility, reportingPeriod, reportingMonth) {
116+
const filtersToDisplay: string[] = [];
117+
118+
if (this.userFacilities.length > 1 && this.facilityFilter?.name) {
119+
aggregate.facility = userFacility?.name;
120+
filtersToDisplay.push(this.facilityFilter.name);
121+
}
122+
123+
aggregate.reportingMonth = reportingMonth;
124+
aggregate.reportingPeriod = reportingPeriod;
125+
if (this.targetAggregatesService.isPreviousPeriod(aggregate.reportingPeriod)) {
126+
filtersToDisplay.push(aggregate.reportingMonth);
127+
}
128+
aggregate.filtersToDisplay = filtersToDisplay;
129+
130+
return aggregate;
131+
}
132+
102133
private async setDefaultFilters() {
103134
this.userFacilities = await this.userSettingsService.getUserFacilities();
135+
this.userFacilities.sort((a, b) => a.name.localeCompare(b.name));
104136
const defaultFilters = {
105137
facility: this.userFacilities.length ? { ...this.userFacilities[0] } : null,
138+
reportingPeriod: ReportingPeriod.CURRENT,
106139
};
107140
this.globalActions.setSidebarFilter({ defaultFilters });
108-
await this.getTargetAggregates(defaultFilters.facility);
141+
await this.getTargetAggregates(defaultFilters.facility, defaultFilters.reportingPeriod);
109142
}
110143
}

0 commit comments

Comments
 (0)