Skip to content

Commit

Permalink
feat(#9269): pass last three months target docs to contact summary (#…
Browse files Browse the repository at this point in the history
…9394)

Adds new analytics property to CHTDatasourceAPI in webapp.
This analytics property gets a targetDocs() list passed to contact-summary. This list has the latest 3 target docs for the contact.
When generating the contact summary of one of the logged in user's facilities, pass the logged in user's target docs to contact-summary.

#9269

(cherry picked from commit bbe5ded)
  • Loading branch information
dianabarsan authored and witash committed Sep 5, 2024
1 parent 1334e21 commit 25d027a
Show file tree
Hide file tree
Showing 35 changed files with 773 additions and 337 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,33 @@ let fields = [];
if (contact.type === 'person') {
// eslint-disable-next-line no-undef
fields = [{ label: 'test.pid', value: contact.patient_id, width: 3 }];
}
// eslint-disable-next-line no-undef
const targetDocs = cht.v1.analytics.getTargetDocs();
if (targetDocs) {
// eslint-disable-next-line no-undef
const targetIdx = contact.type === 'person' ? 0 : 1;
// eslint-disable-next-line no-undef
const targetDoc = targetDocs[targetIdx];
const card = {
label: 'Activity this month',
fields: [],
};
// eslint-disable-next-line no-undef
card.fields.push({ label: 'Last updated', value: targetDoc.date_updated });
card.fields.push({ label: 'Reporting period', value: targetDoc.reporting_period });

// eslint-disable-next-line no-undef
if (targetDoc) {
const card = {
label: 'Activity this month',
fields: [],
};
// eslint-disable-next-line no-undef
card.fields.push({ label: 'Last updated', value: targetDoc.date_updated });
// eslint-disable-next-line no-undef
targetDoc.targets.forEach(target => {
let value;
if (target.type === 'percent') {
value = (target.value.total ? target.value.pass * 100 / target.value.total : 0) + '%';
} else {
value = target.value.pass;
}
card.fields.push({ label: target.title.en, value: value });
});
cards.push(card);
}
targetDoc.targets.forEach(target => {
let value;
if (target.type === 'percent') {
value = (target.value.total ? target.value.pass * 100 / target.value.total : 0) + '%';
} else {
value = target.value.pass;
}
card.fields.push({ label: target.title.en, value: value });
});
cards.push(card);
}
return {
fields: fields,
Expand Down
63 changes: 61 additions & 2 deletions tests/e2e/default/targets/target-aggregates.wdio-spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const fs = require('fs');
const uuid = require('uuid').v4;
const utils = require('@utils');
const moment = require('moment');
const commonPage = require('@page-objects/default/common/common.wdio.page');
const analyticsPage = require('@page-objects/default/analytics/analytics.wdio.page');
const targetAggregatesPage = require('@page-objects/default/targets/target-aggregates.wdio.page');
Expand Down Expand Up @@ -262,7 +263,7 @@ describe('Target aggregates', () => {
// assert that the activity card exists and has the right fields.
expect(await contactsPage.getContactCardTitle()).to.equal('Activity this month');

await helperFunctions.validateCardFields(['yesterday Clarissa', '40', '50%']);
await helperFunctions.validateCardFields(['yesterday Clarissa', moment().format('YYYY-MM'), '40', '50%']);

await browser.back();

Expand All @@ -278,13 +279,71 @@ describe('Target aggregates', () => {
expect(await contactsPage.getContactInfoName()).to.equal('Prometheus');
// assert that the activity card exists and has the right fields.
expect(await contactsPage.getContactCardTitle()).to.equal('Activity this month');
await helperFunctions.validateCardFields(['yesterday Prometheus', '18', '15%']);
await helperFunctions.validateCardFields(['yesterday Prometheus', moment().format('YYYY-MM'), '18', '15%']);

await browser.back();
const secondTargetItem =
await (await targetAggregatesPage.getTargetItem(expectedTargets[1], CURRENT_PERIOD, districtHospital1.name));
await helperFunctions.assertTitle(secondTargetItem.title, expectedTargets[1].title);
});

it('should display targets of current user on home place', async () => {
const targetsConfig = [
{ id: 'a_target', type: 'count', title: { en: 'what a target!' }, aggregate: true },
{ id: 'b_target', type: 'percent', title: { en: 'the most target' }, aggregate: true },
];
const contactSummaryScript = fs
.readFileSync(`${__dirname}/config/contact-summary-target-aggregates.js`, 'utf8');

const clarissa = contactDocs.find(doc => doc.name === NAMES_DH1[0]);
const prometheus = contactDocs.find(doc => doc.name === NAMES_DH1[1]);
const targets = {
'Clarissa': [
{ id: 'a_target', value: { total: 50, pass: 40 } },
{ id: 'b_target', value: { total: 20, pass: 10 } }
],
'Prometheus': [
{ id: 'a_target', value: { total: 20, pass: 18 } },
{ id: 'b_target', value: { total: 40, pass: 6 } }
],
[onlineUser.contact.name]: [
{ id: 'a_target', value: { total: 1, pass: 1 } },
{ id: 'b_target', value: { total: 1, pass: 1 } }
],
};

const targetsForContact = (contact) => {
return helperFunctions.docTags.map(tag => ({
_id: `target~${tag}~${contact._id}~irrelevant`,
reporting_period: tag,
targets: targets[contact.name],
owner: contact._id,
user: 'irrelevant',
date_updated: `yesterday ${contact.name}`,
}));
};
const targetDocs = [
...targetsForContact(clarissa),
...targetsForContact(prometheus),
...targetsForContact(onlineUser.contact),
];

await utils.saveDocs(targetDocs);
await helperFunctions.updateAggregateTargetsSettings(targetsConfig, onlineUser, contactSummaryScript);

await commonPage.goToPeople(onlineUser.place._id);
// wait until contact-summary is loaded
expect(await contactsPage.getContactInfoName()).to.equal(districtHospital1.name);
// assert that the activity card exists and has the right fields.
expect(await contactsPage.getContactCardTitle()).to.equal('Activity this month');

await helperFunctions.validateCardFields([
`yesterday ${onlineUser.contact.name}`,
moment().subtract(1, 'month').format('YYYY-MM'),
'1',
'100%'
]);
});
});

describe('Offline user with multiple places associated', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ const generateTargetValuesByContact = (contactNames) => {
const docTags = [
// current targets
moment().format('YYYY-MM'),
// previous months targets
moment().date(10).subtract(1, 'month').format('YYYY-MM'),
// previous months targets
moment().date(10).subtract(2, 'month').format('YYYY-MM'),
// previous months targets
moment().date(10).subtract(3, 'month').format('YYYY-MM'),
// next month targets, in case the reporting period switches mid-test
moment().date(10).add(1, 'month').format('YYYY-MM'),
];
Expand Down
13 changes: 9 additions & 4 deletions webapp/src/ts/actions/global.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createAction, Store } from '@ngrx/store';

import { createSingleValueAction, createMultiValueAction } from '@mm-actions/actionUtils';
import { createMultiValueAction, createSingleValueAction } from '@mm-actions/actionUtils';

export const Actions = {
updateReplicationStatus: createSingleValueAction('UPDATE_REPLICATION_STATUS', 'replicationStatus'),
Expand Down Expand Up @@ -38,7 +38,8 @@ export const Actions = {
setUnreadCount: createSingleValueAction('SET_UNREAD_COUNT', 'unreadCount'),
updateUnreadCount: createSingleValueAction('UPDATE_UNREAD_COUNT', 'unreadCount'),
setTranslationsLoaded: createAction('SET_TRANSLATIONS_LOADED'),
setUserFacilityId: createSingleValueAction('SET_USER_FACILITY_ID', 'userFacilityId'),
setUserFacilityIds: createSingleValueAction('SET_USER_FACILITY_IDS', 'userFacilityIds'),
setUserContactId: createSingleValueAction('SET_USER_CONTACT_ID', 'userContactId'),
setTrainingCardFormId: createSingleValueAction('SET_TRAINING_CARD_FORM_ID', 'trainingCardFormId'),
};

Expand Down Expand Up @@ -241,8 +242,12 @@ export class GlobalActions {
return this.store.dispatch(Actions.setTranslationsLoaded());
}

setUserFacilityId(userFacilityId) {
return this.store.dispatch(Actions.setUserFacilityId(userFacilityId));
setUserFacilityIds(userFacilityIds) {
return this.store.dispatch(Actions.setUserFacilityIds(userFacilityIds));
}

setUserContactId(userContactId) {
return this.store.dispatch(Actions.setUserContactId(userContactId));
}

setTrainingCardFormId(trainingCard) {
Expand Down
18 changes: 18 additions & 0 deletions webapp/src/ts/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ import { TranslateService } from '@mm-services/translate.service';
import { AnalyticsModulesService } from '@mm-services/analytics-modules.service';
import { AnalyticsActions } from '@mm-actions/analytics';
import { TrainingCardsService } from '@mm-services/training-cards.service';
import { FormService } from '@mm-services/form.service';
import { OLD_REPORTS_FILTER_PERMISSION } from '@mm-modules/reports/reports-filters.component';
import { OLD_ACTION_BAR_PERMISSION } from '@mm-components/actionbar/actionbar.component';
import { BrowserDetectorService } from '@mm-services/browser-detector.service';
import { BrowserCompatibilityComponent } from '@mm-modals/browser-compatibility/browser-compatibility.component';
import { PerformanceService } from '@mm-services/performance.service';
import { UserSettings, UserSettingsService } from '@mm-services/user-settings.service';

const SYNC_STATUS = {
inProgress: {
Expand Down Expand Up @@ -136,6 +138,8 @@ export class AppComponent implements OnInit, AfterViewInit {
private trainingCardsService: TrainingCardsService,
private matIconRegistry: MatIconRegistry,
private browserDetectorService: BrowserDetectorService,
private userSettingsService: UserSettingsService,
private formService: FormService,
) {
this.globalActions = new GlobalActions(store);
this.analyticsActions = new AnalyticsActions(store);
Expand Down Expand Up @@ -282,6 +286,7 @@ export class AppComponent implements OnInit, AfterViewInit {
.then(() => this.chtDatasourceService.isInitialized())
.then(() => this.checkPrivacyPolicy())
.then(() => (this.initialisationComplete = true))
.then(() => this.initUser())
.then(() => this.initRulesEngine())
.then(() => this.initTransitions())
.then(() => this.initForms())
Expand All @@ -307,6 +312,12 @@ export class AppComponent implements OnInit, AfterViewInit {
this.initAnalyticsModules();
}

private async initUser() {
const userSettings:UserSettings = await this.userSettingsService.get();
this.globalActions.setUserContactId(userSettings.contact_id);
this.globalActions.setUserFacilityIds(userSettings.facility_id);
}

ngAfterViewInit() {
this.enableOldActionBar();
this.subscribeToSideFilterStore();
Expand Down Expand Up @@ -467,6 +478,13 @@ export class AppComponent implements OnInit, AfterViewInit {
this.trainingCardFormId = trainingCardFormId;
this.displayTrainingCards();
});

combineLatest([
this.store.select(Selectors.getUserContactId),
this.store.select(Selectors.getUserFacilityIds),
]).subscribe(([ userContactId, userFacilityIds ]) => {
this.formService.setUserContext(userFacilityIds, userContactId);
});
}

private displayTrainingCards() {
Expand Down
31 changes: 17 additions & 14 deletions webapp/src/ts/effects/contacts.effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class ContactsEffects {
private selectedContact;
private contactIdToLoad;
private userFacilityIds;
private userContactId;

constructor(
private actions$: Actions,
Expand All @@ -43,11 +44,13 @@ export class ContactsEffects {
combineLatest(
this.store.select(Selectors.getSelectedContact),
this.store.select(Selectors.getContactIdToLoad),
this.store.select(Selectors.getUserFacilityId),
).subscribe(([ selectedContact, contactIdToLoad, userFacilityId ]) => {
this.store.select(Selectors.getUserFacilityIds),
this.store.select(Selectors.getUserContactId),
).subscribe(([ selectedContact, contactIdToLoad, userFacilityIds, userContactId ]) => {
this.selectedContact = selectedContact;
this.contactIdToLoad = contactIdToLoad;
this.userFacilityIds = userFacilityId;
this.userFacilityIds = userFacilityIds;
this.userContactId = userContactId;
});
}

Expand Down Expand Up @@ -176,18 +179,18 @@ export class ContactsEffects {
});
}

private loadTargetDoc(contactId, trackName) {
private async loadTargetDoc(contactId, trackName) {
const trackPerformance = this.performanceService.track();
return this.targetAggregateService
.getCurrentTargetDoc(this.selectedContact)
.then(targetDoc => {
return this
.verifySelectedContactNotChanged(contactId)
.then(() => this.contactsActions.receiveSelectedContactTargetDoc(targetDoc));
})
.finally(() => {
trackPerformance?.stop({ name: [ ...trackName, 'load_targets' ].join(':') });
});

const targetDocs = await this.targetAggregateService.getTargetDocs(
this.selectedContact,
this.userFacilityIds,
this.userContactId
);
await this.verifySelectedContactNotChanged(contactId);
this.contactsActions.receiveSelectedContactTargetDoc(targetDocs);

trackPerformance?.stop({ name: [ ...trackName, 'load_targets' ].join(':') });
}

private loadTasks(contactId, trackName) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { combineLatest, Subscription, Subject } from 'rxjs';
import { combineLatest, Subject, Subscription } from 'rxjs';
import { Store } from '@ngrx/store';

import { Selectors } from '@mm-selectors/index';
Expand All @@ -9,6 +9,8 @@ import { TargetAggregatesService } from '@mm-services/target-aggregates.service'
import { GlobalActions } from '@mm-actions/global';
import { TranslateService } from '@mm-services/translate.service';

import { ReportingPeriod } from '@mm-modules/analytics/analytics-target-aggregates-sidebar-filter.component';

@Component({
selector: 'analytics-target-aggregates-detail',
templateUrl: './analytics-target-aggregates-detail.component.html'
Expand Down Expand Up @@ -106,7 +108,7 @@ export class AnalyticsTargetAggregatesDetailComponent implements OnInit, OnDestr
}

private getReportingPeriodText(aggregate) {
if (this.targetAggregatesService.isCurrentPeriod(aggregate.reportingPeriod)) {
if (aggregate.reportingPeriod === ReportingPeriod.CURRENT) {
return this.translateService.instant(this.selected.subtitle_translation_key);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export class AnalyticsTargetAggregatesComponent implements OnInit, OnDestroy {

aggregate.reportingMonth = reportingMonth;
aggregate.reportingPeriod = reportingPeriod;
if (this.targetAggregatesService.isPreviousPeriod(aggregate.reportingPeriod)) {
if (aggregate.reportingPeriod === ReportingPeriod.PREVIOUS) {
filtersToDisplay.push(aggregate.reportingMonth);
}
aggregate.filtersToDisplay = filtersToDisplay;
Expand Down
4 changes: 2 additions & 2 deletions webapp/src/ts/modules/contacts/contacts-content.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { ActivatedRoute, Router } from '@angular/router';
import { combineLatest, Subscription } from 'rxjs';
Expand Down Expand Up @@ -104,7 +104,7 @@ export class ContactsContentComponent implements OnInit, OnDestroy {

private getUserFacility() {
const subscription = this.store
.select(Selectors.getUserFacilityId)
.select(Selectors.getUserFacilityIds)
.pipe(first(id => id !== null))
.subscribe((userFacilityIds) => {
const shouldDisplayHomePlace = userFacilityIds &&
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy, AfterViewInit, NgZone } from '@angular/core';
import { AfterViewInit, Component, NgZone, OnDestroy, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { combineLatest, Subscription } from 'rxjs';
import { ActivatedRoute, Router } from '@angular/router';
Expand Down
3 changes: 1 addition & 2 deletions webapp/src/ts/modules/contacts/contacts.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, OnInit, OnDestroy, AfterViewInit } from '@angular/core';
import { AfterViewInit, Component, OnDestroy, OnInit } from '@angular/core';
import { combineLatest, Subscription } from 'rxjs';
import { Store } from '@ngrx/store';
import { Router } from '@angular/router';
Expand Down Expand Up @@ -230,7 +230,6 @@ export class ContactsComponent implements OnInit, AfterViewInit, OnDestroy {
const facilityIds = this
.getUserFacilityId(userSettings)
.filter(id => !!id);
this.globalActions.setUserFacilityId(facilityIds);

let homePlaces = await this.getDataRecordsService.get(facilityIds);
homePlaces = homePlaces?.filter(place => !!place);
Expand Down
9 changes: 6 additions & 3 deletions webapp/src/ts/reducers/global.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ const initialState = {
version: null,
snackbarContent: null as any,
translationsLoaded: false,
userFacilityId: null,
userFacilityIds: [],
userContactId: null,
trainingCardFormId: null,
};

Expand Down Expand Up @@ -204,9 +205,11 @@ const _globalReducer = createReducer(
return { ...state, unreadCount: { ...state.unreadCount, ...unreadCount } };
}),
on(Actions.setTranslationsLoaded, (state) => ({ ...state, translationsLoaded: true })),
on(Actions.setUserFacilityId, (state, { payload: { userFacilityId }}) => {
return { ...state, userFacilityId };
on(Actions.setUserFacilityIds, (state, { payload: { userFacilityIds }}) => {
userFacilityIds = Array.isArray(userFacilityIds) ? userFacilityIds : [userFacilityIds];
return { ...state, userFacilityIds };
}),
on(Actions.setUserContactId, (state, { payload: { userContactId }}) => ({ ...state, userContactId })),
on(Actions.setTrainingCardFormId, (state, { payload: { trainingCardFormId }}) => {
return { ...state, trainingCardFormId };
}),
Expand Down
Loading

0 comments on commit 25d027a

Please sign in to comment.