diff --git a/.vscode/launch.json b/.vscode/launch.json index f0a142628..d08ca05b9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,38 +1,36 @@ { - "version": "0.2.0", - "configurations": [ - { - "type": "chrome", - "request": "attach", - "name": "Unit tests", - "address": "localhost", - "port": 9333, - "sourceMaps": true, - "webRoot": "${workspaceRoot}" - }, - { - "name": "ng serve", - "type": "chrome", - "request": "launch", - "url": "http://localhost:3000/#", - "webRoot": "${workspaceFolder}" - }, - { - "name": "npm run test", - "type": "chrome", - "request": "launch", - "url": "http://localhost:9876/debug.html", - "webRoot": "${workspaceFolder}" - }, - { - "name": "ng e2e", - "type": "node", - "request": "launch", - "program": "${workspaceFolder}/node_modules/protractor/bin/protractor", - "protocol": "inspector", - "args": [ - "${workspaceFolder}/e2e/protractor.conf.js" - ] - } - ] + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "attach", + "name": "Unit tests", + "address": "localhost", + "port": 9333, + "sourceMaps": true, + "webRoot": "${workspaceRoot}" + }, + { + "name": "ng serve", + "type": "chrome", + "request": "launch", + "url": "http://localhost:3000/#", + "webRoot": "${workspaceFolder}" + }, + { + "name": "npm run test", + "type": "chrome", + "request": "launch", + "url": "http://localhost:9876/debug.html", + "webRoot": "${workspaceFolder}" + }, + { + "name": "ng e2e", + "type": "node", + "request": "launch", + "program": "${workspaceFolder}/node_modules/protractor/bin/protractor", + "protocol": "inspector", + "args": ["${workspaceFolder}/e2e/protractor.conf.js"] + } + ] } diff --git a/package-lock.json b/package-lock.json index 0b683431e..f5d2e1c78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ngx-amrs", - "version": "2.16.5-SNAPSHOT", + "version": "2.17.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "ngx-amrs", - "version": "2.16.5-SNAPSHOT", + "version": "2.17.1", "dependencies": { "@ampath-kenya/ngx-openmrs-formentry": "2.12.23", "@angular/animations": "^6.1.0", diff --git a/src/app/clinic-dashboard/general/pre-appointment-outreach/pre-appointment-outreach.component.ts b/src/app/clinic-dashboard/general/pre-appointment-outreach/pre-appointment-outreach.component.ts index 33936e856..d81010b4a 100644 --- a/src/app/clinic-dashboard/general/pre-appointment-outreach/pre-appointment-outreach.component.ts +++ b/src/app/clinic-dashboard/general/pre-appointment-outreach/pre-appointment-outreach.component.ts @@ -32,11 +32,13 @@ export class PreAppointmentOutreachComponent implements OnInit { private ALL = 'All'; private FOLLOW_UP_SUCCESSFUL = 'Follow-up Successful'; private FAILED_FOLLOW_UP_ATTEMPT = 'Failed Follow-up Attempt'; + private NO_FOLLOW_UP_ATTEMPT = 'Follow-up Not Attempted'; public filterTypeOptions: any[] = [ this.ALL, this.FOLLOW_UP_SUCCESSFUL, - this.FAILED_FOLLOW_UP_ATTEMPT + this.FAILED_FOLLOW_UP_ATTEMPT, + this.NO_FOLLOW_UP_ATTEMPT ]; public selectedFilterType = 'All'; // defaults to All // TODO refactor this later @@ -102,6 +104,11 @@ export class PreAppointmentOutreachComponent implements OnInit { this.explainedFilterType = 'Patient for whom follow-up attempts have been unsuccessful.'; break; + case this.NO_FOLLOW_UP_ATTEMPT: + this.mappedSelectedFilterType = 2; + this.explainedFilterType = + 'Patients for whom there has been no follow-up attempt.'; + break; default: this.explainedFilterType = ''; } diff --git a/src/app/etl-api/clinical-notes-resource.service.ts b/src/app/etl-api/clinical-notes-resource.service.ts index 7a10bb3ce..59260434b 100644 --- a/src/app/etl-api/clinical-notes-resource.service.ts +++ b/src/app/etl-api/clinical-notes-resource.service.ts @@ -15,7 +15,8 @@ export class ClinicalNotesResourceService { public getClinicalNotes( patientUuid: string, startIndex: number, - limit: number + limit: number, + isHEIActive: boolean ) { const api = this.appSettingsService.getEtlServer() + @@ -32,7 +33,9 @@ export class ClinicalNotesResourceService { const params: HttpParams = new HttpParams() .set('startIndex', (startIndex as any) as string) - .set('limit', (limit as any) as string); + .set('limit', (limit as any) as string) + .set('includeNonClinicalEncounter', 'false') + .set('isHEIActive', (isHEIActive as any) as string); return this.http.get(api, { params: params }); } diff --git a/src/app/etl-api/hiv-patient-clinical-summary-resource.service.ts b/src/app/etl-api/hiv-patient-clinical-summary-resource.service.ts index 20d428938..4780dfb6e 100644 --- a/src/app/etl-api/hiv-patient-clinical-summary-resource.service.ts +++ b/src/app/etl-api/hiv-patient-clinical-summary-resource.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'; import { AppSettingsService } from '../app-settings/app-settings.service'; import { Observable } from 'rxjs'; import { HttpClient, HttpParams } from '@angular/common/http'; - @Injectable() export class HivPatientClinicalSummaryResourceService { constructor( @@ -10,7 +9,10 @@ export class HivPatientClinicalSummaryResourceService { protected appSettingsService: AppSettingsService ) {} - public fetchPatientSummary(patientUuid: string): Observable { + public fetchPatientSummary( + patientUuid: string, + isHEIActive?: any + ): Observable { const api: string = this.appSettingsService.getEtlServer() + '/patient/' + @@ -18,8 +20,9 @@ export class HivPatientClinicalSummaryResourceService { '/hiv-patient-clinical-summary'; const params: HttpParams = new HttpParams() - .set('startIndex', (0 as any) as string) - .set('limit', (20 as any) as string); + .set('startIndex', '0') + .set('limit', '20') + .set('isHEIActive', (isHEIActive as any) as string); return this.http.get(api, { params: params }); } diff --git a/src/app/etl-api/hiv-summary-resource.service.ts b/src/app/etl-api/hiv-summary-resource.service.ts index e995061f8..4f96362d5 100644 --- a/src/app/etl-api/hiv-summary-resource.service.ts +++ b/src/app/etl-api/hiv-summary-resource.service.ts @@ -6,6 +6,7 @@ import { HttpClient, HttpParams } from '@angular/common/http'; @Injectable() export class HivSummaryResourceService { + public months: string; constructor( protected http: HttpClient, protected appSettingsService: AppSettingsService @@ -19,7 +20,8 @@ export class HivSummaryResourceService { patientUuid: string, startIndex: number, limit: number, - includeNonClinicalEncounter?: boolean + includeNonClinicalEncounter?: boolean, + isHEIActive?: any ): Observable { let url = this.getUrl(); url += '/' + patientUuid + '/hiv-summary'; @@ -40,8 +42,8 @@ export class HivSummaryResourceService { .set( 'includeNonClinicalEncounter', (includeNonClinicalEncounter as any) as string - ); - + ) + .set('isHEIActive', (isHEIActive as any) as string); return this.http .get(url, { params: params diff --git a/src/app/etl-api/pre-appointment-outreach-resource.service.ts b/src/app/etl-api/pre-appointment-outreach-resource.service.ts index 4d9f57e78..390c6c850 100644 --- a/src/app/etl-api/pre-appointment-outreach-resource.service.ts +++ b/src/app/etl-api/pre-appointment-outreach-resource.service.ts @@ -27,6 +27,9 @@ export class PreAppointmentOutreachResourceService { if (params.processOutcome === 0) { urlParams = urlParams.set('failedOutcome', '1'); } + if (params.processOutcome === 2) { + urlParams = urlParams.set('unknownOutcome', '0'); + } const url = this.getUrl('ml-weekly-predictions'); const request = this.http diff --git a/src/app/lab-order-search/lab-order-search-post.component.ts b/src/app/lab-order-search/lab-order-search-post.component.ts index 41bf6b168..bcd6ca1c2 100644 --- a/src/app/lab-order-search/lab-order-search-post.component.ts +++ b/src/app/lab-order-search/lab-order-search-post.component.ts @@ -41,6 +41,7 @@ interface Identifier { }) export class LabOrderSearchPostComponent implements OnInit, OnChanges { public _order: any = null; + isHEIActive: any; @Input() set order(order: any) { this.selectedLabLocation = null; @@ -129,6 +130,11 @@ export class LabOrderSearchPostComponent implements OnInit, OnChanges { }); this.patient = this.order.patient; this.person = new Person(this.order.patient.person); + if (Moment().diff(Moment(this.person.birthdate), 'months') <= 18) { + this.isHEIActive = true; + } else { + this.isHEIActive = false; + } this.searchIdentifiers = this.labOrdersSearchHelperService.searchIdentifiers( this.order.patient.identifiers ); @@ -197,17 +203,19 @@ export class LabOrderSearchPostComponent implements OnInit, OnChanges { } public loadHivSummary(patientUuid) { - this.hivSummaryService.getHivSummary(patientUuid, 0, 1, false).subscribe( - (data) => { - this.hivSummary = data && data.length > 0 ? data[0] : null; - this.isBusy = false; - }, - (err) => { - this.error = - 'An error occured while loading Hiv Summary. Please try again.'; - this.isBusy = false; - } - ); + this.hivSummaryService + .getHivSummary(patientUuid, 0, 1, false, this.isHEIActive) + .subscribe( + (data) => { + this.hivSummary = data && data.length > 0 ? data[0] : null; + this.isBusy = false; + }, + (err) => { + this.error = + 'An error occured while loading Hiv Summary. Please try again.'; + this.isBusy = false; + } + ); } public displayDnaPcrInputs() { diff --git a/src/app/navigation/side-navigation/patient-side-nav/patient-side-nav-routes.factory.ts b/src/app/navigation/side-navigation/patient-side-nav/patient-side-nav-routes.factory.ts index 8d53bb30b..523d713bf 100644 --- a/src/app/navigation/side-navigation/patient-side-nav/patient-side-nav-routes.factory.ts +++ b/src/app/navigation/side-navigation/patient-side-nav/patient-side-nav-routes.factory.ts @@ -3,6 +3,7 @@ import { Injectable } from '@angular/core'; import { RoutesProviderService } from '../../../shared/dynamic-route/route-config-provider.service'; import { RouteModel } from '../../../shared/dynamic-route/route.model'; import { Patient } from '../../../models/patient.model'; +import * as Moment from 'moment'; @Injectable() export class PatientRoutesFactory { constructor(public routesProvider: RoutesProviderService) {} @@ -16,6 +17,19 @@ export class PatientRoutesFactory { patientRoutesConfig = this.processSharedRoutes(patientRoutesConfig); const routes: RouteModel[] = []; + if (Moment().diff(Moment(patient.person.birthdate), 'months') <= 18) { + patientRoutesConfig.sharedRoutes.hiv[3] = { + url: 'hiv-summary', + label: 'HEI Summary', + icon: 'fa fa-child' + }; + } else { + patientRoutesConfig.sharedRoutes.hiv[3] = { + url: 'hiv-summary', + label: 'HIV Summary', + icon: 'fa fa-medkit' + }; + } if (Array.isArray(patientRoutesConfig['programs'])) { for (const program of patientRoutesConfig.programs) { if ( diff --git a/src/app/patient-dashboard/common/clinical-notes/clinical-notes.component.ts b/src/app/patient-dashboard/common/clinical-notes/clinical-notes.component.ts index 9d030d231..c6d9bb6c4 100644 --- a/src/app/patient-dashboard/common/clinical-notes/clinical-notes.component.ts +++ b/src/app/patient-dashboard/common/clinical-notes/clinical-notes.component.ts @@ -6,6 +6,8 @@ import { AppFeatureAnalytics } from '../../../shared/app-analytics/app-feature-a import { ClinicalNotesResourceService } from '../../../etl-api/clinical-notes-resource.service'; import { ClinicalNotesHelperService } from './clinical-notes.helper'; import { Subscription } from 'rxjs'; +import { PatientResourceService } from 'src/app/openmrs-api/patient-resource.service'; +import * as Moment from 'moment'; @Component({ selector: 'app-clinical-notes', @@ -25,6 +27,8 @@ export class ClinicalNotesComponent implements OnInit, OnDestroy { public notes: Array = []; + public isHEIActive = false; + private helper: ClinicalNotesHelperService; private subscription: Subscription; @@ -36,7 +40,8 @@ export class ClinicalNotesComponent implements OnInit, OnDestroy { constructor( private route: ActivatedRoute, private notesResource: ClinicalNotesResourceService, - private appFeatureAnalytics: AppFeatureAnalytics + private appFeatureAnalytics: AppFeatureAnalytics, + private patientResourceService: PatientResourceService ) { this.helper = new ClinicalNotesHelperService(); } @@ -51,16 +56,24 @@ export class ClinicalNotesComponent implements OnInit, OnDestroy { this.subscription = this.route.parent.params.subscribe((params: Params) => { this.patientUuid = params['patient_uuid']; - this.getNotes(0, 10, (err, notes) => { - if (err) { - console.error(err); - return; - } - - this.notes = notes; - - this.fetching = false; - }); + this.patientResourceService + .getPatientByUuid(this.patientUuid) + .subscribe((result) => { + this.isHEIActive = + Moment().diff(Moment(result.person.birthdate), 'months') <= 18 + ? true + : false; + this.getNotes(0, 10, this.isHEIActive, (err, notes) => { + if (err) { + console.error(err); + return; + } + + this.notes = notes; + + this.fetching = false; + }); + }); }); } @@ -76,7 +89,7 @@ export class ClinicalNotesComponent implements OnInit, OnDestroy { this.fetching = false; - this.getNotes(this.nextStartIndex, 10, (err, notes) => { + this.getNotes(this.nextStartIndex, 10, this.isHEIActive, (err, notes) => { if (err) { console.error(err); return; @@ -92,9 +105,9 @@ export class ClinicalNotesComponent implements OnInit, OnDestroy { }); } - public getNotes(startIndex: number, limit: number, cb) { + public getNotes(startIndex: number, limit: number, isHEIACTIVE: boolean, cb) { this.isBusy = this.notesResource - .getClinicalNotes(this.patientUuid, startIndex, limit) + .getClinicalNotes(this.patientUuid, startIndex, limit, this.isHEIActive) .pipe(take(1)) .subscribe( (data: any) => { diff --git a/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.css b/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.css new file mode 100644 index 000000000..4bc51f852 --- /dev/null +++ b/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.css @@ -0,0 +1,36 @@ +p { + padding: 8px; + background-color: rgba(29, 112, 219, 0.842); + color: #fff; + border-radius: 3px; +} + +.header { + font-size: 16px; + font-weight: 600; + margin-left: 20px; + color: rgb(5, 102, 212); + display: block; + width: 100%; +} + +.wrapper-container { + margin-top: 18px; + width: 100%; +} + +.self-container { + margin-top: 18px; + width: 100%; +} + +.wrapper { + padding-bottom: 32px; +} + +.btn-print { + font-size: 24px; + float: right; + margin-right: 20px; + cursor: pointer; +} diff --git a/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.html b/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.html new file mode 100644 index 000000000..3cd83d21e --- /dev/null +++ b/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.html @@ -0,0 +1,1009 @@ +
+
+
+ +
+
+
+

Encounter Details

+
    +
  • + Follow Up Date: + {{ + mappedAttributes.obs['PLANNED FOLLOW-UP DATE'] + }} +
  • +
  • + Date Of Last Follow-Up : + {{ + mappedAttributes.obs['DATE OF LAST FOLLOW-UP'] + }} +
  • +
  • + Case Manager: + {{ mappedAttributes.attributes['Case Manager'] }} +
  • +
+
+
+

Clients/Patient's Information

+
    +
  • + Marital status: + {{ mappedAttributes.obs['CIVIL STATUS'] }} +
  • +
  • + Health Center: + {{ mappedAttributes.attributes['Health Center'] }} +
  • +
  • + Religious affiliation & location: + {{ mappedAttributes.obs.RELIGION }} +
  • +
  • + Patient/Client category: + {{ mappedAttributes.obs['PATIENT TYPE'] }} +
  • +
+
+
+

Other Personal Information

+
    +
  • + No of children: + {{ + mappedAttributes.obs['NUMBER OF CHILDREN LIVING IN HOME'] + }} +
  • +
  • + No of siblings: + {{ mappedAttributes.obs['NUMBER OF SIBLINGS'] }} +
  • +
  • + Names of family members who know about the status of the client: + {{ + mappedAttributes.obs['HIV STATUS DICLOSURE TO HOUSEHOLD MEMBERS'] + }} +
  • +
+
+
+

Locator Information

+
    +
  • + Client/Parent/Guardians preferred place of contact: + {{ + mappedAttributes.obs['PREFERRED PLACE OF CONTACT'] + }} +
  • +
  • + Time: - + {{ + mappedAttributes.obs['PREFERRED DAY AND TIME OF CONTACT, CODED'] + }} +
  • +
  • + Physical Description of the patient/client/Guardian: + {{ + mappedAttributes.obs['PHYSICAL EXAM NOTE, FREETEXT'] + }} +
  • +
  • + Additional comments: + {{ + mappedAttributes.obs['CLINICAL COMMENTS, GENERAL'] + }} +
  • +
  • + Indicate if patient is from AMPATH catchment area: + {{ mappedAttributes.obs['AMPATH CATCHMENT AREA'] }} +
  • +
+
+
+

Residence and Personal Information

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Official name of client : + {{ mappedAttributes.attributes['Caregiver Name'] }} + + Name commonly called : + {{ mappedAttributes.attributes['Caregiver common name'] }} +
+ Tribe : + {{ mappedAttributes.attributes.Tribe }} + + Phone number : + {{ mappedAttributes.attributes['Contact Phone Number'] }} +
+ Alternative Phone No. : + {{ + mappedAttributes.attributes[ + 'Alternative contact phone number' + ] + }} + + Occupation : {{ mappedAttributes.attributes['POLICE OFFICER'] }} +
+ Relationship: {{ mappedAttributes.attributes['GRANDPARENT'] }} + + Location :{{ mappedAttributes.attributes['Workplace'] }} +
+
+
+
Place of Work
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+ Town : + {{ mappedAttributes.attributes['Workplace'] }} + + Institution/Business: {{ mappedAttributes.attributes['Workplace Institution'] }} +
+ Location : + {{ mappedAttributes.attributes['Workplace Location'] }} + + Department/section : {{ mappedAttributes.attributes['Workplace department'] }} +
+ well known name : {{ mappedAttributes.attributes['Workplace Known Name'] }} +
+
+
+
+
Rural Direction
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ General route : + {{ mappedAttributes.attributes['Driving Route'] }} + + Nearest centre: {{ + mappedAttributes.attributes['Rural nearest shopping centre'] + }} +
+ Stage : {{ mappedAttributes.attributes['Rural bus stage'] }} + + Village : + {{ mappedAttributes.attributes['Rural village'] }} +
+ Nearest landmark : {{ mappedAttributes.attributes['Rural landmark'] }} + + Homestead name : {{ mappedAttributes.attributes['Rural homestead'] }} +
+ Whom to ask :{{ + mappedAttributes.attributes[ + 'Rural person reporting information' + ] + }} +
+
+
+
+
Urban Direction (check)
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Town : + {{ mappedAttributes.attributes['Client residence'] }} + + Estate: {{ mappedAttributes.attributes['Client urban estate'] }} +
+ Stage : {{ mappedAttributes.attributes['Bus Stage'] }} + + Section : + {{ mappedAttributes.attributes['Client urban section'] }} +
+ Nearest landmark : {{ mappedAttributes.attributes['Landmark'] }} + + Plot name: {{ mappedAttributes.attributes['Plot number'] }} +
+ Landlord : {{ mappedAttributes.attributes['Landlord name'] }} + + Health Center : {{ mappedAttributes.attributes['Health Center'] }} +
+
+
+
+ +
+

Spouse Details

+
+
+ + + + + + + + + + + + + + + + + + +
+ Name of Spouse : + {{ mappedAttributes.attributes['Partner Name'] }} + + Name commonly called : {{ mappedAttributes.attributes['Partner common name'] }} +
+ Tribe : {{ mappedAttributes.attributes['Partner tribe'] }} + + Phone number : + {{ + mappedAttributes.attributes['Partner Contact Phone Number'] + }} +
+
+
+
Rural Direction
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ General route : + {{ + mappedAttributes.attributes['Partner rural general route'] + }} + + Nearest centre: {{ + mappedAttributes.attributes[ + 'Partner rural nearest shopping centre' + ] + }} +
+ Stage : {{ + mappedAttributes.attributes['Partner rural bus stage'] + }} + + Village : + {{ mappedAttributes.attributes['Partner rural village'] }} +
+ Nearest landmark : {{ mappedAttributes.attributes['Partner rural landmark'] }} + + Homestead name : + {{ mappedAttributes.attributes['Partner rural homestead'] }} +
+ Whom to ask : + {{ + mappedAttributes.attributes[ + 'Partner rural person reporting information' + ] + }} +
+
+
+
+
Urban Direction
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Town : + {{ mappedAttributes.attributes['Partner urban residence'] }} + + Estate: {{ mappedAttributes.attributes['Partner urban section'] }} +
+ Stage : {{ + mappedAttributes.attributes['Partner urban bus stage'] + }} + + Section : + {{ mappedAttributes.attributes['Partner urban section'] }} +
+ Nearest landmark : {{ mappedAttributes.attributes['Partner urban landmark'] }} + + Plot name: {{ mappedAttributes.attributes['Plot number'] }} +
+ Landlord : {{ + mappedAttributes.attributes['Partner urban landlord name'] + }} + + Nearest well known neighbor: {{ + mappedAttributes.attributes[ + 'Partner urban well known neighbor name' + ] + }} +
+ Whom to ask :{{ + mappedAttributes.attributes[ + 'Partner urban person reporting information' + ] + }} +
+
+
+
+

Next of Kin Details

+
+
+ + + + + + + + + + + + + + + + + + +
+ Name of next of kin : + {{ mappedAttributes.attributes['Next of Kin name'] }} + + Name commonly called : {{ mappedAttributes.attributes['Next of Kin Common Name'] }} +
+ Tribe : + {{ mappedAttributes.attributes['Next of Kin Tribe'] }} + + Phone number : + {{ + mappedAttributes.attributes[ + 'Next of Kin Contact Phone Number' + ] + }} +
+
+
+
Rural Direction
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ General route : + {{ + mappedAttributes.attributes[ + 'Next of kin rural general route' + ] + }} + + Nearest centre: {{ + mappedAttributes.attributes[ + 'Next of Kin rural nearest shopping Centre' + ] + }} +
+ Stage : {{ + mappedAttributes.attributes['Next of kin rural bus stage'] + }} + + Village : + {{ + mappedAttributes.attributes['Next of kin Rural Village'] + }} +
+ Nearest landmark : {{ + mappedAttributes.attributes['Next of kin rural landmark'] + }} + + Homestead name : + {{ + mappedAttributes.attributes['Next of kin rural Homestead'] + }} +
+ Whom to ask :{{ + mappedAttributes.attributes[ + 'Next of kin rural person reporting information' + ] + }} +
+
+
+
+
Urban Direction
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Town : + {{ + mappedAttributes.attributes['Next of kin urban residence'] + }} + + Estate: {{ + mappedAttributes.attributes['Next of Kin Urban Estate'] + }} +
+ Stage : {{ + mappedAttributes.attributes['Next of kin urban bus stage'] + }} + + Section : + {{ + mappedAttributes.attributes['Next of Kin Urban Section'] + }} +
+ Nearest landmark : {{ + mappedAttributes.attributes['Next of Kin Urban Landmark'] + }} + + Plot name / Number: {{ + mappedAttributes.attributes[ + 'Next of kin urban plot number' + ] + }} +
+ Landlord : {{ + mappedAttributes.attributes[ + 'Next of kin urban landlord name' + ] + }} + + Nearest well known neighbor: {{ + mappedAttributes.attributes[ + 'Next of Kin urban well known neighbor name' + ] + }} +
+ Whom to ask : + {{ + mappedAttributes.attributes[ + 'Next of kin urban person reporting information' + ] + }} +
+
+
+
+

Treatment supporter name

+
+
+ + + + + + + + + + + + + + + + + + + + + +
+ Treatment supporter name : + {{ mappedAttributes.attributes['Treatment Supporter Name'] }} + + Common name: {{ + mappedAttributes.attributes[ + 'Treatment Supporter common name' + ] + }} +
+ Tribe : + {{ mappedAttributes.attributes['Treatment supporter tribe'] }} + + Phone number : + {{ + mappedAttributes.attributes[ + 'Treatment Supporter Contact Phone Number' + ] + }} +
+ Location of worship: + {{ + mappedAttributes.attributes[ + 'Treatment Supporter location of religious worship' + ] + }} +
+
+
+
Rural Direction
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ General route : + {{ + mappedAttributes.attributes[ + 'Treatment Supporter Rural General Route' + ] + }} + + Nearest centre: {{ + mappedAttributes.attributes[ + 'Treatment supporter rural nearest shopping Centre' + ] + }} +
+ Stage : {{ + mappedAttributes.attributes[ + 'Treatment Supporter Rural Bus Stage' + ] + }} + + Village : + {{ + mappedAttributes.attributes['Treatment Supporter Village'] + }} +
+ Nearest landmark : + {{ + mappedAttributes.attributes[ + 'Treatment Supporter Rural Landmark' + ] + }} +
+ Whom to ask :{{ + mappedAttributes.attributes[ + 'Treatment Support Rural Person Reporting Info' + ] + }} +
+
+
+
+
Place of Work
+
+ + + + + + + + + + + + + + + + + + + + + +
+ Town : + {{ + mappedAttributes.attributes[ + 'Treatment Supporter workplace' + ] + }} + + Institution/Business: {{ + mappedAttributes.attributes[ + 'Treatment Supporter Workplace Institution' + ] + }} +
+ Location : {{ + mappedAttributes.attributes[ + 'Treatment Supporter workplace' + ] + }} + + Department/section : + {{ + mappedAttributes.attributes[ + 'Treatment Supporter workplace Department' + ] + }} +
+ well known name : {{ + mappedAttributes.attributes[ + 'Treatment Supporter Workplace Known Name' + ] + }} +
+
+
+
+
Urban Direction
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Town : + {{ + mappedAttributes.attributes[ + 'Treatment Supporter Urban Residence' + ] + }} + + Estate: {{ + mappedAttributes.attributes[ + 'Treatment Supporter Urban Estate' + ] + }} +
+ Stage : {{ + mappedAttributes.attributes[ + 'Treatment supporter urban bus stage' + ] + }} + + Section : + {{ + mappedAttributes.attributes[ + 'Treatment Supporter Urban Section' + ] + }} +
+ Nearest landmark : {{ + mappedAttributes.attributes[ + 'Treatment Supporter Urban Landmark' + ] + }} + + Plot name: {{ + mappedAttributes.attributes[ + 'Treatment Supporter Urban Plot number' + ] + }} +
+ Landlord : {{ + mappedAttributes.attributes[ + 'Treatment Supporter urban landlord' + ] + }} + + Nearest well known neighbor: {{ + mappedAttributes.attributes[ + 'Treatment supporter urban well known neighbour' + ] + }} +
+ Whom to ask: {{ + mappedAttributes.attributes[ + 'Treatment Support Urban Person Reporting Info' + ] + }} +
+
+
+
+
+
+
diff --git a/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.ts b/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.ts new file mode 100644 index 000000000..ff1eaaf41 --- /dev/null +++ b/src/app/patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component.ts @@ -0,0 +1,97 @@ +import { Component, Input, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-locator-pretty-viewer', + templateUrl: './locator-pretty-viewer.component.html', + styleUrls: ['./locator-pretty-viewer.component.css'] +}) +export class LocatorPrettyViewerComponent implements OnInit { + @Input() locatorData: any; + + data: any; + mappedAttributes: any; + constructor() {} + + ngOnInit() { + this.getData(); + } + + getData() { + if (this.locatorData) { + const { obs, patient } = this.locatorData.existingOrders; + + if (patient) { + const { + person: { attributes } + } = patient; + this.data = { + obs, + attributes + }; + } + } + this.mappedAttributes = this.generateMappings(this.data); + console.log('mappedAttributes', this.mappedAttributes); + } + + generateMappings(data: any) { + const mappings = { + obs: {}, + attributes: {} + }; + + if (data) { + for (const type of ['obs', 'attributes']) { + if (data[type]) { + for (const item of data[type]) { + if (type === 'obs' && item.concept.name.display) { + mappings[type][item.concept.name.display] = + item.value.display || item.value; + } else if (type === 'attributes' && item.display) { + const parts = item.display.split('='); + if (parts.length === 2) { + mappings[type][parts[0].trim()] = parts[1].trim(); + } else { + mappings[type][item.display] = item.display; + } + } + } + } + } + } + return mappings; + } + + generatePDF() { + const printContents = document.getElementById('wrapper-container'); + + if (!printContents) { + return; + } + + const contentToPrint = printContents.innerHTML; + const popupWin = window.open( + '', + '_blank', + 'top=0,left=0,height=100%,width=auto' + ); + + popupWin.document.open(); + popupWin.document.write(` + + + Locator Map Details + + + ${contentToPrint} + + `); + popupWin.document.close(); + + // Use an event listener to trigger the print and close actions + popupWin.addEventListener('load', () => { + popupWin.print(); + popupWin.close(); + }); + } +} diff --git a/src/app/patient-dashboard/common/formentry/pretty-encounter-viewer.component.html b/src/app/patient-dashboard/common/formentry/pretty-encounter-viewer.component.html index 6b0e1021e..178f9dd6d 100644 --- a/src/app/patient-dashboard/common/formentry/pretty-encounter-viewer.component.html +++ b/src/app/patient-dashboard/common/formentry/pretty-encounter-viewer.component.html @@ -1,10 +1,14 @@
- +
+ +
+
+ + +
-
{{ errorMessage }}
diff --git a/src/app/patient-dashboard/common/formentry/pretty-encounter-viewer.component.ts b/src/app/patient-dashboard/common/formentry/pretty-encounter-viewer.component.ts index afe4dbae2..b5ea8df09 100644 --- a/src/app/patient-dashboard/common/formentry/pretty-encounter-viewer.component.ts +++ b/src/app/patient-dashboard/common/formentry/pretty-encounter-viewer.component.ts @@ -26,6 +26,9 @@ export class PrettyEncounterViewerComponent implements OnInit { this.displayEncounterObs(encounter); } } + @Input() fromLocatorMap: boolean; + + public locatorData: Form; public form: Form; public showLoader: boolean; public error: boolean; @@ -138,6 +141,7 @@ export class PrettyEncounterViewerComponent implements OnInit { this.selectedEncounter ); this.form = unpopulatedform; + this.locatorData = unpopulatedform; this.showLoader = false; this.error = false; }); diff --git a/src/app/patient-dashboard/common/locator-map/locator-map-details.component.css b/src/app/patient-dashboard/common/locator-map/locator-map-details.component.css new file mode 100644 index 000000000..6c4a2453f --- /dev/null +++ b/src/app/patient-dashboard/common/locator-map/locator-map-details.component.css @@ -0,0 +1,27 @@ +.patient-info-row { + margin-right: 0px; + margin-left: 0px; +} + +.info_section_title { + font-size: 20px; + color: #203864; +} +.edit_link span { + font-size: 1.1em; +} +.edit_link .fa { + display: inline; +} +.edit_link:hover { + cursor: pointer; +} +.spacing { + margin-right: 15px; +} +.smaller-icon { + font-size: 12px; +} +#encounter .modal-nav-header { + padding-bottom: 20px; +} diff --git a/src/app/patient-dashboard/common/locator-map/locator-map-details.component.html b/src/app/patient-dashboard/common/locator-map/locator-map-details.component.html new file mode 100644 index 000000000..06aaa1c0b --- /dev/null +++ b/src/app/patient-dashboard/common/locator-map/locator-map-details.component.html @@ -0,0 +1,105 @@ + +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + +
Landmark : {{ landmark }}Workplace : {{ workplace }}
+ Well Known Neighbour : {{ nearestNeighbour }} + + Treatment Supporter Name : {{ treatmentSupporter }} +
Well Known child Name : {{ knownChild }}Tribe {{ tribe }}
+
+ + +
diff --git a/src/app/patient-dashboard/common/locator-map/locator-map-details.component.spec.ts b/src/app/patient-dashboard/common/locator-map/locator-map-details.component.spec.ts new file mode 100644 index 000000000..c43e52abb --- /dev/null +++ b/src/app/patient-dashboard/common/locator-map/locator-map-details.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LocatorMapDetailsComponent } from './locator-map-details.component'; + +describe('LocatorMapDetailsComponent', () => { + let component: LocatorMapDetailsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [LocatorMapDetailsComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LocatorMapDetailsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/patient-dashboard/common/locator-map/locator-map-details.component.ts b/src/app/patient-dashboard/common/locator-map/locator-map-details.component.ts new file mode 100644 index 000000000..292af49ed --- /dev/null +++ b/src/app/patient-dashboard/common/locator-map/locator-map-details.component.ts @@ -0,0 +1,170 @@ +import { + Component, + OnInit, + EventEmitter, + Input, + Output, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { PatientService } from '../../services/patient.service'; +import { PersonAttributeResourceService } from './../../../openmrs-api/person-attribute-resource.service'; +import { PrettyEncounterViewerComponent } from '../patient-dashboard/common/formentry/pretty-encounter-viewer.component'; +import { EncounterResourceService } from '../../../openmrs-api/encounter-resource.service'; +import { Patient } from '../../../models/patient.model'; +import { Subscription } from 'rxjs'; +import { Router } from '@angular/router'; +import { take } from 'rxjs/operators'; +import { ModalComponent } from 'ng2-bs3-modal/ng2-bs3-modal'; +import { ModalDirective } from 'ngx-bootstrap/modal'; + +import * as _ from 'lodash'; +@Component({ + selector: 'locator-map-details', + templateUrl: './locator-map-details.component.html', + styleUrls: ['./locator-map-details.component.css'] +}) +export class LocatorMapDetailsComponent implements OnInit { + public patient: Patient = new Patient({}); + + public display = false; + public subscription: Subscription; + public patientLocatorEncounterUuid: string; + public patientLocatorEncounter: any; + public editDetails = false; + public patientEncounters: Array = []; + @ViewChild('staticModal') + public staticModal: ModalDirective; + @ViewChild('modal') + public modal: ModalComponent; + @Output() public isBusy = new EventEmitter(); + @Output() public ShowPrettyEncounterViewer = new EventEmitter(); + @Output() public EncounterObservations = new EventEmitter(); + private patient_uuid: string; + private tribe: string; + private nearestNeighbour: string; + private landmark: string; + private workplace: string; + private knownChild: string; + private treatmentSupporter: string; + private locatorMapFormUuid = '18992298-4fe3-4c77-af9c-df8cf31b6e2b'; + constructor( + private patientService: PatientService, + private personAttributeResourceService: PersonAttributeResourceService, + private router: Router, + private encounterResourceService: EncounterResourceService + ) {} + + public showDialog() { + this.display = true; + } + public close() { + this.modal.close(); + } + public dismissed() { + this.modal.dismiss(); + } + + public showEncounterObservations(encounter) { + this.display = true; + this.isBusy.emit(true); + this.EncounterObservations.emit(encounter); + // console.log('Show observations', encounter); + } + ngOnInit() { + this.subscription = this.patientService.currentlyLoadedPatient.subscribe( + (patient) => { + this.patient = new Patient({}); + if (patient) { + this.patient = patient; + this.getPatientLocation(); + this.getPatientEncounters(); + } + } + ); + } + + public getPatientLocation() { + const patientUuid = this.patient.uuid; + this.personAttributeResourceService + .getPersonAttributesByUuid(patientUuid) + .subscribe((res) => { + res.results.forEach((a: any) => { + if (a.attributeType.uuid === '4dcc4901-d4a1-422a-b6a0-2b24594a0dc6') { + this.knownChild = a.value; + } else if ( + a.attributeType.uuid === '254e3b6a-eeec-4714-9c5f-776cc4d30191' + ) { + this.landmark = a.value; + } else if ( + a.attributeType.uuid === '4dae5b87-884d-4f88-b2fb-85cda2be37d6' + ) { + this.workplace = a.value; + } else if ( + a.attributeType.uuid === '38f592c5-9e44-4629-8561-c2429bc6062d' + ) { + this.nearestNeighbour = a.value; + } else if ( + a.attributeType.uuid === '20360c21-2241-47b6-8442-04aa3594544b' + ) { + this.treatmentSupporter = a.value; + } else if ( + a.attributeType.uuid === 'fb74a24a-13a9-11df-a1f1-0026b9348838' + ) { + this.tribe = a.value; + } + }); + }); + } + public fillLocatorDetails() { + const patientUuid = this.patient.uuid; + + if (patientUuid === undefined || patientUuid === null) { + return; + } + + if (this.patientEncounters.length > 0) { + const url = `/patient-dashboard/patient/${patientUuid}/general/general/formentry/${this.locatorMapFormUuid}`; + this.router.navigate([url], { + queryParams: { + encounter: this.patientLocatorEncounterUuid, + visitTypeUuid: '' + } + }); + } else { + this.router.navigate([ + '/patient-dashboard/patient/' + + patientUuid + + '/general/general/formentry/' + + this.locatorMapFormUuid + ]); + } + } + + public getPatientEncounters() { + this.encounterResourceService + .getEncountersByPatientUuid(this.patient.uuid, false, null) + .pipe(take(1)) + .subscribe((resp) => { + this.patientEncounters = resp.reverse().filter((encounter) => { + if (encounter.form) { + return encounter.form.uuid === this.locatorMapFormUuid; + } + }); + if (this.patientEncounters.length > 0) { + this.editDetails = true; + this.patientLocatorEncounter = _.first(this.patientEncounters); + this.patientLocatorEncounterUuid = _.first( + this.patientEncounters + ).uuid; + } + }); + } + + // tslint:disable-next-line: use-life-cycle-interface + public ngOnDestroy(): void { + if (this.subscription) { + this.subscription.unsubscribe(); + } + } +} diff --git a/src/app/patient-dashboard/common/locator-map/locator-map.component.html b/src/app/patient-dashboard/common/locator-map/locator-map.component.html index 1ac00ef6b..1eb3af07c 100644 --- a/src/app/patient-dashboard/common/locator-map/locator-map.component.html +++ b/src/app/patient-dashboard/common/locator-map/locator-map.component.html @@ -1,4 +1,13 @@ -
+ +
+
+ + +
--> + diff --git a/src/app/patient-dashboard/common/locator-map/locator-map.component.ts b/src/app/patient-dashboard/common/locator-map/locator-map.component.ts index 46b9f26b4..541bd2ab4 100644 --- a/src/app/patient-dashboard/common/locator-map/locator-map.component.ts +++ b/src/app/patient-dashboard/common/locator-map/locator-map.component.ts @@ -16,6 +16,10 @@ import { PatientService } from '../../services/patient.service'; styleUrls: ['./locator-map.css'] }) export class LocatorMapComponent implements OnInit, OnDestroy { + public display = false; + public addDialog = false; + public showSuccessAlert = false; + public showErrorAlert = false; public dataModel: string; public mapInfo: any; public lastUpdatedDate: string; @@ -39,7 +43,15 @@ export class LocatorMapComponent implements OnInit, OnDestroy { private personResourceService: PersonResourceService ) {} - public ngOnInit() { + public ngOnInit(): void {} + + public ngOnDestroy(): void {} + + public showDialog() { + this.display = true; + } + + /*public ngOnInit() { this.subscriptions.push( this.patientService.currentlyLoadedPatient.subscribe((patient) => { if (patient) { @@ -185,5 +197,5 @@ export class LocatorMapComponent implements OnInit, OnDestroy { public resetValues(): void { this.dataModel = null; this.pdfAvailable = false; - } + } */ } diff --git a/src/app/patient-dashboard/common/locator-map/locator-map.css b/src/app/patient-dashboard/common/locator-map/locator-map.css index 7e3aef70e..8de4801e2 100644 --- a/src/app/patient-dashboard/common/locator-map/locator-map.css +++ b/src/app/patient-dashboard/common/locator-map/locator-map.css @@ -4,3 +4,6 @@ img { a img { width: 200px; } +.edit-locator-dialog { + top: 170px !important; +} diff --git a/src/app/patient-dashboard/common/ovc-snapshot/ovc-snapshot.component.ts b/src/app/patient-dashboard/common/ovc-snapshot/ovc-snapshot.component.ts index 851330d81..8b52703ce 100644 --- a/src/app/patient-dashboard/common/ovc-snapshot/ovc-snapshot.component.ts +++ b/src/app/patient-dashboard/common/ovc-snapshot/ovc-snapshot.component.ts @@ -38,6 +38,7 @@ export class OvcSnapshotComponent implements OnInit { public exitReason: any; nonEnrollmentFormFilled = false; nonEnrollmentReason: string; + isHEIActive: boolean; constructor( private patientService: PatientService, private hivSummaryResourceService: HivSummaryResourceService, @@ -49,6 +50,12 @@ export class OvcSnapshotComponent implements OnInit { (patient) => { this.patient = new Patient({}); if (patient) { + this.isHEIActive = patient.enrolledPrograms.some((program) => { + return ( + program.programUuid === 'a8e7c30d-6d2f-401c-bb52-d4433689a36b' && + program.isEnrolled === true + ); + }); this.programManagerUrl = '/patient-dashboard/patient/' + patient.uuid + @@ -90,7 +97,7 @@ export class OvcSnapshotComponent implements OnInit { public getHivSummary(patient) { this.loadingData = true; this.hivSummaryResourceService - .getHivSummary(patient.uuid, 0, 10) + .getHivSummary(patient.uuid, 0, 10, false, this.isHEIActive) .pipe(take(1)) .subscribe((results) => { let latestVlResult: any; diff --git a/src/app/patient-dashboard/common/patient-banner/patient-banner.component.html b/src/app/patient-dashboard/common/patient-banner/patient-banner.component.html index 48b5f9829..eb55436c8 100644 --- a/src/app/patient-dashboard/common/patient-banner/patient-banner.component.html +++ b/src/app/patient-dashboard/common/patient-banner/patient-banner.component.html @@ -531,6 +531,7 @@

diff --git a/src/app/patient-dashboard/common/patient-banner/patient-banner.component.ts b/src/app/patient-dashboard/common/patient-banner/patient-banner.component.ts index 3ba192380..7fe36d0a1 100644 --- a/src/app/patient-dashboard/common/patient-banner/patient-banner.component.ts +++ b/src/app/patient-dashboard/common/patient-banner/patient-banner.component.ts @@ -10,7 +10,7 @@ import { } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; -import { take } from 'rxjs/operators'; +import { filter, map, take } from 'rxjs/operators'; import * as Moment from 'moment'; import * as _ from 'lodash'; import { BsModalRef, BsModalService } from 'ngx-bootstrap'; @@ -25,6 +25,7 @@ import { FamilyTestingService } from 'src/app/etl-api/family-testing-resource.se import { EncounterResourceService } from 'src/app/openmrs-api/encounter-resource.service'; import { PersonAttributeResourceService } from './../../../openmrs-api/person-attribute-resource.service'; import { environment } from 'src/environments/environment'; +import { PatientProgramService } from '../../programs/patient-programs.service'; @Component({ selector: 'patient-banner', templateUrl: './patient-banner.component.html', @@ -62,6 +63,8 @@ export class PatientBannerComponent implements OnInit, OnDestroy, OnChanges { public displayContacts = false; public contactsExist = false; public patientEncounters: Array = []; + public isSelectedRelationProgramHEI = false; + public isHEIActive = false; constructor( private patientService: PatientService, @@ -72,7 +75,8 @@ export class PatientBannerComponent implements OnInit, OnDestroy, OnChanges { private propertyLocationService: UserDefaultPropertiesService, private familyTestingService: FamilyTestingService, private encounterResourceService: EncounterResourceService, - private personAttributeResourceService: PersonAttributeResourceService + private personAttributeResourceService: PersonAttributeResourceService, + private patientProgramService: PatientProgramService ) {} public ngOnInit() { @@ -191,6 +195,7 @@ export class PatientBannerComponent implements OnInit, OnDestroy, OnChanges { public openRelationshipModal(template: TemplateRef, relationship) { this.relationship = relationship; + this.isHEIActive = relationship.programs[26].isEnrolled; this.modalRef = this.modalService.show(template, this.modalConfig); } @@ -243,7 +248,17 @@ export class PatientBannerComponent implements OnInit, OnDestroy, OnChanges { .pipe(take(1)) .subscribe( (results) => { - this.relationships = results; + // this.relationships = results; + for (let i = 0; i < results.length; i++) { + this.patientProgramService + .getCurrentlyEnrolledPatientPrograms(results[i].relatedPersonUuid) + .pipe(take(1)) + .subscribe((programs) => { + const rel = results[i]; + rel['programs'] = programs; // attach relationship to programs + this.relationships[i] = rel; + }); + } }, (err) => { console.error(err); diff --git a/src/app/patient-dashboard/common/patient-dashboard.common.module.ts b/src/app/patient-dashboard/common/patient-dashboard.common.module.ts index a0a05e65d..4c8ee52de 100644 --- a/src/app/patient-dashboard/common/patient-dashboard.common.module.ts +++ b/src/app/patient-dashboard/common/patient-dashboard.common.module.ts @@ -93,6 +93,7 @@ import { EditDemographicsComponent } from './patient-info/edit-demographics.comp import { VisitPeriodComponent } from './visit/visit-period/visit-period.component'; import { LocatorMapComponent } from './locator-map/locator-map.component'; import { SecurePipe } from './locator-map/secure.pipe'; +import { LocatorMapDetailsComponent } from './locator-map/locator-map-details.component'; import { CohortMemberModule } from '../../patient-list-cohort/cohort-member/cohort-member.module'; import { EditHealtCenterComponent } from './patient-info/edit-healthcenter.component'; import { VisitEncountersListComponent } from './visit-encounters/visit-encounters-list.component'; @@ -213,6 +214,7 @@ import { UserDefaultPropertiesService } from 'src/app/user-default-properties/us VisitSummaryComponent, LocatorMapComponent, SecurePipe, + LocatorMapDetailsComponent, VisitEncountersListComponent, VisitEncountersComponent, VisitDetailsComponent, @@ -270,6 +272,7 @@ import { UserDefaultPropertiesService } from 'src/app/user-default-properties/us TodayVisitsComponent, LocatorMapComponent, SecurePipe, + LocatorMapDetailsComponent, AgePipe, VisitEncountersListComponent, VisitEncountersComponent, diff --git a/src/app/patient-dashboard/common/patient-encounters/patient-encounter-observations.component.html b/src/app/patient-dashboard/common/patient-encounters/patient-encounter-observations.component.html index 6f1dc7513..263f178b2 100644 --- a/src/app/patient-dashboard/common/patient-encounters/patient-encounter-observations.component.html +++ b/src/app/patient-dashboard/common/patient-encounters/patient-encounter-observations.component.html @@ -64,9 +64,8 @@

- + +
diff --git a/src/app/patient-dashboard/common/patient-identifier/edit-patient-identifier.component.ts b/src/app/patient-dashboard/common/patient-identifier/edit-patient-identifier.component.ts index dd1c6f7f9..1202659d7 100644 --- a/src/app/patient-dashboard/common/patient-identifier/edit-patient-identifier.component.ts +++ b/src/app/patient-dashboard/common/patient-identifier/edit-patient-identifier.component.ts @@ -433,6 +433,7 @@ export class EditPatientIdentifierComponent implements OnInit, OnDestroy { const idType = this.identifierType.val ? this.identifierType.val : this.identifierType.value; + this.patientResourceService .searchPatient(this.patientIdentifier) .pipe(take(1)) @@ -440,6 +441,7 @@ export class EditPatientIdentifierComponent implements OnInit, OnDestroy { if (result.length > 0 && this.identifierHasChanged()) { _.each(result, (ids) => { _.each(ids.identifiers, (id) => { + console.log('This is ID', idType, id); if ( id.identifier === this.patientIdentifier && id.identifierType.uuid === idType @@ -451,8 +453,6 @@ export class EditPatientIdentifierComponent implements OnInit, OnDestroy { parentIdTypes.includes(idType) ) { return (hasSameIdTypeAndValue = false); - } else { - hasSameIdTypeAndValue = true; } }); }); diff --git a/src/app/patient-dashboard/common/patient-info/patient-info.component.css b/src/app/patient-dashboard/common/patient-info/patient-info.component.css index 8ae442d25..289922b12 100644 --- a/src/app/patient-dashboard/common/patient-info/patient-info.component.css +++ b/src/app/patient-dashboard/common/patient-info/patient-info.component.css @@ -19,3 +19,9 @@ .edit_link:hover { cursor: pointer; } +.spacing { + margin-right: 10px; +} +.smaller-icon { + font-size: 12px; +} diff --git a/src/app/patient-dashboard/common/patient-info/patient-info.component.html b/src/app/patient-dashboard/common/patient-info/patient-info.component.html index 82fb0026f..642d890a3 100644 --- a/src/app/patient-dashboard/common/patient-info/patient-info.component.html +++ b/src/app/patient-dashboard/common/patient-info/patient-info.component.html @@ -69,7 +69,9 @@
Identifiers
+
+
Relationships
@@ -78,9 +80,13 @@
Relationships

+
-
Outreach Locator Map
+
Patient Location Details
+
+ +
diff --git a/src/app/patient-dashboard/common/patient-info/patient-info.component.ts b/src/app/patient-dashboard/common/patient-info/patient-info.component.ts index 337d51def..7f08ad0a0 100644 --- a/src/app/patient-dashboard/common/patient-info/patient-info.component.ts +++ b/src/app/patient-dashboard/common/patient-info/patient-info.component.ts @@ -13,6 +13,7 @@ import { Subscription } from 'rxjs'; export class PatientInfoComponent implements OnInit, OnDestroy { public patient: Patient; public subs: Subscription[] = []; + public display = false; constructor( private appFeatureAnalytics: AppFeatureAnalytics, diff --git a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-historical.component.ts b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-historical.component.ts index a62c232fc..962a0141b 100644 --- a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-historical.component.ts +++ b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-historical.component.ts @@ -25,6 +25,7 @@ export class HivSummaryHistoricalComponent implements OnInit, OnDestroy { public nextStartIndex: number = 0; public hasMedicationRtc = false; public hasMdtSessionNo = false; + isHEIActive: boolean; constructor( private hivSummaryService: HivSummaryService, @@ -46,6 +47,12 @@ export class HivSummaryHistoricalComponent implements OnInit, OnDestroy { const patientSub = this.patientService.currentlyLoadedPatient.subscribe( (patient) => { if (patient) { + this.isHEIActive = patient.enrolledPrograms.some((program) => { + return ( + program.programUuid === 'a8e7c30d-6d2f-401c-bb52-d4433689a36b' && + program.isEnrolled === true + ); + }); this.patient = patient; this.patientUuid = this.patient.person.uuid; this.loadHivSummary(this.patientUuid, this.nextStartIndex); @@ -77,7 +84,7 @@ export class HivSummaryHistoricalComponent implements OnInit, OnDestroy { public loadHivSummary(patientUuid, nextStartIndex) { const summarySub = this.hivSummaryService - .getHivSummary(patientUuid, nextStartIndex, 20, false) + .getHivSummary(patientUuid, nextStartIndex, 20, false, this.isHEIActive) .subscribe( (data) => { if (data) { diff --git a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-latest.component.html b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-latest.component.html index 4419d5242..213903d83 100644 --- a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-latest.component.html +++ b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-latest.component.html @@ -7,7 +7,7 @@ {{ error.message }}
-
+
+
+
    +
  • + Last Appt Date: + {{ + (hivSummary?.prev_rtc_date < 0 + ? hivSummary?.date_enrolled + : hivSummary?.encounter_datetime + ) | date: 'dd-MM-yyyy' + }} + ({{ hivSummary?.encounter_type_name }}) +
  • +
  • + RTC Date: {{ hivSummary?.rtc_date | date: 'dd-MM-yyyy' }} +
  • +
  • + Date of enrollment: {{ hivSummary?.date_enrolled | date: 'dd-MM-yyyy' }} +
  • +
  • + Current weight (kg): + {{ hivSummary?.weight !== null ? hivSummary?.weight : 'NONE' }} +
  • +
  • + Last PCR status: {{ lastPCRStatus }} +
  • +
  • + Last PCR Date: {{ lastPCRDate | date: 'dd-MM-yyyy' }} +
  • +
  • + Current ART Prophylaxis: {{ hivSummary?.cur_arv_meds }} +
  • +
  • + Current PCP Prophylaxis: {{ pcpProphylaxis }} +
  • +
  • + Infant Feeding Method: {{ infantFeedingMethod }} +
  • +
  • + HEI outcome at 18 months: {{ heiOutCome }} +
  • +
+
diff --git a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-latest.component.ts b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-latest.component.ts index cbf75a62f..0c1b3edbf 100644 --- a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-latest.component.ts +++ b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary-latest.component.ts @@ -30,6 +30,7 @@ interface Covid19StatusSummary { }) export class HivSummaryLatestComponent implements OnInit, OnDestroy { @Input() patientUuid: string; + @Input() isHEIActive: boolean = false; public loadingHivSummary: boolean = false; public hivSummary: any; public subscription: Subscription[] = []; @@ -52,6 +53,11 @@ export class HivSummaryLatestComponent implements OnInit, OnDestroy { second_dose_vaccine_administered: '', covid_screening_outcome_this_visit: '' }; + public lastPCRDate: string; + public lastPCRStatus: string; + public infantFeedingMethod: string; + public heiOutCome: string; + public pcpProphylaxis: string; constructor( private hivSummaryService: HivSummaryService, @@ -159,7 +165,7 @@ export class HivSummaryLatestComponent implements OnInit, OnDestroy { public loadHivSummary(patientUuid) { const summarySub = this.hivSummaryService - .getHivSummary(patientUuid, 0, 1, false) + .getHivSummary(patientUuid, 0, 1, false, this.isHEIActive) .subscribe( (data) => { if (data) { @@ -231,6 +237,13 @@ export class HivSummaryLatestComponent implements OnInit, OnDestroy { this.hivSummary.vl_1_date = filtered.vl_1_date; this.hivSummary.vl_1 = filtered.vl_1; } + if (this.isHEIActive) { + this.lastPCRDate = this.getLastPCRDate(); + this.lastPCRStatus = this.getLastPCRStatus(); + this.infantFeedingMethod = this.getInfantFeedingMethod(); + this.heiOutCome = this.getHEIOutcome(); + this.pcpProphylaxis = this.getPCPprophylaxis(); + } } this.getPatientEligibility(this.hivSummary); this.loadingHivSummary = false; @@ -280,7 +293,10 @@ export class HivSummaryLatestComponent implements OnInit, OnDestroy { private getPatientEligibility(summary) { if (summary) { - if (this.patient.person.gender === 'M') { + if (this.isHEIActive) { + this.ineligibiltyReason = 'An Infant'; + this.eligiblePatient = false; + } else if (this.patient.person.gender === 'M') { this.ineligibiltyReason = 'Male Patient'; this.eligiblePatient = false; } else if ( @@ -351,4 +367,106 @@ export class HivSummaryLatestComponent implements OnInit, OnDestroy { } }); } + + public getLastPCRDate(): string { + let last_pcr_date: string = ''; + + if (this.hivSummary.hiv_dna_pcr_4_date !== null) { + last_pcr_date = this.hivSummary.hiv_dna_pcr_4_date; + } else if (this.hivSummary.hiv_dna_pcr_3_date !== null) { + last_pcr_date = this.hivSummary.hiv_dna_pcr_3_date; + } else if (this.hivSummary.hiv_dna_pcr_2_date !== null) { + last_pcr_date = this.hivSummary.hiv_dna_pcr_2_date; + } else if (this.hivSummary.hiv_dna_pcr_1_date !== null) { + last_pcr_date = this.hivSummary.hiv_dna_pcr_1_date; + } else { + return ''; + } + + return last_pcr_date; + } + + public getLastPCRStatus(): string { + let last_pcr_status: number; + + if (this.hivSummary.hiv_dna_pcr_resulted !== null) { + last_pcr_status = this.hivSummary.hiv_dna_pcr_resulted; + } else if (this.hivSummary.hiv_dna_pcr_4 !== null) { + last_pcr_status = this.hivSummary.hiv_dna_pcr_4; + } else if (this.hivSummary.hiv_dna_pcr_3 !== null) { + last_pcr_status = this.hivSummary.hiv_dna_pcr_3; + } else if (this.hivSummary.hiv_dna_pcr_2 !== null) { + last_pcr_status = this.hivSummary.hiv_dna_pcr_2; + } else if (this.hivSummary.hiv_dna_pcr_1 !== null) { + last_pcr_status = this.hivSummary.hiv_dna_pcr_1; + } else { + last_pcr_status = null; + } + if (last_pcr_status === 664) { + return 'NEGATIVE'; + } else if (last_pcr_status === 703) { + return 'POSITIVE'; + } else if (last_pcr_status === 1118) { + return 'NOT DONE'; + } else if (last_pcr_status === 1138) { + return 'INDETERMINATE'; + } else if (last_pcr_status === 1304) { + return 'POOR SAMPLE QUALITY'; + } else { + return 'NONE'; + } + } + + public getInfantFeedingMethod(): string { + const INFANT_FEEDING_METHODS = [ + 'NONE', + 'EXPRESSED BREASTMILK', + 'WEANED', + 'INFANT FORMULA', + 'BREASTFEEDING PREDOMINATELY', + 'MIXED FEEDING', + 'BREASTFEEDING EXCLUSIVELY', + 'COW MILK', + 'REGULAR FOOD', + 'BREASTFEEDING', + 'LIQUID FOODS OTHER THAN BREAST MILK', + 'WATER', + 'SOLID FOOD', + 'UJI', + 'OTHER NON-CODED', + 'COMPLEMENTARY FEEDING', + 'PLUMPY NUT', + 'NEVER BREASTFED', + 'CHILD ON REPLACEMENT FEEDING' + ]; + + return INFANT_FEEDING_METHODS[this.hivSummary.infant_feeding_method]; + } + + public getHEIOutcome(): string { + const HEI_OUT_COME = [ + '', + 'PATIENT TRANSFERRED OUT', + 'LOST TO FOLLOWUP', + 'PATIENT DIED', + 'OTHER NON-CODED', + 'DISCHARGED AT 18 MONTHS', + 'HIV COMPREHENSIVE CARE UNIT' + ]; + + const index = + this.hivSummary.hei_outcome !== null ? this.hivSummary.hei_outcome : 0; + + return HEI_OUT_COME[index]; + } + public getPCPprophylaxis(): string { + const pcp = this.hivSummary.pcp_prophylaxis; + if (pcp === 92) { + return 'ACZONE'; + } + if (pcp === 916) { + return 'SEPTRIN'; + } + return 'NONE'; + } } diff --git a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.component.html b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.component.html index 6ccbdbaff..bb5809209 100644 --- a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.component.html +++ b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.component.html @@ -7,10 +7,18 @@

- + + + + diff --git a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.component.ts b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.component.ts index c28b14b8c..b746c91f4 100644 --- a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.component.ts +++ b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.component.ts @@ -4,6 +4,7 @@ import { HivSummaryService } from './hiv-summary.service'; import { PatientService } from '../../services/patient.service'; import { Router, ActivatedRoute } from '@angular/router'; import { Subscription } from 'rxjs'; +import * as Moment from 'moment'; const mdtProgramUuid = 'c4246ff0-b081-460c-bcc5-b0678012659e'; @Component({ selector: 'app-hiv-summary', @@ -16,8 +17,12 @@ export class HivSummaryComponent implements OnInit, OnDestroy { patientUuid: string; gbvScreeningLabel: String; gbvScreeningResult: any; + age: any; + patient: any; public subscription = new Subscription(); + isHEIActive = false; + constructor( private appFeatureAnalytics: AppFeatureAnalytics, private hivSummaryService: HivSummaryService, @@ -26,15 +31,23 @@ export class HivSummaryComponent implements OnInit, OnDestroy { ) {} public ngOnInit() { - this.loadHivSummary(); this.getPatient(); + this.loadHivSummary(); } public getPatient() { const patientSub = this.patientService.currentlyLoadedPatient.subscribe( (patient) => { if (patient) { + this.isHEIActive = patient.enrolledPrograms.some((program) => { + return ( + program.programUuid === 'a8e7c30d-6d2f-401c-bb52-d4433689a36b' && + program.isEnrolled === true + ); + }); this.patientUuid = patient.person.uuid; + this.patient = patient; + this.age = Moment().diff(Moment(patient.person.birthdate), 'months'); patient.person.age > 19 ? (this.gbvScreeningLabel = 'GBV Screening') : (this.gbvScreeningLabel = 'VAC Screening'); @@ -50,7 +63,13 @@ export class HivSummaryComponent implements OnInit, OnDestroy { public loadHivSummary() { this.patientService.currentlyLoadedPatientUuid .flatMap((patientUuid) => - this.hivSummaryService.getHivSummary(patientUuid, 0, 1, false) + this.hivSummaryService.getHivSummary( + patientUuid, + 0, + 1, + false, + this.isHEIActive + ) ) .subscribe((data: any) => { if (data) { diff --git a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.service.ts b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.service.ts index 7efef9adb..2f5f607fa 100644 --- a/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.service.ts +++ b/src/app/patient-dashboard/hiv/hiv-summary/hiv-summary.service.ts @@ -16,16 +16,17 @@ export class HivSummaryService { patientUuid: string, startIndex: number, limit: number, - includeNonClinicalEncounter?: boolean + includeNonClinicalEncounter?: boolean, + isHEIActive?: any ): Observable { const hivSummary: BehaviorSubject = new BehaviorSubject(null); - this.hivSummaryResourceService .getHivSummary( patientUuid, startIndex, this.limit, - includeNonClinicalEncounter + includeNonClinicalEncounter, + isHEIActive ) .pipe(take(1)) .subscribe( diff --git a/src/app/patient-dashboard/hiv/patient-clinical-summaries/hiv-patient-clinical-summary.component.ts b/src/app/patient-dashboard/hiv/patient-clinical-summaries/hiv-patient-clinical-summary.component.ts index 8ac726f69..9c8e8a01c 100644 --- a/src/app/patient-dashboard/hiv/patient-clinical-summaries/hiv-patient-clinical-summary.component.ts +++ b/src/app/patient-dashboard/hiv/patient-clinical-summaries/hiv-patient-clinical-summary.component.ts @@ -26,6 +26,7 @@ export class HivPatientClinicalSummaryComponent implements OnInit, OnDestroy { public summaryEndDate: any = null; public errorFlag = false; private subscription: Subscription; + isHEIActive: boolean; constructor( private patientClinicalSummary: HivPatientClinicalSummaryService, @@ -53,13 +54,19 @@ export class HivPatientClinicalSummaryComponent implements OnInit, OnDestroy { this.patient = new Patient({}); if (patient) { this.patient = patient; + this.isHEIActive = patient.enrolledPrograms.some((program) => { + return ( + program.programUuid === 'a8e7c30d-6d2f-401c-bb52-d4433689a36b' && + program.isEnrolled === true + ); + }); this.hivSummaryService - .getHivSummary(patient.uuid, 0, 1, false) + .getHivSummary(patient.uuid, 0, 1, false, this.isHEIActive) .subscribe((data) => { if (data) { for (const summary of data) { this.patientClinicalSummaryResource - .fetchPatientSummary(patient.uuid) + .fetchPatientSummary(patient.uuid, this.isHEIActive) .pipe(take(1)) .subscribe( (pdfDependencies) => { diff --git a/src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.html b/src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.html index 38ca60d78..7cbc151b5 100644 --- a/src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.html +++ b/src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.html @@ -69,7 +69,7 @@ >

-
+

VL Category: {{ this.viralLoadCategory }}Last Encounter

-

Location: {{ latestEncounterLocation?.name }}

+

+ Location: + {{ + latestEncounterLocation?.name + ? latestEncounterLocation?.name + : patientData.clinic + }} +

-
+

Date: {{ patientData?.encounter_datetime | date: 'dd-MM-yyyy' }}

-
+

Type: {{ @@ -106,7 +125,7 @@

Last Encounter

ARV Regimen: {{ patientData?.cur_arv_meds }}

-
+

Last Viral Load: {{ patientData?.latest_vl | zeroVl }} @@ -141,7 +160,7 @@

Last Encounter

RTC Date: {{ patientData?.rtc_date | date: 'dd-MM-yyyy' }}

-

+

Disclosure Status: {{ hivDisclosureStatus }} @@ -192,7 +211,10 @@

Last Encounter

-
+

Care Status: diff --git a/src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.ts b/src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.ts index 46e9c19cb..9a2d15ad2 100644 --- a/src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.ts +++ b/src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.ts @@ -123,6 +123,8 @@ export class HivProgramSnapshotComponent implements OnInit { public hasPredictedScore = false; public prediction: any; + public isHEIActive = false; + constructor( private hivSummaryResourceService: HivSummaryResourceService, private encounterResourceService: EncounterResourceService, @@ -140,6 +142,12 @@ export class HivProgramSnapshotComponent implements OnInit { if (_.isNil(this.patient)) { this.hasError = true; } else { + this.isHEIActive = this.patient.enrolledPrograms.some((program) => { + return ( + program.programUuid === 'a8e7c30d-6d2f-401c-bb52-d4433689a36b' && + program.isEnrolled === true + ); + }); this.hasData = false; this.getHivSummary(patientUuid); this.getPredictedScore(patientUuid); @@ -160,7 +168,7 @@ export class HivProgramSnapshotComponent implements OnInit { public getHivSummary(patientUuid: string) { this.loadingData = true; this.hivSummaryResourceService - .getHivSummary(patientUuid, 0, 10) + .getHivSummary(patientUuid, 0, 10, false, this.isHEIActive) .pipe(take(1)) .subscribe((results) => { let latestVlResult: any; diff --git a/src/app/patient-dashboard/patient-dashboard.routes.ts b/src/app/patient-dashboard/patient-dashboard.routes.ts index 59d9d52fb..fddbe47ca 100644 --- a/src/app/patient-dashboard/patient-dashboard.routes.ts +++ b/src/app/patient-dashboard/patient-dashboard.routes.ts @@ -13,6 +13,7 @@ import { PatientMonthlyStatusComponent } from './hiv/patient-status-change/patie import { FromentryGuard } from './common/formentry/formentry.guard'; import { FormCreationDataResolverService } from './common/formentry/form-creation-data-resolver.service'; import { LocatorMapComponent } from './common/locator-map/locator-map.component'; +import { LocatorMapDetailsComponent } from './common/locator-map/locator-map-details.component'; import { VisitEncountersComponent } from './common/visit-encounters/visit-encounters.component'; import { GeneralLandingPageComponent } from './general-landing-page/landing-page.component'; import { PatientSearchContainerComponent } from '../patient-search/patient-search-container.component'; @@ -146,6 +147,10 @@ export const routes = [ path: ':programClass/:program/locator-map', component: LocatorMapComponent }, + { + path: ':programClass/:program/locator-map-details', + component: LocatorMapDetailsComponent + }, { path: ':programClass/:program/program-manager', component: ProgramManagerContainerComponent, diff --git a/src/app/shared/ngamrs-shared.module.ts b/src/app/shared/ngamrs-shared.module.ts index c98696108..6241b3075 100644 --- a/src/app/shared/ngamrs-shared.module.ts +++ b/src/app/shared/ngamrs-shared.module.ts @@ -76,6 +76,7 @@ import { KibanaVizComponent } from './kibana-viz/kibana-viz.component'; import { SnakeCaseToTitlePipe } from './pipes/snake-case-to-title.pipe'; import { ProgramSnapshotNegativesComponent } from '../patient-dashboard/hiv/program-snapshot-negatives/program-snapshot-negatives.component'; import { AngularMultiSelectModule } from 'angular2-multiselect-dropdown/angular2-multiselect-dropdown'; +import { LocatorPrettyViewerComponent } from '../patient-dashboard/common/formentry/locator-pretty-viewer/locator-pretty-viewer.component'; @NgModule({ imports: [ @@ -177,7 +178,8 @@ import { AngularMultiSelectModule } from 'angular2-multiselect-dropdown/angular2 MatIconModule, MatExpansionModule, MatTooltipModule, - SnakeCaseToTitlePipe + SnakeCaseToTitlePipe, + LocatorPrettyViewerComponent ], declarations: [ DisplayErrorComponent, @@ -197,7 +199,7 @@ import { AngularMultiSelectModule } from 'angular2-multiselect-dropdown/angular2 PatientEncounterObservationsComponent, PrettyEncounterViewerComponent, CdmProgramSnapshotComponent, - + LocatorPrettyViewerComponent, SnakeCaseToTitlePipe ], providers: [