diff --git a/src/actions/CT/OTZ/OtzAlhivOnArtByAgeSexActions.js b/src/actions/CT/OTZ/OtzAlhivOnArtByAgeSexActions.js new file mode 100644 index 00000000..f2273a1a --- /dev/null +++ b/src/actions/CT/OTZ/OtzAlhivOnArtByAgeSexActions.js @@ -0,0 +1,36 @@ +import moment from 'moment'; +import { CACHING, PAGES } from '../../../constants'; +import * as actionTypes from '../../types'; +import { getAll } from '../../../views/Shared/Api'; + +export const loadAlhivOnArtByAgeSex = () => async (dispatch, getState) => { + const diffInMinutes = moment().diff( + moment(getState().otzAlhivOnArtByAgeSex.lastFetch), + 'minutes' + ); + if (getState().ui.ctTab !== 'otz' && + getState().ui.currentPage !== PAGES.ct) { + return; + } + else if ((diffInMinutes < CACHING.LONG) && getState().filters.filtered === false) { + return; + } else { + await dispatch(fetchAlhivOnArtByAgeSex()); + } +} + +export const fetchAlhivOnArtByAgeSex = () => async (dispatch, getState) => { + dispatch({ type: actionTypes.CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_REQUEST }); + const params = { + county: getState().filters.counties, + subCounty: getState().filters.subCounties, + facility: getState().filters.facilities, + partner: getState().filters.partners, + agency: getState().filters.agencies, + project: getState().filters.projects, + gender: getState().filters.genders, + datimAgeGroup: getState().filters.datimAgeGroups, + }; + const response = await getAll('care-treatment/getAlhivOnArtByAgeSex', params); + dispatch({ type: actionTypes.CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_FETCH, payload: { filtered: getState().filters.filtered, list: response }}); +}; diff --git a/src/actions/types.js b/src/actions/types.js index 1cf33da2..688cb4a1 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -625,6 +625,10 @@ export const CT_OTZ_VL_SUPPRESSION_NOT_ENROLLED_BY_PARTNER_REQUEST = 'CT_OTZ_VL_ export const CT_OTZ_VL_SUPPRESSION_NOT_ENROLLED_BY_PARTNER_FETCH = 'CT_OTZ_VL_SUPPRESSION_NOT_ENROLLED_BY_PARTNER_FETCH'; export const CT_OTZ_VL_SUPPRESSION_NOT_ENROLLED_BY_PARTNER_FAILED = 'CT_OTZ_VL_SUPPRESSION_NOT_ENROLLED_BY_PARTNER_FAILED'; +export const CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_REQUEST = 'CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_REQUEST'; +export const CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_FETCH = 'CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_FETCH'; +export const CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_FAILED = 'CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_FAILED'; + export const CT_OVC_OVERALL_SERV_REQUEST = 'CT_OVC_OVERALL_SERV_REQUEST' export const CT_OVC_OVERALL_SERV_FETCH = 'CT_OVC_OVERALL_SERV_FETCH' export const CT_OVC_OVERALL_SERV_FAILED = 'CT_OVC_OVERALL_SERV_FAILED' diff --git a/src/reducers/CT/OTZ/otzAlhivOnArtByAgeSex.js b/src/reducers/CT/OTZ/otzAlhivOnArtByAgeSex.js new file mode 100644 index 00000000..ca0705ab --- /dev/null +++ b/src/reducers/CT/OTZ/otzAlhivOnArtByAgeSex.js @@ -0,0 +1,31 @@ +import * as actionTypes from "../../../actions/types"; + +const initialState = { + lastFetch: null, + loading: false, + listUnfiltered: [], + listFiltered: [], +}; + +export default (state = initialState, action) => { + let newState = { ...state }; + switch (action.type) { + case actionTypes.CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_REQUEST: + newState.loading = true; + return newState; + case actionTypes.CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_FETCH: + if (action.payload.filtered === true) { + newState.listFiltered = action.payload.list; + } else { + newState.listUnfiltered = action.payload.list; + newState.lastFetch = Date.now(); + } + newState.loading = false; + return newState; + case actionTypes.CT_OTZ_ALHIV_ON_ART_BY_AGE_SEX_FAILED: + newState.loading = false; + return newState; + default: + return state; + } +} diff --git a/src/reducers/index.js b/src/reducers/index.js index a5652607..fdde4b82 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -149,6 +149,7 @@ import otzOutcomesByPartner from './CT/OTZ/otzOutcomesByPartner'; import otzTotalAdolescents from './CT/OTZ/otzTotalAdolescents'; import otzEnrolled from './CT/OTZ/otzEnrolled'; import otzTotalWithVlResults from './CT/OTZ/otzTotalWithVlResults'; +import otzAlhivOnArtByAgeSex from './CT/OTZ/otzAlhivOnArtByAgeSex'; import otzTotalWithWithResultsLessThan1000 from './CT/OTZ/otzTotalWithWithResultsLessThan1000'; import ovcOverallServ from './CT/OVC/ovcOverallServ'; import ovcServByGender from './CT/OVC/ovcServByGender'; @@ -456,6 +457,7 @@ export default combineReducers({ consistencyByFacilityNotReported, + otzAlhivOnArtByAgeSex, otzEnrollmentAmongAlhivOnArtBySex, otzEnrollmentAmongAlhivOnArtByAge, otzEnrollmentAmongAlhivOnArtByCounty, diff --git a/src/selectors/AgeGroupsArray.js b/src/selectors/AgeGroupsArray.js index a0f3ce23..5e428b69 100644 --- a/src/selectors/AgeGroupsArray.js +++ b/src/selectors/AgeGroupsArray.js @@ -1,3 +1,4 @@ export let childrenAgeGroups = [' Under 1', '01 to 04','05 to 09','10 to 14']; export let adultAgeGroups = ['15 to 19','20 to 24','25 to 29','30 to 34','35 to 39','40 to 44','45 to 49','50 to 54','55 to 59','60 to 64','65+']; export let ovcAgeGroups = [' Under 1', '01 to 04','05 to 09','10 to 14', '15 to 19']; +export let otzAgeGroups = ['10 to 14', '15 to 19']; diff --git a/src/selectors/CT/OTZ/otzAlhivOnArtByAgeSex.js b/src/selectors/CT/OTZ/otzAlhivOnArtByAgeSex.js new file mode 100644 index 00000000..916d413b --- /dev/null +++ b/src/selectors/CT/OTZ/otzAlhivOnArtByAgeSex.js @@ -0,0 +1,40 @@ +import { createSelector } from 'reselect'; +import * as ageGroups from '../../AgeGroupsArray'; +import _ from 'lodash'; + +const filtered = state => state.filters.filtered; +const listFiltered = state => state.otzAlhivOnArtByAgeSex.listFiltered; +const listUnfiltered = state => state.otzAlhivOnArtByAgeSex.listUnfiltered; + +export const getOtzAlhivOnArtByAgeSex = createSelector( + [listUnfiltered, listFiltered, filtered], + (listUnfiltered, listFiltered, filtered) => { + const list = filtered ? listFiltered : listUnfiltered; + let otzAgeGroups = ageGroups.otzAgeGroups; + + let distributionMale = []; + let distributionFemale = []; + + for (const ageGroup of otzAgeGroups) { + const ageGroupMaleFilter = list?.filter(obj => obj.AgeGroup === ageGroup && (obj.Gender.toLowerCase() === "M".toLowerCase() || obj.Gender.toLowerCase() === "Male".toLowerCase())); + const ageGroupFemaleFilter = list.filter(obj => obj.AgeGroup === ageGroup && (obj.Gender.toLowerCase() === "F".toLowerCase() || obj.Gender.toLowerCase() === "Female".toLowerCase())); + if (ageGroupMaleFilter.length > 0) { + distributionMale.push(ageGroupMaleFilter[0].CALHIVonART); + } else { + distributionMale.push(0); + } + + if (ageGroupFemaleFilter.length > 0) { + distributionFemale.push(ageGroupFemaleFilter[0].CALHIVonART); + } else { + distributionFemale.push(0); + } + } + + let max = _.max([_.max(distributionMale), _.max(distributionFemale)]); + distributionMale = distributionMale.map(x => x * -1); + + return { max, otzAgeGroups, distributionMale, distributionFemale }; + // return filtered ? listFiltered : listUnfiltered; + } +); diff --git a/src/selectors/CT/OTZ/otzDistributionOfPatientsByAgeSex.js b/src/selectors/CT/OTZ/otzDistributionOfPatientsByAgeSex.js index b8244286..8458e7e2 100644 --- a/src/selectors/CT/OTZ/otzDistributionOfPatientsByAgeSex.js +++ b/src/selectors/CT/OTZ/otzDistributionOfPatientsByAgeSex.js @@ -11,8 +11,8 @@ export const getOtzDistributionOfPatientsByAgeSex = createSelector( [listUnfiltered, listFiltered, filtered], (listUnfiltered, listFiltered, filtered) => { const list = filtered ? listFiltered : listUnfiltered; - - let otzAgeGroups = ['10 to 14', '15 to 19', '20 to 24']; + + let otzAgeGroups = ['10 to 14', '15 to 19']; let distributionMale = []; let distributionFemale = []; diff --git a/src/selectors/CT/OTZ/otzNotEnrolledAmongAlHivByPartner.js b/src/selectors/CT/OTZ/otzNotEnrolledAmongAlHivByPartner.js index 75b147be..e4f37595 100644 --- a/src/selectors/CT/OTZ/otzNotEnrolledAmongAlHivByPartner.js +++ b/src/selectors/CT/OTZ/otzNotEnrolledAmongAlHivByPartner.js @@ -19,7 +19,7 @@ export const getOtzNotEnrolledAmongAlHivOnArtByPartner = createSelector( (obj) =>{ return obj.partner === listElement.CTPartner; }); - + if (filterTotalAdolescents.length > 0) { const percentage = (listElement.Num / @@ -33,7 +33,7 @@ export const getOtzNotEnrolledAmongAlHivOnArtByPartner = createSelector( }); } } - + arrayVal.sort((a, b) => { return b.y - a.y; }); diff --git a/src/selectors/CT/OTZ/otzProportionOfAlHivEnrolledInOtzWhoHaveCompletedTrainingByCounty.js b/src/selectors/CT/OTZ/otzProportionOfAlHivEnrolledInOtzWhoHaveCompletedTrainingByCounty.js index 89175481..ecaea5bb 100644 --- a/src/selectors/CT/OTZ/otzProportionOfAlHivEnrolledInOtzWhoHaveCompletedTrainingByCounty.js +++ b/src/selectors/CT/OTZ/otzProportionOfAlHivEnrolledInOtzWhoHaveCompletedTrainingByCounty.js @@ -17,7 +17,7 @@ export const getProportionOfAlhivEnrolledInOtzWhoHaveCompletedTrainingByCounty = let percent = 0; const selectedCounty = listCounty.filter(obj => obj.County === listElement.County); if (selectedCounty.length > 0) { - percent = ((listElement.count_training / selectedCounty[0].count_training) * 100); + percent = ((listElement.count_training / selectedCounty[0].alhiv) * 100); } ArrayList.push( { diff --git a/src/selectors/CT/OTZ/otzProportionOfAlHivEnrolledInOtzWhoHaveCompletedTrainingByPartner.js b/src/selectors/CT/OTZ/otzProportionOfAlHivEnrolledInOtzWhoHaveCompletedTrainingByPartner.js index a6c867c6..5213767a 100644 --- a/src/selectors/CT/OTZ/otzProportionOfAlHivEnrolledInOtzWhoHaveCompletedTrainingByPartner.js +++ b/src/selectors/CT/OTZ/otzProportionOfAlHivEnrolledInOtzWhoHaveCompletedTrainingByPartner.js @@ -17,8 +17,9 @@ export const getProportionOfAlhivEnrolledInOtzWhoHaveCompletedTrainingByPartner let percent = 0; const selectedPartner = listPartner.filter(obj => obj.partner === listElement.partner); if (selectedPartner.length > 0) { - percent = ((listElement.count_training / selectedPartner[0].count_training) * 100); + percent = ((listElement.count_training / selectedPartner[0].alhiv) * 100); } + console.log(selectedPartner[0].alhiv, percent, listElement.count_training) ArrayList.push( { count_training: listElement.count_training, diff --git a/src/views/CT/CT.js b/src/views/CT/CT.js index 1c28d7f7..3bf98fd2 100644 --- a/src/views/CT/CT.js +++ b/src/views/CT/CT.js @@ -335,14 +335,14 @@ import { import { loadViralLoadOverallNumberGt1000CopiesSecondlineRegiment } from '../../actions/CT/ViralLoad/viralLoadOverallNumberTestsGt1000CopiesSecondlineRegiment'; -import { loadCurrentOnArtVerified } from './../../actions/CT/CurrentOnArt/currentOnArtVerifiedActions'; +import { loadCurrentOnArtVerified } from '../../actions/CT/CurrentOnArt/currentOnArtVerifiedActions'; import { loadCurrentOnArtVerifiedByPartner } from './../../actions/CT/CurrentOnArt/currentOnArtVerifiedByPartnerActions'; import { loadCurrentOnArtVerifiedByCounty } from './../../actions/CT/CurrentOnArt/currentOnArtVerifiedByCountyActions'; -import { loadCurrentOnArtVerifiedByAgeSex } from './../../actions/CT/CurrentOnArt/currentOnArtVerifiedByAgeSexActions'; +import { loadCurrentOnArtVerifiedByAgeSex } from '../../actions/CT/CurrentOnArt/currentOnArtVerifiedByAgeSexActions'; import { loadOtzEnrollmentTrend } from '../../actions/CT/OTZ/OtzEnrollmentTrendsActions'; import { loadOtzEnrollmentByAgeSex } from '../../actions/CT/OTZ/OtzEnrollmentByAgeSexActions'; import { loadOtzNotEnrolledPartner } from '../../actions/CT/OTZ/OtzNotEnrolledByPartnerActions'; -import { loadOtzNotEnrolledCounty } from './../../actions/CT/OTZ/OtzNotEnrolledByCountyActions'; +import { loadOtzNotEnrolledCounty } from '../../actions/CT/OTZ/OtzNotEnrolledByCountyActions'; import { loadAlHivWithReSuppression } from '../../actions/CT/OTZ/AlHivWithReSuppressionActions'; import { loadOtzVlSuppressionByAgeNotEnrolled } from '../../actions/CT/OTZ/OtzVlSuppressionByAgeNotEnrolledActions'; import { loadOtzVlSuppressionBySexNotEnrolled } from '../../actions/CT/OTZ/OtzVlSuppressionBySexNotEnrolledActions'; @@ -361,6 +361,7 @@ import { loadIITTracing } from './../../actions/CT/TreatmentOutcomes/IITTracingA import { loadIITTracingOutcomes } from './../../actions/CT/TreatmentOutcomes/IITTracingOutcomesActions'; import { loadViralLoadUptakeUToU } from '../../actions/CT/ViralLoad/viralLoadUptakeUToUActions'; import { loadViralLoadCategorizationUToU } from '../../actions/CT/ViralLoad/viralLoadCategorizationUToUActions'; +import { loadAlhivOnArtByAgeSex } from '../../actions/CT/OTZ/OtzAlhivOnArtByAgeSexActions'; const NewOnArt = Loadable({ loader: () => import('./NewOnArt/NewOnArt'), loading: Loading, delay: LOADING_DELAY }); const CurrentOnArt = Loadable({ @@ -729,6 +730,7 @@ const CT = () => { dispatch(loadOtzVlSuppressionBySexNotEnrolled()); dispatch(loadOtzVlSuppressionByPartnerNotEnrolled()); dispatch(loadOtzVlSuppressionByCountyNotEnrolled()); + dispatch(loadAlhivOnArtByAgeSex()); break; case 'ovc': dispatch(loadOvcOverallServ()); diff --git a/src/views/CT/OTZ/OTZByAgeSex.js b/src/views/CT/OTZ/OTZByAgeSex.js index cdd837b0..b311700a 100644 --- a/src/views/CT/OTZ/OTZByAgeSex.js +++ b/src/views/CT/OTZ/OTZByAgeSex.js @@ -43,16 +43,7 @@ const OTZByAgeSex = () => { }, }, }, - { - // min: -ovcAgeSex.distributionMale.max, - // max: ovcAgeSex.distributionFemale.max, - title: { text: 'MALE' }, - labels: { - formatter: function () { - return Math.abs(this.value); - }, - }, - }, + ], plotOptions: { series: { stacking: 'normal' }, @@ -107,7 +98,7 @@ const OTZByAgeSex = () => { - + ); }; diff --git a/src/views/CT/OTZ/OTZDistributionOfCALHIVByAgeSex.js b/src/views/CT/OTZ/OTZDistributionOfCALHIVByAgeSex.js new file mode 100644 index 00000000..779f8813 --- /dev/null +++ b/src/views/CT/OTZ/OTZDistributionOfCALHIVByAgeSex.js @@ -0,0 +1,98 @@ +import { Card, CardBody, CardHeader } from 'reactstrap'; +import HighchartsReact from 'highcharts-react-official'; +import Highcharts from 'highcharts'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useSelector } from 'react-redux'; +import * as otzDistributionOfCALHIVByAgeSexSelector from '../../../selectors/CT/OTZ/otzAlhivOnArtByAgeSex'; + +const OTZDistributionOfCALHIVByAgeSex = () => { + const [ovcDistributionOfALHIVByAgeSex, setOvcDistributionOfALHIVByAgeSex] = useState({}); + const distributionOfALHIVByAgeSex = useSelector(otzDistributionOfCALHIVByAgeSexSelector.getOtzAlhivOnArtByAgeSex); + + const loadOvcDistributionOfALHIVByAgeSex = useCallback(async () => { + setOvcDistributionOfALHIVByAgeSex({ + chart: { type: 'bar' }, + title: { text: '' }, + xAxis: [ + { + categories: [ + '15 to 19', + '10 to 14', + ], + title: { text: '' }, + reversed: false, + }, + { + categories: [ + '15 to 19', + '10 to 14', + ], + title: { text: '' }, + reversed: false, + linkedTo: 0, + opposite: true, + }, + ], + yAxis: [ + { + min: -distributionOfALHIVByAgeSex.max, + max: distributionOfALHIVByAgeSex.max, + title: { text: 'Number Of Patients' }, + labels: { + formatter: function () { + return Math.abs(this.value); + }, + }, + }, + ], + plotOptions: { + series: { stacking: 'normal' }, + }, + tooltip: { + formatter: function () { + return ( + '' + + this.series.name + + ', Age Group ' + + this.point.category + + '
' + + 'Number Of Patients: ' + + Highcharts.numberFormat(Math.abs(this.point.y), 1) + ); + }, + }, + legend: { align: 'left', verticalAlign: 'top', y: 0, x: 80 }, + series: [ + { + name: 'Female', + data: distributionOfALHIVByAgeSex.distributionFemale.reverse(), + color: '#EA4C8B', + }, + { + name: 'Male', + data: distributionOfALHIVByAgeSex.distributionMale.reverse(), + color: '#14084D', + }, + ], + }); + }, [distributionOfALHIVByAgeSex]); + + useEffect(() => { + loadOvcDistributionOfALHIVByAgeSex(); + }, [loadOvcDistributionOfALHIVByAgeSex]); + + return ( + + + DISTRIBUTION OF ALHIV PATIENTS BY AGE AND SEX + + +
+ +
+
+
+ ); +}; + +export default OTZDistributionOfCALHIVByAgeSex; diff --git a/src/views/CT/OTZ/OTZTabs.js b/src/views/CT/OTZ/OTZTabs.js index 544e3c48..e73dd7e1 100644 --- a/src/views/CT/OTZ/OTZTabs.js +++ b/src/views/CT/OTZ/OTZTabs.js @@ -17,7 +17,7 @@ const OtzEnrollmentTrends = Loadable({ loading: Loading, delay: LOADING_DELAY, }); -const OVCDistributionOfCALHIVByAgeSex = Loadable({ loader: () => import('../OVC/OVCDistributionOfCALHIVByAgeSex'), loading: Loading, delay: LOADING_DELAY }); +const OTZDistributionOfCALHIVByAgeSex = Loadable({ loader: () => import('./OTZDistributionOfCALHIVByAgeSex'), loading: Loading, delay: LOADING_DELAY }); const OtzEnrollmentAmongAlhivOnArtByPartner = Loadable({ loader: () => import('./OtzEnrollmentAmongAlhivOnArtByPartner'), loading: Loading, delay: LOADING_DELAY }); const OtzNotEnrolledAmongAlhivOnArtByCounty = Loadable({ loader: () => import('./OtzNotEnrolledAmongAlhivOnArtByCounty'), @@ -207,7 +207,7 @@ const OTZTabs = () => { UNSUPPRESSED →{' '} Adolescents on OTZ (10-19 years) who are current on treatment with valid viral load - results of > 1,000 copies/ml + results of ≥ 200 copies/ml
  • Completed Training →{' '} @@ -242,7 +242,7 @@ const OTZTabs = () => { - + diff --git a/src/views/CT/OTZ/OtzEnrollmentAmongAlhivOnArtBySex.js b/src/views/CT/OTZ/OtzEnrollmentAmongAlhivOnArtBySex.js index 2358742b..0a2aab41 100644 --- a/src/views/CT/OTZ/OtzEnrollmentAmongAlhivOnArtBySex.js +++ b/src/views/CT/OTZ/OtzEnrollmentAmongAlhivOnArtBySex.js @@ -56,7 +56,6 @@ const OtzEnrollmentAmongAlhivOnArtBySex = () => { crosshair: true }, yAxis: { - type: 'logarithmic', minorTickInterval: 0.1, title: { text: 'PERCENTAGE OF PATIENTS' diff --git a/src/views/CT/OTZ/OtzNotEnrolledAmongAlhivOnArtByPartner.js b/src/views/CT/OTZ/OtzNotEnrolledAmongAlhivOnArtByPartner.js index 23bff687..5ffca4f5 100644 --- a/src/views/CT/OTZ/OtzNotEnrolledAmongAlhivOnArtByPartner.js +++ b/src/views/CT/OTZ/OtzNotEnrolledAmongAlhivOnArtByPartner.js @@ -50,7 +50,7 @@ const OtzNotEnrolledAmongAlhivOnArtByPartner = () => { }, series: [ { - name: 'ADOLESCENTS RECIEVING HIV CARE, NOT ENROLLED IN OTZ BY PARTNER', + name: 'ADOLESCENTS RECEIVING HIV CARE, NOT ENROLLED IN OTZ BY PARTNER', data: otzEnrollmentsByPartner, color: '#14084D', }, @@ -68,7 +68,7 @@ const OtzNotEnrolledAmongAlhivOnArtByPartner = () => { className="trends-header" style={{ textTransform: 'none' }} > - ADOLESCENTS RECIEVING HIV CARE, NOT ENROLLED IN OTZ BY PARTNER + ADOLESCENTS RECEIVING HIV CARE, NOT ENROLLED IN OTZ BY PARTNER