Skip to content

Commit 3214295

Browse files
chore(#9231): filter aggregate targets by period (#9283)
Co-authored-by: Jennifer Q <[email protected]>
1 parent 4f612e8 commit 3214295

26 files changed

+777
-105
lines changed

api/resources/translations/messages-en.properties

+2
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ analytics.target.aggregates.reported = Reported
349349
analytics.target.aggregates.select.error = Error loading target aggregate.
350350
analytics.target.aggregates.supervisees.meeting.goal = CHWs meeting goal
351351
analytics.target.aggregates.total = Total
352+
analytics.target.aggregates.reporting_period = Reporting period
352353
analytics.target.goal = Goal
353354
analytics.target.goal.help = If you don't want to display a goal enter a value of "-1".
354355
analytics.target.icon = Icon
@@ -1327,6 +1328,7 @@ targets.pnc_registrations.title = PNC registrations
13271328
targets.pnc_visits.title = PNC visits
13281329
targets.pregnancy_registrations.title = New pregnancies
13291330
targets.this_month.subtitle = This month
1331+
targets.last_month.subtitle = Last month
13301332
targets.vaccines_given.title = Vaccines given
13311333
task.date = Due date
13321334
task.days.left = {DAYS, plural, one{1 day left} other{\# days left}}

api/resources/translations/messages-es.properties

+3-1
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ analytics.target.aggregates.reported = Reportado
349349
analytics.target.aggregates.select.error = Error al cargar el objetivo consolidado.
350350
analytics.target.aggregates.supervisees.meeting.goal = Promotores de salud comunitaria que alcanzaron la meta.
351351
analytics.target.aggregates.total = Total
352+
analytics.target.aggregates.reporting_period = Periodo del informe
352353
analytics.target.goal = Meta
353354
analytics.target.goal.help = Si no desea mostrar una meta, ingrese el valor de "-1".
354355
analytics.target.icon = Icono
@@ -638,7 +639,7 @@ email.invalid = Dirección de correo electrónico no válida.
638639
empty = El mensaje esta en blanco, por favor reenvielo. Si continua teniendo problemas, informe a su supervisor.
639640
enketo.constraint.invalid = Valor no permitido
640641
enketo.constraint.required = Este campo es obligatorio
641-
enketo.drawwidget.annotation = anotación
642+
enketo.drawwidget.annotation = anotación
642643
enketo.drawwidget.drawing = dibujo
643644
enketo.drawwidget.signature = firma
644645
enketo.error.max_attachment_size = Los archivos subidos exceden el límite de tamaño total. Suba archivos más pequeños.
@@ -1327,6 +1328,7 @@ targets.pnc_registrations.title = Registros de CP
13271328
targets.pnc_visits.title = Visitas de CP
13281329
targets.pregnancy_registrations.title = Nuevos embarazos
13291330
targets.this_month.subtitle = Este mes
1331+
targets.last_month.subtitle = El mes pasado
13301332
targets.vaccines_given.title = Vacunas administradas
13311333
task.date = Fecha límite
13321334
task.days.left = {DAYS, plural, one{falta 1 día} other{faltan \# dias}}

api/resources/translations/messages-fr.properties

+2
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ analytics.target.aggregates.reported = Signalé
349349
analytics.target.aggregates.select.error = Erreur lors du chargement de l'agrégat objectif.
350350
analytics.target.aggregates.supervisees.meeting.goal = ASC qui ont atteint l'objectif
351351
analytics.target.aggregates.total = Total
352+
analytics.target.aggregates.reporting_period = Période des rapports
352353
analytics.target.goal = But
353354
analytics.target.goal.help = Si vous ne souhaitez pas afficher d'objectif, saisissez la valeur "-1".
354355
analytics.target.icon = Icone
@@ -1327,6 +1328,7 @@ targets.pnc_registrations.title = Enregistrements CPoN
13271328
targets.pnc_visits.title = Visites CPoN
13281329
targets.pregnancy_registrations.title = Nouvelles grossesses
13291330
targets.this_month.subtitle = Ce mois
1331+
targets.last_month.subtitle = Le mois dernier
13301332
targets.vaccines_given.title = Vaccins donnés
13311333
task.date = Date d'échéance
13321334
task.days.left = {JOURS, plural, one{1 jour restant} other{\# jours restants}}

api/resources/translations/messages-id.properties

+2
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,7 @@ analytics.target.aggregates.reported =
344344
analytics.target.aggregates.select.error =
345345
analytics.target.aggregates.supervisees.meeting.goal =
346346
analytics.target.aggregates.total =
347+
analytics.target.aggregates.reporting_period = Periode pelaporan
347348
analytics.target.goal = Tujuan
348349
analytics.target.goal.help =
349350
analytics.target.icon = Icon
@@ -1244,6 +1245,7 @@ targets.pnc_registrations.title =
12441245
targets.pnc_visits.title =
12451246
targets.pregnancy_registrations.title = Kehamilan terdaftar
12461247
targets.this_month.subtitle = Bulan ini
1248+
targets.last_month.subtitle = Bulan sebelumnya
12471249
targets.vaccines_given.title = Vaksin yang diberikan
12481250
task.date = Batas Tanggal Terakhir
12491251
task.days.left =

api/resources/translations/messages-ne.properties

+3-1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ analytics.target.aggregates.reported =
348348
analytics.target.aggregates.select.error =
349349
analytics.target.aggregates.supervisees.meeting.goal =
350350
analytics.target.aggregates.total =
351+
analytics.target.aggregates.reporting_period = रिपोर्टिङ अवधि
351352
analytics.target.goal =
352353
analytics.target.goal.help =
353354
analytics.target.icon =
@@ -1253,7 +1254,8 @@ targets.past_3mos.subtitle =
12531254
targets.pnc_registrations.title =
12541255
targets.pnc_visits.title =
12551256
targets.pregnancy_registrations.title =
1256-
targets.this_month.subtitle =
1257+
targets.this_month.subtitle = यो महिना
1258+
targets.last_month.subtitle = अघिल्लो महिना
12571259
targets.vaccines_given.title =
12581260
task.date = अनुमानित मिति
12591261
task.days.left =

api/resources/translations/messages-sw.properties

+2
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ analytics.target.aggregates.reported = Imeripotiwa
349349
analytics.target.aggregates.select.error = Hitilafu katika kupakia jumla ya malengo
350350
analytics.target.aggregates.supervisees.meeting.goal = Wafanyikazi wa afya wa Jamii wanafikisha lengo
351351
analytics.target.aggregates.total = Jumla
352+
analytics.target.aggregates.reporting_period = Kipindi cha kuripoti
352353
analytics.target.goal = Lengo
353354
analytics.target.goal.help = Ikiwa hutaki kuonyesha lengo weka thamani ya "-1"
354355
analytics.target.icon = Ikoni
@@ -1327,6 +1328,7 @@ targets.pnc_registrations.title = Usajili wa PNC
13271328
targets.pnc_visits.title = Ziara za PNC
13281329
targets.pregnancy_registrations.title = Mimba mpya
13291330
targets.this_month.subtitle = Mwezi huu
1331+
targets.last_month.subtitle = Mwezi uliopita
13301332
targets.vaccines_given.title = Chanjo iliyopewa
13311333
task.date = Tarehe ya kukamilisha
13321334
task.days.left = {DAYS, plural, one{Imesalia siku 1} other{Zimesalia siku \#}}

shared-libs/calendar-interval/src/index.js

+12
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ const getInterval = (intervalStartDate, referenceDate = moment()) => {
5050
};
5151
};
5252

53+
const getPreviousInterval = (intervalStartDate, referenceDate = moment()) => {
54+
referenceDate = referenceDate.clone().subtract(1, 'month');
55+
return getInterval(intervalStartDate, referenceDate);
56+
};
57+
5358
module.exports = {
5459
// Returns the timestamps of the start and end of the current calendar interval
5560
// @param {Number} [intervalStartDate=1] - day of month when interval starts (1 - 31)
@@ -59,6 +64,13 @@ module.exports = {
5964
// [12-31 -> 01-30], [01-31 -> 02-[28|29]], [03-01 -> 03-30], [03-31 -> 04-30], [05-01 -> 05-30], [05-31 - 06-30]
6065
getCurrent: (intervalStartDate) => getInterval(intervalStartDate),
6166

67+
getPrevious: (intervalStartDate, referenceDate) => {
68+
if (referenceDate) {
69+
return getPreviousInterval(intervalStartDate, moment(referenceDate));
70+
}
71+
return getPreviousInterval(intervalStartDate);
72+
},
73+
6274
/**
6375
* Returns the timestamps of the start and end of the a calendar interval that contains a reference date
6476
* @param {Number} [intervalStartDate=1] - day of month when interval starts (1 - 31)

shared-libs/calendar-interval/test/index.js

+74
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,80 @@ describe('CalendarInterval', () => {
252252
});
253253
});
254254

255+
describe('getPrevious', () => {
256+
it('returns 1st of previous month when month start is 1', () => {
257+
clock = sinon.useFakeTimers(moment('2024-07-15 21:10:01').valueOf());
258+
chai.expect(service.getPrevious(1)).to.deep.equal({
259+
start: moment('2024-06-01 00:00:00').valueOf(),
260+
end: moment('2024-06-30 23:59:59:999').valueOf(),
261+
});
262+
clock.restore();
263+
});
264+
265+
it('returns 1st of previous month when reference date is provided', () => {
266+
const referenceDate = '2024-07-15';
267+
chai.expect(service.getPrevious(1, referenceDate)).to.deep.equal({
268+
start: moment('2024-06-01 00:00:00').valueOf(),
269+
end: moment('2024-06-30 23:59:59:999').valueOf(),
270+
});
271+
});
272+
273+
it('returns 1st of previous month when reference date provided is in the future', () => {
274+
const referenceDate = '2025-07-15';
275+
chai.expect(service.getPrevious(1, referenceDate)).to.deep.equal({
276+
start: moment('2025-06-01 00:00:00').valueOf(),
277+
end: moment('2025-06-30 23:59:59:999').valueOf(),
278+
});
279+
});
280+
281+
it('returns n-th of the previous month when month start is n <= current date', () => {
282+
clock = sinon.useFakeTimers(moment('2018-03-20 21:10:01').valueOf());
283+
chai.expect(service.getPrevious(15)).to.deep.equal({
284+
start: moment('2018-02-15 00:00:00').valueOf(),
285+
end: moment('2018-03-14 23:59:59:999').valueOf(),
286+
});
287+
clock.restore();
288+
});
289+
290+
it('returns n-th of two months ago when month start is n > current date', () => {
291+
clock = sinon.useFakeTimers(moment('2018-03-10 21:10:01').valueOf());
292+
chai.expect(service.getPrevious(20)).to.deep.equal({
293+
start: moment('2018-01-20 00:00:00').valueOf(),
294+
end: moment('2018-02-19 23:59:59:999').valueOf(),
295+
});
296+
clock.restore();
297+
});
298+
299+
it('returns correct previous period when incorrect start date values', () => {
300+
clock = sinon.useFakeTimers(moment('2018-02-10').valueOf());
301+
[null, undefined, -1, 'date', false, 0, 35].forEach((invalidStart) => {
302+
chai.expect(service.getPrevious(invalidStart)).to.deep.equal({
303+
start: moment('2018-01-01 00:00:00').valueOf(),
304+
end: moment('2018-01-31 23:59:59:999').valueOf(),
305+
});
306+
});
307+
clock.restore();
308+
});
309+
310+
it('returns correct previous period when start date same as current date', () => {
311+
clock = sinon.useFakeTimers(moment('2018-04-15').valueOf());
312+
chai.expect(service.getPrevious(15)).to.deep.equal({
313+
start: moment('2018-03-15 00:00:00').valueOf(),
314+
end: moment('2018-04-14 23:59:59:999').valueOf(),
315+
});
316+
clock.restore();
317+
});
318+
319+
it('returns correct start date in previous month if month has 30 days', () => {
320+
clock = sinon.useFakeTimers(moment('2018-05-15').valueOf());
321+
chai.expect(service.getPrevious(31)).to.deep.equal({
322+
start: moment('2018-03-31 00:00:00').valueOf(),
323+
end: moment('2018-04-30 23:59:59:999').valueOf(),
324+
});
325+
clock.restore();
326+
});
327+
});
328+
255329
describe('getInterval', () => {
256330
it('returns 1st of current month when month start is not set or incorrect', () => {
257331
let timestamp;

webapp/src/css/sidebar-filter.less

+1-2
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@
104104
padding-left: 18px;
105105
padding-right: 18px;
106106
width: 100%;
107-
height: 100%;
108107

109108
.filter-options-title {
110109
display: block;
@@ -114,7 +113,7 @@
114113
color: @gray-ultra-dark;
115114
}
116115

117-
.filter-option-place {
116+
.filter-radio-option {
118117
padding-top: 20px;
119118

120119
.filter-option-wrapper {

webapp/src/css/targets.less

+5-1
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,12 @@
163163
left: 0;
164164
right: 0;
165165

166-
.target-detail .heading-content .aggregate-targets-facility {
166+
.target-detail .heading-content .aggregate-targets-details {
167167
display: block;
168+
span:not(:last-child):after {
169+
content: '\2022';
170+
padding: 0 5px;
171+
}
168172
}
169173
}
170174

webapp/src/ts/components/filters/analytics-filter/analytics-filter.component.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import { AuthService } from '@mm-services/auth.service';
1818
import { SessionService } from '@mm-services/session.service';
1919
import { TelemetryService } from '@mm-services/telemetry.service';
2020
import { TargetAggregatesService } from '@mm-services/target-aggregates.service';
21-
import { UserSettingsService } from '@mm-services/user-settings.service';
2221
import { OLD_REPORTS_FILTER_PERMISSION } from '@mm-modules/reports/reports-filters.component';
2322
import { OLD_ACTION_BAR_PERMISSION } from '@mm-components/actionbar/actionbar.component';
2423
import { AGGREGATE_TARGETS_ID } from '@mm-services/analytics-modules.service';
@@ -45,7 +44,6 @@ export class AnalyticsFilterComponent implements AfterContentInit, AfterContentC
4544
private sessionService: SessionService,
4645
private telemetryService: TelemetryService,
4746
private targetAggregatesService: TargetAggregatesService,
48-
private userSettingsService: UserSettingsService
4947
) {
5048
this.globalActions = new GlobalActions(store);
5149
}
@@ -122,14 +120,12 @@ export class AnalyticsFilterComponent implements AfterContentInit, AfterContentC
122120

123121
private async canDisplayFilterButton() {
124122
const isAdmin = this.sessionService.isAdmin();
125-
const [hasMultipleFacilities, checkPermissions, isTargetAggregateEnabled] = await Promise.all([
126-
this.userSettingsService.hasMultipleFacilities(),
123+
const [checkPermissions, isTargetAggregateEnabled] = await Promise.all([
127124
this.checkPermissions(),
128125
this.isTargetAggregateEnabled(),
129126
]);
130127

131128
this.showFilterButton = !isAdmin &&
132-
hasMultipleFacilities &&
133129
checkPermissions &&
134130
this.isTargetAggregates() &&
135131
isTargetAggregateEnabled;

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@
1616
<div class="heading-content">
1717
<h2 *ngIf="selected.translation_key; else noTranslationKeyTpl">{{ selected.translation_key | translate }}</h2>
1818
<ng-template #noTranslationKeyTpl><h2>{{ selected.title | translateFrom }}</h2></ng-template>
19-
<div class="aggregate-targets-facility" *ngIf="selected?.facility">{{ selected?.facility }}</div>
19+
<div class="aggregate-targets-details">
20+
<span *ngIf="selected?.facility">{{ selected?.facility }}</span>
21+
</div>
2022
</div>
2123
</div>
2224

@@ -35,7 +37,7 @@ <h3>{{'analytics.target.aggregates.reported' | translate}}</h3>
3537
</div>
3638
<div class="col-xs-6 col-md-8 text-right">
3739
<h3 *ngIf="selected.subtitle_translation_key">
38-
{{ selected.subtitle_translation_key | translate }}
40+
{{ reportingPeriod }}
3941
</h3>
4042
</div>
4143
</div>

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

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export class AnalyticsTargetAggregatesDetailComponent implements OnInit, OnDestr
2020
subscriptions: Subscription = new Subscription();
2121
selected: any = null;
2222
error: any = null;
23+
reportingPeriod;
2324
private prevAggregateId;
2425
private prevAggregates;
2526
private aggregates = null;
@@ -58,6 +59,9 @@ export class AnalyticsTargetAggregatesDetailComponent implements OnInit, OnDestr
5859
this.aggregates = aggregates;
5960
this.selected = selected;
6061
this.error = error;
62+
if (this.selected) {
63+
this.reportingPeriod = this.getReportingPeriodText(this.selected);
64+
}
6165
});
6266
this.subscriptions.add(subscriptionStore);
6367
}
@@ -110,4 +114,12 @@ export class AnalyticsTargetAggregatesDetailComponent implements OnInit, OnDestr
110114
this.globalActions.setTitle(title);
111115
this.targetAggregatesActions.setSelectedTargetAggregate(aggregateDetails);
112116
}
117+
118+
private getReportingPeriodText(aggregate) {
119+
if (this.targetAggregatesService.isCurrentPeriod(aggregate.reportingPeriod)) {
120+
return this.translateService.instant(this.selected.subtitle_translation_key);
121+
}
122+
123+
return this.selected.reportingMonth;
124+
}
113125
}

0 commit comments

Comments
 (0)