From a66c2ef7586e7837b02956d9639b2fff53b6d8d5 Mon Sep 17 00:00:00 2001 From: kantush Date: Thu, 26 Oct 2023 13:25:42 +0300 Subject: [PATCH 01/19] Fix type annotation --- .../patient-side-nav.component.html | 14 + .../otz-snapshot/otz-snapshot.component.css | 260 ++++++++++++++++++ .../otz-snapshot/otz-snapshot.component.html | 163 +++++++++++ .../otz-snapshot.component.spec.ts | 24 ++ .../otz-snapshot/otz-snapshot.component.ts | 127 +++++++++ .../patient-banner.component.html | 12 + .../patient-banner.component.ts | 23 +- .../common/patient-dashboard.common.module.ts | 4 +- .../patient-dashboard.routes.ts | 5 + .../new-program/new-program.component.html | 2 +- .../new-program/new-program.component.ts | 33 ++- 11 files changed, 656 insertions(+), 11 deletions(-) create mode 100644 src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.css create mode 100644 src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html create mode 100644 src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.spec.ts create mode 100644 src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts diff --git a/src/app/navigation/side-navigation/patient-side-nav/patient-side-nav.component.html b/src/app/navigation/side-navigation/patient-side-nav/patient-side-nav.component.html index f7c227afb..1fd2284a7 100644 --- a/src/app/navigation/side-navigation/patient-side-nav/patient-side-nav.component.html +++ b/src/app/navigation/side-navigation/patient-side-nav/patient-side-nav.component.html @@ -61,5 +61,19 @@ {{ route.label }} +
  • + + + Z + + + OTZ + +
  • diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.css b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.css new file mode 100644 index 000000000..4afd9ba5d --- /dev/null +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.css @@ -0,0 +1,260 @@ +.btn-success.text-white { + color: white !important; +} + +@media screen and (min-width: 600px) { + .program-header { + width: 70%; + } +} + +.program-header-wrapper { + /* background-color: #203864; */ + color: #ccc; +} + +.program .program-header, +.program .program-footer { + margin: 0 20px 0 20px; + font-size: 1.72rem; + border: none; + padding: 0 0; + font-family: Lato, 'Helvetica Neue', Arial, Helvetica, sans-serif; + font-weight: 700; + line-height: 36px; + text-transform: none; + color: #fff; + opacity: 0.9; +} + +.program.non-enrolled .program-body { + padding: 12px; +} + +.program.non-enrolled .program-header-wrapper { + color: inherit; +} + +.program-container-fluid { + padding-right: 15px; + padding-left: 15px; +} + +.program .program-body { + padding-top: 12px; + padding-bottom: 12px; +} + +.program.non-enrolled .program-body { + border-top: 1px solid rgba(34, 36, 38, 0.15); +} + +.program .program-footer { + /* background-color: whitesmoke; */ + color: #fff; + margin: 0; + padding: 5px 12px; + /* border: 1px solid rgba(34, 36, 38, 0.15); */ + border-top: 0; +} + +.program-footer a.btn { + color: #fff !important; + display: inline-block; + margin-right: 10px; + padding: 6px 9px; +} + +.program-footer a.btn:last-child { + margin-right: 0; +} + +a.btn.btn-info { + margin-bottom: 0; + margin-left: 0; +} + +.component-title { + font-size: 22px; + text-transform: capitalize; + padding-bottom: 8px; + border-bottom: 1px solid rgba(34, 36, 38, 0.15); + margin-bottom: 20px; + padding-left: 2.5rem; +} + +.program hr { + margin: 1rem 0; + line-height: 1; + height: 0; + font-weight: 700; + font-size: 1rem; + clear: both; + text-transform: uppercase; + letter-spacing: 0.05em; + color: rgba(0, 0, 0, 0.85); + user-select: none; + border-top: 1px solid rgba(34, 36, 38, 0.15); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.program .enrolled { + margin-bottom: 20px; +} + +.clear { + clear: both; +} + +h3 { + padding-top: 0; +} + +.program-header-wrapper { + background-color: #203864; + color: #ccc; + border: 2px solid rgba(34, 36, 38, 0.15); + border-radius: 4px; + margin-bottom: 8px; +} + +.program.non-enrolled .program-body { + padding: 12px; +} + +.program.non-enrolled .program-header-wrapper { + background-color: darkred; + color: #ccc; +} + +.program .program-body { + padding-top: 12px; + padding-bottom: 12px; + border-left: 1px solid rgba(34, 36, 38, 0.15); + border-right: 1px solid rgba(34, 36, 38, 0.15); + border-bottom: 1px solid rgba(34, 36, 38, 0.15); +} + +.program .program-footer { + /* background-color: whitesmoke; */ + color: #fff; + margin: 0; + padding: 5px; + /* border: 1px solid rgba(34, 36, 38, 0.15); */ + border-top: 0; +} + +.program-container-fluid { + padding: 0 10px 0 10px; +} + +.program hr { + margin: 1rem 0; + line-height: 1; + height: 0; + font-weight: 700; + font-size: 1rem; + clear: both; + text-transform: uppercase; + letter-spacing: 0.05em; + color: rgba(0, 0, 0, 0.85); + user-select: none; + border-top: 1px solid rgba(34, 36, 38, 0.15); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.program .enrolled { + margin-bottom: 20px; +} + +.clear { + clear: both; +} + +.fa-pencil:before { + margin-right: 5px; +} + +label.buttons { + height: 22px; + display: block; +} + +.enroll-button { + margin-top: -2px; +} + +.buttons button { + float: left; +} + +.otz-header { + display: flex; + justify-content: space-between; +} + +ul li { + list-style: none !important; + padding-top: 24px; + font-weight: 400; + font-size: 18px; + font-style: bold; +} + +.otz-nav-header li { + list-style: none !important; + padding: 6px 22px; + margin: 0 2px; + border: 1px solid #1081c2; + border-radius: 4px; + font-size: 18px; + color: rgb(0, 140, 255); + cursor: pointer; +} + +.otz-nav-header { + display: flex; + justify-content: space-between; + margin-left: -40px; +} + +.otz-content-wrapper { + margin-left: -38px; +} + +.thead-blue { + background-color: #086becee; + color: #fff; +} + +.theader-appoint { + padding: 8px 4px; + font-size: 18px; + margin: 0 2px; +} + +.ldl-col { + color: green; +} + +.low-risk-col { + color: orangered; +} + +.high-risk-col { + color: orange; +} + +.treatment-col { + color: red; +} + +.disc-form { + color: black; + background-color: MediumSeaGreen; + padding: 8px; + border-radius: 4px; + width: 50%; + font-size: 20px; + font-weight: bold; +} diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html new file mode 100644 index 000000000..0d9efb19e --- /dev/null +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html @@ -0,0 +1,163 @@ +
    +
    +
    +

    + OTZ Program (enrolled on {{ dateEnrolled }}) +

    +
    +
    +
      +
    • + Summary +
    • +
    • + Appointments +
    • +
    • + Adherence +
    • +
    • + Viral load +
    • +
    + + +
    +
    + +
    +
      +
    • Last Encounter Date:
    • +
    • ARV Regimen:
    • +
    • RTC Date:
    • +
    • Module:
    • +
    • Last Viral Load:
    • +
    • Last Viral Load Date:
    • +
    • Viral Load Categorization:
    • +
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    Latest appointmentVisit typeLatest RTC + Medication pick-up date +
    2023/11/12initial visit2023/11/1511/14/2023
    +
    +
    + +
    + + + + + + + + + + + + + +
    Encounter DateAdherence type
    2023/11/12adherence type
    +
    +
    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DateViral LoadViral Load Category
    20/02/20230LDL
    20/02/2022150Low Risk Low Level Viremia
    20/02/2021500High Risk Low Level Viremia
    20/02/202010000Suspected Treatment Failure
    +
    +
    +
    + +
    +
    diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.spec.ts b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.spec.ts new file mode 100644 index 000000000..16e1099be --- /dev/null +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.spec.ts @@ -0,0 +1,24 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { OtzSnapshotComponent } from './otz-snapshot.component'; + +describe('OtzSnapshotComponent', () => { + let component: OtzSnapshotComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [OtzSnapshotComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(OtzSnapshotComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts new file mode 100644 index 000000000..895bfee9b --- /dev/null +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts @@ -0,0 +1,127 @@ +import { Component, OnInit } from '@angular/core'; +import { Patient } from 'src/app/models/patient.model'; +import { PatientService } from '../../services/patient.service'; +import { HivSummaryResourceService } from 'src/app/etl-api/hiv-summary-resource.service'; +import { EncounterResourceService } from 'src/app/openmrs-api/encounter-resource.service'; +import { take } from 'rxjs/operators'; +import * as moment from 'moment'; +import * as _ from 'lodash'; + +@Component({ + selector: 'app-otz-snapshot', + templateUrl: './otz-snapshot.component.html', + styleUrls: ['./otz-snapshot.component.css'] +}) +export class OtzSnapshotComponent implements OnInit { + selectedItem = 'summary'; + subscription: any; + patient: Patient; + otzEnrollment = false; + programManagerUrl: any; + dateEnrolled: any; + dateCompleted: any; + loadingData: boolean; + hasLoadedData: boolean; + patientCareStatus: any; + hivDisclosureStatus: string; + clinicalEncounters: any; + patientData: any; + isVirallyUnsuppressed: boolean; + hasData: boolean; + isHEIActive: boolean; + + constructor( + private patientService: PatientService, + private hivSummaryResourceService: HivSummaryResourceService, + private _encounterResource: EncounterResourceService + ) {} + + ngOnInit() { + this.subscription = this.patientService.currentlyLoadedPatient.subscribe( + (patient) => { + this.patient = new Patient({}); + if (patient) { + this.programManagerUrl = + '/patient-dashboard/patient/' + + patient.uuid + + '/general/general/program-manager/new-program'; + this.getOtzEnrollments(patient.enrolledPrograms); + // this.retrieveNonEnrollmentandExitEncounter(patient); + // this.retrieveHivDisclosureStatus(patient); + // this.getHivSummary(patient); + } + } + ); + } + + selectItem(item: string) { + this.selectedItem = item; + } + + private getOtzEnrollments(enrolledPrograms) { + const otz = enrolledPrograms.filter( + (program) => + program.concept.uuid === 'fd90d6b2-7302-4a9c-ad1b-1f93eff77afb' + ); + if (otz.length > 0 && otz[0].isEnrolled) { + this.dateEnrolled = otz[0].dateEnrolled; + this.otzEnrollment = true; + } else { + this.dateCompleted = otz[0].dateCompleted; + } + } + + public getHivSummary(patient) { + this.loadingData = true; + this.hivSummaryResourceService + .getHivSummary(patient.uuid, 0, 10, false, this.isHEIActive) + .pipe(take(1)) + .subscribe((results) => { + let latestVlResult: any; + let latestVlDate = ''; + let latestVl = null; + this.loadingData = false; + this.hasLoadedData = true; + if (results[0]) { + latestVlResult = this.getlatestVlResult(results); + latestVlDate = latestVlResult.vl_1_date; + latestVl = latestVlResult.vl_1; + latestVl = latestVlResult.vl_1; + this.patientCareStatus = results[0].patient_care_status; + this.hivDisclosureStatus = + results[0].hiv_status_disclosed === 1 ? 'Yes' : 'No'; + } + this.clinicalEncounters = this.clinicalEncounters(results); + this.patientData = _.first(this.clinicalEncounters); + const patientDataCopy = this.patientData; + + if (!_.isNil(this.patientData)) { + // assign latest vl and vl_1_date + this.patientData = Object.assign(patientDataCopy, { + vl_1_date: latestVlDate, + vl_1: latestVl + }); + // flag red if VL > 1000 && (vl_1_date > (arv_start_date + 6 months)) + if ( + (this.patientData.vl_1 > 1000 && + moment(this.patientData.vl_1_date) > + moment(this.patientData.arv_start_date).add(6, 'months')) || + this.patientData.prev_arv_line !== this.patientData.cur_arv_line + ) { + this.isVirallyUnsuppressed = true; + } + this.hasData = true; + } + }); + } + private getlatestVlResult(hivSummaryData) { + const orderByVlDate = _.orderBy( + hivSummaryData, + (hivSummary) => { + return moment(hivSummary.vl_1_date); + }, + ['desc'] + ); + return orderByVlDate[0]; + } +} 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 eb55436c8..d1a0dd5c4 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 @@ -403,6 +403,18 @@ OVC ID:Not assigned + + Enroll client to OTZ + +
    @@ -128,8 +133,8 @@

    - 2023/11/12 - adherence type + {{ patientData?.encounter_datetime }} + {{ patientData?.cur_arv_adherence }} diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts index 1611caf58..c9108ea45 100644 --- a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts @@ -20,6 +20,7 @@ export class OtzSnapshotComponent implements OnInit { patient: Patient; otzEnrollment = false; programManagerUrl: any; + groupManagerUrl: any; otzProgramExit: any; dateEnrolled: any; dateCompleted: any; @@ -32,6 +33,7 @@ export class OtzSnapshotComponent implements OnInit { isHEIActive: boolean; viralLoadCategory: string; viralLoadHistory: any[]; + isPatientEligibleForOtz = false; constructor( private patientService: PatientService, @@ -61,7 +63,9 @@ export class OtzSnapshotComponent implements OnInit { '/patient-dashboard/patient/' + patient.uuid + '/general/general/formentry/ab16711d-890d-4128-95ce-0e955babd711'; - this.getOtzEnrollments(patient.enrolledPrograms); + this.groupManagerUrl = + '/clinic-dashboard/18c343eb-b353-462a-9139-b16606e6b6c2/hiv/group-manager'; + this.getOtzEnrollments(patient.person.age, patient.enrolledPrograms); this.getHivSummary(patient); this.getHistoricalPatientLabResults(patient); } @@ -73,7 +77,10 @@ export class OtzSnapshotComponent implements OnInit { this.selectedItem = item; } - private getOtzEnrollments(enrolledPrograms) { + private getOtzEnrollments(age, enrolledPrograms) { + if (age >= 9 && age <= 19) { + this.isPatientEligibleForOtz = true; + } const otz = enrolledPrograms.filter( (program) => program.concept.uuid === 'fd90d6b2-7302-4a9c-ad1b-1f93eff77afb' @@ -106,6 +113,7 @@ export class OtzSnapshotComponent implements OnInit { this.clinicalEncounters = this.getClinicalEncounters(results); this.patientData = _.first(this.clinicalEncounters); const patientDataCopy = this.patientData; + console.log('patientDAta', this.patientData); if (!_.isNil(this.patientData)) { // assign latest vl and vl_1_date 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 4d35e318e..249cabc65 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 @@ -404,7 +404,11 @@ Edit Leadership

    >
    - OTZ Champion + Peer Leadership - Community Staff Leadership diff --git a/src/app/group-manager/group-detail/group-detail.component.html b/src/app/group-manager/group-detail/group-detail.component.html index acdfe3b46..133b77188 100644 --- a/src/app/group-manager/group-detail/group-detail.component.html +++ b/src/app/group-manager/group-detail/group-detail.component.html @@ -240,7 +240,10 @@
    {{ enrollmentErrorMessage }}
    -
    +
    The patient is not enrolled in this program.
    +
    + Patient is not eligible for OTZ enrollment +
    + { - console.log('results', results); const res = results[0]; this.otzModule = results[1].result; this.group = res; @@ -215,49 +215,6 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { this.checkIfTodayVisitStarted(this.cohortVisits); this.generateMembersData(res.cohortMembers, res.cohortVisits); }); - // this.subscriptions.add( - // this.communityGroupService.getGroupByUuid(uuid).subscribe( - // (res) => { - // this.group = res; - // _.forEach(this.group.cohortMembers, (member) => { - // member['phoneNumber'] = _.filter( - // member.patient.person.attributes, - // (attribute) => - // attribute.attributeType.uuid === - // '72a759a8-1359-11df-a1f1-0026b9348838' - // )[0]; - // }); - // this.activeMembers = _.filter( - // res.cohortMembers, - // (member) => !member.endDate - // ); - // this.cohortVisits = res.cohortVisits.sort((a: any, b: any) => { - // return Math.abs( - // new Date(b.startDate).getTime() - new Date(a.startDate).getTime() - // ); - // }); - // this.groupVisitDate = { - // date: this.today, - // jsdate: new Date() - // }; - // const isOtz = - // this.group.attributes.find((a) => { - // return a.cohortAttributeType.name === 'programUuid'; - // }).value === '203571d6-a4f2-4953-9e8b-e1105e2340f5'; - // this.cohortOtzModuleResourceService.getCohortOtzModule(this.group.uuid).subscribe((res) => { - // console.log('res', res); - // }); - // this.isOtzProgram = isOtz; - // this.checkIfTodayVisitStarted(this.cohortVisits); - // this.generateMembersData(res.cohortMembers, res.cohortVisits); - // }, - // (error) => { - // this.errorMessage = - // 'An error occurred while trying to load the group, please check your connection and refresh the page.'; - // this.error = true; - // } - // ) - // ); } public checkIfTodayVisitStarted(cohortVisits: any[]) { @@ -562,12 +519,13 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { i++; } const newArray = this.getVisitsArray(cohortMemberVisit); - console.log('newArray', newArray); for (let j = 0; j < conceptStrings.length; j++) { const concept = conceptStrings[j]; newArray.forEach((item) => { if (item.patient_uuid === member.person.uuid) { - const value = item.obs.some((obs) => obs.display === concept); + const value = item.obs.some( + (obs: { display: string }) => obs.display === concept + ); memberRow[`mod${j + 1}`] = value; } }); @@ -722,6 +680,7 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { break; case !validation.notEnrolledInGroupProgram.found: this.validatingEnrollment = false; + this.validateAge(patient); this.showEnrollButton(patient); break; case validation.enrolledInAnotherGroupInSameProgram.found: @@ -778,6 +737,14 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { queryParams }; } + + private validateAge(patient) { + if (patient._person.age >= 9 && patient._person.age <= 19) { + this.showOTZEnrollmentMsg = true; + } else { + this.showOTZEnrollmentMsg = false; + } + } private enrollPatientToGroup(group: Group, patient: Patient) { this.communityGroupMemberService .createMember(group.uuid, patient.uuid) diff --git a/src/app/group-manager/group-editor/group-editor-component.html b/src/app/group-manager/group-editor/group-editor-component.html index 3edff8a87..a5d4e14d6 100644 --- a/src/app/group-manager/group-editor/group-editor-component.html +++ b/src/app/group-manager/group-editor/group-editor-component.html @@ -145,7 +145,8 @@ class="sharp-corners select" placeholder="Please type to search" id="groupProgram" - [(ngModel)]="groupProgram" + [ngModel]="groupProgram" + (ngModelChange)="onProgramChanged($event)" [items]="groupPrograms" name="groupProgramInput" #groupProgramInput="ngModel" diff --git a/src/app/group-manager/group-editor/group-editor-component.ts b/src/app/group-manager/group-editor/group-editor-component.ts index 33d317591..8298b06d1 100644 --- a/src/app/group-manager/group-editor/group-editor-component.ts +++ b/src/app/group-manager/group-editor/group-editor-component.ts @@ -119,6 +119,14 @@ export class GroupEditorComponent implements OnInit { }); } + private autoGenerateOTZGroupNumber() { + this._communityService + .generateGroupNumber(this.facility.value ? this.facility.value : '') + .subscribe((res: any) => { + this.groupNo = res.groupNumber.replace(/DC/g, 'OTZ'); + }); + } + public setUpProviderTypeAhead() { this.providerSuggest .pipe( @@ -195,7 +203,6 @@ export class GroupEditorComponent implements OnInit { this.creatingGroup.emit(true); this.saving = true; if (this.editType.toLowerCase() === 'edit') { - console.log(this.editType); this.updateGroup(); } if (this.editType.toLowerCase() === 'create') { @@ -441,4 +448,12 @@ export class GroupEditorComponent implements OnInit { this.facility = event; this.autoGenerateGroupNumber(); } + + public onProgramChanged(event) { + if (event.value === '203571d6-a4f2-4953-9e8b-e1105e2340f5') { + this.autoGenerateOTZGroupNumber(); + } else { + this.autoGenerateGroupNumber(); + } + } } diff --git a/src/app/group-manager/group-manager-search/group-manager-search.component.html b/src/app/group-manager/group-manager-search/group-manager-search.component.html index bffb2f931..84516fa30 100644 --- a/src/app/group-manager/group-manager-search/group-manager-search.component.html +++ b/src/app/group-manager/group-manager-search/group-manager-search.component.html @@ -53,8 +53,28 @@

    Group Search

    margin-left: 15px; " > - View All Groups In This Facility - + View All DC Groups In This Facility + + +
    diff --git a/src/app/group-manager/group-manager-search/group-manager-search.component.ts b/src/app/group-manager/group-manager-search/group-manager-search.component.ts index 3240ebc22..69208d425 100644 --- a/src/app/group-manager/group-manager-search/group-manager-search.component.ts +++ b/src/app/group-manager/group-manager-search/group-manager-search.component.ts @@ -47,8 +47,8 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { public routeLoading = false; fetchingGroups: boolean; previousLocationUuid: string; - columnDefs = this.generateColumns(); rowData: any; + columnDefs = this.generateColumns(); public gridOptions: GridOptions = this.getGridOptions(); public filterText = ''; hideGroupsInCurrentFacility: boolean; @@ -117,6 +117,30 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { } } + public showOTZGroupsInFacilty() { + this.rowData = []; + this.fetchingGroups = true; + this.isOTZprogram = true; + const locationUuid = this.router.url.split('/')[2]; + if (locationUuid !== this.previousLocationUuid) { + this.fetchingGroups = true; + const sub = this.groupService + .getGroupsByLocationUuid(locationUuid) + .subscribe((res) => { + this.groupsInCurrentFacility = res.map((result) => new Group(result)); + this.hideGroupsInCurrentFacility = false; + this.fetchingGroups = false; + this.previousLocationUuid = locationUuid; + this.rowData = this.groupsInCurrentFacility; + }); + this.columnDefs = this.generateColumns(); + this.subscription.add(sub); + } else { + this.rowData = this.groupsInCurrentFacility; + this.isOTZprogram = true; + } + } + public navigateToGroupDetails(group, newGroup?) { if (this.modalRef) { this.modalRef.hide(); @@ -248,7 +272,7 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { caseSensitive: false } }, - ...(!this.isOTZprogram + ...(this.isOTZprogram ? [ { headerName: 'OTZ Champion', diff --git a/src/app/group-manager/modals/group-transfer-modal.component.ts b/src/app/group-manager/modals/group-transfer-modal.component.ts index 1d97862b0..7d4fcf1a3 100644 --- a/src/app/group-manager/modals/group-transfer-modal.component.ts +++ b/src/app/group-manager/modals/group-transfer-modal.component.ts @@ -21,9 +21,11 @@ import { Patient } from '../../models/patient.model'; @@ -42,7 +44,9 @@ export class GroupTransferModalComponent implements OnInit { constructor(public modalRef: BsModalRef) {} - ngOnInit() {} + ngOnInit() { + console.log('groupToEnroll', this.groupToUnenroll); + } confirm() { this.modalRef.hide(); diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts index c9108ea45..8149baf33 100644 --- a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts @@ -64,7 +64,9 @@ export class OtzSnapshotComponent implements OnInit { patient.uuid + '/general/general/formentry/ab16711d-890d-4128-95ce-0e955babd711'; this.groupManagerUrl = - '/clinic-dashboard/18c343eb-b353-462a-9139-b16606e6b6c2/hiv/group-manager'; + '/patient-dashboard/patient/' + + patient.uuid + + '/general/general/group-enrollment'; this.getOtzEnrollments(patient.person.age, patient.enrolledPrograms); this.getHivSummary(patient); this.getHistoricalPatientLabResults(patient); From 30505bcd226fae6917c229f247d833ed04f07a9b Mon Sep 17 00:00:00 2001 From: sainingo Date: Thu, 30 Nov 2023 17:22:37 +0300 Subject: [PATCH 06/19] wip --- .../cohort-otz-module-resource.service.ts | 42 +++++- .../group-detail/group-detail.component.ts | 124 +++++++++++++++--- .../group-editor/group-editor-component.html | 32 ++++- .../group-editor/group-editor-component.ts | 26 ++++ .../group-manager-search.component.ts | 67 +++++++--- src/app/models/group.model.ts | 63 +++++++++ .../community-group-resource.service.ts | 2 +- .../openmrs-api/encounter-resource.service.ts | 1 + .../common/formentry/formentry.component.html | 10 +- .../common/formentry/formentry.component.ts | 12 +- .../otz-snapshot/otz-snapshot.component.html | 14 +- .../otz-snapshot/otz-snapshot.component.ts | 23 +++- .../group-enrollment.component.ts | 7 + 13 files changed, 373 insertions(+), 50 deletions(-) diff --git a/src/app/etl-api/cohort-otz-module-resource.service.ts b/src/app/etl-api/cohort-otz-module-resource.service.ts index d05b9e5b9..0c936df00 100644 --- a/src/app/etl-api/cohort-otz-module-resource.service.ts +++ b/src/app/etl-api/cohort-otz-module-resource.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { AppSettingsService } from '../app-settings/app-settings.service'; import { Observable } from 'rxjs'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; @Injectable() export class CohortOtzModuleResourceService { @@ -15,7 +15,47 @@ export class CohortOtzModuleResourceService { ); } + public getSummaryUrl(): string { + return ( + this.appSettingsService.getEtlRestbaseurl().trim() + + 'hiv-latest-summaries' + ); + } + + public getPatientsSuppressionsUrl(): string { + return ( + this.appSettingsService.getEtlRestbaseurl().trim() + + 'viral-load-suppression-rate' + ); + } + public getCohortOtzModule(cohortUuid: string): Observable { return this.http.get(this.getUrl() + '/' + cohortUuid); } + public getUrlRequestParams(patientUuids: string[]): HttpParams { + let urlParams: HttpParams = new HttpParams(); + + if (patientUuids && patientUuids.length > 0) { + urlParams = urlParams.set('uuid', patientUuids.join(',')); + } + return urlParams; + } + + public getPatientsLatestHivSummaries(payload: string[]) { + if (!payload || payload.length === 0) { + return null; + } + return this.http.get(this.getSummaryUrl(), { + params: this.getUrlRequestParams(payload) + }); + } + + public getPatientsSuppressionStatus(payload: string[]) { + if (!payload || payload.length === 0) { + return null; + } + return this.http.get(this.getPatientsSuppressionsUrl(), { + params: this.getUrlRequestParams(payload) + }); + } } diff --git a/src/app/group-manager/group-detail/group-detail.component.ts b/src/app/group-manager/group-detail/group-detail.component.ts index 7dff3e9c8..5c987d4c6 100644 --- a/src/app/group-manager/group-detail/group-detail.component.ts +++ b/src/app/group-manager/group-detail/group-detail.component.ts @@ -30,18 +30,6 @@ import { RisonService } from '../../shared/services/rison-service'; import { HttpClient } from '@angular/common/http'; import { flatMap, map } from 'rxjs/operators'; -interface MemberType { - name: any; - person_uuid: any; - identifiers: any; - contacts: any; - member_since: string; - member_to: string; - mod1?: any; - mod2?: any; - mod3?: any; -} - @Component({ selector: 'group-detail', templateUrl: './group-detail.component.html', @@ -131,6 +119,7 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { public isActivityForm = false; public otzModule = []; public cohortVisitArray = []; + public hivSummary: any; public enrollMentModel = { enrollMentUrl: [], queryParams: {} @@ -237,9 +226,33 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { public generateMembersData(cohortMembers, cohortVisits) { this.membersData = []; this.columns = []; - const members = this.generateMemberObject(cohortMembers); - this.membersData = this.generateRowData(members, cohortVisits); - this.columns = this.generateColumns(cohortVisits); + const memberUuids = this.generatePatientUuids(cohortMembers); + this.cohortOtzModuleResourceService + .getPatientsLatestHivSummaries(memberUuids) + .subscribe((result) => { + const summaryMap = this.generateSummaryObject(result); + const members = this.generateMemberObject(cohortMembers); + this.membersData = this.generateRowData( + members, + cohortVisits, + summaryMap + ); + this.columns = this.generateColumns(cohortVisits); + }); + } + + public generatePatientUuids(cohortMembers) { + return cohortMembers.map((member) => { + return member.patient.person.uuid; + }); + } + + public generateSummaryObject(hivSummaries) { + const summaryMap = new Map(); + hivSummaries.forEach((summary) => { + summaryMap.set(summary.uuid, summary); + }); + return summaryMap; } public gridOnCellClick($event) { @@ -480,7 +493,7 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { return present; } - private generateRowData(cohortMembers, cohortVisits) { + private generateRowData(cohortMembers, cohortVisits, summaryMap) { const membersData = []; const cohortMemberVisit = []; const conceptStrings = [ @@ -494,13 +507,31 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { 'OTZ BEYOND THIRD 90: YES' ]; for (const member of cohortMembers) { - const memberRow: MemberType = { + const memberRow = { name: member.person.display, person_uuid: member.person.uuid, identifiers: member.allIdentifiers, contacts: member.person.patientPhoneNumber, member_since: this.datePipe.transform(member.startDate), - member_to: this.datePipe.transform(member.endDate) + member_to: this.datePipe.transform(member.endDate), + latest_vl: summaryMap.has(member.person.uuid) + ? summaryMap.get(member.person.uuid).latest_vl + : '', + latest_vl_date: summaryMap.has(member.person.uuid) + ? summaryMap.get(member.person.uuid).latest_vl_date + : '', + vl_category: summaryMap.has(member.person.uuid) + ? this.getVlCategory(summaryMap.get(member.person.uuid).latest_vl) + : '', + latest_rtc: summaryMap.has(member.person.uuid) + ? summaryMap.get(member.person.uuid).rtc_date + : '', + latest_appointment_date: summaryMap.has(member.person.uuid) + ? summaryMap.get(member.person.uuid).latest_appointment + : '', + adherence_type: summaryMap.has(member.person.uuid) + ? summaryMap.get(member.person.uuid).adherence + : '' }; let i = 0; @@ -512,9 +543,6 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { memberRow[`group_visit_${i}_uuid`] = cohortVisit.uuid; if (cohortVisit.cohortMemberVisits.length > 0) { cohortMemberVisit.push(cohortVisit.cohortMemberVisits); - // if(cohortMemberVisit.includes(cohortVisit.cohortMemberVisits)) { - // cohortMemberVisit.push(cohortVisit.cohortMemberVisits) - // } } i++; } @@ -536,6 +564,21 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { return membersData; } + private getVlCategory(value: number): string { + if (value === null || value === undefined) { + return ''; + } + if (value <= 50) { + return 'LDL'; + } else if (value <= 200) { + return 'Low Risk Low Level Viremia'; + } else if (value <= 500) { + return 'High Risk Low Level Viremia'; + } else { + return 'Suspected Treatment Failure'; + } + } + private getVisitsArray(cohortVisitArray) { const filteredArray = []; @@ -635,10 +678,49 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { } if (this.isOtzProgram) { + columns.push( + { + headerName: 'Latest VL', + field: 'latest_vl', + pinned: 'left', + width: 80 + }, + { + headerName: 'Latest VL Date', + field: 'latest_vl_date', + pinned: 'left', + width: 80 + }, + { + headerName: 'VL Category', + field: 'vl_category', + pinned: 'left', + width: 80 + }, + { + headerName: 'Latest RTC', + field: 'latest_rtc', + pinned: 'left', + width: 80 + }, + { + headerName: 'Latest Appointment Date', + field: 'latest_appointment_date', + pinned: 'left', + width: 80 + }, + { + headerName: 'Adherence Type', + field: 'adherence_type', + pinned: 'left', + width: 80 + } + ); for (let i = 1; i <= 8; i++) { columns.push({ headerName: `Mod ${i}`, field: `mod${i}`, + width: 70, cellRenderer: (column) => { if (column.value) { return ``; diff --git a/src/app/group-manager/group-editor/group-editor-component.html b/src/app/group-manager/group-editor/group-editor-component.html index a5d4e14d6..39a11405b 100644 --- a/src/app/group-manager/group-editor/group-editor-component.html +++ b/src/app/group-manager/group-editor/group-editor-component.html @@ -145,7 +145,7 @@ class="sharp-corners select" placeholder="Please type to search" id="groupProgram" - [ngModel]="groupProgram" + [(ngModel)]="groupProgram" (ngModelChange)="onProgramChanged($event)" [items]="groupPrograms" name="groupProgramInput" @@ -211,6 +211,36 @@
    +
    +
    +
    + +
    +
    +
    +
    + + +
    + Group Activity is required + +
    +
    +
    +

    diff --git a/src/app/group-manager/group-editor/group-editor-component.ts b/src/app/group-manager/group-editor/group-editor-component.ts index 8298b06d1..8aa281072 100644 --- a/src/app/group-manager/group-editor/group-editor-component.ts +++ b/src/app/group-manager/group-editor/group-editor-component.ts @@ -42,8 +42,20 @@ export class GroupEditorComponent implements OnInit { public actionButtonText = `${this.editType} Group`; public groupTypes: any = []; public groupPrograms: any = []; + public groupActivities: string[] = [ + 'Tailoring', + 'Art WorldTable', + 'Tennis', + 'Chess', + 'Football', + 'ReadingDarts', + 'Farming', + 'None' + ]; public groupProgram: any; + public groupActivity: any; public success = false; + public showGroupActivity = false; public message = ''; public busy = false; public providerLoading; @@ -60,6 +72,7 @@ export class GroupEditorComponent implements OnInit { this.groupUuid = state.groupUuid; this.groupName = state.groupName; this.groupProgram = state.groupProgram; + this.groupActivity = state.groupActivity; this.facility = state.facility; this.provider = state.provider; this.address = state.address; @@ -254,6 +267,12 @@ export class GroupEditorComponent implements OnInit { value: this.groupProgram['value'] }); } + if (this.groupActivity !== '') { + attributes.push({ + cohortAttributeType: 'groupActivity', + value: this.groupActivity + }); + } const payLoad = { name: this.groupName, description: '', @@ -292,6 +311,7 @@ export class GroupEditorComponent implements OnInit { this.groupNo = ''; this.groupType = {}; this.groupProgram = {}; + this.groupActivity = {}; this.address = ''; this.provider = ''; this.success = false; @@ -449,11 +469,17 @@ export class GroupEditorComponent implements OnInit { this.autoGenerateGroupNumber(); } + public onGroupActivityChanged(event) { + this.groupActivity = event; + } + public onProgramChanged(event) { if (event.value === '203571d6-a4f2-4953-9e8b-e1105e2340f5') { this.autoGenerateOTZGroupNumber(); + this.showGroupActivity = true; } else { this.autoGenerateGroupNumber(); + this.showGroupActivity = false; } } } diff --git a/src/app/group-manager/group-manager-search/group-manager-search.component.ts b/src/app/group-manager/group-manager-search/group-manager-search.component.ts index 69208d425..0c433c598 100644 --- a/src/app/group-manager/group-manager-search/group-manager-search.component.ts +++ b/src/app/group-manager/group-manager-search/group-manager-search.component.ts @@ -53,6 +53,7 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { public filterText = ''; hideGroupsInCurrentFacility: boolean; public isOTZprogram = false; + public filterOTZ = ''; constructor( private groupService: CommunityGroupService, @@ -99,6 +100,8 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { public showGroupsInFacilty() { this.rowData = []; this.fetchingGroups = true; + this.isOTZprogram = false; + this.filterText = ''; const locationUuid = this.router.url.split('/')[2]; if (locationUuid !== this.previousLocationUuid) { this.fetchingGroups = true; @@ -108,6 +111,7 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { this.groupsInCurrentFacility = res.map((result) => new Group(result)); this.hideGroupsInCurrentFacility = false; this.fetchingGroups = false; + this.isOTZprogram = false; this.previousLocationUuid = locationUuid; this.rowData = this.groupsInCurrentFacility; }); @@ -122,23 +126,29 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { this.fetchingGroups = true; this.isOTZprogram = true; const locationUuid = this.router.url.split('/')[2]; - if (locationUuid !== this.previousLocationUuid) { - this.fetchingGroups = true; - const sub = this.groupService - .getGroupsByLocationUuid(locationUuid) - .subscribe((res) => { - this.groupsInCurrentFacility = res.map((result) => new Group(result)); - this.hideGroupsInCurrentFacility = false; - this.fetchingGroups = false; - this.previousLocationUuid = locationUuid; - this.rowData = this.groupsInCurrentFacility; - }); - this.columnDefs = this.generateColumns(); - this.subscription.add(sub); - } else { - this.rowData = this.groupsInCurrentFacility; - this.isOTZprogram = true; - } + this.fetchingGroups = true; + const sub = this.groupService + .getGroupsByLocationUuid(locationUuid) + .subscribe((res) => { + this.groupsInCurrentFacility = res.map((result) => new Group(result)); + this.hideGroupsInCurrentFacility = false; + this.fetchingGroups = false; + this.isOTZprogram = false; + this.rowData = this.groupsInCurrentFacility; + this.filterText = 'OTZ PROGRAM'; + this.gridOptions.api.onFilterChanged(); + }); + this.columnDefs = this.generateColumns(); + this.subscription.add(sub); + } + + public generatePatientUuids(cohortMembers) { + // create an object with patient uuids as keys for each group + const patientUuids = {}; + cohortMembers.forEach((member) => { + patientUuids[member.uuid] = true; + }); + return Object.keys(patientUuids); } public navigateToGroupDetails(group, newGroup?) { @@ -193,7 +203,8 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { return ( _.includes(node.data.display.toLowerCase(), filterCaseLowercase) || _.includes(node.data.facility.toLowerCase(), filterCaseLowercase) || - _.includes(node.data.status.toLowerCase(), filterCaseLowercase) + _.includes(node.data.status.toLowerCase(), filterCaseLowercase) || + _.includes(node.data.program, this.filterText) ); } @@ -274,6 +285,26 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { }, ...(this.isOTZprogram ? [ + { + headerName: 'Viral Suppression', + field: 'viralSuppression', + sortable: true, + filter: 'agTextColumnFilter', + width: 200, + filterParams: { + caseSensitive: false + } + }, + { + headerName: 'Last Meeting Date', + field: 'lastMeetingDate', + sortable: true, + filter: 'agTextColumnFilter', + width: 200, + filterParams: { + caseSensitive: false + } + }, { headerName: 'OTZ Champion', field: 'otzChampion', diff --git a/src/app/models/group.model.ts b/src/app/models/group.model.ts index 5c205a6c8..bbad3ee2a 100644 --- a/src/app/models/group.model.ts +++ b/src/app/models/group.model.ts @@ -38,6 +38,17 @@ export class Group extends BaseModel { @serializable() public get status() { + const lastMeetingDate = this.getLatestMeetingDate( + this._openmrsModel.cohortVisits + ); + // if last meeting date is more than 3 months ago, group is inactive + if (lastMeetingDate) { + const today = new Date(); + const threeMonthsAgo = new Date(today.setMonth(today.getMonth() - 3)); + if (lastMeetingDate < threeMonthsAgo) { + return 'Inactive'; + } + } return this._openmrsModel.endDate ? 'Disbanded' : 'Active'; } @@ -62,6 +73,31 @@ export class Group extends BaseModel { return this.getGroupMembersCount(this._openmrsModel.cohortMembers); } + @serializable() + public get otzChampion() { + const attrType = this.getCurrentLeader(this._openmrsModel.cohortLeaders); + if (attrType) { + return attrType.person.display; + } + return null; + } + + @serializable() + public get groupActivity() { + const attrType = 'groupActivity'; + return this.getAttribute(attrType, this._openmrsModel.attributes); + } + + @serializable() + public get viralSuppression() { + return Math.floor(Math.random() * 100) + 1 + '%'; + } + + @serializable() + public get lastMeetingDate() { + return this.getLatestMeetingDate(this._openmrsModel.cohortVisits); + } + public getAttribute(attributeType, attributes) { const attr = _.filter( attributes, @@ -73,10 +109,37 @@ export class Group extends BaseModel { return null; } + public getLatestMeetingDate(startDates) { + if (startDates.length > 0) { + const latestStartDateString = startDates.reduce( + (maxDate, currentDateObject) => { + const currentStartDate = new Date(currentDateObject.startDate); + const maxStartDate = maxDate ? new Date(maxDate.startDate) : null; + + if (!maxStartDate || currentStartDate > maxStartDate) { + return currentDateObject; + } else { + return maxDate; + } + }, + null + ).startDate; + return new Date(latestStartDateString); + } + } + public getGroupMembersCount(cohortMembers) { const active_members = cohortMembers.filter( (current) => current.endDate == null ); return active_members ? active_members.length : 0; } + + public getCurrentLeader(allLeaders: any[]) { + const currentLeader = _.filter( + allLeaders, + (leader) => leader.endDate == null + )[0]; + return currentLeader; + } } diff --git a/src/app/openmrs-api/community-group-resource.service.ts b/src/app/openmrs-api/community-group-resource.service.ts index 1c3f759a2..01e928abf 100644 --- a/src/app/openmrs-api/community-group-resource.service.ts +++ b/src/app/openmrs-api/community-group-resource.service.ts @@ -12,7 +12,7 @@ export class CommunityGroupService { public cachedResults: BehaviorSubject = new BehaviorSubject([]); public v = 'full'; public _v = - 'custom:(uuid,name,description,startDate,endDate,location:(display),attributes,cohortMembers:(uuid,endDate))'; + 'custom:(uuid,name,description,cohortLeaders,startDate,endDate,location:(display),cohortVisits:(startDate),attributes,cohortMembers:(uuid,endDate))'; constructor( private http: HttpClient, diff --git a/src/app/openmrs-api/encounter-resource.service.ts b/src/app/openmrs-api/encounter-resource.service.ts index ce1b9f197..a9f6f8181 100644 --- a/src/app/openmrs-api/encounter-resource.service.ts +++ b/src/app/openmrs-api/encounter-resource.service.ts @@ -11,6 +11,7 @@ export class EncounterResourceService { 'patient:(uuid,uuid),form:(uuid,name),' + 'visit:(uuid,display,auditInfo,startDatetime,stopDatetime,location:(uuid,display)' + ',visitType:(uuid,name)),' + + 'obs:(uuid,obsDatetime,concept:(uuid,uuid,name:(display),datatype),value:ref,groupMembers),' + 'location:ref,encounterType:ref,encounterProviders:(uuid,display,provider:(uuid,display)))'; constructor( diff --git a/src/app/patient-dashboard/common/formentry/formentry.component.html b/src/app/patient-dashboard/common/formentry/formentry.component.html index e3862f136..f8725d48d 100644 --- a/src/app/patient-dashboard/common/formentry/formentry.component.html +++ b/src/app/patient-dashboard/common/formentry/formentry.component.html @@ -261,13 +261,21 @@
    Patient Search +
    -
    +
    +
    +

    + OTZ Program (discontinued on + {{ otzDiscontinuationDate | date: 'dd-MM-yyyy' }}) +

    +

    + Reason for discontinuation: + {{ reasonForDiscontinuation }} +

    +
    +
    +

    OTZ Program (enrolled on {{ dateEnrolled }}) diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts index 8149baf33..0211700f3 100644 --- a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts @@ -32,6 +32,9 @@ export class OtzSnapshotComponent implements OnInit { hasData: boolean; isHEIActive: boolean; viralLoadCategory: string; + isOtzDiscontinued = false; + reasonForDiscontinuation: string; + otzDiscontinuationDate: any; viralLoadHistory: any[]; isPatientEligibleForOtz = false; @@ -39,7 +42,7 @@ export class OtzSnapshotComponent implements OnInit { private patientService: PatientService, private hivSummaryResourceService: HivSummaryResourceService, private labsResourceService: LabsResourceService, - private _encounterResource: EncounterResourceService, + private encounterResource: EncounterResourceService, private router: Router, private route: ActivatedRoute ) {} @@ -70,6 +73,23 @@ export class OtzSnapshotComponent implements OnInit { this.getOtzEnrollments(patient.person.age, patient.enrolledPrograms); this.getHivSummary(patient); this.getHistoricalPatientLabResults(patient); + this.encounterResource + .getEncounterByUuid('409b4532-9013-4ceb-8519-adb94136230f') + .subscribe((res) => { + if (res && patient.person.uuid === res.patient.uuid) { + const reasonForDiscontinuation = res.obs.find((obs) => { + return ( + obs.concept.uuid === 'a89e3f94-1350-11df-a1f1-0026b9348838' + ); + }); + if (reasonForDiscontinuation) { + this.isOtzDiscontinued = true; + this.reasonForDiscontinuation = + reasonForDiscontinuation.value.display; + this.otzDiscontinuationDate = res.encounterDatetime; + } + } + }); } } ); @@ -115,7 +135,6 @@ export class OtzSnapshotComponent implements OnInit { this.clinicalEncounters = this.getClinicalEncounters(results); this.patientData = _.first(this.clinicalEncounters); const patientDataCopy = this.patientData; - console.log('patientDAta', this.patientData); if (!_.isNil(this.patientData)) { // assign latest vl and vl_1_date diff --git a/src/app/patient-dashboard/group-enrollment/group-enrollment/group-enrollment.component.ts b/src/app/patient-dashboard/group-enrollment/group-enrollment/group-enrollment.component.ts index cada56556..140cc8328 100644 --- a/src/app/patient-dashboard/group-enrollment/group-enrollment/group-enrollment.component.ts +++ b/src/app/patient-dashboard/group-enrollment/group-enrollment/group-enrollment.component.ts @@ -81,16 +81,23 @@ export class GroupEnrollmentComponent implements OnInit, OnDestroy { public onEnrollmentTypeChange($event: MatRadioChange) { let enrolledInDc = false; + let enrolledInOtz = false; _.forEach(this.currentEnrolledPrograms, (currentProgram) => { if ( currentProgram.programUuid === '334c9e98-173f-4454-a8ce-f80b20b7fdf0' ) { enrolledInDc = true; + } else if ( + currentProgram.programUuid === '203571d6-a4f2-4953-9e8b-e1105e2340f5' + ) { + enrolledInOtz = true; } }); if (!enrolledInDc) { this.errorMessage = `Patient needs to be enrolled in DC program first.`; + } else if (!enrolledInOtz) { + this.errorMessage = `Patient needs to be enrolled in OTZ program first.`; } this.enrollmentType = $event.value; } From f8b631f9390748bf4c58953829972d05f5acb5a6 Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Fri, 3 Nov 2023 18:29:16 +0300 Subject: [PATCH 07/19] for unsuccessful contact attempts, added maroon filter (#1682) --- .../pre-appointment-patient-list.component.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app/shared/data-lists/pre-appointment-patient-list/pre-appointment-patient-list.component.ts b/src/app/shared/data-lists/pre-appointment-patient-list/pre-appointment-patient-list.component.ts index 85bdd42b7..db8be8df5 100644 --- a/src/app/shared/data-lists/pre-appointment-patient-list/pre-appointment-patient-list.component.ts +++ b/src/app/shared/data-lists/pre-appointment-patient-list/pre-appointment-patient-list.component.ts @@ -80,6 +80,11 @@ export class PreAppointmentPatientListComponent return { 'background-color': 'green', color: 'white' }; } else if (params.data.rescheduled_date !== null) { return { 'background-color': 'yellow' }; + } else if ( + params.data.follow_up_type !== null && + params.data.was_follow_up_successful === 0 + ) { + return { 'background-color': 'maroon', color: 'white' }; } else { return {}; } From 6252b8dcdc69864570f5d803c75bae370931aec9 Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Wed, 8 Nov 2023 17:22:43 +0300 Subject: [PATCH 08/19] for unsuccessfulcontact attempts, added pink filter (#1683) --- .../pre-appointment-patient-list.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/data-lists/pre-appointment-patient-list/pre-appointment-patient-list.component.ts b/src/app/shared/data-lists/pre-appointment-patient-list/pre-appointment-patient-list.component.ts index db8be8df5..6f34b3081 100644 --- a/src/app/shared/data-lists/pre-appointment-patient-list/pre-appointment-patient-list.component.ts +++ b/src/app/shared/data-lists/pre-appointment-patient-list/pre-appointment-patient-list.component.ts @@ -84,7 +84,7 @@ export class PreAppointmentPatientListComponent params.data.follow_up_type !== null && params.data.was_follow_up_successful === 0 ) { - return { 'background-color': 'maroon', color: 'white' }; + return { 'background-color': 'pink' }; } else { return {}; } From 19b7380c8ea8e1b05ddd338055de1e8fbd5b88e8 Mon Sep 17 00:00:00 2001 From: Saningo Lekalantula Date: Wed, 15 Nov 2023 15:37:21 +0300 Subject: [PATCH 09/19] POC-558 (#1678) * Change the Male/Female gender disaagregation to start with Female then Male * Change the Male/Female gender disaagregation to start with Female then Male --------- Co-authored-by: kantush Co-authored-by: Drizzentic --- .../prep-monthly-report-view.component.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.ts b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.ts index 50c8a85d7..eb08b6854 100644 --- a/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.ts +++ b/src/app/hiv-care-lib/prep-report/monthly/prep-monthly-report-view/prep-monthly-report-view.component.ts @@ -55,6 +55,12 @@ export class PrepMonthlyReportViewComponent implements OnInit, OnChanges { this.indicatorSelected.emit(payload); } + swapIndices(arr: any[]) { + for (let i = 0; i < arr.length - 1; i += 2) { + [arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]; + } + } + public buildTableBody() { this.tableSectionData = this.SummaryData; this.tableSectionIndicators = this.sectionDefs; @@ -88,6 +94,13 @@ export class PrepMonthlyReportViewComponent implements OnInit, OnChanges { } ); + // Find the first occurrence of 'F' in the original array + const firstFIndex = this.genderGroups.indexOf('F'); + + this.genderGroups = this.genderGroups + .slice(firstFIndex) + .concat(this.genderGroups.slice(0, firstFIndex)); + // Table data // Remove the first two sections const allData = this.tableSectionIndicators.slice(2); @@ -96,6 +109,7 @@ export class PrepMonthlyReportViewComponent implements OnInit, OnChanges { this.tableData.push({ sectionTitle: section.sectionTitle, sectionData: section.indicators.map((sect) => { + this.swapIndices(sect.indicators); return { rowTitle: sect.label, rowData: sect.indicators.map((val) => { From 13829a720d6f4f5356c17e1fe38888d7d62066c5 Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Wed, 29 Nov 2023 10:14:37 +0300 Subject: [PATCH 10/19] POC-492: Modified pre-appointment to display failed phone attempts (#1681) --- .../pre-appointment-outreach.component.ts | 5 +++++ 1 file changed, 5 insertions(+) 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 d81010b4a..7bcd5431c 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 @@ -215,6 +215,11 @@ export class PreAppointmentOutreachComponent implements OnInit { width: 100, field: 'rescheduled_date' }, + { + headerName: 'No. of Failed Phone Attempts', + width: 100, + field: 'number_of_failed_phone_attempts' + }, { headerName: 'Contact Reached', width: 100, From f75a46330bffcfdb3a1492b7b9efb103828aa46d Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Wed, 29 Nov 2023 12:19:53 +0300 Subject: [PATCH 11/19] POC-570:remove program snapshot tag after patient has made clinical visit (#1687) * remove program snapshot tag after patient has made clinical visit * fixed pre-appoinment-reminder tag on program snapshot * POC-570:fixed pre-appoinment-reminder tag on program snapshot * Update src/app/patient-dashboard/hiv/program-snapshot/hiv-program-snapshot.component.ts --------- Co-authored-by: Drizzentic --- .../hiv/program-snapshot/hiv-program-snapshot.component.html | 5 ++++- .../hiv/program-snapshot/hiv-program-snapshot.component.ts | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) 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 bcde35032..a9a4f621c 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 @@ -57,7 +57,10 @@

    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 050f7b703..d4150513d 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 @@ -299,7 +299,8 @@ export class HivProgramSnapshotComponent implements OnInit { if ( result && result.predicted_prob_disengage && - result.predicted_risk + result.predicted_risk && + result.observed_rtc_date === null ) { this.hasPredictedScore = true; this.prediction = result; From 3cf09c29df6df2d202a5996c9d2e785f4925a9a8 Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Thu, 30 Nov 2023 10:49:05 +0300 Subject: [PATCH 12/19] POC-495 (#1685) * customised toastr for pre-appointment rescheduled appointments * added pre-appointment banner for patients who rescheduled appointments * added customised toastr for predicted patients who rescheduled appointments * POC-495: added customised toastr for predicted patients with rescheduled appointments added customised toastr for predicted patients who rescheduled appointments POC-495: added customised toastr for predicted patients with rescheduled appointments --------- Co-authored-by: Drizzentic --- .../patient-reminder-custom.component.css | 30 +++++++++++++++++++ .../patient-reminder.component.css | 5 ++++ .../patient-reminders.component.ts | 10 ++++++- .../patient-reminders.components.html | 14 +++++++++ 4 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/app/patient-dashboard/common/patient-reminders/patient-reminder-custom.component.css b/src/app/patient-dashboard/common/patient-reminders/patient-reminder-custom.component.css index 4354e7953..8da650363 100644 --- a/src/app/patient-dashboard/common/patient-reminders/patient-reminder-custom.component.css +++ b/src/app/patient-dashboard/common/patient-reminders/patient-reminder-custom.component.css @@ -20,3 +20,33 @@ :host.toast.toast-warning { background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=') !important; } + +/* Custom toast class for ml custom notification type */ +::ng-deep .ngx-toastr-custom-type { + position: relative; + overflow: hidden; + margin: 0 0 6px; + padding: 15px 15px 15px 50px; + width: 300px; + border-radius: 3px 3px 3px 3px; + background-position: 15px center; + background-repeat: no-repeat; + background-size: 24px; + box-shadow: 0 0 12px #999999; + color: #271e1e; + background-color: #ffff00; + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=') !important; +} + +/* Additional styles for toastr */ +.ngx-toastr-custom-type .toast-title { + font-weight: bold; +} + +.ngx-toastr-custom-type .toast-close-button { + position: absolute; + top: 0; + right: 0; + padding: 8px; + cursor: pointer; +} diff --git a/src/app/patient-dashboard/common/patient-reminders/patient-reminder.component.css b/src/app/patient-dashboard/common/patient-reminders/patient-reminder.component.css index b0af0f6c7..cdca47d99 100644 --- a/src/app/patient-dashboard/common/patient-reminders/patient-reminder.component.css +++ b/src/app/patient-dashboard/common/patient-reminders/patient-reminder.component.css @@ -1,3 +1,8 @@ patient-reminders .panel-body { padding: 0px !important; } + +:host.toast.alert-ml { + background-color: #ffff00; + border-color: #bdaaad; +} diff --git a/src/app/patient-dashboard/common/patient-reminders/patient-reminders.component.ts b/src/app/patient-dashboard/common/patient-reminders/patient-reminders.component.ts index 2c879f7b5..b5d2c0eb0 100644 --- a/src/app/patient-dashboard/common/patient-reminders/patient-reminders.component.ts +++ b/src/app/patient-dashboard/common/patient-reminders/patient-reminders.component.ts @@ -136,7 +136,15 @@ export class PatientRemindersComponent implements OnInit, OnDestroy { this.toastrConfig ); } - + if (reminder.type === 'ml') { + toast = this.toastrService.show(reminder.message, reminder.title, { + extendedTimeOut: 0, + timeOut: 0, + positionClass: 'toast-bottom-right', + closeButton: true, + toastClass: 'ngx-toastr-custom-type' + }); + } if (reminder.type === 'info') { toast = this.toastrService.info( reminder.message, diff --git a/src/app/patient-dashboard/common/patient-reminders/patient-reminders.components.html b/src/app/patient-dashboard/common/patient-reminders/patient-reminders.components.html index 2331b28d7..a0b69ee7d 100644 --- a/src/app/patient-dashboard/common/patient-reminders/patient-reminders.components.html +++ b/src/app/patient-dashboard/common/patient-reminders/patient-reminders.components.html @@ -45,4 +45,18 @@ > {{reminder.message}}

    +
    + × + {{reminder.message}} +
    From 8f667c599d7973cff2b09c5e05c07769208e5974 Mon Sep 17 00:00:00 2001 From: sainingo Date: Wed, 6 Dec 2023 09:36:44 +0300 Subject: [PATCH 13/19] wip --- .../group-detail/group-detail-summary.component.html | 6 ++++++ .../group-detail/group-detail-summary.component.ts | 10 ++++++++++ .../group-editor/group-editor-component.ts | 10 +++++++++- .../group-manager-search.component.ts | 11 +++++++---- src/app/models/group.model.ts | 2 +- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/app/group-manager/group-detail/group-detail-summary.component.html b/src/app/group-manager/group-detail/group-detail-summary.component.html index ea031336d..70c114249 100644 --- a/src/app/group-manager/group-detail/group-detail-summary.component.html +++ b/src/app/group-manager/group-detail/group-detail-summary.component.html @@ -108,6 +108,12 @@

    Group Summary

    + + + Group Activity: + {{ groupActivity?.value }} + +
    diff --git a/src/app/group-manager/group-detail/group-detail-summary.component.ts b/src/app/group-manager/group-detail/group-detail-summary.component.ts index 3314dde3f..b2b2783cb 100644 --- a/src/app/group-manager/group-detail/group-detail-summary.component.ts +++ b/src/app/group-manager/group-detail/group-detail-summary.component.ts @@ -56,6 +56,7 @@ export class GroupDetailSummaryComponent implements OnInit, OnDestroy { public group: Group; public groupNumber: any; public landmark: any; + public groupActivity: any; public provider: any; public program: any; public currentLeader: any; @@ -105,6 +106,10 @@ export class GroupDetailSummaryComponent implements OnInit, OnDestroy { 'landmark', this.group.attributes ); + this.groupActivity = this.communityGroupService.getGroupAttribute( + 'groupActivity', + this.group.attributes + ); this.currentLeader = this.getCurrentLeader( group.cohortLeaders, group.cohortMembers @@ -348,6 +353,10 @@ export class GroupDetailSummaryComponent implements OnInit, OnDestroy { 'landmark', this.group.attributes ); + this.groupActivity = this.communityGroupService.getGroupAttribute( + 'groupActivity', + this.group.attributes + ); this.currentLeader = this.getCurrentLeader( group.cohortLeaders, group.cohortMembers @@ -562,6 +571,7 @@ export class GroupDetailSummaryComponent implements OnInit, OnDestroy { groupProgram: { label: program['name'], value: program['uuid'] }, provider: { label: provider.person.display, value: provider.person.uuid }, address: this.landmark.value, + groupActivity: this.groupActivity.value, groupUuid: this.group.uuid, actionButtonText: 'Save Changes' }; diff --git a/src/app/group-manager/group-editor/group-editor-component.ts b/src/app/group-manager/group-editor/group-editor-component.ts index 8aa281072..8a3b3eb89 100644 --- a/src/app/group-manager/group-editor/group-editor-component.ts +++ b/src/app/group-manager/group-editor/group-editor-component.ts @@ -56,6 +56,7 @@ export class GroupEditorComponent implements OnInit { public groupActivity: any; public success = false; public showGroupActivity = false; + public otzProgramUuid = '203571d6-a4f2-4953-9e8b-e1105e2340f5'; public message = ''; public busy = false; public providerLoading; @@ -111,6 +112,12 @@ export class GroupEditorComponent implements OnInit { this.setDefaultProgram(); this.autoGenerateGroupNumber(); } + if ( + this.editType.toLowerCase() === 'edit' && + this.groupProgram.value === this.otzProgramUuid + ) { + this.showGroupActivity = true; + } this.route.parent.parent.parent.url.subscribe((urlSegment: any) => { if (!_.isEmpty(this.facilities)) { @@ -471,10 +478,11 @@ export class GroupEditorComponent implements OnInit { public onGroupActivityChanged(event) { this.groupActivity = event; + this.showGroupActivity = true; } public onProgramChanged(event) { - if (event.value === '203571d6-a4f2-4953-9e8b-e1105e2340f5') { + if (event.value === this.otzProgramUuid) { this.autoGenerateOTZGroupNumber(); this.showGroupActivity = true; } else { diff --git a/src/app/group-manager/group-manager-search/group-manager-search.component.ts b/src/app/group-manager/group-manager-search/group-manager-search.component.ts index 0c433c598..fddeba992 100644 --- a/src/app/group-manager/group-manager-search/group-manager-search.component.ts +++ b/src/app/group-manager/group-manager-search/group-manager-search.component.ts @@ -131,22 +131,25 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { .getGroupsByLocationUuid(locationUuid) .subscribe((res) => { this.groupsInCurrentFacility = res.map((result) => new Group(result)); + this.generatePatientUuids(this.groupsInCurrentFacility); this.hideGroupsInCurrentFacility = false; this.fetchingGroups = false; this.isOTZprogram = false; this.rowData = this.groupsInCurrentFacility; this.filterText = 'OTZ PROGRAM'; - this.gridOptions.api.onFilterChanged(); + if (this.gridOptions.api) { + this.gridOptions.api.onFilterChanged(); + } }); this.columnDefs = this.generateColumns(); this.subscription.add(sub); } - public generatePatientUuids(cohortMembers) { + public generatePatientUuids(cohort) { // create an object with patient uuids as keys for each group const patientUuids = {}; - cohortMembers.forEach((member) => { - patientUuids[member.uuid] = true; + cohort.forEach((uuid) => { + patientUuids[uuid._openmrsModel.uuid] = uuid._openmrsModel.uuid; }); return Object.keys(patientUuids); } diff --git a/src/app/models/group.model.ts b/src/app/models/group.model.ts index bbad3ee2a..9ca745c94 100644 --- a/src/app/models/group.model.ts +++ b/src/app/models/group.model.ts @@ -77,7 +77,7 @@ export class Group extends BaseModel { public get otzChampion() { const attrType = this.getCurrentLeader(this._openmrsModel.cohortLeaders); if (attrType) { - return attrType.person.display; + return attrType.person.display.replace(/\d+|-/g, ''); } return null; } From bca26742f4ec66be5072c61110fc90efd06a26e6 Mon Sep 17 00:00:00 2001 From: sainingo Date: Wed, 13 Dec 2023 11:38:48 +0300 Subject: [PATCH 14/19] Add cohort viral load suppression rate --- .../group-detail-summary.component.html | 2 +- .../group-detail/group-detail.component.ts | 66 ++++++++++++------- .../group-editor/group-editor-component.html | 26 ++++++++ .../group-editor/group-editor-component.ts | 25 ++++++- .../group-manager-search.component.html | 2 +- .../group-manager-search.component.ts | 31 ++++++--- src/app/models/group.model.ts | 8 ++- .../otz-snapshot/otz-snapshot.component.html | 2 +- .../otz-snapshot/otz-snapshot.component.ts | 2 +- .../patient-banner.component.ts | 2 +- 10 files changed, 126 insertions(+), 40 deletions(-) diff --git a/src/app/group-manager/group-detail/group-detail-summary.component.html b/src/app/group-manager/group-detail/group-detail-summary.component.html index 70c114249..f7a444eb1 100644 --- a/src/app/group-manager/group-detail/group-detail-summary.component.html +++ b/src/app/group-manager/group-detail/group-detail-summary.component.html @@ -72,7 +72,7 @@

    Group Summary

    Leader: - {{ currentLeader.person.display }} ({{ leadershipType }}), + {{ currentLeader.person.display }}, since {{ currentLeader.startDate | date: 'medium' }} diff --git a/src/app/group-manager/group-detail/group-detail.component.ts b/src/app/group-manager/group-detail/group-detail.component.ts index 5c987d4c6..a47c92f87 100644 --- a/src/app/group-manager/group-detail/group-detail.component.ts +++ b/src/app/group-manager/group-detail/group-detail.component.ts @@ -25,7 +25,6 @@ import { GridOptions } from 'ag-grid'; import { GroupTransferModalComponent } from '../modals/group-transfer-modal.component'; import { RetrospectiveDataEntryService } from '../../retrospective-data-entry/services/retrospective-data-entry.service'; import { CohortOtzModuleResourceService } from 'src/app/etl-api/cohort-otz-module-resource.service'; -import { ObsResourceService } from '../../openmrs-api/obs-resource.service'; import { RisonService } from '../../shared/services/rison-service'; import { HttpClient } from '@angular/common/http'; import { flatMap, map } from 'rxjs/operators'; @@ -100,6 +99,7 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { formatted: Moment().format('YYYY-MM-DD') }; public cohortVisits = []; + public numberOfMembers: number; public patientVisitPayload: any; public visitTypes = []; public selectedPatient: Patient; @@ -117,7 +117,6 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { public showOTZEnrollmentMsg = false; public isOtzProgram = false; public isActivityForm = false; - public otzModule = []; public cohortVisitArray = []; public hivSummary: any; public enrollMentModel = { @@ -135,7 +134,6 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { private modalService: BsModalService, private risonService: RisonService, private retrospectiveService: RetrospectiveDataEntryService, - private obsResourceService: ObsResourceService, private cohortOtzModuleResourceService: CohortOtzModuleResourceService, private http: HttpClient @@ -168,12 +166,11 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { public loadGroup() { const uuid = this.activatedRoute.snapshot.paramMap.get('uuid'); const dcOtzSubs = forkJoin([ - this.communityGroupService.getGroupByUuid(uuid), - this.cohortOtzModuleResourceService.getCohortOtzModule(uuid) + this.communityGroupService.getGroupByUuid(uuid) ]); dcOtzSubs.subscribe((results) => { const res = results[0]; - this.otzModule = results[1].result; + this.numberOfMembers = res.cohortMembers.length; this.group = res; _.forEach(this.group.cohortMembers, (member) => { member['phoneNumber'] = _.filter( @@ -324,6 +321,11 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { } public showModal(templateRef: TemplateRef) { + if (this.numberOfMembers > 15 && this.isOtzProgram) { + this.successMessage = + 'You have reached Maximum number of members in this club'; + return; + } if (this.modalRef) { this.modalRef.hide(); } @@ -498,13 +500,13 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { const cohortMemberVisit = []; const conceptStrings = [ 'OTZ ORIENTATION: YES', + 'OTZ TREATMENT LITERACY: YES', 'OTZ PARTICIPATION: YES', + 'PEER TO PEER MENTORSHIP DONE: YES', 'OTZ LEADERSHIP: YES', - 'OTZ TREATMENT LITERACY: YES', + 'EDUCATION ON PREVENTION METHODS DONE: YES', 'OTZ FUTURE DECISION MAKING: YES', - 'TRANSITION TO ADULT CARE: YES', - 'OTZ SRH: YES', - 'OTZ BEYOND THIRD 90: YES' + 'TRANSITION TO ADULT CLINIC: YES' ]; for (const member of cohortMembers) { const memberRow = { @@ -514,6 +516,8 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { contacts: member.person.patientPhoneNumber, member_since: this.datePipe.transform(member.startDate), member_to: this.datePipe.transform(member.endDate), + gender: member.person.gender, + age: member.person.age, latest_vl: summaryMap.has(member.person.uuid) ? summaryMap.get(member.person.uuid).latest_vl : '', @@ -643,22 +647,24 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { width: 100 }, { headerName: 'Name', field: 'name', pinned: 'left', width: 100 }, - { headerName: 'Contacts', field: 'contacts', pinned: 'left', width: 100 }, - { - headerName: 'Member From', - field: 'member_since', - pinned: 'left', - width: 100 - }, - { - headerName: 'Member To', - field: 'member_to', - pinned: 'left', - width: 100 - } + { headerName: 'Contacts', field: 'contacts', pinned: 'left', width: 100 } ); let index = 0; if (!this.isOtzProgram) { + columns.push( + { + headerName: 'Member From', + field: 'member_since', + pinned: 'left', + width: 100 + }, + { + headerName: 'Member To', + field: 'member_to', + pinned: 'left', + width: 100 + } + ); for (const cohortVisit of cohortVisits) { columns.push({ headerName: `${this.datePipe.transform( @@ -679,6 +685,18 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { if (this.isOtzProgram) { columns.push( + { + headerName: 'Gender', + field: 'gender', + pinned: 'left', + width: 80 + }, + { + headerName: 'Age', + field: 'age', + pinned: 'left', + width: 80 + }, { headerName: 'Latest VL', field: 'latest_vl', @@ -821,7 +839,7 @@ export class GroupDetailComponent implements OnInit, OnDestroy, AfterViewInit { } private validateAge(patient) { - if (patient._person.age >= 9 && patient._person.age <= 19) { + if (patient._person.age > 9 && patient._person.age <= 24) { this.showOTZEnrollmentMsg = true; } else { this.showOTZEnrollmentMsg = false; diff --git a/src/app/group-manager/group-editor/group-editor-component.html b/src/app/group-manager/group-editor/group-editor-component.html index 39a11405b..9c7043b7f 100644 --- a/src/app/group-manager/group-editor/group-editor-component.html +++ b/src/app/group-manager/group-editor/group-editor-component.html @@ -241,6 +241,32 @@ +
    + +
    + + + + + +
    +

    diff --git a/src/app/group-manager/group-editor/group-editor-component.ts b/src/app/group-manager/group-editor/group-editor-component.ts index 8a3b3eb89..79c3260f0 100644 --- a/src/app/group-manager/group-editor/group-editor-component.ts +++ b/src/app/group-manager/group-editor/group-editor-component.ts @@ -38,6 +38,25 @@ export class GroupEditorComponent implements OnInit { public provider: any; public address: string; public groupType: any; + public visitStartedToday: boolean; + retroVisitDate: any; + visitStartedForThisDate: boolean; + retrospectiveOn: boolean; + public visitStartedRetro: boolean; + selectedFutureGroupVisitDate: boolean; + public visitTypes = []; + selectedPastGroupVisitDate: boolean; + public currentMonth = Moment().month() + 1; + public today = { + year: Moment().year(), + month: this.currentMonth, + day: Moment().date() + }; + public groupDateCreated: any = { + date: this.today, + jsdate: new Date(), + formatted: Moment().format('YYYY-MM-DD') + }; public editType = 'create'; public actionButtonText = `${this.editType} Group`; public groupTypes: any = []; @@ -284,7 +303,8 @@ export class GroupEditorComponent implements OnInit { name: this.groupName, description: '', location: this.facility.value, - startDate: Moment().format('YYYY-MM-DD'), + startDate: + this.groupDateCreated.formatted || Moment().format('YYYY-MM-DD'), cohortType: DEFAULT_GROUP_TYPE, groupCohort: true, attributes: attributes @@ -481,6 +501,9 @@ export class GroupEditorComponent implements OnInit { this.showGroupActivity = true; } + public changedGroupVisitDate(event) { + this.groupDateCreated = event; + } public onProgramChanged(event) { if (event.value === this.otzProgramUuid) { this.autoGenerateOTZGroupNumber(); diff --git a/src/app/group-manager/group-manager-search/group-manager-search.component.html b/src/app/group-manager/group-manager-search/group-manager-search.component.html index 84516fa30..1af579c73 100644 --- a/src/app/group-manager/group-manager-search/group-manager-search.component.html +++ b/src/app/group-manager/group-manager-search/group-manager-search.component.html @@ -70,7 +70,7 @@

    Group Search

    margin-left: 15px; " > - View All OTZ Groups In This Facility + View All OTZ Clubs In This Facility { - this.groupsInCurrentFacility = res.map((result) => new Group(result)); - this.generatePatientUuids(this.groupsInCurrentFacility); + this.groupsInCurrentFacility = res.map((result) => { + const groupInstance = new Group(result); + const cohortUuid = this.generateCohortUuids([groupInstance]); + this.cohortOtzModuleResourceService + .getPatientsSuppressionStatus(Array.from(cohortUuid.keys())) + .subscribe((supressionRate: any) => { + if (supressionRate.result.length > 0) { + groupInstance.viralSuppression = + supressionRate.result[0].suppression_rate_percentage.toFixed( + 2 + ) + '%'; + } + }); + return groupInstance; + }); this.hideGroupsInCurrentFacility = false; this.fetchingGroups = false; this.isOTZprogram = false; @@ -141,17 +156,17 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { this.gridOptions.api.onFilterChanged(); } }); + this.columnDefs = this.generateColumns(); this.subscription.add(sub); } - public generatePatientUuids(cohort) { - // create an object with patient uuids as keys for each group - const patientUuids = {}; + public generateCohortUuids(cohort) { + const patientUuids = new Map(); cohort.forEach((uuid) => { - patientUuids[uuid._openmrsModel.uuid] = uuid._openmrsModel.uuid; + patientUuids.set(uuid._openmrsModel.uuid, uuid._openmrsModel); }); - return Object.keys(patientUuids); + return patientUuids; } public navigateToGroupDetails(group, newGroup?) { diff --git a/src/app/models/group.model.ts b/src/app/models/group.model.ts index 9ca745c94..a5a9c6310 100644 --- a/src/app/models/group.model.ts +++ b/src/app/models/group.model.ts @@ -4,6 +4,7 @@ import * as _ from 'lodash'; const program_visits_config = require('../program-visit-encounter-search/program-visits-config.json'); export class Group extends BaseModel { + private _viralSuppression: string; constructor(openmrsModel?: any) { super(openmrsModel); this._openmrsModel.display = this._openmrsModel.name; @@ -88,9 +89,12 @@ export class Group extends BaseModel { return this.getAttribute(attrType, this._openmrsModel.attributes); } - @serializable() public get viralSuppression() { - return Math.floor(Math.random() * 100) + 1 + '%'; + return this._viralSuppression || 'Unkown ' + '%'; + } + + public set viralSuppression(value: string) { + this._viralSuppression = value; } @serializable() diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html index b7b675d5d..a9a9fd43e 100644 --- a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html @@ -1,6 +1,6 @@
    -

    Patient not eligible for OTZ Program (age 9 and 19)

    +

    Patient not eligible for OTZ Program (age 10 and 24)

    diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts index 0211700f3..e4c9a810a 100644 --- a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts @@ -100,7 +100,7 @@ export class OtzSnapshotComponent implements OnInit { } private getOtzEnrollments(age, enrolledPrograms) { - if (age >= 9 && age <= 19) { + if (age > 9 && age <= 24) { this.isPatientEligibleForOtz = true; } const otz = enrolledPrograms.filter( 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 2e0e064e9..301732f05 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 @@ -308,7 +308,7 @@ export class PatientBannerComponent implements OnInit, OnDestroy, OnChanges { } private getOtzEnrollments(age, enrolledPrograms) { - if (age >= 9 && age <= 19) { + if (age > 9 && age <= 24) { this.isPatientEligibleForOtz = true; } const otz = enrolledPrograms.filter( From b254c2ee28d4af7c9d51ea929a93c5f6126d0a2c Mon Sep 17 00:00:00 2001 From: sainingo Date: Wed, 13 Dec 2023 11:41:05 +0300 Subject: [PATCH 15/19] Rename variables --- src/app/etl-api/cohort-otz-module-resource.service.ts | 6 +++--- .../group-manager-search/group-manager-search.component.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/etl-api/cohort-otz-module-resource.service.ts b/src/app/etl-api/cohort-otz-module-resource.service.ts index 0c936df00..72b85ba45 100644 --- a/src/app/etl-api/cohort-otz-module-resource.service.ts +++ b/src/app/etl-api/cohort-otz-module-resource.service.ts @@ -22,7 +22,7 @@ export class CohortOtzModuleResourceService { ); } - public getPatientsSuppressionsUrl(): string { + public getCohortSuppressionsUrl(): string { return ( this.appSettingsService.getEtlRestbaseurl().trim() + 'viral-load-suppression-rate' @@ -50,11 +50,11 @@ export class CohortOtzModuleResourceService { }); } - public getPatientsSuppressionStatus(payload: string[]) { + public getCohortSuppressionStatus(payload: string[]) { if (!payload || payload.length === 0) { return null; } - return this.http.get(this.getPatientsSuppressionsUrl(), { + return this.http.get(this.getCohortSuppressionsUrl(), { params: this.getUrlRequestParams(payload) }); } diff --git a/src/app/group-manager/group-manager-search/group-manager-search.component.ts b/src/app/group-manager/group-manager-search/group-manager-search.component.ts index 65f91f3a7..ac6e6982d 100644 --- a/src/app/group-manager/group-manager-search/group-manager-search.component.ts +++ b/src/app/group-manager/group-manager-search/group-manager-search.component.ts @@ -136,7 +136,7 @@ export class GroupManagerSearchComponent implements OnInit, OnDestroy { const groupInstance = new Group(result); const cohortUuid = this.generateCohortUuids([groupInstance]); this.cohortOtzModuleResourceService - .getPatientsSuppressionStatus(Array.from(cohortUuid.keys())) + .getCohortSuppressionStatus(Array.from(cohortUuid.keys())) .subscribe((supressionRate: any) => { if (supressionRate.result.length > 0) { groupInstance.viralSuppression = From 296e053de1f1dc6cc29c31a216f710f435d36978 Mon Sep 17 00:00:00 2001 From: sainingo Date: Wed, 13 Dec 2023 16:28:46 +0300 Subject: [PATCH 16/19] Refactoring --- .../otz-snapshot/otz-snapshot.component.html | 14 +++---- .../otz-snapshot/otz-snapshot.component.ts | 40 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html index a9a9fd43e..f9364cfb6 100644 --- a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.html @@ -3,16 +3,16 @@

    Patient not eligible for OTZ Program (age 10 and 24)

    -
    -

    - OTZ Program (discontinued on +
    +

    + OTZ Program (Discontinued on {{ otzDiscontinuationDate | date: 'dd-MM-yyyy' }})

    -

    - Reason for discontinuation: - {{ reasonForDiscontinuation }} -

    +

    + Reason for Discontinuation: + {{ reasonForDiscontinuation }} +

    diff --git a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts index e4c9a810a..3974c4851 100644 --- a/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts +++ b/src/app/patient-dashboard/common/otz-snapshot/otz-snapshot.component.ts @@ -73,23 +73,7 @@ export class OtzSnapshotComponent implements OnInit { this.getOtzEnrollments(patient.person.age, patient.enrolledPrograms); this.getHivSummary(patient); this.getHistoricalPatientLabResults(patient); - this.encounterResource - .getEncounterByUuid('409b4532-9013-4ceb-8519-adb94136230f') - .subscribe((res) => { - if (res && patient.person.uuid === res.patient.uuid) { - const reasonForDiscontinuation = res.obs.find((obs) => { - return ( - obs.concept.uuid === 'a89e3f94-1350-11df-a1f1-0026b9348838' - ); - }); - if (reasonForDiscontinuation) { - this.isOtzDiscontinued = true; - this.reasonForDiscontinuation = - reasonForDiscontinuation.value.display; - this.otzDiscontinuationDate = res.encounterDatetime; - } - } - }); + this.getOtzDiscontinuation(patient); } } ); @@ -100,9 +84,6 @@ export class OtzSnapshotComponent implements OnInit { } private getOtzEnrollments(age, enrolledPrograms) { - if (age > 9 && age <= 24) { - this.isPatientEligibleForOtz = true; - } const otz = enrolledPrograms.filter( (program) => program.concept.uuid === 'fd90d6b2-7302-4a9c-ad1b-1f93eff77afb' @@ -113,6 +94,25 @@ export class OtzSnapshotComponent implements OnInit { } else { this.dateCompleted = otz[0].dateCompleted; } + if (age > 9 && age <= 24) { + this.isPatientEligibleForOtz = true; + } + } + + private getOtzDiscontinuation(patient) { + patient.encounters.filter((encounter) => { + console.log(encounter); + const reasonForDiscontinuation = encounter.obs.filter((obs) => { + return obs.concept.uuid === 'a89e3f94-1350-11df-a1f1-0026b9348838'; + }); + console.log(reasonForDiscontinuation); + if (reasonForDiscontinuation.length > 0) { + this.isOtzDiscontinued = true; + this.reasonForDiscontinuation = + reasonForDiscontinuation[0].value.display; + this.otzDiscontinuationDate = encounter.encounterDatetime; + } + }); } public getHivSummary(patient) { From 429777fde4fc68009e59f9ea3683b1f261515242 Mon Sep 17 00:00:00 2001 From: Angie-540 <96350406+Angie-540@users.noreply.github.com> Date: Thu, 14 Dec 2023 11:19:34 +0300 Subject: [PATCH 17/19] POC-599:Add Jua Mtoto Wako to program snapshot (#1691) * POC-599:Add Jua Mtoto Wako to program snapshot * POC-599: Add JMW to program snapshot * POC-599: Add Jua Mtoto Wako to program snapshot --------- Co-authored-by: Rugut Kibet Enock --- .../hiv-program-snapshot.component.html | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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 a9a4f621c..520c5fd7f 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 @@ -72,6 +72,20 @@ >

    +
    +

    + Jua Mtoto Wako +

    +

    Date: Thu, 14 Dec 2023 12:10:54 +0300 Subject: [PATCH 18/19] POC-605:Remove CovidAlert from program snapshot (#1690) Co-authored-by: Rugut Kibet Enock --- .../hiv-program-snapshot.component.html | 36 ------------------- 1 file changed, 36 deletions(-) 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 520c5fd7f..838eaba9c 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 @@ -19,42 +19,6 @@ >

    -
    -

    - COVID-19 Assessment Status : - {{ covid19VaccinationSummary?.vaccination_status }} -

    -
    -
    -

    - COVID-19 Screening Outcome : - {{ - covid19VaccinationSummary?.covid_screening_outcome_this_visit - }} -

    -