diff --git a/.ddev/config.local.yaml.example b/.ddev/config.local.yaml.example index f8d2a7e7f3..8344e64089 100644 --- a/.ddev/config.local.yaml.example +++ b/.ddev/config.local.yaml.example @@ -59,4 +59,5 @@ hooks: - exec: drush vset hedley_admin_feature_tuberculosis_management_enabled 1 - exec: drush vset hedley_admin_feature_group_education_enabled 1 - exec: drush vset hedley_admin_feature_report_to_whatsapp_enabled 1 + - exec: drush vset hedley_admin_feature_hiv_management_enabled 1 - exec: drush uli diff --git a/client/src/assets/scss/_dashboard.scss b/client/src/assets/scss/_dashboard.scss index 2b0eca0115..053b7c023b 100644 --- a/client/src/assets/scss/_dashboard.scss +++ b/client/src/assets/scss/_dashboard.scss @@ -104,10 +104,9 @@ &.page-filters { background-color: transparent; min-height: 40px; - padding: 25px 0; - margin-bottom: 25px; + padding: 15px 0; + margin-bottom: 35px; display: flex; - border-bottom: solid 1px $color-white; button { background-color: $color-white; @@ -133,16 +132,11 @@ } } - &.page-filters.center { - justify-content: center; - } - - &.page-filters.nurse { - border-bottom: none; + &.page-filters.top-row { margin-bottom: 0; } - &.page-filters.nurse.center { + &.page-filters.center { justify-content: center; } @@ -721,3 +715,89 @@ width: 100%; } } + +.dashboard.group-education { + + ul.session-topics { + color: $color-white; + font-size: 24px; + font-weight: 700; + } + + .sessions-table, + .patients-table { + padding: 20px; + width: 100%; + + .entry { + background: $color-white; + border-bottom: 2px solid $color-gray-border; + display: flex; + font-size: 18px; + font-weight: 500; + padding: 20px; + text-align: center; + } + + .entry.header { + font-weight: 700; + } + + .entry:last-child { + border-bottom: none; + } + } + + .sessions-table .entry { + + .topics { + margin: 0; + padding-left: 10px; + text-align: left; + width: 380px; + + li { + line-height: 24px; + margin-bottom: 0; + } + } + + .date { + align-self: center; + margin-left: 20px; + text-align: left; + width: 120px; + } + + .attendance { + align-self: center; + width: 120px; + } + + .icon-forward { + align-self: center; + background: url(#{$img-path}icon-forward-blue.svg) center center no-repeat; + background-size: 45px 50px; + height: 50px; + width: 50px; + } + + .icon-forward.hidden { + visibility: hidden; + } + } + + .patients-table .entry { + + .name, + .gender { + align-self: center; + text-align: left; + } + + .name { + margin-left: 20px; + width: 65%; + } + } +} diff --git a/client/src/assets/scss/_new.scss b/client/src/assets/scss/_new.scss index 9465380caa..1fe50fbf3c 100644 --- a/client/src/assets/scss/_new.scss +++ b/client/src/assets/scss/_new.scss @@ -2333,7 +2333,8 @@ div.page-activity.prenatal { div.page-activity.ncd, div.page-activity.well-child, -div.page-activity.tuberculosis { +div.page-activity.tuberculosis, +div.page-activity.hiv { .ui.full.segment .full.content { @@ -3557,12 +3558,7 @@ div.page-participant.group { } } -div.page-participant.acute-illness, -div.page-participant.nutrition, -div.page-participant.home-visit, -div.page-participant.well-child, -div.page-participant.prenatal, -div.page-participant.ncd { +div.page-participant.individual { padding-bottom: 35px; p { @@ -3885,7 +3881,11 @@ div.page-encounter.child-scoreboard, div.page-activity.child-scoreboard, div.page-report.child-scoreboard, div.page-encounter.tuberculosis, -div.page-activity.tuberculosis { +div.page-activity.tuberculosis, +div.page-report.tuberculosis, +div.page-encounter.hiv, +div.page-activity.hiv, +div.page-report.hiv { .details { padding-left: 25px; @@ -4696,6 +4696,39 @@ div.page-activity.patient-record { margin: auto 0; } + .heading.group-education, + .entry.group-education { + display: grid; + grid-gap: 20px; + grid-template-columns: 60% auto; + text-align: center; + } + + .entry.group-education { + background: $color-white; + border-bottom: 2px solid $color-gray-border; + font-size: 18px; + font-weight: 500; + text-align: left; + } + + .entry.group-education.header { + font-weight: 700; + } + + .entry.group-education:last-child { + border-bottom: none; + } + .entry.group-education .topics { + margin: 0; + padding-left: 20px; + } + + .entry.group-education .date { + align-self: center; + text-align: center; + } + .ui.unstackable.items .actions { margin-bottom: 30px; } @@ -4816,6 +4849,7 @@ div.page-activity.ncd { } } } + div.page-activity.wellbeing { .ui.button .counter { @@ -5482,3 +5516,49 @@ div.page-activity.stock-management { } } + +div.page-activity.hiv { + + .ui.full.segment { + + .form.danger-signs { + + .label { + font-weight: 500; + } + + .label.header { + font-size: 24px; + font-weight: 700; + } + + .form-input.date { + border: 2px solid $color-light-gray; + color: $color-text; + height: 2em; + padding: 5px; + text-align: center; + width: 80%; + } + + input.checkbox, + input.checkbox:focus { + height: 3rem; + width: 100%; + } + } + + .form.prescribed-medication { + + .checkbox-select-input .section { + margin-bottom: 30px; + margin-top: 40px; + + .label { + margin-left: 20px; + } + } + } + + } +} diff --git a/client/src/elm/App/Fetch.elm b/client/src/elm/App/Fetch.elm index aa1dbb7d2d..8263e7b563 100644 --- a/client/src/elm/App/Fetch.elm +++ b/client/src/elm/App/Fetch.elm @@ -24,6 +24,9 @@ import Pages.EducationSession.Fetch import Pages.EducationSession.Model import Pages.GlobalCaseManagement.Fetch import Pages.GroupEncounterTypes.Fetch +import Pages.HIV.Activity.Fetch +import Pages.HIV.Encounter.Fetch +import Pages.HIV.Participant.Fetch import Pages.HomeVisit.Activity.Fetch import Pages.HomeVisit.Encounter.Fetch import Pages.IndividualEncounterParticipants.Fetch @@ -237,6 +240,15 @@ fetch model = ) |> Maybe.withDefault [] + UserPage (HIVParticipantPage personId) -> + getLoggedInData model + |> Maybe.map + (\_ -> + Pages.HIV.Participant.Fetch.fetch personId model.indexedDb + |> List.map MsgIndexedDb + ) + |> Maybe.withDefault [] + UserPage (IndividualEncounterParticipantsPage encounterType) -> getLoggedInData model |> Maybe.map @@ -379,6 +391,14 @@ fetch model = ) |> Maybe.withDefault [] + UserPage (HIVEncounterPage id) -> + Pages.HIV.Encounter.Fetch.fetch id model.indexedDb + |> List.map MsgIndexedDb + + UserPage (HIVActivityPage id activity) -> + Pages.HIV.Activity.Fetch.fetch id activity model.indexedDb + |> List.map MsgIndexedDb + UserPage (NutritionProgressReportPage id) -> Pages.Nutrition.ProgressReport.Fetch.fetch id model.indexedDb |> List.map MsgIndexedDb diff --git a/client/src/elm/App/Model.elm b/client/src/elm/App/Model.elm index 1894977b71..0236d0fedb 100644 --- a/client/src/elm/App/Model.elm +++ b/client/src/elm/App/Model.elm @@ -18,6 +18,7 @@ import AssocList as Dict exposing (Dict) import Backend.AcuteIllnessActivity.Model exposing (AcuteIllnessActivity) import Backend.ChildScoreboardActivity.Model exposing (ChildScoreboardActivity) import Backend.Entities exposing (..) +import Backend.HIVActivity.Model exposing (HIVActivity) import Backend.HomeVisitActivity.Model exposing (HomeVisitActivity) import Backend.Measurement.Model exposing (LaboratoryTest) import Backend.Model @@ -46,6 +47,8 @@ import Pages.Dashboard.Model import Pages.Device.Model import Pages.EducationSession.Model import Pages.GlobalCaseManagement.Model +import Pages.HIV.Activity.Model +import Pages.HIV.Encounter.Model import Pages.HomeVisit.Activity.Model import Pages.HomeVisit.Encounter.Model import Pages.IndividualEncounterParticipants.Model @@ -309,6 +312,8 @@ type alias LoggedInModel = , tuberculosisEncounterPages : Dict TuberculosisEncounterId Pages.Tuberculosis.Encounter.Model.Model , tuberculosisActivityPages : Dict ( TuberculosisEncounterId, TuberculosisActivity ) Pages.Tuberculosis.Activity.Model.Model , educationSessionPages : Dict EducationSessionId Pages.EducationSession.Model.Model + , hivEncounterPages : Dict HIVEncounterId Pages.HIV.Encounter.Model.Model + , hivActivityPages : Dict ( HIVEncounterId, HIVActivity ) Pages.HIV.Activity.Model.Model , traceContactPages : Dict AcuteIllnessTraceContactId Pages.TraceContact.Model.Model , clinicalProgressReportPages : Dict PrenatalEncounterId Pages.Prenatal.ProgressReport.Model.Model , patientRecordPages : Dict PersonId Pages.PatientRecord.Model.Model @@ -360,6 +365,8 @@ emptyLoggedInModel site villageId nurse = , tuberculosisEncounterPages = Dict.empty , tuberculosisActivityPages = Dict.empty , educationSessionPages = Dict.empty + , hivEncounterPages = Dict.empty + , hivActivityPages = Dict.empty , traceContactPages = Dict.empty , clinicalProgressReportPages = Dict.empty , patientRecordPages = Dict.empty @@ -425,6 +432,7 @@ type MsgLoggedIn | MsgPageNCDRecurrentEncounter NCDEncounterId Pages.NCD.RecurrentEncounter.Model.Msg | MsgPageChildScoreboardEncounter ChildScoreboardEncounterId Pages.ChildScoreboard.Encounter.Model.Msg | MsgPageTuberculosisEncounter TuberculosisEncounterId Pages.Tuberculosis.Encounter.Model.Msg + | MsgPageHIVEncounter HIVEncounterId Pages.HIV.Encounter.Model.Msg | MsgPageEducationSession EducationSessionId Pages.EducationSession.Model.Msg | MsgPagePrenatalActivity PrenatalEncounterId PrenatalActivity Pages.Prenatal.Activity.Model.Msg | MsgPagePrenatalRecurrentActivity PrenatalEncounterId PrenatalRecurrentActivity Pages.Prenatal.RecurrentActivity.Model.Msg @@ -437,6 +445,7 @@ type MsgLoggedIn | MsgPageNCDRecurrentActivity NCDEncounterId NCDRecurrentActivity Pages.NCD.RecurrentActivity.Model.Msg | MsgPageChildScoreboardActivity ChildScoreboardEncounterId ChildScoreboardActivity Pages.ChildScoreboard.Activity.Model.Msg | MsgPageTuberculosisActivity TuberculosisEncounterId TuberculosisActivity Pages.Tuberculosis.Activity.Model.Msg + | MsgPageHIVActivity HIVEncounterId HIVActivity Pages.HIV.Activity.Model.Msg | MsgPagePregnancyOutcome IndividualEncounterParticipantId Pages.Prenatal.Outcome.Model.Msg | MsgPageAcuteIllnessProgressReport AcuteIllnessEncounterId Pages.AcuteIllness.ProgressReport.Model.Msg | MsgPageNutritionProgressReport NutritionEncounterId Pages.Nutrition.ProgressReport.Model.Msg diff --git a/client/src/elm/App/Update.elm b/client/src/elm/App/Update.elm index 0f9abcd70d..5fab7ccdc5 100644 --- a/client/src/elm/App/Update.elm +++ b/client/src/elm/App/Update.elm @@ -51,6 +51,10 @@ import Pages.Device.Update import Pages.EducationSession.Model import Pages.EducationSession.Update import Pages.GlobalCaseManagement.Update +import Pages.HIV.Activity.Model +import Pages.HIV.Activity.Update +import Pages.HIV.Encounter.Model +import Pages.HIV.Encounter.Update import Pages.HomeVisit.Activity.Model import Pages.HomeVisit.Activity.Update import Pages.HomeVisit.Encounter.Model @@ -593,6 +597,19 @@ update msg model = , extraMsgs ) + MsgPageHIVEncounter id subMsg -> + let + ( subModel, subCmd, extraMsgs ) = + data.hivEncounterPages + |> Dict.get id + |> Maybe.withDefault Pages.HIV.Encounter.Model.emptyModel + |> Pages.HIV.Encounter.Update.update subMsg + in + ( { data | hivEncounterPages = Dict.insert id subModel data.hivEncounterPages } + , Cmd.map (MsgLoggedIn << MsgPageHIVEncounter id) subCmd + , extraMsgs + ) + MsgPagePrenatalActivity id activity subMsg -> let ( subModel, subCmd, extraMsgs ) = @@ -747,6 +764,19 @@ update msg model = , extraMsgs ) + MsgPageHIVActivity id activity subMsg -> + let + ( subModel, subCmd, extraMsgs ) = + data.hivActivityPages + |> Dict.get ( id, activity ) + |> Maybe.withDefault Pages.HIV.Activity.Model.emptyModel + |> Pages.HIV.Activity.Update.update currentDate id model.indexedDb subMsg + in + ( { data | hivActivityPages = Dict.insert ( id, activity ) subModel data.hivActivityPages } + , Cmd.map (MsgLoggedIn << MsgPageHIVActivity id activity) subCmd + , extraMsgs + ) + MsgPagePregnancyOutcome id subMsg -> let ( subModel, subCmd, appMsgs ) = diff --git a/client/src/elm/App/View.elm b/client/src/elm/App/View.elm index a77081d953..c8bebce8de 100644 --- a/client/src/elm/App/View.elm +++ b/client/src/elm/App/View.elm @@ -42,6 +42,11 @@ import Pages.EducationSession.Model import Pages.EducationSession.View import Pages.GlobalCaseManagement.View import Pages.GroupEncounterTypes.View +import Pages.HIV.Activity.Model +import Pages.HIV.Activity.View +import Pages.HIV.Encounter.Model +import Pages.HIV.Encounter.View +import Pages.HIV.Participant.View import Pages.HomeVisit.Activity.Model import Pages.HomeVisit.Activity.View import Pages.HomeVisit.Encounter.Model @@ -419,6 +424,7 @@ viewUserPage page deviceName site features geoInfo reverseGeoInfo model configur subPage currentDate site + features healthCenterId isChw (Tuple.second loggedInModel.nurse) @@ -527,6 +533,10 @@ viewUserPage page deviceName site features geoInfo reverseGeoInfo model configur Pages.Tuberculosis.Participant.View.view model.language currentDate healthCenterId id model.indexedDb |> flexPageWrapper configured.config model + HIVParticipantPage id -> + Pages.HIV.Participant.View.view model.language currentDate healthCenterId id model.indexedDb + |> flexPageWrapper configured.config model + IndividualEncounterParticipantsPage encounterType -> Pages.IndividualEncounterParticipants.View.view model.language currentDate @@ -986,6 +996,26 @@ viewUserPage page deviceName site features geoInfo reverseGeoInfo model configur |> Html.map (MsgLoggedIn << MsgPageEducationSession id) |> flexPageWrapper configured.config model + HIVEncounterPage id -> + let + page_ = + Dict.get id loggedInModel.hivEncounterPages + |> Maybe.withDefault Pages.HIV.Encounter.Model.emptyModel + in + Pages.HIV.Encounter.View.view model.language currentDate site id model.indexedDb page_ + |> Html.map (MsgLoggedIn << MsgPageHIVEncounter id) + |> flexPageWrapper configured.config model + + HIVActivityPage id activity -> + let + page_ = + Dict.get ( id, activity ) loggedInModel.hivActivityPages + |> Maybe.withDefault Pages.HIV.Activity.Model.emptyModel + in + Pages.HIV.Activity.View.view model.language currentDate id activity model.indexedDb page_ + |> Html.map (MsgLoggedIn << MsgPageHIVActivity id activity) + |> flexPageWrapper configured.config model + TraceContactPage traceContactId -> let page_ = diff --git a/client/src/elm/Backend/Dashboard/Decoder.elm b/client/src/elm/Backend/Dashboard/Decoder.elm index 375956c0ba..c747571a5b 100644 --- a/client/src/elm/Backend/Dashboard/Decoder.elm +++ b/client/src/elm/Backend/Dashboard/Decoder.elm @@ -4,6 +4,7 @@ import AssocList as Dict exposing (Dict) import Backend.AcuteIllnessEncounter.Decoder exposing (decodeAcuteIllnessDiagnosis, decodeAcuteIllnessEncounterType) import Backend.AcuteIllnessEncounter.Types exposing (AcuteIllnessDiagnosis(..), AcuteIllnessEncounterType(..)) import Backend.Dashboard.Model exposing (..) +import Backend.EducationSession.Decoder exposing (decodeEducationTopic) import Backend.Entities exposing (VillageId) import Backend.IndividualEncounterParticipant.Decoder exposing (decodeDeliveryLocation, decodeIndividualEncounterParticipantOutcome) import Backend.Measurement.Decoder @@ -71,7 +72,9 @@ decodeDashboardStatsRaw = |> required "child_scoreboard_data" (list decodeChildScoreboardDataItem) |> required "nutrition_individual_data" (list decodeNutritionIndividualDataItem) |> required "nutrition_group_data" (list decodeNutritionGroupDataItem) + |> required "group_education_data" decodeGroupEducationData |> required "villages_with_residents" decodeVillagesWithResidents + |> required "patients_details" decodePatientsDetails |> required "timestamp" string |> required "stats_cache_hash" string @@ -86,23 +89,21 @@ decodeCaseManagementData = decodeCaseManagementDataForYear : Decoder (Dict ProgramType (List CaseManagement)) decodeCaseManagementDataForYear = dict (list decodeCaseManagement) - |> andThen - (\dict -> - LegacyDict.toList dict - |> List.map - (\( k, v ) -> - ( programTypeFromString k, v ) - ) - |> Dict.fromList - |> succeed - ) + |> andThen (legacyDictToDict programTypeFromString) + + +legacyDictToDict : (String -> k) -> LegacyDict.Dict String v -> Decoder (Dict k v) +legacyDictToDict toKeyFunc = + LegacyDict.toList + >> List.map (\( k, v ) -> ( toKeyFunc k, v )) + >> Dict.fromList + >> succeed decodeCaseManagement : Decoder CaseManagement decodeCaseManagement = succeed CaseManagement |> required "id" decodeInt - |> required "name" string |> required "birth_date" decodeYYYYMMDD |> required "gender" decodeGender |> required "nutrition" decodeCaseNutrition @@ -121,16 +122,7 @@ decodeCaseNutrition = decodeNutritionValueDict : Decoder NutritionValue -> Decoder (Dict Int NutritionValue) decodeNutritionValueDict decoder = dict (decodeWithFallback (NutritionValue Neutral "X") decoder) - |> andThen - (\dict -> - LegacyDict.toList dict - |> List.map - (\( k, v ) -> - ( Maybe.withDefault 1 (String.toInt k), v ) - ) - |> Dict.fromList - |> succeed - ) + |> andThen (legacyDictToDict (String.toInt >> Maybe.withDefault 1)) decodeZScoreNutritionValue : Decoder NutritionValue @@ -168,16 +160,7 @@ decodeMuacNutritionValue = decodeChildrenBeneficiariesData : Decoder (Dict ProgramType (List ChildrenBeneficiariesStats)) decodeChildrenBeneficiariesData = dict (list decodeChildrenBeneficiariesStats) - |> andThen - (\dict -> - LegacyDict.toList dict - |> List.map - (\( k, v ) -> - ( programTypeFromString k, v ) - ) - |> Dict.fromList - |> succeed - ) + |> andThen (legacyDictToDict programTypeFromString) decodeChildrenBeneficiariesStats : Decoder ChildrenBeneficiariesStats @@ -187,20 +170,17 @@ decodeChildrenBeneficiariesStats = |> required "gender" decodeGender |> required "birth_date" decodeYYYYMMDD |> required "created" decodeYYYYMMDD - |> required "name" string - |> required "mother_name" string - |> optional "phone_number" (nullable string) Nothing + |> optional "mother_id" (nullable decodeInt) Nothing |> required "graduation_date" decodeYYYYMMDD decodeParticipantStats : Decoder ParticipantStats decodeParticipantStats = succeed ParticipantStats - |> required "name" string + |> required "id" decodeInt |> required "gender" decodeGender |> required "birth_date" decodeYYYYMMDD - |> required "mother_name" string - |> optional "phone_number" (nullable string) Nothing + |> optional "mother_id" (nullable decodeInt) Nothing |> required "expected_date" decodeYYYYMMDD @@ -229,31 +209,13 @@ decodeTotalEncountersForVillages = decodeTotalEncountersForVillages_ : Decoder (Dict VillageId (Dict ProgramType Periods)) decodeTotalEncountersForVillages_ = dict decodeTotalEncounters - |> andThen - (\dict -> - LegacyDict.toList dict - |> List.map - (\( k, v ) -> - ( toEntityUuid k, v ) - ) - |> Dict.fromList - |> succeed - ) + |> andThen (legacyDictToDict toEntityUuid) decodeTotalEncounters : Decoder (Dict ProgramType Periods) decodeTotalEncounters = dict decodePeriods - |> andThen - (\dict -> - LegacyDict.toList dict - |> List.map - (\( k, v ) -> - ( programTypeFromString k, v ) - ) - |> Dict.fromList - |> succeed - ) + |> andThen (legacyDictToDict programTypeFromString) decodePeriods : Decoder Periods @@ -291,26 +253,12 @@ programTypeFromString string = decodeVillagesWithResidents : Decoder (Dict VillageId (List Int)) decodeVillagesWithResidents = oneOf - [ decodeVillagesWithResidents_ + [ dict (list decodeInt) + |> andThen (legacyDictToDict toEntityUuid) , succeed Dict.empty ] -decodeVillagesWithResidents_ : Decoder (Dict VillageId (List Int)) -decodeVillagesWithResidents_ = - dict (list int) - |> andThen - (\dict -> - LegacyDict.toList dict - |> List.map - (\( k, v ) -> - ( toEntityUuid k, v ) - ) - |> Dict.fromList - |> succeed - ) - - decodeAcuteIllnessDataItem : Decoder AcuteIllnessDataItem decodeAcuteIllnessDataItem = succeed AcuteIllnessDataItem @@ -538,3 +486,46 @@ decodeNutritionGroupEncounterDataItem = |> optional "zscore_wasting" (nullable decodeFloat) Nothing |> optional "muac" (nullable decodeFloat) Nothing |> optional "nutrition_signs" (decodeEverySet decodeChildNutritionSign) EverySet.empty + + +decodePatientsDetails : Decoder (Dict PersonIdentifier PatientDetails) +decodePatientsDetails = + oneOf + [ dict decodePatientDetails + |> andThen + (LegacyDict.toList + >> List.filterMap + (\( k, v ) -> + String.toInt k + |> Maybe.map (\key -> ( key, v )) + ) + >> Dict.fromList + >> succeed + ) + , succeed Dict.empty + ] + + +decodePatientDetails : Decoder PatientDetails +decodePatientDetails = + succeed PatientDetails + |> required "name" string + |> required "gender" decodeGender + |> optional "phone_number" (nullable string) Nothing + + +decodeGroupEducationData : Decoder (Dict VillageId (List EducationSessionData)) +decodeGroupEducationData = + oneOf + [ dict (list decodeEducationSessionData) + |> andThen (legacyDictToDict toEntityUuid) + , succeed Dict.empty + ] + + +decodeEducationSessionData : Decoder EducationSessionData +decodeEducationSessionData = + succeed EducationSessionData + |> required "start_date" decodeYYYYMMDD + |> required "education_topics" (decodeEverySet decodeEducationTopic) + |> required "participating_patients" (decodeEverySet decodeInt) diff --git a/client/src/elm/Backend/Dashboard/Encoder.elm b/client/src/elm/Backend/Dashboard/Encoder.elm index 82232ac209..2b9a8f9f3a 100644 --- a/client/src/elm/Backend/Dashboard/Encoder.elm +++ b/client/src/elm/Backend/Dashboard/Encoder.elm @@ -3,6 +3,7 @@ module Backend.Dashboard.Encoder exposing (encodeDashboardStatsRaw) import AssocList as Dict exposing (Dict) import Backend.AcuteIllnessEncounter.Encoder exposing (encodeAcuteIllnessDiagnosis, encodeAcuteIllnessEncounterType) import Backend.Dashboard.Model exposing (..) +import Backend.EducationSession.Encoder exposing (encodeEducationTopic) import Backend.Entities exposing (VillageId) import Backend.IndividualEncounterParticipant.Encoder exposing (encodeDeliveryLocation, encodeIndividualEncounterParticipantOutcome) import Backend.Measurement.Encoder @@ -34,7 +35,7 @@ import Gizra.NominalDate exposing (encodeYYYYMMDD) import Json.Encode exposing (..) import Json.Encode.Extra exposing (maybe) import Restful.Endpoint exposing (fromEntityUuid) -import Utils.Json exposing (encodeEverySet) +import Utils.Json exposing (encodeEverySet, encodeIfSet) encodeDashboardStatsRaw : DashboardStatsRaw -> List ( String, Value ) @@ -53,7 +54,9 @@ encodeDashboardStatsRaw stats = , encodeChildScoreboardData stats.childScoreboardData , encodeNutritionIndividualData stats.nutritionIndividualData , encodeNutritionGroupData stats.nutritionGroupData + , encodeGroupEducationData stats.groupEducationData , encodeVillagesWithResidents stats.villagesWithResidents + , encodePatientsDetails stats.patientsDetails , ( "timestamp", string stats.timestamp ) , ( "stats_cache_hash", string stats.cacheHash ) ] @@ -82,7 +85,6 @@ encodeCasesManagementForYear dict = encodeCaseManagement : CaseManagement -> List ( String, Value ) encodeCaseManagement caseManagement = [ ( "id", int caseManagement.identifier ) - , ( "name", string caseManagement.name ) , ( "birth_date", encodeYYYYMMDD caseManagement.birthDate ) , ( "gender", encodeGender caseManagement.gender ) , ( "nutrition", object <| encodeCaseNutrition caseManagement.nutrition ) @@ -131,14 +133,12 @@ encodeChildrenBeneficiariesData dict = encodeChildrenBeneficiariesStats : ChildrenBeneficiariesStats -> List ( String, Value ) encodeChildrenBeneficiariesStats stats = [ ( "id", int stats.identifier ) - , ( "name", string stats.name ) , ( "gender", encodeGender stats.gender ) , ( "birth_date", encodeYYYYMMDD stats.birthDate ) , ( "created", encodeYYYYMMDD stats.memberSince ) - , ( "mother_name", string stats.motherName ) - , ( "phone_number", maybe string stats.phoneNumber ) , ( "graduation_date", encodeYYYYMMDD stats.graduationDate ) ] + ++ encodeIfSet "mother_id" stats.motherIdentifier int encodeCompletedPrograms : List ParticipantStats -> ( String, Value ) @@ -165,13 +165,12 @@ encodeMissedSessions statsList = encodeParticipantStats : ParticipantStats -> List ( String, Value ) encodeParticipantStats stats = - [ ( "name", string stats.name ) + [ ( "id", int stats.identifier ) , ( "gender", encodeGender stats.gender ) , ( "birth_date", encodeYYYYMMDD stats.birthDate ) - , ( "mother_name", string stats.motherName ) - , ( "phone_number", maybe string stats.phoneNumber ) , ( "expected_date", encodeYYYYMMDD stats.expectedDate ) ] + ++ encodeIfSet "mother_id" stats.motherIdentifier int encodeTotalEncountersData : TotalEncountersData -> ( String, Value ) @@ -575,3 +574,49 @@ encodeNutritionGroupEncounterDataItem item = ++ zscoreUnderweight ++ zscoreWasting ++ muac + + +encodePatientsDetails : Dict PersonIdentifier PatientDetails -> ( String, Value ) +encodePatientsDetails dict = + let + value = + Dict.toList dict + |> List.map + (\( k, v ) -> + ( String.fromInt k, encodePatientDetails v ) + ) + |> object + in + ( "patients_details", value ) + + +encodePatientDetails : PatientDetails -> Value +encodePatientDetails details = + object <| + [ ( "name", string details.name ) + , ( "gender", encodeGender details.gender ) + ] + ++ encodeIfSet "phone_number" details.phoneNumber string + + +encodeGroupEducationData : Dict VillageId (List EducationSessionData) -> ( String, Value ) +encodeGroupEducationData dict = + let + value = + Dict.toList dict + |> List.map + (\( villageId, sessionData ) -> + ( fromEntityUuid villageId, list encodeEducationSessionData sessionData ) + ) + |> object + in + ( "group_education_data", value ) + + +encodeEducationSessionData : EducationSessionData -> Value +encodeEducationSessionData data = + object + [ ( "start_date", encodeYYYYMMDD data.startDate ) + , ( "education_topics", encodeEverySet encodeEducationTopic data.topics ) + , ( "participating_patients", encodeEverySet int data.participants ) + ] diff --git a/client/src/elm/Backend/Dashboard/Model.elm b/client/src/elm/Backend/Dashboard/Model.elm index 115e1df351..67b396c371 100644 --- a/client/src/elm/Backend/Dashboard/Model.elm +++ b/client/src/elm/Backend/Dashboard/Model.elm @@ -5,6 +5,7 @@ module Backend.Dashboard.Model exposing (..) import AssocList as Dict exposing (Dict) import Backend.AcuteIllnessEncounter.Types exposing (AcuteIllnessDiagnosis, AcuteIllnessEncounterType) +import Backend.EducationSession.Model exposing (EducationTopic(..)) import Backend.Entities exposing (VillageId) import Backend.IndividualEncounterParticipant.Model exposing (DeliveryLocation, IndividualEncounterParticipantOutcome) import Backend.Measurement.Model @@ -43,9 +44,16 @@ type alias AssembledData = , nutritionIndividualData : List NutritionIndividualDataItem , nutritionGroupData : List NutritionGroupDataItem , nutritionPageData : NutritionPageData + , groupEducationData : List EducationSessionData + , healthCenterVillages : List VillageId + , patientsDetails : Dict PersonIdentifier PatientDetails } + +-- type alias GroupEducationData = + + type alias NutritionPageData = { caseNutritionTotalsLastYear : List CaseNutritionTotal , caseNutritionTotalsThisYear : List CaseNutritionTotal @@ -77,7 +85,9 @@ type alias DashboardStatsRaw = , childScoreboardData : List ChildScoreboardDataItem , nutritionIndividualData : List NutritionIndividualDataItem , nutritionGroupData : List NutritionGroupDataItem + , groupEducationData : Dict VillageId (List EducationSessionData) , villagesWithResidents : Dict VillageId (List PersonIdentifier) + , patientsDetails : Dict PersonIdentifier PatientDetails -- UTC Date and time on which statistics were generated. , timestamp : String @@ -103,7 +113,9 @@ emptyModel = , childScoreboardData = [] , nutritionIndividualData = [] , nutritionGroupData = [] + , groupEducationData = Dict.empty , villagesWithResidents = Dict.empty + , patientsDetails = Dict.empty , timestamp = "" , cacheHash = "" } @@ -116,7 +128,6 @@ type alias DashboardStats = , familyPlanning : List FamilyPlanningStats , missedSessions : List ParticipantStats , totalEncounters : TotalEncountersData - , villagesWithResidents : Dict VillageId (List PersonIdentifier) -- UTC Date and time on which statistics were generated. , timestamp : String @@ -141,7 +152,6 @@ type alias CaseManagementData = type alias CaseManagement = { identifier : PersonIdentifier - , name : String , birthDate : NominalDate , gender : Gender , nutrition : CaseNutrition @@ -175,9 +185,7 @@ type alias ChildrenBeneficiariesStats = , gender : Gender , birthDate : NominalDate , memberSince : NominalDate - , name : String - , motherName : String - , phoneNumber : Maybe String + , motherIdentifier : Maybe PersonIdentifier , graduationDate : NominalDate } @@ -189,11 +197,10 @@ type alias FamilyPlanningStats = type alias ParticipantStats = - { name : String + { identifier : PersonIdentifier , gender : Gender , birthDate : NominalDate - , motherName : String - , phoneNumber : Maybe String + , motherIdentifier : Maybe PersonIdentifier , expectedDate : NominalDate } @@ -443,3 +450,17 @@ type alias NutritionEncounterDataItem = , muac : Maybe Float , nutritionSigns : EverySet ChildNutritionSign } + + +type alias PatientDetails = + { name : String + , gender : Gender + , phoneNumber : Maybe String + } + + +type alias EducationSessionData = + { startDate : NominalDate + , topics : EverySet EducationTopic + , participants : EverySet PersonIdentifier + } diff --git a/client/src/elm/Backend/Decoder.elm b/client/src/elm/Backend/Decoder.elm index d7a849cbf4..5078c04d2f 100644 --- a/client/src/elm/Backend/Decoder.elm +++ b/client/src/elm/Backend/Decoder.elm @@ -6,6 +6,7 @@ import Backend.Clinic.Decoder exposing (decodeClinic) import Backend.Counseling.Decoder exposing (decodeCounselingSchedule, decodeCounselingTopic) import Backend.Dashboard.Decoder exposing (decodeDashboardStatsRaw) import Backend.EducationSession.Decoder exposing (decodeEducationSession) +import Backend.HIVEncounter.Decoder exposing (decodeHIVEncounter) import Backend.HealthCenter.Decoder exposing (decodeCatchmentArea, decodeHealthCenter) import Backend.HomeVisitEncounter.Decoder exposing (decodeHomeVisitEncounter) import Backend.IndividualEncounterParticipant.Decoder exposing (decodeIndividualEncounterParticipant) @@ -176,6 +177,30 @@ decodeRevision = "height" -> decodeWithUuid HeightRevision decodeHeight + "hiv_diagnostics" -> + decodeWithUuid HIVDiagnosticsRevision decodeHIVDiagnostics + + "hiv_encounter" -> + decodeWithUuid HIVEncounterRevision decodeHIVEncounter + + "hiv_follow_up" -> + decodeWithUuid HIVFollowUpRevision decodeHIVFollowUp + + "hiv_health_education" -> + decodeWithUuid HIVHealthEducationRevision decodeHIVHealthEducation + + "hiv_medication" -> + decodeWithUuid HIVMedicationRevision decodeHIVMedication + + "hiv_referral" -> + decodeWithUuid HIVReferralRevision decodeHIVReferral + + "hiv_symptom_review" -> + decodeWithUuid HIVSymptomReviewRevision decodeHIVSymptomReview + + "hiv_treatment_review" -> + decodeWithUuid HIVTreatmentReviewRevision decodeHIVTreatmentReview + "home_visit_encounter" -> decodeWithUuid HomeVisitEncounterRevision decodeHomeVisitEncounter diff --git a/client/src/elm/Backend/EducationSession/Decoder.elm b/client/src/elm/Backend/EducationSession/Decoder.elm index 8cc89dfa75..77d9c54c16 100644 --- a/client/src/elm/Backend/EducationSession/Decoder.elm +++ b/client/src/elm/Backend/EducationSession/Decoder.elm @@ -1,4 +1,4 @@ -module Backend.EducationSession.Decoder exposing (decodeEducationSession) +module Backend.EducationSession.Decoder exposing (decodeEducationSession, decodeEducationTopic) import Backend.EducationSession.Model exposing (..) import Backend.EducationSession.Utils exposing (..) diff --git a/client/src/elm/Backend/EducationSession/Encoder.elm b/client/src/elm/Backend/EducationSession/Encoder.elm index cd462e9f92..4e66af510b 100644 --- a/client/src/elm/Backend/EducationSession/Encoder.elm +++ b/client/src/elm/Backend/EducationSession/Encoder.elm @@ -1,4 +1,4 @@ -module Backend.EducationSession.Encoder exposing (encodeEducationSession) +module Backend.EducationSession.Encoder exposing (encodeEducationSession, encodeEducationTopic) import Backend.EducationSession.Model exposing (..) import Backend.EducationSession.Utils exposing (..) diff --git a/client/src/elm/Backend/Endpoints.elm b/client/src/elm/Backend/Endpoints.elm index a61226431b..c51191719b 100644 --- a/client/src/elm/Backend/Endpoints.elm +++ b/client/src/elm/Backend/Endpoints.elm @@ -18,6 +18,9 @@ import Backend.EducationSession.Decoder exposing (decodeEducationSession) import Backend.EducationSession.Encoder exposing (encodeEducationSession) import Backend.EducationSession.Model exposing (EducationSession) import Backend.Entities exposing (..) +import Backend.HIVEncounter.Decoder exposing (decodeHIVEncounter) +import Backend.HIVEncounter.Encoder exposing (encodeHIVEncounter) +import Backend.HIVEncounter.Model exposing (HIVEncounter) import Backend.HealthCenter.Decoder exposing (decodeHealthCenter) import Backend.HealthCenter.Model exposing (HealthCenter) import Backend.HomeVisitEncounter.Decoder exposing (decodeHomeVisitEncounter) @@ -1435,7 +1438,72 @@ tuberculosisTreatmentReviewEndpoint = |> withValueEncoder (object << encodeTuberculosisTreatmentReview) -educationSessionEndpoint : ReadWriteEndPoint Error EducationSessionId EducationSession EducationSession () +educationSessionEndpoint : ReadWriteEndPoint Error EducationSessionId EducationSession EducationSession (Maybe PersonId) educationSessionEndpoint = swEndpoint "nodes/education_session" decodeEducationSession |> withValueEncoder (object << encodeEducationSession) + |> withParamsEncoder encodeEducationSessionParams + + +encodeEducationSessionParams : Maybe PersonId -> List ( String, String ) +encodeEducationSessionParams mPersonId = + case mPersonId of + Just id -> + [ ( "participant", fromEntityUuid id ) ] + + Nothing -> + [] + + +hivEncounterEndpoint : ReadWriteEndPoint Error HIVEncounterId HIVEncounter HIVEncounter (List IndividualEncounterParticipantId) +hivEncounterEndpoint = + swEndpoint "nodes/hiv_encounter" decodeHIVEncounter + |> withValueEncoder (object << encodeHIVEncounter) + |> withParamsEncoder encodeIndividualEncounterParams + + +hivMeasurementsEndpoint : ReadOnlyEndPoint Error HIVEncounterId HIVMeasurements () +hivMeasurementsEndpoint = + swEndpoint "nodes/hiv-measurements" decodeHIVMeasurements + + +hivDiagnosticsEndpoint : ReadWriteEndPoint Error HIVDiagnosticsId HIVDiagnostics HIVDiagnostics () +hivDiagnosticsEndpoint = + swEndpoint "nodes/hiv_diagnostics" decodeHIVDiagnostics + |> withValueEncoder (object << encodeHIVDiagnostics) + + +hivFollowUpEndpoint : ReadWriteEndPoint Error HIVFollowUpId HIVFollowUp HIVFollowUp () +hivFollowUpEndpoint = + swEndpoint "nodes/hiv_follow_up" decodeHIVFollowUp + |> withValueEncoder (object << encodeHIVFollowUp) + + +hivHealthEducationEndpoint : ReadWriteEndPoint Error HIVHealthEducationId HIVHealthEducation HIVHealthEducation () +hivHealthEducationEndpoint = + swEndpoint "nodes/hiv_health_education" decodeHIVHealthEducation + |> withValueEncoder (object << encodeHIVHealthEducation) + + +hivMedicationEndpoint : ReadWriteEndPoint Error HIVMedicationId HIVMedication HIVMedication () +hivMedicationEndpoint = + swEndpoint "nodes/hiv_medication" decodeHIVMedication + |> withValueEncoder (object << encodeHIVMedication) + + +hivReferralEndpoint : ReadWriteEndPoint Error HIVReferralId HIVReferral HIVReferral () +hivReferralEndpoint = + swEndpoint "nodes/hiv_referral" decodeHIVReferral + |> withValueEncoder (object << encodeHIVReferral) + + +hivSymptomReviewEndpoint : ReadWriteEndPoint Error HIVSymptomReviewId HIVSymptomReview HIVSymptomReview () +hivSymptomReviewEndpoint = + swEndpoint "nodes/hiv_symptom_review" decodeHIVSymptomReview + |> withValueEncoder (object << encodeHIVSymptomReview) + + +hivTreatmentReviewEndpoint : ReadWriteEndPoint Error HIVTreatmentReviewId HIVTreatmentReview HIVTreatmentReview () +hivTreatmentReviewEndpoint = + swEndpoint "nodes/hiv_treatment_review" decodeHIVTreatmentReview + |> withValueEncoder (object << encodeHIVTreatmentReview) diff --git a/client/src/elm/Backend/Entities.elm b/client/src/elm/Backend/Entities.elm index 0d58f87f59..6ac53f3154 100644 --- a/client/src/elm/Backend/Entities.elm +++ b/client/src/elm/Backend/Entities.elm @@ -1613,3 +1613,67 @@ type alias EducationSessionId = type EducationSessionUuidType = EducationSessionUuidType + + +type alias HIVEncounterId = + EntityUuid HIVEncounterUuidType + + +type HIVEncounterUuidType + = HIVEncounterUuidType + + +type alias HIVDiagnosticsId = + EntityUuid HIVDiagnosticsUuidType + + +type HIVDiagnosticsUuidType + = HIVDiagnosticsUuidType + + +type alias HIVFollowUpId = + EntityUuid HIVFollowUpUuidType + + +type HIVFollowUpUuidType + = HIVFollowUpUuidType + + +type alias HIVHealthEducationId = + EntityUuid HIVHealthEducationUuidType + + +type HIVHealthEducationUuidType + = HIVHealthEducationUuidType + + +type alias HIVMedicationId = + EntityUuid HIVMedicationUuidType + + +type HIVMedicationUuidType + = HIVMedicationUuidType + + +type alias HIVReferralId = + EntityUuid HIVReferralUuidType + + +type HIVReferralUuidType + = HIVReferralUuidType + + +type alias HIVSymptomReviewId = + EntityUuid HIVSymptomReviewUuidType + + +type HIVSymptomReviewUuidType + = HIVSymptomReviewUuidType + + +type alias HIVTreatmentReviewId = + EntityUuid HIVTreatmentReviewUuidType + + +type HIVTreatmentReviewUuidType + = HIVTreatmentReviewUuidType diff --git a/client/src/elm/Backend/Fetch.elm b/client/src/elm/Backend/Fetch.elm index 6c0f6e76af..8fbbf1ab26 100644 --- a/client/src/elm/Backend/Fetch.elm +++ b/client/src/elm/Backend/Fetch.elm @@ -302,6 +302,13 @@ shouldFetch currentTime model msg = |> Maybe.withDefault NotAsked |> isNotAsked + FetchNCDEncountersForParticipants ids -> + if List.isEmpty ids then + False + + else + List.any (\id -> not (Dict.member id model.ncdEncountersByParticipant)) ids + FetchNCDMeasurements id -> Dict.get id model.ncdMeasurements |> Maybe.withDefault NotAsked @@ -351,11 +358,45 @@ shouldFetch currentTime model msg = |> Maybe.withDefault NotAsked |> isNotAsked + FetchHIVEncounter id -> + Dict.get id model.hivEncounters + |> Maybe.withDefault NotAsked + |> isNotAsked + + FetchHIVEncounters ids -> + if List.isEmpty ids then + False + + else + List.any (\id -> not (Dict.member id model.hivEncounters)) ids + + FetchHIVEncountersForParticipant id -> + Dict.get id model.hivEncountersByParticipant + |> Maybe.withDefault NotAsked + |> isNotAsked + + FetchHIVEncountersForParticipants ids -> + if List.isEmpty ids then + False + + else + List.any (\id -> not (Dict.member id model.hivEncountersByParticipant)) ids + + FetchHIVMeasurements id -> + Dict.get id model.hivMeasurements + |> Maybe.withDefault NotAsked + |> isNotAsked + FetchEducationSession id -> Dict.get id model.educationSessions |> Maybe.withDefault NotAsked |> isNotAsked + FetchEducationSessionsForPerson id -> + Dict.get id model.educationSessionsByPerson + |> Maybe.withDefault NotAsked + |> isNotAsked + FetchStockManagementMeasurements id -> Dict.get id model.stockManagementMeasurements |> Maybe.withDefault NotAsked @@ -561,9 +602,21 @@ forget msg model = FetchTuberculosisMeasurements id -> { model | tuberculosisMeasurements = Dict.remove id model.tuberculosisMeasurements } + FetchHIVEncounter id -> + { model | hivEncounters = Dict.remove id model.hivEncounters } + + FetchHIVEncountersForParticipant id -> + { model | hivEncountersByParticipant = Dict.remove id model.hivEncountersByParticipant } + + FetchHIVMeasurements id -> + { model | hivMeasurements = Dict.remove id model.hivMeasurements } + FetchEducationSession id -> { model | educationSessions = Dict.remove id model.educationSessions } + FetchEducationSessionsForPerson id -> + { model | educationSessionsByPerson = Dict.remove id model.educationSessionsByPerson } + FetchStockManagementMeasurements id -> { model | stockManagementMeasurements = Dict.remove id model.stockManagementMeasurements } diff --git a/client/src/elm/Backend/HIVActivity/Model.elm b/client/src/elm/Backend/HIVActivity/Model.elm new file mode 100644 index 0000000000..f90aaabf93 --- /dev/null +++ b/client/src/elm/Backend/HIVActivity/Model.elm @@ -0,0 +1,12 @@ +module Backend.HIVActivity.Model exposing (..) + +{-| This module provides types relating to the UI for presenting +prenatal activities. +-} + + +type HIVActivity + = Diagnostics + | Medication + | SymptomReview + | NextSteps diff --git a/client/src/elm/Backend/HIVActivity/Utils.elm b/client/src/elm/Backend/HIVActivity/Utils.elm new file mode 100644 index 0000000000..781bac6951 --- /dev/null +++ b/client/src/elm/Backend/HIVActivity/Utils.elm @@ -0,0 +1,55 @@ +module Backend.HIVActivity.Utils exposing (..) + +import Backend.HIVActivity.Model exposing (..) +import EverySet +import Gizra.NominalDate exposing (NominalDate) +import Maybe.Extra exposing (isJust) +import Translate exposing (Language, translate) + + +activityToString : HIVActivity -> String +activityToString activity = + case activity of + Diagnostics -> + "diagnostics" + + Medication -> + "medication" + + SymptomReview -> + "symptoms" + + NextSteps -> + "next-steps" + + +activityFromString : String -> Maybe HIVActivity +activityFromString s = + case s of + "diagnostics" -> + Just Diagnostics + + "medication" -> + Just Medication + + "symptoms" -> + Just SymptomReview + + "next-steps" -> + Just NextSteps + + _ -> + Nothing + + +{-| Returns a string representing an icon for the activity, for use in a +"class" attribute. +-} +getActivityIcon : HIVActivity -> String +getActivityIcon activity = + activityToString activity + + +allActivities : List HIVActivity +allActivities = + [ Diagnostics, Medication, SymptomReview, NextSteps ] diff --git a/client/src/elm/Backend/HIVEncounter/Decoder.elm b/client/src/elm/Backend/HIVEncounter/Decoder.elm new file mode 100644 index 0000000000..26803bdc8a --- /dev/null +++ b/client/src/elm/Backend/HIVEncounter/Decoder.elm @@ -0,0 +1,16 @@ +module Backend.HIVEncounter.Decoder exposing (decodeHIVEncounter) + +import Backend.HIVEncounter.Model exposing (..) +import Gizra.NominalDate exposing (decodeYYYYMMDD) +import Json.Decode exposing (Decoder, nullable, succeed) +import Json.Decode.Pipeline exposing (optional, optionalAt, required, requiredAt) +import Restful.Endpoint exposing (decodeEntityUuid) + + +decodeHIVEncounter : Decoder HIVEncounter +decodeHIVEncounter = + succeed HIVEncounter + |> required "individual_participant" decodeEntityUuid + |> requiredAt [ "scheduled_date", "value" ] decodeYYYYMMDD + |> optionalAt [ "scheduled_date", "value2" ] (nullable decodeYYYYMMDD) Nothing + |> optional "shard" (nullable decodeEntityUuid) Nothing diff --git a/client/src/elm/Backend/HIVEncounter/Encoder.elm b/client/src/elm/Backend/HIVEncounter/Encoder.elm new file mode 100644 index 0000000000..35e5a88bbe --- /dev/null +++ b/client/src/elm/Backend/HIVEncounter/Encoder.elm @@ -0,0 +1,25 @@ +module Backend.HIVEncounter.Encoder exposing (encodeHIVEncounter) + +import Backend.HIVEncounter.Model exposing (..) +import Gizra.NominalDate exposing (encodeYYYYMMDD) +import Json.Encode exposing (..) +import Json.Encode.Extra exposing (maybe) +import Restful.Endpoint exposing (encodeEntityUuid) +import Utils.Json exposing (encodeIfSet) + + +{-| Encodes a `HIVEncounter`. +-} +encodeHIVEncounter : HIVEncounter -> List ( String, Value ) +encodeHIVEncounter session = + [ ( "scheduled_date" + , object + [ ( "value", encodeYYYYMMDD session.startDate ) + , ( "value2", maybe encodeYYYYMMDD session.endDate ) + ] + ) + , ( "individual_participant", encodeEntityUuid session.participant ) + , ( "deleted", bool False ) + , ( "type", string "hiv_encounter" ) + ] + ++ encodeIfSet "shard" session.shard encodeEntityUuid diff --git a/client/src/elm/Backend/HIVEncounter/Model.elm b/client/src/elm/Backend/HIVEncounter/Model.elm new file mode 100644 index 0000000000..77a816dc2e --- /dev/null +++ b/client/src/elm/Backend/HIVEncounter/Model.elm @@ -0,0 +1,70 @@ +module Backend.HIVEncounter.Model exposing (..) + +import Backend.Entities exposing (..) +import Backend.Measurement.Model exposing (..) +import Gizra.NominalDate exposing (NominalDate) +import RemoteData exposing (RemoteData(..), WebData) + + +type alias HIVEncounter = + { participant : IndividualEncounterParticipantId + , startDate : NominalDate + , endDate : Maybe NominalDate + , shard : Maybe HealthCenterId + } + + +emptyHIVEncounter : IndividualEncounterParticipantId -> NominalDate -> Maybe HealthCenterId -> HIVEncounter +emptyHIVEncounter participant startDate shard = + { participant = participant + , startDate = startDate + , endDate = Nothing + , shard = shard + } + + +{-| This is a subdivision of ModelIndexedDb that tracks requests in-progress +to peform the updates indicated by the `Msg` type below. +-} +type alias Model = + { closeHIVEncounter : WebData () + , saveDiagnostics : WebData () + , savePrescribedMedication : WebData () + , saveTreatmentReview : WebData () + , saveSymptomReview : WebData () + , saveReferral : WebData () + , saveHealthEducation : WebData () + , saveFollowUp : WebData () + } + + +emptyModel : Model +emptyModel = + { closeHIVEncounter = NotAsked + , saveDiagnostics = NotAsked + , savePrescribedMedication = NotAsked + , saveTreatmentReview = NotAsked + , saveSymptomReview = NotAsked + , saveReferral = NotAsked + , saveHealthEducation = NotAsked + , saveFollowUp = NotAsked + } + + +type Msg + = CloseHIVEncounter + | HandleClosedHIVEncounter (WebData ()) + | SaveDiagnostics PersonId (Maybe HIVDiagnosticsId) HIVDiagnosticsValue + | HandleSavedDiagnostics (WebData ()) + | SavePrescribedMedication PersonId (Maybe HIVMedicationId) HIVMedicationValue + | HandleSavedPrescribedMedication (WebData ()) + | SaveTreatmentReview PersonId (Maybe HIVTreatmentReviewId) TreatmentOngoingValue + | HandleSavedTreatmentReview (WebData ()) + | SaveSymptomReview PersonId (Maybe HIVSymptomReviewId) HIVSymptomReviewValue + | HandleSavedSymptomReview (WebData ()) + | SaveReferral PersonId (Maybe HIVReferralId) SendToHCValue + | HandleSavedReferral (WebData ()) + | SaveHealthEducation PersonId (Maybe HIVHealthEducationId) HIVHealthEducationValue + | HandleSavedHealthEducation (WebData ()) + | SaveFollowUp PersonId (Maybe HIVFollowUpId) FollowUpValue + | HandleSavedFollowUp (WebData ()) diff --git a/client/src/elm/Backend/HIVEncounter/Update.elm b/client/src/elm/Backend/HIVEncounter/Update.elm new file mode 100644 index 0000000000..c22fb16203 --- /dev/null +++ b/client/src/elm/Backend/HIVEncounter/Update.elm @@ -0,0 +1,127 @@ +module Backend.HIVEncounter.Update exposing (update) + +import App.Model +import App.Utils exposing (triggerRollbarOnFailure) +import Backend.Endpoints exposing (..) +import Backend.Entities exposing (..) +import Backend.HIVEncounter.Model exposing (..) +import Backend.Utils exposing (saveMeasurementCmd, sw) +import Gizra.NominalDate exposing (NominalDate) +import Maybe.Extra exposing (unwrap) +import RemoteData exposing (RemoteData(..)) +import Restful.Endpoint exposing (toCmd, withoutDecoder) + + +update : + NominalDate + -> Maybe NurseId + -> Maybe HealthCenterId + -> HIVEncounterId + -> Maybe HIVEncounter + -> Msg + -> Model + -> ( Model, Cmd Msg, List App.Model.Msg ) +update currentDate nurseId healthCenterId encounterId maybeEncounter msg model = + case msg of + CloseHIVEncounter -> + maybeEncounter + |> unwrap ( model, Cmd.none, [] ) + (\encounter -> + ( { model | closeHIVEncounter = Loading } + , { encounter | endDate = Just currentDate } + |> sw.patchFull hivEncounterEndpoint encounterId + |> withoutDecoder + |> toCmd (RemoteData.fromResult >> HandleClosedHIVEncounter) + , [] + ) + ) + + HandleClosedHIVEncounter data -> + ( { model | closeHIVEncounter = data } + , Cmd.none + , triggerRollbarOnFailure data + ) + + SaveDiagnostics personId valueId value -> + ( { model | saveDiagnostics = Loading } + , saveMeasurementCmd currentDate encounterId personId nurseId healthCenterId valueId value hivDiagnosticsEndpoint HandleSavedDiagnostics + , [] + ) + + HandleSavedDiagnostics data -> + ( { model | saveDiagnostics = data } + , Cmd.none + , triggerRollbarOnFailure data + ) + + SavePrescribedMedication personId valueId value -> + ( { model | savePrescribedMedication = Loading } + , saveMeasurementCmd currentDate encounterId personId nurseId healthCenterId valueId value hivMedicationEndpoint HandleSavedPrescribedMedication + , [] + ) + + HandleSavedPrescribedMedication data -> + ( { model | savePrescribedMedication = data } + , Cmd.none + , triggerRollbarOnFailure data + ) + + SaveTreatmentReview personId valueId value -> + ( { model | saveTreatmentReview = Loading } + , saveMeasurementCmd currentDate encounterId personId nurseId healthCenterId valueId value hivTreatmentReviewEndpoint HandleSavedTreatmentReview + , [] + ) + + HandleSavedTreatmentReview data -> + ( { model | saveTreatmentReview = data } + , Cmd.none + , triggerRollbarOnFailure data + ) + + SaveSymptomReview personId valueId value -> + ( { model | saveSymptomReview = Loading } + , saveMeasurementCmd currentDate encounterId personId nurseId healthCenterId valueId value hivSymptomReviewEndpoint HandleSavedSymptomReview + , [] + ) + + HandleSavedSymptomReview data -> + ( { model | saveSymptomReview = data } + , Cmd.none + , triggerRollbarOnFailure data + ) + + SaveReferral personId valueId value -> + ( { model | saveReferral = Loading } + , saveMeasurementCmd currentDate encounterId personId nurseId healthCenterId valueId value hivReferralEndpoint HandleSavedReferral + , [] + ) + + HandleSavedReferral data -> + ( { model | saveReferral = data } + , Cmd.none + , triggerRollbarOnFailure data + ) + + SaveHealthEducation personId valueId value -> + ( { model | saveHealthEducation = Loading } + , saveMeasurementCmd currentDate encounterId personId nurseId healthCenterId valueId value hivHealthEducationEndpoint HandleSavedHealthEducation + , [] + ) + + HandleSavedHealthEducation data -> + ( { model | saveHealthEducation = data } + , Cmd.none + , triggerRollbarOnFailure data + ) + + SaveFollowUp personId valueId value -> + ( { model | saveFollowUp = Loading } + , saveMeasurementCmd currentDate encounterId personId nurseId healthCenterId valueId value hivFollowUpEndpoint HandleSavedFollowUp + , [] + ) + + HandleSavedFollowUp data -> + ( { model | saveFollowUp = data } + , Cmd.none + , triggerRollbarOnFailure data + ) diff --git a/client/src/elm/Backend/IndividualEncounterParticipant/Decoder.elm b/client/src/elm/Backend/IndividualEncounterParticipant/Decoder.elm index 2f971059e8..68acb7f359 100644 --- a/client/src/elm/Backend/IndividualEncounterParticipant/Decoder.elm +++ b/client/src/elm/Backend/IndividualEncounterParticipant/Decoder.elm @@ -50,9 +50,14 @@ decodeIndividualEncounterParticipantOutcome = succeed (Tuberculosis tuberculosisOutcome) Nothing -> - acuteIllnessOutcomeFromString s - |> Maybe.map (AcuteIllness >> succeed) - |> Maybe.withDefault (s ++ " is not a recognized IndividualEncounterParticipantOutcome" |> fail) + case hivOutcomeFromString s of + Just hivOutcome -> + succeed (HIV hivOutcome) + + Nothing -> + acuteIllnessOutcomeFromString s + |> Maybe.map (AcuteIllness >> succeed) + |> Maybe.withDefault (s ++ " is not a recognized IndividualEncounterParticipantOutcome" |> fail) ) diff --git a/client/src/elm/Backend/IndividualEncounterParticipant/Encoder.elm b/client/src/elm/Backend/IndividualEncounterParticipant/Encoder.elm index 73838544b9..33bfa264d9 100644 --- a/client/src/elm/Backend/IndividualEncounterParticipant/Encoder.elm +++ b/client/src/elm/Backend/IndividualEncounterParticipant/Encoder.elm @@ -47,6 +47,9 @@ encodeIndividualEncounterParticipantOutcome participantOutcome = Tuberculosis outcome -> encodeTuberculosisOutcome outcome + HIV outcome -> + encodeHIVOutcome outcome + encodePregnancyOutcome : PregnancyOutcome -> Value encodePregnancyOutcome outcome = @@ -66,3 +69,8 @@ encodeAcuteIllnessOutcome outcome = encodeTuberculosisOutcome : TuberculosisOutcome -> Value encodeTuberculosisOutcome outcome = tuberculosisOutcomeToString outcome |> string + + +encodeHIVOutcome : HIVOutcome -> Value +encodeHIVOutcome outcome = + hivOutcomeToString outcome |> string diff --git a/client/src/elm/Backend/IndividualEncounterParticipant/Model.elm b/client/src/elm/Backend/IndividualEncounterParticipant/Model.elm index 8065eba655..1cedc97e21 100644 --- a/client/src/elm/Backend/IndividualEncounterParticipant/Model.elm +++ b/client/src/elm/Backend/IndividualEncounterParticipant/Model.elm @@ -53,6 +53,7 @@ type Msg = ClosePrenatalSession NominalDate PregnancyOutcome DeliveryLocation | CloseAcuteIllnessSession AcuteIllnessOutcome | CloseTuberculosisSession TuberculosisOutcome + | CloseHIVSession HIVOutcome | SetEddDate NominalDate | SetNewborn PersonId | HandleUpdatedIndividualEncounterParticipant (WebData ()) @@ -68,13 +69,14 @@ type IndividualEncounterType = AcuteIllnessEncounter | AntenatalEncounter | ChildScoreboardEncounter + | HIVEncounter | HomeVisitEncounter - -- @todo : can be removed? - | InmmunizationEncounter | NCDEncounter | NutritionEncounter | TuberculosisEncounter | WellChildEncounter + -- @todo : can be removed? + | InmmunizationEncounter type DeliveryLocation @@ -86,6 +88,7 @@ type IndividualEncounterParticipantOutcome = AcuteIllness AcuteIllnessOutcome | Pregnancy PregnancyOutcome | Tuberculosis TuberculosisOutcome + | HIV HIVOutcome type AcuteIllnessOutcome @@ -97,6 +100,17 @@ type AcuteIllnessOutcome | OutcomeOther +allAcuteIllnessOutcome : List AcuteIllnessOutcome +allAcuteIllnessOutcome = + [ OutcomeIllnessResolved + , OutcomeLostToFollowUp + , OutcomeMovedOutsideCA + , OutcomePatientDied + , OutcomeReferredToHC + , OutcomeOther + ] + + type PregnancyOutcome = OutcomeLiveAtTerm | OutcomeLivePreTerm @@ -105,10 +119,6 @@ type PregnancyOutcome | OutcomeAbortions -type TuberculosisOutcome - = OutcomeNotDiagnosed - - allPregnancyOutcome : List PregnancyOutcome allPregnancyOutcome = [ OutcomeLiveAtTerm @@ -119,12 +129,9 @@ allPregnancyOutcome = ] -allAcuteIllnessOutcome : List AcuteIllnessOutcome -allAcuteIllnessOutcome = - [ OutcomeIllnessResolved - , OutcomeLostToFollowUp - , OutcomeMovedOutsideCA - , OutcomePatientDied - , OutcomeReferredToHC - , OutcomeOther - ] +type TuberculosisOutcome + = TuberculosisOutcomeNotDiagnosed + + +type HIVOutcome + = HIVOutcomeNotDiagnosed diff --git a/client/src/elm/Backend/IndividualEncounterParticipant/Update.elm b/client/src/elm/Backend/IndividualEncounterParticipant/Update.elm index 74cd2c9fc1..b14c851992 100644 --- a/client/src/elm/Backend/IndividualEncounterParticipant/Update.elm +++ b/client/src/elm/Backend/IndividualEncounterParticipant/Update.elm @@ -55,6 +55,19 @@ update currentDate participantId maybeParticipant msg model = ) model + CloseHIVSession outcome -> + updateIndividualEncounterParticipant currentDate + participantId + maybeParticipant + (\participant -> + { participant + | endDate = Just currentDate + , dateConcluded = Just currentDate + , outcome = Just (HIV outcome) + } + ) + model + SetEddDate eddDate -> updateIndividualEncounterParticipant currentDate participantId diff --git a/client/src/elm/Backend/IndividualEncounterParticipant/Utils.elm b/client/src/elm/Backend/IndividualEncounterParticipant/Utils.elm index ef70b82ce0..bbed592fd3 100644 --- a/client/src/elm/Backend/IndividualEncounterParticipant/Utils.elm +++ b/client/src/elm/Backend/IndividualEncounterParticipant/Utils.elm @@ -19,6 +19,9 @@ individualEncounterTypeToString encounterType = ChildScoreboardEncounter -> "child-scoreboard" + HIVEncounter -> + "hiv" + HomeVisitEncounter -> "home-visit" @@ -50,6 +53,9 @@ individualEncounterTypeFromString string = "child-scoreboard" -> Just ChildScoreboardEncounter + "hiv" -> + Just HIVEncounter + "home-visit" -> Just HomeVisitEncounter @@ -236,7 +242,7 @@ deliveryLocationFromString location = tuberculosisOutcomeToString : TuberculosisOutcome -> String tuberculosisOutcomeToString outcome = case outcome of - OutcomeNotDiagnosed -> + TuberculosisOutcomeNotDiagnosed -> "not-dignosed" @@ -244,7 +250,24 @@ tuberculosisOutcomeFromString : String -> Maybe TuberculosisOutcome tuberculosisOutcomeFromString outcome = case outcome of "not-dignosed" -> - Just OutcomeNotDiagnosed + Just TuberculosisOutcomeNotDiagnosed + + _ -> + Nothing + + +hivOutcomeToString : HIVOutcome -> String +hivOutcomeToString outcome = + case outcome of + HIVOutcomeNotDiagnosed -> + "hiv-not-dignosed" + + +hivOutcomeFromString : String -> Maybe HIVOutcome +hivOutcomeFromString outcome = + case outcome of + "hiv-not-dignosed" -> + Just HIVOutcomeNotDiagnosed _ -> Nothing diff --git a/client/src/elm/Backend/Measurement/Decoder.elm b/client/src/elm/Backend/Measurement/Decoder.elm index fdba6aa553..5a7898c6e8 100644 --- a/client/src/elm/Backend/Measurement/Decoder.elm +++ b/client/src/elm/Backend/Measurement/Decoder.elm @@ -68,6 +68,11 @@ decodeTuberculosisMeasurement = decodeMeasurement "tuberculosis_encounter" +decodeHIVMeasurement : Decoder value -> Decoder (Measurement HIVEncounterId value) +decodeHIVMeasurement = + decodeMeasurement "hiv_encounter" + + decodeMeasurement : String -> Decoder value -> Decoder (Measurement (EntityUuid a) value) decodeMeasurement encounterTag valueDecoder = succeed Measurement @@ -210,6 +215,7 @@ decodeFollowUpMeasurements = |> optional "prenatal_follow_up" (map Dict.fromList <| list (decodeWithEntityUuid decodePrenatalFollowUp)) Dict.empty |> optional "well_child_follow_up" (map Dict.fromList <| list (decodeWithEntityUuid decodeWellChildFollowUp)) Dict.empty |> optional "tuberculosis_follow_up" (map Dict.fromList <| list (decodeWithEntityUuid decodeTuberculosisFollowUp)) Dict.empty + |> optional "hiv_follow_up" (map Dict.fromList <| list (decodeWithEntityUuid decodeHIVFollowUp)) Dict.empty |> optional "acute_illness_trace_contact" (map Dict.fromList <| list (decodeWithEntityUuid decodeAcuteIllnessTraceContact)) Dict.empty |> optional "prenatal_labs_results" (map Dict.fromList <| list (decodeWithEntityUuid decodePrenatalLabsResults)) Dict.empty |> optional "ncd_labs_results" (map Dict.fromList <| list (decodeWithEntityUuid decodeNCDLabsResults)) Dict.empty @@ -316,6 +322,18 @@ decodeTuberculosisMeasurements = |> optional "tuberculosis_treatment_review" (decodeHead decodeTuberculosisTreatmentReview) Nothing +decodeHIVMeasurements : Decoder HIVMeasurements +decodeHIVMeasurements = + succeed HIVMeasurements + |> optional "hiv_diagnostics" (decodeHead decodeHIVDiagnostics) Nothing + |> optional "hiv_follow_up" (decodeHead decodeHIVFollowUp) Nothing + |> optional "hiv_health_education" (decodeHead decodeHIVHealthEducation) Nothing + |> optional "hiv_medication" (decodeHead decodeHIVMedication) Nothing + |> optional "hiv_referral" (decodeHead decodeHIVReferral) Nothing + |> optional "hiv_symptom_review" (decodeHead decodeHIVSymptomReview) Nothing + |> optional "hiv_treatment_review" (decodeHead decodeHIVTreatmentReview) Nothing + + decodeStockManagementMeasurements : Decoder StockManagementMeasurements decodeStockManagementMeasurements = succeed StockManagementMeasurements @@ -5563,3 +5581,107 @@ decodeTuberculosisSymptom = decodeTuberculosisTreatmentReview : Decoder TuberculosisTreatmentReview decodeTuberculosisTreatmentReview = decodeTuberculosisMeasurement decodeTreatmentOngoingValue + + +decodeHIVDiagnostics : Decoder HIVDiagnostics +decodeHIVDiagnostics = + decodeHIVMeasurement decodeHIVDiagnosticsValue + + +decodeHIVDiagnosticsValue : Decoder HIVDiagnosticsValue +decodeHIVDiagnosticsValue = + succeed HIVDiagnosticsValue + |> required "hiv_diagnosis_signs" (decodeEverySet decodeHIVDiagnosisSign) + |> optional "positive_result_date" (nullable Gizra.NominalDate.decodeYYYYMMDD) Nothing + + +decodeHIVDiagnosisSign : Decoder HIVDiagnosisSign +decodeHIVDiagnosisSign = + string + |> andThen + (\result -> + hivDiagnosisSignFromString result + |> Maybe.map succeed + |> Maybe.withDefault (result ++ " is not a recognized HIVDiagnosisSign" |> fail) + ) + + +decodeHIVFollowUp : Decoder HIVFollowUp +decodeHIVFollowUp = + decodeHIVMeasurement decodeFollowUpValue + + +decodeHIVHealthEducation : Decoder HIVHealthEducation +decodeHIVHealthEducation = + decodeHIVMeasurement decodeHIVHealthEducationValue + + +decodeHIVHealthEducationValue : Decoder HIVHealthEducationValue +decodeHIVHealthEducationValue = + decodeEverySet decodeHIVHealthEducationSign + |> field "hiv_health_education_signs" + + +decodeHIVHealthEducationSign : Decoder HIVHealthEducationSign +decodeHIVHealthEducationSign = + string + |> andThen + (\result -> + hivHealthEducationSignFromString result + |> Maybe.map succeed + |> Maybe.withDefault (result ++ " is not a recognized HIVHealthEducationSign" |> fail) + ) + + +decodeHIVMedication : Decoder HIVMedication +decodeHIVMedication = + decodeHIVMeasurement decodeHIVMedicationValue + + +decodeHIVMedicationValue : Decoder HIVMedicationValue +decodeHIVMedicationValue = + decodeEverySet decodeHIVPrescribedMedication + |> field "prescribed_hiv_medications" + + +decodeHIVPrescribedMedication : Decoder HIVPrescribedMedication +decodeHIVPrescribedMedication = + string + |> andThen + (\result -> + hivPrescribedMedicationFromString result + |> Maybe.map succeed + |> Maybe.withDefault (result ++ " is not a recognized HIVPrescribedMedication" |> fail) + ) + + +decodeHIVReferral : Decoder HIVReferral +decodeHIVReferral = + decodeHIVMeasurement decodeSendToHCValue + + +decodeHIVSymptomReview : Decoder HIVSymptomReview +decodeHIVSymptomReview = + decodeHIVMeasurement decodeHIVSymptomReviewValue + + +decodeHIVSymptomReviewValue : Decoder HIVSymptomReviewValue +decodeHIVSymptomReviewValue = + decodeEverySet decodeHIVSymptom + |> field "hiv_symptoms" + + +decodeHIVSymptom : Decoder HIVSymptom +decodeHIVSymptom = + string + |> andThen + (\result -> + hivSymptomFromString result + |> Maybe.map succeed + |> Maybe.withDefault (result ++ " is not a recognized HIVSymptom" |> fail) + ) + + +decodeHIVTreatmentReview : Decoder HIVTreatmentReview +decodeHIVTreatmentReview = + decodeHIVMeasurement decodeTreatmentOngoingValue diff --git a/client/src/elm/Backend/Measurement/Encoder.elm b/client/src/elm/Backend/Measurement/Encoder.elm index 3f04f10146..327b0f20c0 100644 --- a/client/src/elm/Backend/Measurement/Encoder.elm +++ b/client/src/elm/Backend/Measurement/Encoder.elm @@ -936,6 +936,11 @@ encodeTuberculosisMeasurement = encodeMeasurement "tuberculosis_encounter" +encodeHIVMeasurement : (value -> List ( String, Value )) -> HIVMeasurement value -> List ( String, Value ) +encodeHIVMeasurement = + encodeMeasurement "hiv_encounter" + + encodeMeasurement : String -> (value -> List ( String, Value )) -> Measurement (EntityUuid a) value -> List ( String, Value ) encodeMeasurement encounterTag encoder measurement = List.concat @@ -4518,3 +4523,91 @@ encodeTuberculosisSymptom = encodeTuberculosisTreatmentReview : TuberculosisTreatmentReview -> List ( String, Value ) encodeTuberculosisTreatmentReview = encodeTuberculosisMeasurement (encodeTreatmentOngoingValueWithType "tuberculosis_treatment_review") + + +encodeHIVDiagnostics : HIVDiagnostics -> List ( String, Value ) +encodeHIVDiagnostics = + encodeHIVMeasurement encodeHIVDiagnosticsValue + + +encodeHIVDiagnosticsValue : HIVDiagnosticsValue -> List ( String, Value ) +encodeHIVDiagnosticsValue value = + [ ( "hiv_diagnosis_signs", encodeEverySet encodeHIVDiagnosisSign value.signs ) + , ( "deleted", bool False ) + , ( "type", string "hiv_diagnostics" ) + ] + ++ encodeNullable "positive_result_date" value.positiveResultDate Gizra.NominalDate.encodeYYYYMMDD + + +encodeHIVDiagnosisSign : HIVDiagnosisSign -> Value +encodeHIVDiagnosisSign = + hivDiagnosisSignToString >> string + + +encodeHIVFollowUp : HIVFollowUp -> List ( String, Value ) +encodeHIVFollowUp = + encodeHIVMeasurement (encodeFollowUpValueWithType "hiv_follow_up") + + +encodeHIVHealthEducation : HIVHealthEducation -> List ( String, Value ) +encodeHIVHealthEducation = + encodeHIVMeasurement encodeHIVHealthEducationValue + + +encodeHIVHealthEducationValue : HIVHealthEducationValue -> List ( String, Value ) +encodeHIVHealthEducationValue value = + [ ( "hiv_health_education_signs", encodeEverySet encodeHIVHealthEducationSign value ) + , ( "deleted", bool False ) + , ( "type", string "hiv_health_education" ) + ] + + +encodeHIVHealthEducationSign : HIVHealthEducationSign -> Value +encodeHIVHealthEducationSign = + hivHealthEducationSignToString >> string + + +encodeHIVMedication : HIVMedication -> List ( String, Value ) +encodeHIVMedication = + encodeHIVMeasurement encodeHIVMedicationValue + + +encodeHIVMedicationValue : HIVMedicationValue -> List ( String, Value ) +encodeHIVMedicationValue value = + [ ( "prescribed_hiv_medications", encodeEverySet encodeHIVPrescribedMedication value ) + , ( "deleted", bool False ) + , ( "type", string "hiv_medication" ) + ] + + +encodeHIVPrescribedMedication : HIVPrescribedMedication -> Value +encodeHIVPrescribedMedication = + hivPrescribedMedicationToString >> string + + +encodeHIVReferral : HIVReferral -> List ( String, Value ) +encodeHIVReferral = + encodeHIVMeasurement (encodeSendToHCValueWithType "hiv_referral") + + +encodeHIVSymptomReview : HIVSymptomReview -> List ( String, Value ) +encodeHIVSymptomReview = + encodeHIVMeasurement encodeHIVSymptomReviewValue + + +encodeHIVSymptomReviewValue : HIVSymptomReviewValue -> List ( String, Value ) +encodeHIVSymptomReviewValue value = + [ ( "hiv_symptoms", encodeEverySet encodeHIVSymptom value ) + , ( "deleted", bool False ) + , ( "type", string "hiv_symptom_review" ) + ] + + +encodeHIVSymptom : HIVSymptom -> Value +encodeHIVSymptom = + hivSymptomToString >> string + + +encodeHIVTreatmentReview : HIVTreatmentReview -> List ( String, Value ) +encodeHIVTreatmentReview = + encodeHIVMeasurement (encodeTreatmentOngoingValueWithType "hiv_treatment_review") diff --git a/client/src/elm/Backend/Measurement/Model.elm b/client/src/elm/Backend/Measurement/Model.elm index d61c050895..fb1e622cf4 100644 --- a/client/src/elm/Backend/Measurement/Model.elm +++ b/client/src/elm/Backend/Measurement/Model.elm @@ -73,6 +73,10 @@ type alias TuberculosisMeasurement value = Measurement TuberculosisEncounterId value +type alias HIVMeasurement value = + Measurement HIVEncounterId value + + -- GROUP MEASUREMENT TYPES @@ -2956,10 +2960,10 @@ type alias TuberculosisSymptomReviewValue = type TuberculosisSymptom - = SymptomNightSweats - | SymptomBloodInSputum - | SymptomWeightLoss - | SymptomSevereFatigue + = TuberculosisSymptomNightSweats + | TuberculosisSymptomBloodInSputum + | TuberculosisSymptomWeightLoss + | TuberculosisSymptomSevereFatigue | NoTuberculosisSymptoms @@ -2968,6 +2972,119 @@ type alias TuberculosisTreatmentReview = +-- HIV: + + +type alias HIVDiagnostics = + HIVMeasurement HIVDiagnosticsValue + + +type alias HIVDiagnosticsValue = + { signs : EverySet HIVDiagnosisSign + , positiveResultDate : Maybe NominalDate + } + + +type HIVDiagnosisSign + = HIVResultPositiveReported + | HIVResultPositiveKnown + | HIVResultDateEstimated + | NoHIVDiagnosisSigns + + +type alias HIVFollowUp = + HIVMeasurement FollowUpValue + + +type alias HIVHealthEducation = + HIVMeasurement HIVHealthEducationValue + + +type alias HIVHealthEducationValue = + EverySet HIVHealthEducationSign + + +type HIVHealthEducationSign + = EducationPositiveResult + | EducationSaferSexPractices + | EducationEncouragedPartnerTesting + | EducationFamilyPlanningOptions + | NoHIVHealthEducationSigns + + +type alias HIVMedication = + HIVMeasurement HIVMedicationValue + + +type alias HIVMedicationValue = + EverySet HIVPrescribedMedication + + +type HIVPrescribedMedication + = HIVMedicationDolutegravirLamivudineTenofovir + | HIVMedicationAtazanavirRitonavir + | HIVMedicationDolutegravir + | HIVMedicationAbacavirLamivudine + | HIVMedicationLamivudineTenofovir + | HIVMedicationZidovudine + | HIVMedicationLamivudineZidovudineNevirapine + | HIVMedicationEfavirenzLamivudineTenofovir + | HIVMedicationLamivudineZidovudine + | HIVMedicationLopinavirRitonavir + | HIVMedicationDarunavirRitonavir + | HIVMedicationDarunavirCobicistat + | HIVMedicationRaltegravir + | HIVMedicationEfavirenz + | HIVMedicationNevirapine + | HIVMedicationEtravirine + | HIVMedicationTenofovir + | HIVMedicationLamivudine + | HIVMedicationAbacavir + | HIVMedicationBactrim + | HIVMedicationDapsone + | HIVMedicationIsoniazid + | HIVMedicationFluconazole + | HIVMedicationAzithromycin + | NoHIVPrescribedMedications + + +type alias HIVReferral = + HIVMeasurement SendToHCValue + + +type alias HIVSymptomReview = + HIVMeasurement HIVSymptomReviewValue + + +type alias HIVSymptomReviewValue = + EverySet HIVSymptom + + +type HIVSymptom + = HIVSymptomFever + | HIVSymptomFatigue + | HIVSymptomSwollenLymphNodes + | HIVSymptomSoreThroat + | HIVSymptomRash + | HIVSymptomMuscleJointPain + | HIVSymptomHeadache + | HIVSymptomSevereAbdominalPain + | HIVSymptomNightSweats + | HIVSymptomDiarrhea + | HIVSymptomWeightLoss + | HIVSymptomCoughingUpBlood + | HIVSymptomHairLoss + | HIVSymptomMouthUlcers + | HIVSymptomDifficultyBreathing + | HIVSymptomVomiting + | NoHIVSymptoms + + +type alias HIVTreatmentReview = + HIVMeasurement TreatmentOngoingValue + + + -- Stock Management: @@ -3238,6 +3355,7 @@ type alias FollowUpMeasurements = , prenatal : Dict PrenatalFollowUpId PrenatalFollowUp , wellChild : Dict WellChildFollowUpId WellChildFollowUp , tuberculosis : Dict TuberculosisFollowUpId TuberculosisFollowUp + , hiv : Dict HIVFollowUpId HIVFollowUp , traceContacts : Dict AcuteIllnessTraceContactId AcuteIllnessTraceContact , prenatalLabs : Dict PrenatalLabsResultsId PrenatalLabsResults , ncdLabs : Dict NCDLabsResultsId NCDLabsResults @@ -3346,6 +3464,17 @@ type alias TuberculosisMeasurements = } +type alias HIVMeasurements = + { diagnostics : Maybe ( HIVDiagnosticsId, HIVDiagnostics ) + , followUp : Maybe ( HIVFollowUpId, HIVFollowUp ) + , healthEducation : Maybe ( HIVHealthEducationId, HIVHealthEducation ) + , medication : Maybe ( HIVMedicationId, HIVMedication ) + , referral : Maybe ( HIVReferralId, HIVReferral ) + , symptomReview : Maybe ( HIVSymptomReviewId, HIVSymptomReview ) + , treatmentReview : Maybe ( HIVTreatmentReviewId, HIVTreatmentReview ) + } + + {-| A set of measurements that includes all required data for Stock management data presentation. -} diff --git a/client/src/elm/Backend/Measurement/Utils.elm b/client/src/elm/Backend/Measurement/Utils.elm index d6b508a5c1..74984435ad 100644 --- a/client/src/elm/Backend/Measurement/Utils.elm +++ b/client/src/elm/Backend/Measurement/Utils.elm @@ -19,6 +19,33 @@ import SyncManager.Model exposing (SiteFeature) import Utils.NominalDate exposing (sortTuplesByDateDesc) +generatePreviousMeasurements : + (ModelIndexedDb -> IndividualEncounterParticipantId -> List ( encounterId, { encounter | startDate : NominalDate } )) + -> (ModelIndexedDb -> Dict encounterId (WebData measurements)) + -> Maybe encounterId + -> IndividualEncounterParticipantId + -> ModelIndexedDb + -> List ( NominalDate, ( encounterId, measurements ) ) +generatePreviousMeasurements encountersByParticipantFunc measurementsByEncouterFunc currentEncounterId participantId db = + encountersByParticipantFunc db participantId + |> List.filterMap + (\( encounterId, encounter ) -> + -- We do not want to get data of current encounter. + if currentEncounterId == Just encounterId then + Nothing + + else + case Dict.get encounterId (measurementsByEncouterFunc db) of + Just (Success data) -> + Just ( encounter.startDate, ( encounterId, data ) ) + + _ -> + Nothing + ) + -- Most recent date to least recent date. + |> List.sortWith sortTuplesByDateDesc + + {-| Given a MUAC in cm, classify according to the measurement tool shown at -} @@ -3945,16 +3972,16 @@ tuberculosisDiagnosisFromString diagnosis = tuberculosisSymptomToString : TuberculosisSymptom -> String tuberculosisSymptomToString symptom = case symptom of - SymptomNightSweats -> + TuberculosisSymptomNightSweats -> "night-sweats" - SymptomBloodInSputum -> + TuberculosisSymptomBloodInSputum -> "blood-in-sputum" - SymptomWeightLoss -> + TuberculosisSymptomWeightLoss -> "wight-loss" - SymptomSevereFatigue -> + TuberculosisSymptomSevereFatigue -> "severe-fatigue" NoTuberculosisSymptoms -> @@ -3965,16 +3992,16 @@ tuberculosisSymptomFromString : String -> Maybe TuberculosisSymptom tuberculosisSymptomFromString symptom = case symptom of "night-sweats" -> - Just SymptomNightSweats + Just TuberculosisSymptomNightSweats "blood-in-sputum" -> - Just SymptomBloodInSputum + Just TuberculosisSymptomBloodInSputum "wight-loss" -> - Just SymptomWeightLoss + Just TuberculosisSymptomWeightLoss "severe-fatigue" -> - Just SymptomSevereFatigue + Just TuberculosisSymptomSevereFatigue "none" -> Just NoTuberculosisSymptoms @@ -4088,28 +4115,351 @@ tuberculosisPrescribedMedicationFromString sign = Nothing -generatePreviousMeasurements : - (ModelIndexedDb -> IndividualEncounterParticipantId -> List ( encounterId, { encounter | startDate : NominalDate } )) - -> (ModelIndexedDb -> Dict encounterId (WebData measurements)) - -> Maybe encounterId - -> IndividualEncounterParticipantId - -> ModelIndexedDb - -> List ( NominalDate, ( encounterId, measurements ) ) -generatePreviousMeasurements encountersByParticipantFunc measurementsByEncouterFunc currentEncounterId participantId db = - encountersByParticipantFunc db participantId - |> List.filterMap - (\( encounterId, encounter ) -> - -- We do not want to get data of current encounter. - if currentEncounterId == Just encounterId then - Nothing +hivDiagnosisSignToString : HIVDiagnosisSign -> String +hivDiagnosisSignToString diagnosis = + case diagnosis of + HIVResultPositiveReported -> + "result-positive-reported" - else - case Dict.get encounterId (measurementsByEncouterFunc db) of - Just (Success data) -> - Just ( encounter.startDate, ( encounterId, data ) ) + HIVResultPositiveKnown -> + "result-positive-known" - _ -> - Nothing - ) - -- Most recent date to least recent date. - |> List.sortWith sortTuplesByDateDesc + HIVResultDateEstimated -> + "result-date-estimated" + + NoHIVDiagnosisSigns -> + "none" + + +hivDiagnosisSignFromString : String -> Maybe HIVDiagnosisSign +hivDiagnosisSignFromString diagnosis = + case diagnosis of + "result-positive-reported" -> + Just HIVResultPositiveReported + + "result-positive-known" -> + Just HIVResultPositiveKnown + + "result-date-estimated" -> + Just HIVResultDateEstimated + + "none" -> + Just NoHIVDiagnosisSigns + + _ -> + Nothing + + +hivPrescribedMedicationToString : HIVPrescribedMedication -> String +hivPrescribedMedicationToString sign = + case sign of + HIVMedicationDolutegravirLamivudineTenofovir -> + "dtg-3tc-tdf" + + HIVMedicationAtazanavirRitonavir -> + "atz-r" + + HIVMedicationDolutegravir -> + "dtg" + + HIVMedicationAbacavirLamivudine -> + "abc-3tc" + + HIVMedicationLamivudineTenofovir -> + "3tc-tdf" + + HIVMedicationZidovudine -> + "azt" + + HIVMedicationLamivudineZidovudineNevirapine -> + "3tc-azt-nvp" + + HIVMedicationEfavirenzLamivudineTenofovir -> + "efv-3tc-tdf" + + HIVMedicationLamivudineZidovudine -> + "3tc-azt" + + HIVMedicationLopinavirRitonavir -> + "lvp-r" + + HIVMedicationDarunavirRitonavir -> + "drv-r" + + HIVMedicationDarunavirCobicistat -> + "drv-c" + + HIVMedicationRaltegravir -> + "ral" + + HIVMedicationEfavirenz -> + "efv" + + HIVMedicationNevirapine -> + "nvp" + + HIVMedicationEtravirine -> + "etr" + + HIVMedicationTenofovir -> + "tdf" + + HIVMedicationLamivudine -> + "3tc" + + HIVMedicationAbacavir -> + "abc" + + HIVMedicationBactrim -> + "bactrim" + + HIVMedicationDapsone -> + "dapsone" + + HIVMedicationIsoniazid -> + "isoniazid" + + HIVMedicationFluconazole -> + "fluconazole" + + HIVMedicationAzithromycin -> + "azithromycin" + + NoHIVPrescribedMedications -> + "none" + + +hivPrescribedMedicationFromString : String -> Maybe HIVPrescribedMedication +hivPrescribedMedicationFromString sign = + case sign of + "dtg-3tc-tdf" -> + Just HIVMedicationDolutegravirLamivudineTenofovir + + "atz-r" -> + Just HIVMedicationAtazanavirRitonavir + + "dtg" -> + Just HIVMedicationDolutegravir + + "abc-3tc" -> + Just HIVMedicationAbacavirLamivudine + + "3tc-tdf" -> + Just HIVMedicationLamivudineTenofovir + + "azt" -> + Just HIVMedicationZidovudine + + "3tc-azt-nvp" -> + Just HIVMedicationLamivudineZidovudineNevirapine + + "efv-3tc-tdf" -> + Just HIVMedicationEfavirenzLamivudineTenofovir + + "3tc-azt" -> + Just HIVMedicationLamivudineZidovudine + + "lvp-r" -> + Just HIVMedicationLopinavirRitonavir + + "drv-r" -> + Just HIVMedicationDarunavirRitonavir + + "drv-c" -> + Just HIVMedicationDarunavirCobicistat + + "ral" -> + Just HIVMedicationRaltegravir + + "efv" -> + Just HIVMedicationEfavirenz + + "nvp" -> + Just HIVMedicationNevirapine + + "etr" -> + Just HIVMedicationEtravirine + + "tdf" -> + Just HIVMedicationTenofovir + + "3tc" -> + Just HIVMedicationLamivudine + + "abc" -> + Just HIVMedicationAbacavir + + "bactrim" -> + Just HIVMedicationBactrim + + "dapsone" -> + Just HIVMedicationDapsone + + "isoniazid" -> + Just HIVMedicationIsoniazid + + "fluconazole" -> + Just HIVMedicationFluconazole + + "azithromycin" -> + Just HIVMedicationAzithromycin + + "none" -> + Just NoHIVPrescribedMedications + + _ -> + Nothing + + +hivSymptomToString : HIVSymptom -> String +hivSymptomToString symptom = + case symptom of + HIVSymptomFever -> + "fever" + + HIVSymptomFatigue -> + "fatigue" + + HIVSymptomSwollenLymphNodes -> + "swollen-lymph-nodes" + + HIVSymptomSoreThroat -> + "sore-throat" + + HIVSymptomRash -> + "rash" + + HIVSymptomMuscleJointPain -> + "muscle-joint-pain" + + HIVSymptomHeadache -> + "headache" + + HIVSymptomSevereAbdominalPain -> + "severe-abdominal-pain" + + HIVSymptomNightSweats -> + "night-sweats" + + HIVSymptomDiarrhea -> + "diarrhea" + + HIVSymptomWeightLoss -> + "wight-loss" + + HIVSymptomCoughingUpBlood -> + "coughing-up-blood" + + HIVSymptomHairLoss -> + "hair-loss" + + HIVSymptomMouthUlcers -> + "mouth-ulcers" + + HIVSymptomDifficultyBreathing -> + "difficulty-breathing" + + HIVSymptomVomiting -> + "vomiting" + + NoHIVSymptoms -> + "none" + + +hivSymptomFromString : String -> Maybe HIVSymptom +hivSymptomFromString symptom = + case symptom of + "fever" -> + Just HIVSymptomFever + + "fatigue" -> + Just HIVSymptomFatigue + + "swollen-lymph-nodes" -> + Just HIVSymptomSwollenLymphNodes + + "sore-throat" -> + Just HIVSymptomSoreThroat + + "rash" -> + Just HIVSymptomRash + + "muscle-joint-pain" -> + Just HIVSymptomMuscleJointPain + + "headache" -> + Just HIVSymptomHeadache + + "severe-abdominal-pain" -> + Just HIVSymptomSevereAbdominalPain + + "night-sweats" -> + Just HIVSymptomNightSweats + + "diarrhea" -> + Just HIVSymptomDiarrhea + + "wight-loss" -> + Just HIVSymptomWeightLoss + + "coughing-up-blood" -> + Just HIVSymptomCoughingUpBlood + + "hair-loss" -> + Just HIVSymptomHairLoss + + "mouth-ulcers" -> + Just HIVSymptomMouthUlcers + + "difficulty-breathing" -> + Just HIVSymptomDifficultyBreathing + + "vomiting" -> + Just HIVSymptomVomiting + + "none" -> + Just NoHIVSymptoms + + _ -> + Nothing + + +hivHealthEducationSignToString : HIVHealthEducationSign -> String +hivHealthEducationSignToString diagnosis = + case diagnosis of + EducationPositiveResult -> + "positive-result" + + EducationSaferSexPractices -> + "safer-sex-practices" + + EducationEncouragedPartnerTesting -> + "encouraged-partner-testing" + + EducationFamilyPlanningOptions -> + "family-planning-options" + + NoHIVHealthEducationSigns -> + "none" + + +hivHealthEducationSignFromString : String -> Maybe HIVHealthEducationSign +hivHealthEducationSignFromString diagnosis = + case diagnosis of + "positive-result" -> + Just EducationPositiveResult + + "safer-sex-practices" -> + Just EducationSaferSexPractices + + "encouraged-partner-testing" -> + Just EducationEncouragedPartnerTesting + + "family-planning-options" -> + Just EducationFamilyPlanningOptions + + "none" -> + Just NoHIVHealthEducationSigns + + _ -> + Nothing diff --git a/client/src/elm/Backend/Model.elm b/client/src/elm/Backend/Model.elm index 406cc7c7fd..73da00a1f5 100644 --- a/client/src/elm/Backend/Model.elm +++ b/client/src/elm/Backend/Model.elm @@ -31,6 +31,7 @@ import Backend.Counseling.Model exposing (CounselingSchedule, CounselingTopic, E import Backend.Dashboard.Model exposing (DashboardStatsRaw) import Backend.EducationSession.Model exposing (EducationSession) import Backend.Entities exposing (..) +import Backend.HIVEncounter.Model exposing (HIVEncounter) import Backend.HealthCenter.Model exposing (CatchmentArea, HealthCenter) import Backend.HomeVisitEncounter.Model exposing (HomeVisitEncounter) import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterParticipant, IndividualEncounterType, IndividualParticipantExtraData) @@ -100,6 +101,7 @@ type alias ModelIndexedDb = , ncdEncounterRequests : Dict NCDEncounterId Backend.NCDEncounter.Model.Model , childScoreboardEncounterRequests : Dict ChildScoreboardEncounterId Backend.ChildScoreboardEncounter.Model.Model , tuberculosisEncounterRequests : Dict TuberculosisEncounterId Backend.TuberculosisEncounter.Model.Model + , hivEncounterRequests : Dict HIVEncounterId Backend.HIVEncounter.Model.Model , traceContactRequests : Dict AcuteIllnessTraceContactId Backend.TraceContact.Model.Model , nurseRequests : Dict NurseId Backend.Nurse.Model.Model , resilienceSurveyRequests : Dict NurseId Backend.ResilienceSurvey.Model.Model @@ -132,6 +134,7 @@ type alias ModelIndexedDb = , ncdEncounters : Dict NCDEncounterId (WebData NCDEncounter) , childScoreboardEncounters : Dict ChildScoreboardEncounterId (WebData ChildScoreboardEncounter) , tuberculosisEncounters : Dict TuberculosisEncounterId (WebData TuberculosisEncounter) + , hivEncounters : Dict HIVEncounterId (WebData HIVEncounter) , individualParticipants : Dict IndividualEncounterParticipantId (WebData IndividualEncounterParticipant) , traceContacts : Dict AcuteIllnessTraceContactId (WebData AcuteIllnessTraceContact) , educationSessions : Dict EducationSessionId (WebData EducationSession) @@ -146,6 +149,7 @@ type alias ModelIndexedDb = , ncdEncountersByParticipant : Dict IndividualEncounterParticipantId (WebData (Dict NCDEncounterId NCDEncounter)) , childScoreboardEncountersByParticipant : Dict IndividualEncounterParticipantId (WebData (Dict ChildScoreboardEncounterId ChildScoreboardEncounter)) , tuberculosisEncountersByParticipant : Dict IndividualEncounterParticipantId (WebData (Dict TuberculosisEncounterId TuberculosisEncounter)) + , hivEncountersByParticipant : Dict IndividualEncounterParticipantId (WebData (Dict HIVEncounterId HIVEncounter)) , prenatalMeasurements : Dict PrenatalEncounterId (WebData PrenatalMeasurements) , nutritionMeasurements : Dict NutritionEncounterId (WebData NutritionMeasurements) , acuteIllnessMeasurements : Dict AcuteIllnessEncounterId (WebData AcuteIllnessMeasurements) @@ -155,6 +159,7 @@ type alias ModelIndexedDb = , ncdMeasurements : Dict NCDEncounterId (WebData NCDMeasurements) , childScoreboardMeasurements : Dict ChildScoreboardEncounterId (WebData ChildScoreboardMeasurements) , tuberculosisMeasurements : Dict TuberculosisEncounterId (WebData TuberculosisMeasurements) + , hivMeasurements : Dict HIVEncounterId (WebData HIVMeasurements) , stockManagementMeasurements : Dict HealthCenterId (WebData StockManagementMeasurements) , stockManagementData : Dict HealthCenterId (WebData StockManagementData) , pregnancyByNewborn : Dict PersonId (WebData (Maybe ( IndividualEncounterParticipantId, IndividualEncounterParticipant ))) @@ -177,6 +182,9 @@ type alias ModelIndexedDb = -- Stock Management. , stockUpdates : WebData (Dict StockUpdateId StockUpdate) + -- Group Education. + , educationSessionsByPerson : Dict PersonId (WebData (Dict EducationSessionId EducationSession)) + -- Track requests to mutate data. , postPerson : WebData PersonId , postRelationship : Dict PersonId (WebData MyRelationship) @@ -191,6 +199,7 @@ type alias ModelIndexedDb = , postNCDEncounter : Dict IndividualEncounterParticipantId (WebData ( NCDEncounterId, NCDEncounter )) , postChildScoreboardEncounter : Dict IndividualEncounterParticipantId (WebData ( ChildScoreboardEncounterId, ChildScoreboardEncounter )) , postTuberculosisEncounter : Dict IndividualEncounterParticipantId (WebData ( TuberculosisEncounterId, TuberculosisEncounter )) + , postHIVEncounter : Dict IndividualEncounterParticipantId (WebData ( HIVEncounterId, HIVEncounter )) , postEducationSession : WebData ( EducationSessionId, EducationSession ) } @@ -226,6 +235,7 @@ emptyModelIndexedDb = , ncdMeasurements = Dict.empty , childScoreboardMeasurements = Dict.empty , tuberculosisMeasurements = Dict.empty + , hivMeasurements = Dict.empty , stockManagementMeasurements = Dict.empty , stockManagementData = Dict.empty , pregnancyByNewborn = Dict.empty @@ -233,6 +243,8 @@ emptyModelIndexedDb = , childScoreboardEncountersByParticipant = Dict.empty , tuberculosisEncounters = Dict.empty , tuberculosisEncountersByParticipant = Dict.empty + , hivEncounters = Dict.empty + , hivEncountersByParticipant = Dict.empty , educationSessions = Dict.empty , participantForms = NotAsked , participantsByPerson = Dict.empty @@ -248,6 +260,7 @@ emptyModelIndexedDb = , ncdEncounterRequests = Dict.empty , childScoreboardEncounterRequests = Dict.empty , tuberculosisEncounterRequests = Dict.empty + , hivEncounterRequests = Dict.empty , educationSessionRequests = Dict.empty , traceContactRequests = Dict.empty , individualEncounterParticipantRequests = Dict.empty @@ -267,6 +280,7 @@ emptyModelIndexedDb = , resilienceSurveysByNurse = Dict.empty , resilienceMessagesByNurse = Dict.empty , stockUpdates = NotAsked + , educationSessionsByPerson = Dict.empty , postPerson = NotAsked , postRelationship = Dict.empty , postPmtctParticipant = Dict.empty @@ -280,6 +294,7 @@ emptyModelIndexedDb = , postNCDEncounter = Dict.empty , postChildScoreboardEncounter = Dict.empty , postTuberculosisEncounter = Dict.empty + , postHIVEncounter = Dict.empty , postEducationSession = NotAsked } @@ -331,6 +346,7 @@ type MsgIndexedDb | FetchEditableSessionSummaryByActivity SessionId | FetchEditableSessionSummaryByParticipant SessionId | FetchEducationSession EducationSessionId + | FetchEducationSessionsForPerson PersonId | FetchEveryCounselingSchedule | FetchExpectedParticipants SessionId | FetchExpectedSessions PersonId @@ -356,6 +372,7 @@ type MsgIndexedDb | FetchWellChildMeasurements WellChildEncounterId | FetchNCDEncounter NCDEncounterId | FetchNCDEncountersForParticipant IndividualEncounterParticipantId + | FetchNCDEncountersForParticipants (List IndividualEncounterParticipantId) | FetchNCDMeasurements NCDEncounterId | FetchParticipantForms | FetchParticipantsForPerson PersonId @@ -380,6 +397,11 @@ type MsgIndexedDb | FetchTuberculosisEncountersForParticipant IndividualEncounterParticipantId | FetchTuberculosisEncountersForParticipants (List IndividualEncounterParticipantId) | FetchTuberculosisMeasurements TuberculosisEncounterId + | FetchHIVEncounter HIVEncounterId + | FetchHIVEncounters (List HIVEncounterId) + | FetchHIVEncountersForParticipant IndividualEncounterParticipantId + | FetchHIVEncountersForParticipants (List IndividualEncounterParticipantId) + | FetchHIVMeasurements HIVEncounterId | MarkForRecalculationStockManagementData HealthCenterId | FetchVillages | FetchTraceContact AcuteIllnessTraceContactId @@ -398,6 +420,7 @@ type MsgIndexedDb | HandleFetchedChildScoreboardMeasurements ChildScoreboardEncounterId (WebData ChildScoreboardMeasurements) | HandleFetchedClinics (WebData (Dict ClinicId Clinic)) | HandleFetchedEducationSession EducationSessionId (WebData EducationSession) + | HandleFetchedEducationSessionsForPerson PersonId (WebData (Dict EducationSessionId EducationSession)) | HandleFetchedEveryCounselingSchedule (WebData EveryCounselingSchedule) | HandleFetchedExpectedParticipants SessionId (WebData ExpectedParticipants) | HandleFetchedExpectedSessions PersonId (WebData (Dict SessionId Session)) @@ -423,6 +446,7 @@ type MsgIndexedDb | HandleFetchedWellChildMeasurements WellChildEncounterId (WebData WellChildMeasurements) | HandleFetchedNCDEncounter NCDEncounterId (WebData NCDEncounter) | HandleFetchedNCDEncountersForParticipant IndividualEncounterParticipantId (WebData (Dict NCDEncounterId NCDEncounter)) + | HandleFetchedNCDEncountersForParticipants (WebData (Dict IndividualEncounterParticipantId (Dict NCDEncounterId NCDEncounter))) | HandleFetchedNCDMeasurements NCDEncounterId (WebData NCDMeasurements) | HandleFetchedParticipantForms (WebData (Dict ParticipantFormId ParticipantForm)) | HandleFetchedParticipantsForPerson PersonId (WebData (Dict PmtctParticipantId PmtctParticipant)) @@ -446,6 +470,11 @@ type MsgIndexedDb | HandleFetchedTuberculosisEncountersForParticipant IndividualEncounterParticipantId (WebData (Dict TuberculosisEncounterId TuberculosisEncounter)) | HandleFetchedTuberculosisEncountersForParticipants (WebData (Dict IndividualEncounterParticipantId (Dict TuberculosisEncounterId TuberculosisEncounter))) | HandleFetchedTuberculosisMeasurements TuberculosisEncounterId (WebData TuberculosisMeasurements) + | HandleFetchedHIVEncounter HIVEncounterId (WebData HIVEncounter) + | HandleFetchedHIVEncounters (WebData (Dict HIVEncounterId HIVEncounter)) + | HandleFetchedHIVEncountersForParticipant IndividualEncounterParticipantId (WebData (Dict HIVEncounterId HIVEncounter)) + | HandleFetchedHIVEncountersForParticipants (WebData (Dict IndividualEncounterParticipantId (Dict HIVEncounterId HIVEncounter))) + | HandleFetchedHIVMeasurements HIVEncounterId (WebData HIVMeasurements) | HandleFetchedVillages (WebData (Dict VillageId Village)) | HandleFetchedTraceContact AcuteIllnessTraceContactId (WebData AcuteIllnessTraceContact) | HandleFetchedPregnancyByNewborn PersonId (WebData (Maybe ( IndividualEncounterParticipantId, IndividualEncounterParticipant ))) @@ -464,6 +493,7 @@ type MsgIndexedDb | PostNCDEncounter NCDEncounter | PostChildScoreboardEncounter ChildScoreboardEncounter | PostTuberculosisEncounter TuberculosisEncounter + | PostHIVEncounter HIVEncounter | PostEducationSession EducationSession -- Messages which handle responses to mutating data | HandlePostedPerson (Maybe PersonId) Initiator (WebData PersonId) @@ -480,6 +510,7 @@ type MsgIndexedDb | HandlePostedNCDEncounter IndividualEncounterParticipantId (WebData ( NCDEncounterId, NCDEncounter )) | HandlePostedChildScoreboardEncounter IndividualEncounterParticipantId (WebData ( ChildScoreboardEncounterId, ChildScoreboardEncounter )) | HandlePostedTuberculosisEncounter IndividualEncounterParticipantId (WebData ( TuberculosisEncounterId, TuberculosisEncounter )) + | HandlePostedHIVEncounter IndividualEncounterParticipantId (WebData ( HIVEncounterId, HIVEncounter )) | HandlePostedEducationSession (WebData ( EducationSessionId, EducationSession )) -- Operations we may want to perform when logout is clicked. | HandleLogout @@ -497,6 +528,7 @@ type MsgIndexedDb | MsgNCDEncounter NCDEncounterId Backend.NCDEncounter.Model.Msg | MsgChildScoreboardEncounter ChildScoreboardEncounterId Backend.ChildScoreboardEncounter.Model.Msg | MsgTuberculosisEncounter TuberculosisEncounterId Backend.TuberculosisEncounter.Model.Msg + | MsgHIVEncounter HIVEncounterId Backend.HIVEncounter.Model.Msg | MsgEducationSession EducationSessionId Backend.EducationSession.Model.Msg | MsgTraceContact AcuteIllnessTraceContactId Backend.TraceContact.Model.Msg | MsgIndividualEncounterParticipant IndividualEncounterParticipantId Backend.IndividualEncounterParticipant.Model.Msg @@ -558,6 +590,14 @@ type Revision | HealthCenterRevision HealthCenterId HealthCenter | HealthEducationRevision HealthEducationId HealthEducation | HeightRevision HeightId Height + | HIVDiagnosticsRevision HIVDiagnosticsId HIVDiagnostics + | HIVEncounterRevision HIVEncounterId HIVEncounter + | HIVFollowUpRevision HIVFollowUpId HIVFollowUp + | HIVHealthEducationRevision HIVHealthEducationId HIVHealthEducation + | HIVMedicationRevision HIVMedicationId HIVMedication + | HIVReferralRevision HIVReferralId HIVReferral + | HIVSymptomReviewRevision HIVSymptomReviewId HIVSymptomReview + | HIVTreatmentReviewRevision HIVTreatmentReviewId HIVTreatmentReview | HomeVisitEncounterRevision HomeVisitEncounterId HomeVisitEncounter | IndividualEncounterParticipantRevision IndividualEncounterParticipantId IndividualEncounterParticipant | IsolationRevision IsolationId Isolation diff --git a/client/src/elm/Backend/NutritionEncounter/Utils.elm b/client/src/elm/Backend/NutritionEncounter/Utils.elm index a9441141d3..4b04272d9f 100644 --- a/client/src/elm/Backend/NutritionEncounter/Utils.elm +++ b/client/src/elm/Backend/NutritionEncounter/Utils.elm @@ -4,6 +4,7 @@ import AssocList as Dict exposing (Dict) import Backend.AcuteIllnessEncounter.Model exposing (AcuteIllnessEncounter) import Backend.ChildScoreboardEncounter.Model exposing (ChildScoreboardEncounter) import Backend.Entities exposing (..) +import Backend.HIVEncounter.Model exposing (HIVEncounter) import Backend.HomeVisitEncounter.Model exposing (HomeVisitEncounter) import Backend.IndividualEncounterParticipant.Model import Backend.Measurement.Model exposing (..) @@ -335,6 +336,11 @@ getTuberculosisEncountersForParticipant = getParticipantEncountersByEncounterType .tuberculosisEncountersByParticipant +getHIVEncountersForParticipant : ModelIndexedDb -> IndividualEncounterParticipantId -> List ( HIVEncounterId, HIVEncounter ) +getHIVEncountersForParticipant = + getParticipantEncountersByEncounterType .hivEncountersByParticipant + + getPrenatalEncountersForParticipant : ModelIndexedDb -> IndividualEncounterParticipantId -> List ( PrenatalEncounterId, PrenatalEncounter ) getPrenatalEncountersForParticipant = getParticipantEncountersByEncounterType .prenatalEncountersByParticipant diff --git a/client/src/elm/Backend/Update.elm b/client/src/elm/Backend/Update.elm index ea2c99e587..a041739cb6 100644 --- a/client/src/elm/Backend/Update.elm +++ b/client/src/elm/Backend/Update.elm @@ -19,6 +19,8 @@ import Backend.EducationSession.Model import Backend.EducationSession.Update import Backend.Endpoints exposing (..) import Backend.Entities exposing (..) +import Backend.HIVEncounter.Model +import Backend.HIVEncounter.Update import Backend.HomeVisitEncounter.Model exposing (emptyHomeVisitEncounter) import Backend.HomeVisitEncounter.Update import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterType(..), IndividualParticipantExtraData(..), IndividualParticipantInitiator(..)) @@ -865,6 +867,49 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h , [] ) + FetchNCDEncountersForParticipants ids -> + let + ncdEncountersByParticipantUpdated = + List.foldl (\id accum -> Dict.insert id Loading accum) model.ncdEncountersByParticipant ids + in + ( { model | ncdEncountersByParticipant = ncdEncountersByParticipantUpdated } + , sw.select ncdEncounterEndpoint ids + |> toCmd + (RemoteData.fromResult + >> RemoteData.map + (.items + >> List.foldl + (\( encounterId, encounter ) accum -> + let + dictParticipantUpdated = + Dict.get encounter.participant accum + |> Maybe.map (Dict.insert encounterId encounter) + |> Maybe.withDefault (Dict.singleton encounterId encounter) + in + Dict.insert encounter.participant dictParticipantUpdated accum + ) + Dict.empty + ) + >> HandleFetchedNCDEncountersForParticipants + ) + , [] + ) + + HandleFetchedNCDEncountersForParticipants webData -> + case RemoteData.toMaybe webData of + Nothing -> + noChange + + Just dict -> + let + dictUpdated = + Dict.map (\_ v -> RemoteData.Success v) dict + in + ( { model | ncdEncountersByParticipant = Dict.union dictUpdated model.ncdEncountersByParticipant } + , Cmd.none + , [] + ) + FetchChildScoreboardEncountersForParticipant id -> ( { model | childScoreboardEncountersByParticipant = Dict.insert id Loading model.childScoreboardEncountersByParticipant } , sw.select childScoreboardEncounterEndpoint [ id ] @@ -934,6 +979,62 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h , [] ) + FetchHIVEncountersForParticipant id -> + ( { model | hivEncountersByParticipant = Dict.insert id Loading model.hivEncountersByParticipant } + , sw.select hivEncounterEndpoint [ id ] + |> toCmd (RemoteData.fromResult >> RemoteData.map (.items >> Dict.fromList) >> HandleFetchedHIVEncountersForParticipant id) + , [] + ) + + HandleFetchedHIVEncountersForParticipant id data -> + ( { model | hivEncountersByParticipant = Dict.insert id data model.hivEncountersByParticipant } + , Cmd.none + , [] + ) + + FetchHIVEncountersForParticipants ids -> + let + hivEncountersByParticipantUpdated = + List.foldl (\id accum -> Dict.insert id Loading accum) model.hivEncountersByParticipant ids + in + ( { model | hivEncountersByParticipant = hivEncountersByParticipantUpdated } + , sw.select hivEncounterEndpoint ids + |> toCmd + (RemoteData.fromResult + >> RemoteData.map + (.items + >> List.foldl + (\( encounterId, encounter ) accum -> + let + dictParticipantUpdated = + Dict.get encounter.participant accum + |> Maybe.map (Dict.insert encounterId encounter) + |> Maybe.withDefault (Dict.singleton encounterId encounter) + in + Dict.insert encounter.participant dictParticipantUpdated accum + ) + Dict.empty + ) + >> HandleFetchedHIVEncountersForParticipants + ) + , [] + ) + + HandleFetchedHIVEncountersForParticipants webData -> + case RemoteData.toMaybe webData of + Nothing -> + noChange + + Just dict -> + let + dictUpdated = + Dict.map (\_ v -> RemoteData.Success v) dict + in + ( { model | hivEncountersByParticipant = Dict.union dictUpdated model.hivEncountersByParticipant } + , Cmd.none + , [] + ) + FetchPrenatalMeasurements id -> ( { model | prenatalMeasurements = Dict.insert id Loading model.prenatalMeasurements } , sw.get prenatalMeasurementsEndpoint id @@ -1093,6 +1194,19 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h , [] ) + FetchHIVMeasurements id -> + ( { model | hivMeasurements = Dict.insert id Loading model.hivMeasurements } + , sw.get hivMeasurementsEndpoint id + |> toCmd (RemoteData.fromResult >> HandleFetchedHIVMeasurements id) + , [] + ) + + HandleFetchedHIVMeasurements id data -> + ( { model | hivMeasurements = Dict.insert id data model.hivMeasurements } + , Cmd.none + , [] + ) + FetchFollowUpParticipants ids -> if List.isEmpty ids then noChange @@ -1579,6 +1693,49 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h , [] ) + FetchHIVEncounter id -> + ( { model | hivEncounters = Dict.insert id Loading model.hivEncounters } + , sw.get hivEncounterEndpoint id + |> toCmd (RemoteData.fromResult >> HandleFetchedHIVEncounter id) + , [] + ) + + HandleFetchedHIVEncounter id data -> + ( { model | hivEncounters = Dict.insert id data model.hivEncounters } + , Cmd.none + , [] + ) + + FetchHIVEncounters ids -> + if List.isEmpty ids then + noChange + + else + let + hivEncountersUpdated = + List.foldl (\id accum -> Dict.insert id Loading accum) model.hivEncounters ids + in + ( { model | hivEncounters = hivEncountersUpdated } + , sw.getMany hivEncounterEndpoint ids + |> toCmd (RemoteData.fromResult >> RemoteData.map Dict.fromList >> HandleFetchedHIVEncounters) + , [] + ) + + HandleFetchedHIVEncounters webData -> + case RemoteData.toMaybe webData of + Nothing -> + noChange + + Just dict -> + let + dictUpdated = + Dict.map (\_ v -> RemoteData.Success v) dict + in + ( { model | hivEncounters = Dict.union dictUpdated model.hivEncounters } + , Cmd.none + , [] + ) + FetchEducationSession id -> ( { model | educationSessions = Dict.insert id Loading model.educationSessions } , sw.get educationSessionEndpoint id @@ -1592,6 +1749,19 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h , [] ) + FetchEducationSessionsForPerson id -> + ( { model | educationSessionsByPerson = Dict.insert id Loading model.educationSessionsByPerson } + , sw.select educationSessionEndpoint (Just id) + |> toCmd (RemoteData.fromResult >> RemoteData.map (.items >> Dict.fromList) >> HandleFetchedEducationSessionsForPerson id) + , [] + ) + + HandleFetchedEducationSessionsForPerson id data -> + ( { model | educationSessionsByPerson = Dict.insert id data model.educationSessionsByPerson } + , Cmd.none + , [] + ) + FetchSession sessionId -> ( { model | sessions = Dict.insert sessionId Loading model.sessions } , sw.get sessionEndpoint sessionId @@ -3583,6 +3753,24 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h , appMsgs ) + MsgHIVEncounter encounterId subMsg -> + let + encounter = + Dict.get encounterId model.hivEncounters + |> Maybe.andThen RemoteData.toMaybe + + requests = + Dict.get encounterId model.hivEncounterRequests + |> Maybe.withDefault Backend.HIVEncounter.Model.emptyModel + + ( subModel, subCmd, appMsgs ) = + Backend.HIVEncounter.Update.update currentDate nurseId healthCenterId encounterId encounter subMsg requests + in + ( { model | hivEncounterRequests = Dict.insert encounterId subModel model.hivEncounterRequests } + , Cmd.map (MsgHIVEncounter encounterId) subCmd + , appMsgs + ) + MsgEducationSession sessionId subMsg -> let encounter = @@ -3990,11 +4178,8 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h ChildScoreboardEncounter -> ChildScoreboardParticipantPage personId - NutritionEncounter -> - NutritionParticipantPage InitiatorParticipantsPage personId - - WellChildEncounter -> - WellChildParticipantPage InitiatorParticipantsPage personId + HIVEncounter -> + HIVParticipantPage personId -- We do not have a direct access to Home Visit -- encounter, since it resides under Nutrition menu. @@ -4005,9 +4190,15 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h NCDEncounter -> NCDParticipantPage InitiatorParticipantsPage personId + NutritionEncounter -> + NutritionParticipantPage InitiatorParticipantsPage personId + TuberculosisEncounter -> TuberculosisParticipantPage personId + WellChildEncounter -> + WellChildParticipantPage InitiatorParticipantsPage personId + -- Note yet implemented. Providing 'default' -- page, to satisfy compiler. InmmunizationEncounter -> @@ -4215,6 +4406,24 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h |> App.Model.MsgIndexedDb ] + HIVEncounter -> + [ Backend.HIVEncounter.Model.emptyHIVEncounter sessionId currentDate healthCenterId + |> Backend.Model.PostHIVEncounter + |> App.Model.MsgIndexedDb + ] + + HomeVisitEncounter -> + [ emptyHomeVisitEncounter sessionId currentDate healthCenterId + |> Backend.Model.PostHomeVisitEncounter + |> App.Model.MsgIndexedDb + ] + + NCDEncounter -> + [ Backend.NCDEncounter.Model.emptyNCDEncounter sessionId currentDate healthCenterId + |> Backend.Model.PostNCDEncounter + |> App.Model.MsgIndexedDb + ] + NutritionEncounter -> case extraData of NutritionData nutritionEncounterType -> @@ -4226,9 +4435,9 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h _ -> [] - HomeVisitEncounter -> - [ emptyHomeVisitEncounter sessionId currentDate healthCenterId - |> Backend.Model.PostHomeVisitEncounter + TuberculosisEncounter -> + [ Backend.TuberculosisEncounter.Model.emptyTuberculosisEncounter sessionId currentDate healthCenterId + |> Backend.Model.PostTuberculosisEncounter |> App.Model.MsgIndexedDb ] @@ -4243,18 +4452,6 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h _ -> [] - NCDEncounter -> - [ Backend.NCDEncounter.Model.emptyNCDEncounter sessionId currentDate healthCenterId - |> Backend.Model.PostNCDEncounter - |> App.Model.MsgIndexedDb - ] - - TuberculosisEncounter -> - [ Backend.TuberculosisEncounter.Model.emptyTuberculosisEncounter sessionId currentDate healthCenterId - |> Backend.Model.PostTuberculosisEncounter - |> App.Model.MsgIndexedDb - ] - InmmunizationEncounter -> [] ) @@ -4509,6 +4706,34 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h , rollbarOnFailure ++ appMsgs ) + PostHIVEncounter hivEncounter -> + ( { model | postHIVEncounter = Dict.insert hivEncounter.participant Loading model.postHIVEncounter } + , sw.post hivEncounterEndpoint hivEncounter + |> toCmd (RemoteData.fromResult >> HandlePostedHIVEncounter hivEncounter.participant) + , [] + ) + + HandlePostedHIVEncounter participantId data -> + let + rollbarOnFailure = + triggerRollbarOnFailure data + + appMsgs = + RemoteData.map + (\( hivEncounterId, _ ) -> + [ App.Model.SetActivePage <| + UserPage <| + Pages.Page.HIVEncounterPage hivEncounterId + ] + ) + data + |> RemoteData.withDefault [] + in + ( { model | postHIVEncounter = Dict.insert participantId data model.postHIVEncounter } + , Cmd.none + , rollbarOnFailure ++ appMsgs + ) + PostEducationSession educationSession -> ( { model | postEducationSession = Loading } , sw.post educationSessionEndpoint educationSession @@ -4898,8 +5123,29 @@ handleRevision currentDate healthCenterId villageId revision (( model, recalc ) let educationSessions = Dict.update uuid (Maybe.map (always (Success data))) model.educationSessions + + -- For every session participant, we check if it has data at + -- educationSessionsByPerson dict. If so, we add the session to + -- that data. + updatedEducationSessionsByPerson = + EverySet.toList data.participants + |> List.foldl + (\personId accum -> + Dict.get personId model.educationSessionsByPerson + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.map + (\sessionsDict -> + let + updatedSessionsDict = + Dict.insert uuid data sessionsDict + in + Dict.insert personId (Success updatedSessionsDict) accum + ) + |> Maybe.withDefault accum + ) + model.educationSessionsByPerson in - ( { model | educationSessions = educationSessions } + ( { model | educationSessions = educationSessions, educationSessionsByPerson = updatedEducationSessionsByPerson } , recalc ) @@ -4991,6 +5237,77 @@ handleRevision currentDate healthCenterId villageId revision (( model, recalc ) , True ) + HIVDiagnosticsRevision uuid data -> + ( mapHIVMeasurements + data.encounterId + (\measurements -> { measurements | diagnostics = Just ( uuid, data ) }) + model + , recalc + ) + + HIVEncounterRevision uuid data -> + let + hivEncounters = + Dict.update uuid (Maybe.map (always (Success data))) model.hivEncounters + + hivEncountersByParticipant = + Dict.remove data.participant model.hivEncountersByParticipant + in + ( { model + | hivEncounters = hivEncounters + , hivEncountersByParticipant = hivEncountersByParticipant + } + , recalc + ) + + HIVFollowUpRevision uuid data -> + ( mapHIVMeasurements + data.encounterId + (\measurements -> { measurements | followUp = Just ( uuid, data ) }) + model + , recalc + ) + + HIVHealthEducationRevision uuid data -> + ( mapHIVMeasurements + data.encounterId + (\measurements -> { measurements | healthEducation = Just ( uuid, data ) }) + model + , recalc + ) + + HIVMedicationRevision uuid data -> + ( mapHIVMeasurements + data.encounterId + (\measurements -> { measurements | medication = Just ( uuid, data ) }) + model + , recalc + ) + + HIVReferralRevision uuid data -> + ( mapHIVMeasurements + data.encounterId + (\measurements -> { measurements | referral = Just ( uuid, data ) }) + model + , recalc + ) + + HIVSymptomReviewRevision uuid data -> + ( mapHIVMeasurements + data.encounterId + (\measurements -> { measurements | symptomReview = Just ( uuid, data ) }) + model + , recalc + ) + + HIVTreatmentReviewRevision uuid data -> + ( mapHIVMeasurements + data.encounterId + (\measurements -> { measurements | treatmentReview = Just ( uuid, data ) }) + model + , recalc + ) + HomeVisitEncounterRevision uuid data -> let homeVisitEncounters = diff --git a/client/src/elm/Backend/Utils.elm b/client/src/elm/Backend/Utils.elm index a4396abac3..2cc4fcb8e2 100644 --- a/client/src/elm/Backend/Utils.elm +++ b/client/src/elm/Backend/Utils.elm @@ -9,6 +9,7 @@ import Backend.Measurement.Model , ChildMeasurementList , ChildScoreboardMeasurements , FollowUpMeasurements + , HIVMeasurements , HomeVisitMeasurements , MotherMeasurementList , NCDMeasurements @@ -163,6 +164,16 @@ mapTuberculosisMeasurements id func model = model +mapHIVMeasurements : Maybe HIVEncounterId -> (HIVMeasurements -> HIVMeasurements) -> ModelIndexedDb -> ModelIndexedDb +mapHIVMeasurements id func model = + case id of + Just encounterId -> + { model | hivMeasurements = Dict.update encounterId (Maybe.map (RemoteData.map func)) model.hivMeasurements } + + Nothing -> + model + + mapStockManagementMeasurements : Maybe HealthCenterId -> (StockManagementMeasurements -> StockManagementMeasurements) -> ModelIndexedDb -> ModelIndexedDb mapStockManagementMeasurements id func model = case id of @@ -283,3 +294,8 @@ tuberculosisManagementEnabled = groupEducationEnabled : EverySet SiteFeature -> Bool groupEducationEnabled = EverySet.member FeatureGroupEducation + + +hivManagementEnabled : EverySet SiteFeature -> Bool +hivManagementEnabled = + EverySet.member FeatureHIVManagement diff --git a/client/src/elm/Measurement/Utils.elm b/client/src/elm/Measurement/Utils.elm index 91b22370d9..1d6d73fe64 100644 --- a/client/src/elm/Measurement/Utils.elm +++ b/client/src/elm/Measurement/Utils.elm @@ -1444,8 +1444,8 @@ treatmentReviewInputsAndTasks language currentDate setTreatmentReviewBoolInputMs if missedDoses then let options = - List.repeat 22 "" - |> List.indexedMap (\index _ -> index) + List.repeat 21 "" + |> List.indexedMap (\index _ -> index + 1) missedDosesInput = viewCustomSelectListInput form.totalMissedDoses diff --git a/client/src/elm/Pages/AcuteIllness/Participant/View.elm b/client/src/elm/Pages/AcuteIllness/Participant/View.elm index 96c95946fc..a9483e9650 100644 --- a/client/src/elm/Pages/AcuteIllness/Participant/View.elm +++ b/client/src/elm/Pages/AcuteIllness/Participant/View.elm @@ -33,7 +33,7 @@ view language currentDate selectedHealthCenter personId isChw initiator db model |> Maybe.withDefault NotAsked in div - [ class "wrap wrap-alt-2 page-participant acute-illness" ] + [ class "wrap wrap-alt-2 page-participant individual acute-illness" ] [ viewHeader language initiator model , div [ class "ui full segment" ] diff --git a/client/src/elm/Pages/ChildScoreboard/Participant/View.elm b/client/src/elm/Pages/ChildScoreboard/Participant/View.elm index 7539f5803d..3e24868967 100644 --- a/client/src/elm/Pages/ChildScoreboard/Participant/View.elm +++ b/client/src/elm/Pages/ChildScoreboard/Participant/View.elm @@ -30,7 +30,7 @@ view language currentDate selectedHealthCenter id db = |> Maybe.withDefault NotAsked in div - [ class "wrap wrap-alt-2 page-participant ncd" ] + [ class "wrap wrap-alt-2 page-participant individual child-scoreboard" ] [ viewHeader language , div [ class "ui full segment" ] diff --git a/client/src/elm/Pages/Dashboard/Model.elm b/client/src/elm/Pages/Dashboard/Model.elm index ff6d3ffc11..67c328cc0e 100644 --- a/client/src/elm/Pages/Dashboard/Model.elm +++ b/client/src/elm/Pages/Dashboard/Model.elm @@ -1,7 +1,7 @@ module Pages.Dashboard.Model exposing (..) import AssocList exposing (Dict) -import Backend.Dashboard.Model exposing (ParticipantStats) +import Backend.Dashboard.Model exposing (EducationSessionData, ParticipantStats) import Backend.Entities exposing (VillageId) import Backend.Measurement.Model exposing (FamilyPlanningSign, Gender, VaccineDose, WellChildVaccineType) import EverySet exposing (EverySet) @@ -111,6 +111,7 @@ type alias Model = , currentBeneficiariesIncidenceChartsFilter : DashboardFilter , currentCaseManagementFilter : DashboardFilter , currentCaseManagementSubFilter : DashboardSubFilter + , educationSessionDrillIn : Maybe EducationSessionData , latestPage : DashboardPage , modalState : Maybe ModalState @@ -144,6 +145,7 @@ emptyModel maybeSelectedVillage = , currentBeneficiariesIncidenceChartsFilter = Stunting , currentCaseManagementFilter = Stunting , currentCaseManagementSubFilter = FilterTotal + , educationSessionDrillIn = Nothing , latestPage = PageMain , modalState = Nothing , monthGap = 0 @@ -249,3 +251,4 @@ type Msg | SetFilterProgramType String | SetSelectedVillage String | SetActivePage Page + | SetEducationSessionDrillIn (Maybe EducationSessionData) diff --git a/client/src/elm/Pages/Dashboard/Update.elm b/client/src/elm/Pages/Dashboard/Update.elm index 8574277d4d..2f605b26e7 100644 --- a/client/src/elm/Pages/Dashboard/Update.elm +++ b/client/src/elm/Pages/Dashboard/Update.elm @@ -158,6 +158,12 @@ update currentDate healthCenterId subPage db msg model = , [ App.Model.SetActivePage page ] ) + SetEducationSessionDrillIn session -> + ( { model | educationSessionDrillIn = session } + , Cmd.none + , [] + ) + getAssembledPermutationMsg : Maybe HealthCenterId -> Model -> List App.Model.Msg getAssembledPermutationMsg healthCenterId model = diff --git a/client/src/elm/Pages/Dashboard/Utils.elm b/client/src/elm/Pages/Dashboard/Utils.elm index 68ad8ffbf1..a02ad772cc 100644 --- a/client/src/elm/Pages/Dashboard/Utils.elm +++ b/client/src/elm/Pages/Dashboard/Utils.elm @@ -15,6 +15,7 @@ import Backend.Dashboard.Model , ChildrenBeneficiariesStats , DashboardStats , DashboardStatsRaw + , EducationSessionData , NCDDataItem , NCDEncounterDataItem , Nutrition @@ -22,6 +23,7 @@ import Backend.Dashboard.Model , NutritionStatus , NutritionValue , PMTCTDataItem + , PatientDetails , Periods , PersonIdentifier , PrenatalDataItem @@ -146,9 +148,24 @@ generateAssembledData currentDate healthCenterId stats db programTypeFilter sele , nutritionIndividualData = generateFilteredData .nutritionIndividualData stats selectedVillageFilter , nutritionGroupData = generateFilteredData .nutritionGroupData stats selectedVillageFilter , nutritionPageData = generateNutritionPageData currentDate filteredStats db programTypeFilter selectedVillageFilter + , groupEducationData = generateGroupEducationData stats selectedVillageFilter + , healthCenterVillages = Dict.keys stats.villagesWithResidents + , patientsDetails = generateFilteredPatientsDetails stats selectedVillageFilter } +generateGroupEducationData : DashboardStatsRaw -> Maybe VillageId -> List EducationSessionData +generateGroupEducationData stats selectedVillageFilter = + case selectedVillageFilter of + Just villageId -> + Dict.get villageId stats.groupEducationData + |> Maybe.withDefault [] + + Nothing -> + Dict.values stats.groupEducationData + |> List.concat + + generateFilteredDashboardStats : DashboardStatsRaw -> FilterProgramType -> Maybe VillageId -> DashboardStats generateFilteredDashboardStats stats programTypeFilter selectedVillageFilter = { caseManagement = @@ -166,16 +183,29 @@ generateFilteredDashboardStats stats programTypeFilter selectedVillageFilter = stats.caseManagement.lastYear |> caseManagementMergeDuplicates } - , childrenBeneficiaries = applyProgramTypeAndResidentsFilters stats.villagesWithResidents programTypeFilter selectedVillageFilter stats.childrenBeneficiaries + , childrenBeneficiaries = + applyProgramTypeAndResidentsFilters stats.villagesWithResidents + programTypeFilter + selectedVillageFilter + stats.childrenBeneficiaries , completedPrograms = stats.completedPrograms , familyPlanning = stats.familyPlanning , missedSessions = stats.missedSessions , totalEncounters = stats.totalEncounters - , villagesWithResidents = stats.villagesWithResidents , timestamp = stats.timestamp } +generateFilteredPatientsDetails : + DashboardStatsRaw + -> Maybe VillageId + -> Dict PersonIdentifier PatientDetails +generateFilteredPatientsDetails stats selectedVillageFilter = + Maybe.andThen (\villageId -> Dict.get villageId stats.villagesWithResidents) selectedVillageFilter + |> Maybe.map (\residents -> Dict.filter (\key _ -> List.member key residents) stats.patientsDetails) + |> Maybe.withDefault stats.patientsDetails + + generateFilteredData : (DashboardStatsRaw -> List { a | identifier : PersonIdentifier }) -> DashboardStatsRaw diff --git a/client/src/elm/Pages/Dashboard/View.elm b/client/src/elm/Pages/Dashboard/View.elm index 8c219eec70..8112b87ee6 100644 --- a/client/src/elm/Pages/Dashboard/View.elm +++ b/client/src/elm/Pages/Dashboard/View.elm @@ -11,6 +11,7 @@ import Backend.Dashboard.Model , CaseNutritionTotal , ChildScoreboardDataItem , DashboardStats + , EducationSessionData , NCDDataItem , Nutrition , NutritionDataItem @@ -19,7 +20,9 @@ import Backend.Dashboard.Model , NutritionValue , PMTCTDataItem , ParticipantStats + , PatientDetails , Periods + , PersonIdentifier , PrenatalDataItem , SPVDataItem , TotalBeneficiaries @@ -32,13 +35,14 @@ import Backend.Model exposing (ModelIndexedDb) import Backend.Nurse.Model exposing (Nurse) import Backend.NutritionEncounter.Model exposing (NutritionEncounterType(..)) import Backend.PrenatalEncounter.Types exposing (PrenatalDiagnosis(..)) +import Backend.Utils exposing (groupEducationEnabled) import Backend.WellChildEncounter.Model exposing (EncounterWarning(..), WellChildEncounterType(..)) import Color exposing (Color) import Date exposing (Month, Unit(..), numberToMonth) import Debug exposing (toString) -import EverySet -import Gizra.Html exposing (emptyNode, showMaybe) -import Gizra.NominalDate exposing (NominalDate, isDiffTruthy, toLastDayOfMonth) +import EverySet exposing (EverySet) +import Gizra.Html exposing (emptyNode, showIf, showMaybe) +import Gizra.NominalDate exposing (NominalDate, formatDDMMYYYY, isDiffTruthy, toLastDayOfMonth) import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (onClick, onInput) @@ -75,7 +79,7 @@ import Scale import Shape exposing (Arc, defaultPieConfig) import Svg import Svg.Attributes exposing (cx, cy, r) -import SyncManager.Model exposing (Site) +import SyncManager.Model exposing (Site, SiteFeature) import Translate exposing (Language, TranslationId, translate, translateText, translationSet) import TypedSvg exposing (g, svg) import TypedSvg.Attributes as Explicit exposing (fill, transform, viewBox) @@ -85,8 +89,19 @@ import Utils.Html exposing (spinner, viewModal) import Utils.NominalDate exposing (sortByDateDesc) -view : Language -> DashboardPage -> NominalDate -> Site -> HealthCenterId -> Bool -> Nurse -> Model -> ModelIndexedDb -> Html Msg -view language page currentDate site healthCenterId isChw nurse model db = +view : + Language + -> DashboardPage + -> NominalDate + -> Site + -> EverySet SiteFeature + -> HealthCenterId + -> Bool + -> Nurse + -> Model + -> ModelIndexedDb + -> Html Msg +view language page currentDate site features healthCenterId isChw nurse model db = let header = case page of @@ -99,10 +114,10 @@ view language page currentDate site healthCenterId isChw nurse model db = else Translate.DashboardLabel in - viewHeader language label PinCodePage + viewHeader language label (SetActivePage PinCodePage) PageAcuteIllness _ -> - viewHeader language Translate.AcuteIllness (UserPage <| DashboardPage PageMain) + viewHeader language Translate.AcuteIllness (SetActivePage <| UserPage <| DashboardPage PageMain) PageNutrition subPage -> let @@ -113,27 +128,38 @@ view language page currentDate site healthCenterId isChw nurse model db = else Translate.ChildNutrition - goBackPage = + goBackAction = case subPage of PageCharts -> - UserPage <| DashboardPage PageMain + SetActivePage <| UserPage <| DashboardPage PageMain PageStats -> - UserPage <| DashboardPage <| PageNutrition PageCharts + SetActivePage <| UserPage <| DashboardPage <| PageNutrition PageCharts PageCaseManagement -> - UserPage <| DashboardPage model.latestPage + SetActivePage <| UserPage <| DashboardPage model.latestPage in - viewHeader language label goBackPage + viewHeader language label goBackAction PagePrenatal -> - viewHeader language Translate.AntenatalCare (UserPage <| DashboardPage PageMain) + viewHeader language Translate.AntenatalCare (SetActivePage <| UserPage <| DashboardPage PageMain) PageNCD _ -> - viewHeader language Translate.NCDs (UserPage <| DashboardPage PageMain) + viewHeader language Translate.NCDs (SetActivePage <| UserPage <| DashboardPage PageMain) PageChildWellness _ -> - viewHeader language Translate.Pediatrics (UserPage <| DashboardPage PageMain) + viewHeader language Translate.Pediatrics (SetActivePage <| UserPage <| DashboardPage PageMain) + + PageGroupEducation -> + let + goBackAction = + if isJust model.educationSessionDrillIn then + SetEducationSessionDrillIn Nothing + + else + SetActivePage <| UserPage <| DashboardPage PageMain + in + viewHeader language Translate.GroupEducation goBackAction content = Dict.get healthCenterId db.computedDashboards @@ -144,7 +170,7 @@ view language page currentDate site healthCenterId isChw nurse model db = ( pageContent, pageClass ) = case page of PageMain -> - ( viewPageMain language currentDate healthCenterId isChw assembled db model + ( viewPageMain language currentDate features healthCenterId isChw assembled db model , "main" ) @@ -161,6 +187,7 @@ view language page currentDate site healthCenterId isChw nurse model db = nurse subPage assembled.stats + assembled.patientsDetails assembled.nutritionPageData db model @@ -175,11 +202,16 @@ view language page currentDate site healthCenterId isChw nurse model db = PageChildWellness subPage -> ( viewChildWellnessPage language currentDate site healthCenterId subPage assembled db model, "child-wellness" ) + + PageGroupEducation -> + ( viewGroupEducationPage language currentDate isChw assembled db model, "group-education" ) in div [ class <| "dashboard " ++ pageClass ] <| - viewFiltersPane language page db model + (viewFiltersPane language page db model + |> showIf (isNothing model.educationSessionDrillIn) + ) :: pageContent - ++ [ viewCustomModal language page isChw nurse assembled.stats db model + ++ [ viewCustomModal language page isChw nurse assembled db model , div [ class "timestamp" ] [ text <| (translate language <| Translate.Dashboard Translate.LastUpdated) ++ ": " ++ assembled.stats.timestamp ++ " UTC" ] ] @@ -193,35 +225,35 @@ view language page currentDate site healthCenterId isChw nurse model db = ] -viewHeader : Language -> TranslationId -> Page -> Html Msg -viewHeader language label goBackPage = +viewHeader : Language -> TranslationId -> Msg -> Html Msg +viewHeader language label goBackAction = div [ class "ui basic head segment" ] [ h1 [ class "ui header" ] [ translateText language label ] , span [ class "link-back" - , onClick <| SetActivePage goBackPage + , onClick goBackAction ] [ span [ class "icon-back" ] [] ] ] -viewPageMain : Language -> NominalDate -> HealthCenterId -> Bool -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) -viewPageMain language currentDate healthCenterId isChw assembled db model = +viewPageMain : Language -> NominalDate -> EverySet SiteFeature -> HealthCenterId -> Bool -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) +viewPageMain language currentDate features healthCenterId isChw assembled db model = if isChw then - viewPageMainForChw language currentDate healthCenterId assembled db model + viewPageMainForChw language currentDate features healthCenterId assembled db model else - viewPageMainForNurse language currentDate healthCenterId assembled db model + viewPageMainForNurse language currentDate features healthCenterId assembled db model -viewPageMainForNurse : Language -> NominalDate -> HealthCenterId -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) -viewPageMainForNurse language currentDate healthCenterId assembled db model = - [ viewMenuForNurse language ] +viewPageMainForNurse : Language -> NominalDate -> EverySet SiteFeature -> HealthCenterId -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) +viewPageMainForNurse language currentDate features healthCenterId assembled db model = + [ viewMenuForNurse language features ] -viewPageMainForChw : Language -> NominalDate -> HealthCenterId -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) -viewPageMainForChw language currentDate healthCenterId assembled db model = +viewPageMainForChw : Language -> NominalDate -> EverySet SiteFeature -> HealthCenterId -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) +viewPageMainForChw language currentDate features healthCenterId assembled db model = let dateLastDayOfSelectedMonth = resolveSelectedDateForMonthSelector currentDate model.monthGap @@ -254,7 +286,7 @@ viewPageMainForChw language currentDate healthCenterId assembled db model = followUps |> Maybe.withDefault ( 0, 0, 0 ) in - [ viewMenuForChw language + [ viewMenuForChw language features , monthSelector language dateLastDayOfSelectedMonth model , div [ class "ui grid" ] [ div [ class "three column row" ] @@ -282,11 +314,12 @@ viewNutritionPage : -> Nurse -> NutritionSubPage -> DashboardStats + -> Dict PersonIdentifier PatientDetails -> NutritionPageData -> ModelIndexedDb -> Model -> List (Html Msg) -viewNutritionPage language currentDate healthCenterId isChw nurse activePage stats data db model = +viewNutritionPage language currentDate healthCenterId isChw nurse activePage stats patientsDetails data db model = case activePage of PageCharts -> viewNutritionChartsPage language currentDate isChw nurse activePage data db model @@ -295,7 +328,7 @@ viewNutritionPage language currentDate healthCenterId isChw nurse activePage sta viewStatsPage language currentDate isChw nurse stats healthCenterId db model PageCaseManagement -> - viewCaseManagementPage language currentDate stats db model + viewCaseManagementPage language currentDate stats patientsDetails db model viewStatsPage : Language -> NominalDate -> Bool -> Nurse -> DashboardStats -> HealthCenterId -> ModelIndexedDb -> Model -> List (Html Msg) @@ -388,8 +421,15 @@ mapMalnorishedByMonth mappedMonth caseManagement = [] -viewCaseManagementPage : Language -> NominalDate -> DashboardStats -> ModelIndexedDb -> Model -> List (Html Msg) -viewCaseManagementPage language currentDate stats db model = +viewCaseManagementPage : + Language + -> NominalDate + -> DashboardStats + -> Dict PersonIdentifier PatientDetails + -> ModelIndexedDb + -> Model + -> List (Html Msg) +viewCaseManagementPage language currentDate stats patientsDetails db model = if model.programTypeFilter /= FilterProgramFbf then [] @@ -437,8 +477,13 @@ viewCaseManagementPage language currentDate stats db model = ) |> List.sortBy Tuple.first |> List.reverse + + name = + Dict.get caseNutrition.identifier patientsDetails + |> Maybe.map .name + |> Maybe.withDefault "" in - { name = caseNutrition.name, nutrition = nutrition } :: accum + { name = name, nutrition = nutrition } :: accum ) [] stats.caseManagement.thisYear @@ -447,18 +492,24 @@ viewCaseManagementPage language currentDate stats db model = _ -> List.foldl (\caseNutrition accum -> + let + name = + Dict.get caseNutrition.identifier patientsDetails + |> Maybe.map .name + |> Maybe.withDefault "" + in case model.currentCaseManagementFilter of Stunting -> - { name = caseNutrition.name, nutrition = filterForCaseManagementTableFunc caseNutrition.nutrition.stunting } :: accum + { name = name, nutrition = filterForCaseManagementTableFunc caseNutrition.nutrition.stunting } :: accum Underweight -> - { name = caseNutrition.name, nutrition = filterForCaseManagementTableFunc caseNutrition.nutrition.underweight } :: accum + { name = name, nutrition = filterForCaseManagementTableFunc caseNutrition.nutrition.underweight } :: accum Wasting -> - { name = caseNutrition.name, nutrition = filterForCaseManagementTableFunc caseNutrition.nutrition.wasting } :: accum + { name = name, nutrition = filterForCaseManagementTableFunc caseNutrition.nutrition.wasting } :: accum MUAC -> - { name = caseNutrition.name, nutrition = filterForCaseManagementTableFunc caseNutrition.nutrition.muac } :: accum + { name = name, nutrition = filterForCaseManagementTableFunc caseNutrition.nutrition.muac } :: accum -- We'll never get here - need to list it to satisfy compiler. MissedSession -> @@ -632,27 +683,48 @@ viewFiltersPane language page db model = filters -viewMenuForNurse : Language -> Html Msg -viewMenuForNurse language = +viewMenuForNurse : Language -> EverySet SiteFeature -> Html Msg +viewMenuForNurse language features = + let + groupEducationButton = + if groupEducationEnabled features then + viewMenuButton language PageGroupEducation Nothing + + else + emptyNode + in div [] - [ div [ class "ui segment page-filters nurse" ] + [ div [ class "ui segment page-filters top-row" ] [ viewMenuButton language PagePrenatal Nothing , viewMenuButton language (PageNutrition PageCharts) Nothing , viewMenuButton language (PageAcuteIllness PageAcuteIllnessOverview) Nothing ] - , div [ class "ui segment page-filters nurse center" ] + , div [ class "ui segment page-filters center" ] [ viewMenuButton language (PageNCD PageHypertension) Nothing , viewMenuButton language (PageChildWellness PageChildWellnessOverview) Nothing + , groupEducationButton ] ] -viewMenuForChw : Language -> Html Msg -viewMenuForChw language = - div [ class "ui segment page-filters" ] - [ viewMenuButton language PagePrenatal Nothing - , viewMenuButton language (PageNutrition PageCharts) Nothing - , viewMenuButton language (PageAcuteIllness PageAcuteIllnessOverview) Nothing +viewMenuForChw : Language -> EverySet SiteFeature -> Html Msg +viewMenuForChw language features = + let + secondRow = + if groupEducationEnabled features then + div [ class "ui segment page-filters center" ] + [ viewMenuButton language PageGroupEducation Nothing ] + + else + emptyNode + in + div [] + [ div [ class "ui segment page-filters top-row" ] + [ viewMenuButton language PagePrenatal Nothing + , viewMenuButton language (PageNutrition PageCharts) Nothing + , viewMenuButton language (PageAcuteIllness PageAcuteIllnessOverview) Nothing + ] + , secondRow ] @@ -1069,6 +1141,116 @@ viewNutritionChartsPage language currentDate isChw nurse activePage data db mode ] +viewGroupEducationPage : Language -> NominalDate -> Bool -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) +viewGroupEducationPage language currentDate isChw assembled db model = + Maybe.map (viewGroupEducationDrillIn language currentDate assembled.patientsDetails) + model.educationSessionDrillIn + |> Maybe.withDefault (viewGroupEducationStandard language currentDate isChw assembled db model) + + +viewGroupEducationDrillIn : Language -> NominalDate -> Dict PersonIdentifier PatientDetails -> EducationSessionData -> List (Html Msg) +viewGroupEducationDrillIn language currentDate patientsDetails session = + let + topics = + EverySet.toList session.topics + |> List.map (\topic -> li [] [ text <| translate language <| Translate.EducationTopic topic ]) + |> ul [ class "session-topics" ] + + tableContent = + headerRow + :: (List.map viewPatientEntry <| + EverySet.toList session.participants + ) + + headerRow = + div [ class "entry header" ] + [ div [ class "name" ] [ text <| translate language Translate.Name ] + , div [ class "gender" ] [ text <| translate language Translate.GenderLabel ] + ] + + viewPatientEntry patientId = + Dict.get patientId patientsDetails + |> Maybe.map + (\patient -> + div [ class "entry" ] + [ div [ class "name" ] [ text patient.name ] + , div [ class "gender" ] [ text <| translate language <| Translate.Gender patient.gender ] + ] + ) + |> Maybe.withDefault emptyNode + in + [ topics + , div [ class "ui grid" ] + [ div [ class "patients-table" ] + tableContent + ] + ] + + +viewGroupEducationStandard : Language -> NominalDate -> Bool -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) +viewGroupEducationStandard language currentDate isChw assembled db model = + let + dateLastDayOfSelectedMonth = + resolveSelectedDateForMonthSelector currentDate model.monthGap + + sessionsDuringSelectedMonth = + List.filter (.startDate >> withinSelectedMonth dateLastDayOfSelectedMonth) assembled.groupEducationData + + attendeesDuringSelectedMonth = + List.map (.participants >> EverySet.toList) sessionsDuringSelectedMonth + |> List.concat + + uniqueAttendeesDuringSelectedMonth = + EverySet.fromList attendeesDuringSelectedMonth + + tableContent = + headerRow + :: List.map viewSessionEntry sessionsDuringSelectedMonth + + headerRow = + div [ class "entry header" ] + [ div [ class "topics" ] [ text <| translate language Translate.GroupEducation ] + , div [ class "date" ] [ text <| translate language Translate.StartDate ] + , div [ class "attendance" ] [ text <| translate language Translate.Attendance ] + ] + + viewSessionEntry session = + let + drillInArrributes = + if isJust model.selectedVillageFilter then + [ class "icon-forward" + , onClick <| SetEducationSessionDrillIn (Just session) + ] + + else + [ class "icon-forward hidden" ] + in + div [ class "entry" ] + [ EverySet.toList session.topics + |> List.map (\topic -> li [] [ text <| translate language <| Translate.EducationTopic topic ]) + |> ul [ class "topics" ] + , div [ class "date" ] + [ text <| formatDDMMYYYY session.startDate ] + , div [ class "attendance" ] + [ text <| String.fromInt <| EverySet.size session.participants ] + , div drillInArrributes [] + ] + in + [ monthSelector language dateLastDayOfSelectedMonth model + , div [ class "ui grid" ] + [ div [ class "three column row" ] + [ chwCard language (Translate.Dashboard Translate.NumberOfGroupSessions) (String.fromInt <| List.length sessionsDuringSelectedMonth) + , chwCard language (Translate.Dashboard Translate.TotalAttendees) (String.fromInt <| List.length attendeesDuringSelectedMonth) + , chwCard language (Translate.Dashboard Translate.UniquePatients) (String.fromInt <| EverySet.size uniqueAttendeesDuringSelectedMonth) + ] + ] + , div [ class "ui grid" ] + [ div [ class "sessions-table" ] + tableContent + ] + ] + + viewPrenatalPage : Language -> NominalDate -> Bool -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) viewPrenatalPage language currentDate isChw assembled db model = let @@ -1444,11 +1626,10 @@ viewMiscCards language currentDate stats monthBeforeStats = totalNewBeneficiariesTable = List.foldl (\childrenBeneficiaries accum -> - { name = childrenBeneficiaries.name + { identifier = childrenBeneficiaries.identifier , gender = childrenBeneficiaries.gender , birthDate = childrenBeneficiaries.birthDate - , motherName = childrenBeneficiaries.motherName - , phoneNumber = childrenBeneficiaries.phoneNumber + , motherIdentifier = childrenBeneficiaries.motherIdentifier , expectedDate = currentDate } :: accum @@ -2165,23 +2346,23 @@ viewPieChartLegend language translateFunc colorFunc signs = ) -viewCustomModal : Language -> DashboardPage -> Bool -> Nurse -> DashboardStats -> ModelIndexedDb -> Model -> Html Msg -viewCustomModal language page isChw nurse stats db model = +viewCustomModal : Language -> DashboardPage -> Bool -> Nurse -> AssembledData -> ModelIndexedDb -> Model -> Html Msg +viewCustomModal language page isChw nurse assembled db model = model.modalState |> Maybe.map (\state -> case state of StatisticsModal title data -> - viewStatsTableModal language title data + viewStatsTableModal language title assembled.patientsDetails data FiltersModal -> - viewFiltersModal language page isChw nurse stats db model + viewFiltersModal language page isChw nurse assembled.healthCenterVillages db model ) |> viewModal -viewStatsTableModal : Language -> String -> List ParticipantStats -> Html Msg -viewStatsTableModal language title data = +viewStatsTableModal : Language -> String -> Dict PersonIdentifier PatientDetails -> List ParticipantStats -> Html Msg +viewStatsTableModal language title patientsDetails data = div [ class "ui tiny active modal segment blue" ] [ div [ class "header" ] @@ -2203,14 +2384,14 @@ viewStatsTableModal language title data = ] ] , tbody [] - (List.map viewModalTableRow data) + (List.map (viewModalTableRow patientsDetails) data) ] ] ] -viewFiltersModal : Language -> DashboardPage -> Bool -> Nurse -> DashboardStats -> ModelIndexedDb -> Model -> Html Msg -viewFiltersModal language page isChw nurse stats db model = +viewFiltersModal : Language -> DashboardPage -> Bool -> Nurse -> List VillageId -> ModelIndexedDb -> Model -> Html Msg +viewFiltersModal language page isChw nurse healthCenterVillages db model = let programTypeFilterInputSection = if isChw then @@ -2281,19 +2462,19 @@ viewFiltersModal language page isChw nurse stats db model = :: options options = - Dict.keys stats.villagesWithResidents - |> List.filterMap - (\villageId -> - Dict.get villageId authorizedVillages - |> Maybe.map - (\village -> - option - [ value (fromEntityUuid villageId) - , selected (model.selectedVillageFilter == Just villageId) - ] - [ text village.name ] - ) - ) + List.filterMap + (\villageId -> + Dict.get villageId authorizedVillages + |> Maybe.map + (\village -> + option + [ value (fromEntityUuid villageId) + , selected (model.selectedVillageFilter == Just villageId) + ] + [ text village.name ] + ) + ) + healthCenterVillages villageInput = select @@ -2335,12 +2516,27 @@ viewFiltersModal language page isChw nurse stats db model = ] -viewModalTableRow : ParticipantStats -> Html Msg -viewModalTableRow rowData = +viewModalTableRow : Dict PersonIdentifier PatientDetails -> ParticipantStats -> Html Msg +viewModalTableRow patientsDetails rowData = + let + name = + Dict.get rowData.identifier patientsDetails + |> Maybe.map .name + |> Maybe.withDefault "" + + ( motherName, phoneNumber ) = + Maybe.andThen + (\motherIdentifier -> + Dict.get motherIdentifier patientsDetails + |> Maybe.map (\details -> ( details.name, details.phoneNumber )) + ) + rowData.motherIdentifier + |> Maybe.withDefault ( "", Nothing ) + in tr [] - [ td [ class "name" ] [ text rowData.name ] - , td [ class "mother-name" ] [ text rowData.motherName ] - , td [ class "phone-number" ] [ text <| Maybe.withDefault "-" rowData.phoneNumber ] + [ td [ class "name" ] [ text name ] + , td [ class "mother-name" ] [ text motherName ] + , td [ class "phone-number" ] [ text <| Maybe.withDefault "-" phoneNumber ] ] diff --git a/client/src/elm/Pages/GlobalCaseManagement/Fetch.elm b/client/src/elm/Pages/GlobalCaseManagement/Fetch.elm index ac0965bd69..a6e941fe80 100644 --- a/client/src/elm/Pages/GlobalCaseManagement/Fetch.elm +++ b/client/src/elm/Pages/GlobalCaseManagement/Fetch.elm @@ -12,6 +12,7 @@ import Gizra.NominalDate exposing (NominalDate) import Pages.GlobalCaseManagement.Utils exposing (..) import Pages.Utils import RemoteData +import Restful.Endpoint exposing (fromEntityUuid) fetch : NominalDate -> HealthCenterId -> Maybe VillageId -> ModelIndexedDb -> List MsgIndexedDb @@ -57,7 +58,11 @@ fetchForCHWAtVillage currentDate villageId db allFollowUps = followUpPatients.immunization fetchIndividualParticipantsMsg = - FetchIndividualEncounterParticipantsForPeople (residentsForNutrition ++ residentsForImmunization) + peopleFromPositiveResultHIVFollowUps + ++ residentsForNutrition + ++ residentsForImmunization + |> Pages.Utils.unique + |> FetchIndividualEncounterParticipantsForPeople -- -- Nutrition follows ups calculations. @@ -137,20 +142,77 @@ fetchForCHWAtVillage currentDate villageId db allFollowUps = fetchTuberculosisEncountersForParticipantMsg = EverySet.toList tuberculosisParticipants |> FetchTuberculosisEncountersForParticipants + + -- + -- HIV follows ups calculations. + -- + -- There are regular HIV follow ups, and 'dummy' HIV + -- follow ups created for positive HIV test results. + ( positiveResultHIVFollowUps, hivFollowUps ) = + Dict.values followUps.hiv + |> List.partition + (\followUp -> + Maybe.map + (\encounterId -> + fromEntityUuid encounterId == "dummy" + ) + followUp.encounterId + |> Maybe.withDefault False + ) + + hivEncounters = + List.filterMap .encounterId hivFollowUps + |> EverySet.fromList + + hivParticipants = + generateHIVParticipants hivEncounters db + + fetchHIVEncountersMsg = + EverySet.toList hivEncounters + |> FetchHIVEncounters + + fetchHIVParticipantsMsg = + EverySet.toList hivParticipants + |> FetchIndividualEncounterParticipants + + fetchHIVEncountersForParticipantMsg = + EverySet.toList hivParticipants + |> FetchHIVEncountersForParticipants + + -- Used to fetch HIV patrticipants for patients (above), + -- and their HIV encounters. + -- We need the HIV encounters to determine if to show follow up + -- entry or not (positive result entry is shown unless there was + -- HIV encounter after result was recorded). + peopleFromPositiveResultHIVFollowUps = + List.map .participantId positiveResultHIVFollowUps + + fetchHIVEncountersForPositiveResultFollowUpsParticipantMsg = + List.map + (\personId -> + resolveIndividualParticipantsForPerson personId HIVEncounter db + ) + peopleFromPositiveResultHIVFollowUps + |> List.concat + |> FetchHIVEncountersForParticipants in [ FetchPeopleInVillage villageId , fetchAcuteIllnessEncountersMsg , fetchPrenatalEncountersMsg , fetchTuberculosisEncountersMsg , fetchWellChildEncountersMsg + , fetchHIVEncountersMsg , fetchAcuteIllnessParticipantsMsg , fetchPrenatalParticipantsMsg , fetchTuberculosisParticipantsMsg , fetchHomeVisitEncountersMsg + , fetchHIVParticipantsMsg , fetchAcuteIllnessEncountersForParticipantMsg , fetchPrenatalEncountersForParticipantMsg , fetchTuberculosisEncountersForParticipantMsg + , fetchHIVEncountersForParticipantMsg , fetchIndividualParticipantsMsg + , fetchHIVEncountersForPositiveResultFollowUpsParticipantMsg ] diff --git a/client/src/elm/Pages/GlobalCaseManagement/Model.elm b/client/src/elm/Pages/GlobalCaseManagement/Model.elm index fd04de97ed..ba6256d9af 100644 --- a/client/src/elm/Pages/GlobalCaseManagement/Model.elm +++ b/client/src/elm/Pages/GlobalCaseManagement/Model.elm @@ -32,11 +32,12 @@ emptyModel = type CaseManagementFilter = FilterAcuteIllness | FilterAntenatal - | FilterNutrition | FilterContactsTrace - | FilterPrenatalLabs - | FilterNCDLabs + | FilterHIV | FilterImmunization + | FilterNCDLabs + | FilterNutrition + | FilterPrenatalLabs | FilterTuberculosis @@ -128,12 +129,28 @@ type alias TuberculosisFollowUpEntry = } +type alias HIVFollowUpItem = + { dateMeasured : NominalDate + , personName : String + , encounterId : Maybe HIVEncounterId + , value : FollowUpValue + } + + +type alias HIVFollowUpEntry = + { participantId : Maybe IndividualEncounterParticipantId + , personId : PersonId + , item : HIVFollowUpItem + } + + type FollowUpEncounterDataType = FollowUpNutrition FollowUpNutritionData | FollowUpAcuteIllness FollowUpAcuteIllnessData | FollowUpPrenatal FollowUpPrenatalData | FollowUpImmunization FollowUpImmunizationData | FollowUpTuberculosis FollowUpTuberculosisData + | FollowUpHIV FollowUpHIVData | CaseManagementContactsTracing @@ -174,6 +191,13 @@ type alias FollowUpTuberculosisData = } +type alias FollowUpHIVData = + { personId : PersonId + , personName : String + , participantId : Maybe IndividualEncounterParticipantId + } + + type alias ContactsTracingEntryData = { itemId : AcuteIllnessTraceContactId , personName : String @@ -210,10 +234,7 @@ type alias NCDLabsEntryData = type alias FollowUpPatients = { nutrition : List PersonId - , acuteIllness : List PersonId - , prenatal : List PersonId , immunization : List PersonId - , tuberculosis : List PersonId } diff --git a/client/src/elm/Pages/GlobalCaseManagement/Update.elm b/client/src/elm/Pages/GlobalCaseManagement/Update.elm index 4bb9d90d4a..bf062654c3 100644 --- a/client/src/elm/Pages/GlobalCaseManagement/Update.elm +++ b/client/src/elm/Pages/GlobalCaseManagement/Update.elm @@ -4,6 +4,7 @@ import App.Model import Backend.AcuteIllnessEncounter.Model exposing (emptyAcuteIllnessEncounter) import Backend.AcuteIllnessEncounter.Types exposing (AcuteIllnessEncounterType(..)) import Backend.Entities exposing (..) +import Backend.HIVEncounter.Model exposing (emptyHIVEncounter) import Backend.HomeVisitEncounter.Model exposing (emptyHomeVisitEncounter) import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterType(..), emptyIndividualEncounterParticipant) import Backend.Model exposing (ModelIndexedDb) @@ -56,6 +57,9 @@ update currentDate healthCenterId msg db model = FollowUpTuberculosis data -> startFollowUpEncounterTuberculosis currentDate selectedHealthCenter data + FollowUpHIV data -> + startFollowUpEncounterHIV currentDate selectedHealthCenter data + -- We should never get here, as Prenatal Encounter got it's own action. FollowUpPrenatal _ -> [] @@ -151,3 +155,23 @@ startFollowUpEncounterTuberculosis currentDate selectedHealthCenter data = |> Backend.Model.PostIndividualEncounterParticipant Backend.IndividualEncounterParticipant.Model.NoIndividualParticipantExtraData |> App.Model.MsgIndexedDb ] + + +startFollowUpEncounterHIV : NominalDate -> HealthCenterId -> FollowUpHIVData -> List App.Model.Msg +startFollowUpEncounterHIV currentDate selectedHealthCenter data = + -- If participant was provided, we create new encounter for existing participant. + Maybe.map + (\participantId -> + [ emptyHIVEncounter participantId currentDate (Just selectedHealthCenter) + |> Backend.Model.PostHIVEncounter + |> App.Model.MsgIndexedDb + ] + ) + data.participantId + |> -- Participant was not provided, so we create new participant (which + -- also creates encounter for newly created participant). + Maybe.withDefault + [ emptyIndividualEncounterParticipant currentDate data.personId Backend.IndividualEncounterParticipant.Model.HIVEncounter selectedHealthCenter + |> Backend.Model.PostIndividualEncounterParticipant Backend.IndividualEncounterParticipant.Model.NoIndividualParticipantExtraData + |> App.Model.MsgIndexedDb + ] diff --git a/client/src/elm/Pages/GlobalCaseManagement/Utils.elm b/client/src/elm/Pages/GlobalCaseManagement/Utils.elm index b08af7c2dc..fcdafb4592 100644 --- a/client/src/elm/Pages/GlobalCaseManagement/Utils.elm +++ b/client/src/elm/Pages/GlobalCaseManagement/Utils.elm @@ -13,7 +13,7 @@ import Backend.Measurement.Model , PrenatalLabsResults ) import Backend.Model exposing (ModelIndexedDb) -import Backend.Utils exposing (tuberculosisManagementEnabled) +import Backend.Utils exposing (hivManagementEnabled, tuberculosisManagementEnabled) import Backend.Village.Model exposing (Village) import Backend.Village.Utils exposing (isVillageResident) import Date exposing (Unit(..)) @@ -22,6 +22,7 @@ import Gizra.NominalDate exposing (NominalDate, diffDays) import Pages.GlobalCaseManagement.Model exposing (..) import Pages.Utils import RemoteData exposing (WebData) +import Restful.Endpoint exposing (fromEntityUuid, toEntityUuid) import SyncManager.Model exposing (SiteFeature) @@ -38,6 +39,12 @@ chwFilters features = else [] ) + ++ (if hivManagementEnabled features then + [ FilterHIV ] + + else + [] + ) nurseFilters : List CaseManagementFilter @@ -380,6 +387,73 @@ generateTuberculosisFollowUps limitDate db followUps followUpsFromAcuteIllness = itemsFromTuberculosis +generateHIVFollowUps : + NominalDate + -> ModelIndexedDb + -> FollowUpMeasurements + -> Dict ( Maybe IndividualEncounterParticipantId, PersonId ) HIVFollowUpItem +generateHIVFollowUps limitDate db followUps = + let + encountersData = + generateHIVEncounters followUps + |> EverySet.toList + |> List.filterMap + (\encounterId -> + Dict.get encounterId db.hivEncounters + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.map (\encounter -> ( encounterId, encounter.participant )) + ) + |> Dict.fromList + in + Dict.values followUps.hiv + |> List.filter (.value >> .resolutionDate >> filterResolvedFollowUps limitDate) + |> List.foldl + (\item accum -> + let + personId = + item.participantId + + encounterIdAsString = + Maybe.map fromEntityUuid item.encounterId + in + if encounterIdAsString == Just "dummy" then + let + newItem = + HIVFollowUpItem item.dateMeasured "" Nothing item.value + in + Dict.insert ( Nothing, personId ) newItem accum + + else + let + encounterData = + Maybe.andThen + (\encounterId -> Dict.get encounterId encountersData) + item.encounterId + in + encounterData + |> Maybe.map + (\participantId -> + let + newItem = + HIVFollowUpItem item.dateMeasured "" item.encounterId item.value + in + Dict.get ( Just participantId, personId ) accum + |> Maybe.map + (\member -> + if Date.compare newItem.dateMeasured member.dateMeasured == GT then + Dict.insert ( Just participantId, personId ) newItem accum + + else + accum + ) + |> Maybe.withDefault + (Dict.insert ( Just participantId, personId ) newItem accum) + ) + |> Maybe.withDefault accum + ) + Dict.empty + + filterResolvedFollowUps : NominalDate -> Maybe NominalDate -> Bool filterResolvedFollowUps limitDate resolutionDate = Maybe.map @@ -420,6 +494,11 @@ generateTuberculosisEncounters followUps = generateEncountersIdsFromMeasurements .tuberculosis followUps +generateHIVEncounters : FollowUpMeasurements -> EverySet HIVEncounterId +generateHIVEncounters followUps = + generateEncountersIdsFromMeasurements .hiv followUps + + generateEncountersIdsFromMeasurements : (FollowUpMeasurements -> Dict measurementId { a | encounterId : Maybe encounterId }) -> FollowUpMeasurements @@ -446,6 +525,11 @@ generateTuberculosisParticipants encounters db = generateParticipantsIdsByEncounters .tuberculosisEncounters encounters db +generateHIVParticipants : EverySet HIVEncounterId -> ModelIndexedDb -> EverySet IndividualEncounterParticipantId +generateHIVParticipants encounters db = + generateParticipantsIdsByEncounters .hivEncounters encounters db + + generateParticipantsIdsByEncounters : (ModelIndexedDb -> Dict encounterId (WebData { a | participant : IndividualEncounterParticipantId })) -> EverySet encounterId @@ -582,10 +666,7 @@ resolveUniquePatientsFromFollowUps limitDate followUps = ++ peopleForNutritionIndividual ++ peopleForWellChild |> Pages.Utils.unique - , acuteIllness = uniquePatientsFromFollowUps .acuteIllness - , prenatal = uniquePatientsFromFollowUps .prenatal , immunization = uniquePatientsFromFollowUps .nextVisit - , tuberculosis = uniquePatientsFromFollowUps .tuberculosis } diff --git a/client/src/elm/Pages/GlobalCaseManagement/View.elm b/client/src/elm/Pages/GlobalCaseManagement/View.elm index 4fde5e52d6..072fcdd4d7 100644 --- a/client/src/elm/Pages/GlobalCaseManagement/View.elm +++ b/client/src/elm/Pages/GlobalCaseManagement/View.elm @@ -22,7 +22,8 @@ import Backend.Measurement.Model import Backend.Model exposing (ModelIndexedDb) import Backend.NutritionEncounter.Utils exposing - ( getHomeVisitEncountersForParticipant + ( getHIVEncountersForParticipant + , getHomeVisitEncountersForParticipant , getTuberculosisEncountersForParticipant , getWellChildEncountersForParticipant ) @@ -30,7 +31,7 @@ import Backend.Person.Utils exposing (generateFullName) import Backend.PrenatalActivity.Model exposing (PrenatalRecurrentActivity(..)) import Backend.PrenatalEncounter.Model exposing (PrenatalEncounterType(..)) import Backend.PrenatalEncounter.Utils exposing (isNurseEncounter) -import Backend.Utils exposing (resolveIndividualParticipantForPerson, tuberculosisManagementEnabled) +import Backend.Utils exposing (hivManagementEnabled, resolveIndividualParticipantForPerson, resolveIndividualParticipantsForPerson, tuberculosisManagementEnabled) import Backend.Village.Utils exposing (resolveVillageResidents) import Backend.WellChildEncounter.Model exposing (WellChildEncounterType(..)) import Date exposing (Unit(..)) @@ -52,7 +53,7 @@ import RemoteData exposing (RemoteData(..)) import SyncManager.Model exposing (SiteFeature) import Translate exposing (Language, translate, translateText) import Utils.Html exposing (viewModal) -import Utils.NominalDate exposing (sortEncounterTuplesDesc) +import Utils.NominalDate exposing (sortDatesDesc, sortEncounterTuplesDesc) import Utils.WebData exposing (viewWebData) @@ -168,6 +169,21 @@ viewContentForChw language currentDate features villageId model db allFollowUps else [] + hivPane = + if hivManagementEnabled features then + let + hivFollowUps = + generateHIVFollowUps currentDate db followUps + |> fillPersonName Tuple.second db + in + [ ( FilterHIV + , viewHIVPane language currentDate hivFollowUps db model + ) + ] + + else + [] + panes = [ ( FilterAcuteIllness, acuteIllnessFollowUpsPane ) , ( FilterAntenatal, prenatalFollowUpsPane ) @@ -175,6 +191,7 @@ viewContentForChw language currentDate features villageId model db allFollowUps , ( FilterImmunization, immunizationFollowUpsPane ) ] ++ tuberculosisPane + ++ hivPane |> List.filterMap (\( type_, pane ) -> if isNothing model.filter || model.filter == Just type_ then @@ -286,6 +303,9 @@ viewStartFollowUpEncounterDialog language dataType = FollowUpTuberculosis data -> startFollowUpDialog TuberculosisEncounter data.personName + FollowUpHIV data -> + startFollowUpDialog HIVEncounter data.personName + -- We should never get here, since Prenatal got -- it's own dialog. FollowUpPrenatal _ -> @@ -913,6 +933,161 @@ viewTuberculosisFollowUpEntry language currentDate entry = viewFollowUpEntry language dueOption item.personName popupData label +viewHIVPane : + Language + -> NominalDate + -> Dict ( Maybe IndividualEncounterParticipantId, PersonId ) HIVFollowUpItem + -> ModelIndexedDb + -> Model + -> Html Msg +viewHIVPane language currentDate itemsDict db model = + let + limitDate = + -- Set limit date for tomorrow, so that we + -- load all available follow ups. + Date.add Days 1 currentDate + + entries = + generateHIVFollowUpEntries language currentDate limitDate itemsDict db + + content = + if List.isEmpty entries then + [ translateText language Translate.NoMatchesFound ] + + else + List.map (viewHIVFollowUpEntry language currentDate) entries + in + div [ class "pane" ] + [ viewItemHeading language FilterHIV + , div [ class "pane-content" ] + content + ] + + +generateHIVFollowUpEntries : + Language + -> NominalDate + -> NominalDate + -> Dict ( Maybe IndividualEncounterParticipantId, PersonId ) HIVFollowUpItem + -> ModelIndexedDb + -> List HIVFollowUpEntry +generateHIVFollowUpEntries language currentDate limitDate itemsDict db = + Dict.map (generateHIVFollowUpEntryData language currentDate limitDate db) itemsDict + |> Dict.values + |> Maybe.Extra.values + + +generateHIVFollowUpEntryData : + Language + -> NominalDate + -> NominalDate + -> ModelIndexedDb + -> ( Maybe IndividualEncounterParticipantId, PersonId ) + -> HIVFollowUpItem + -> Maybe HIVFollowUpEntry +generateHIVFollowUpEntryData language currentDate limitDate db ( mParticipantId, personId ) item = + if item.dateMeasured == currentDate then + -- We do not display follow ups that were scheduled today, + -- since we should not allow starting and encounter, if there + -- was already and encounter completed today (where follow up + -- was scheduled). + Nothing + + else + Maybe.map + (\participantId -> + let + dateConcludedCriteria = + Dict.get participantId db.individualParticipants + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.andThen .dateConcluded + |> Maybe.map (\dateConcluded -> Date.compare dateConcluded limitDate) + in + if dateConcludedCriteria == Just LT then + -- Illness was concluded before limit date, so we do not need to follow up on it. + Nothing + + else + let + allEncountersWithIds = + getHIVEncountersForParticipant db participantId + |> List.filter (\( _, encounter ) -> Date.compare encounter.startDate limitDate == LT) + -- Sort DESC + |> List.sortWith sortEncounterTuplesDesc + in + List.head allEncountersWithIds + |> Maybe.andThen + (\( encounterId, encounter ) -> + -- Follow up belongs to last encounter, which indicates that + -- there was no other encounter that has resolved this follow up. + if item.encounterId == Just encounterId then + HIVFollowUpEntry + (Just participantId) + personId + item + |> Just + + else + -- Last encounter has not originated the follow up. + -- Therefore, we know that follow up is resolved. + Nothing + ) + ) + mParticipantId + -- In case there's no individual participant for item, we know it's an + -- entry for 'dummy' follow up created for positive HIV test result. + |> Maybe.withDefault + (let + -- Resolve date of last HIV encounter. + mDateOfLastHIVEncounter = + resolveIndividualParticipantsForPerson personId HIVEncounter db + |> List.map (getHIVEncountersForParticipant db) + |> List.concat + |> List.map (Tuple.second >> .startDate) + |> List.sortWith sortDatesDesc + |> List.head + + entry = + HIVFollowUpEntry Nothing personId item + in + Maybe.map + (\dateOfLastHIVEncounter -> + -- Generate entry, if date of last HIV encounter was prior to + -- item date (which stores datye of positive HIV result). + if Date.compare dateOfLastHIVEncounter item.dateMeasured == LT then + Just entry + + else + Nothing + ) + mDateOfLastHIVEncounter + |> -- No HIV encounters - record entry. + Maybe.withDefault (Just entry) + ) + + +viewHIVFollowUpEntry : Language -> NominalDate -> HIVFollowUpEntry -> Html Msg +viewHIVFollowUpEntry language currentDate entry = + let + item = + entry.item + + dueOption = + followUpDueOptionByDate currentDate item.dateMeasured item.value.options + + label = + [ p [] [ text <| translate language Translate.HIVFollowUpLabel ] ] + + popupData = + FollowUpHIV <| + FollowUpHIVData + entry.personId + item.personName + entry.participantId + in + viewFollowUpEntry language dueOption item.personName popupData label + + viewFollowUpEntry : Language -> FollowUpDueOption @@ -1232,11 +1407,9 @@ viewLabsEntry language isLabTech personName state label targetPage = "this-week" LabsEntryReadyForReview -> - -- @todo: needs styling? "this-week" LabsEntryReviewed -> - -- @todo: needs styling? "this-week" ) in diff --git a/client/src/elm/Pages/HIV/Activity/Fetch.elm b/client/src/elm/Pages/HIV/Activity/Fetch.elm new file mode 100644 index 0000000000..64f6fcfeca --- /dev/null +++ b/client/src/elm/Pages/HIV/Activity/Fetch.elm @@ -0,0 +1,71 @@ +module Pages.HIV.Activity.Fetch exposing (fetch) + +import AssocList as Dict +import Backend.Entities exposing (..) +import Backend.HIVActivity.Model exposing (HIVActivity(..)) +import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterType(..)) +import Backend.Model exposing (ModelIndexedDb, MsgIndexedDb) +import Backend.NutritionEncounter.Utils exposing (getNCDEncountersForParticipant, getPrenatalEncountersForParticipant) +import Backend.Utils exposing (resolveIndividualParticipantsForPerson) +import Pages.HIV.Encounter.Fetch +import RemoteData + + +fetch : HIVEncounterId -> HIVActivity -> ModelIndexedDb -> List MsgIndexedDb +fetch id activity db = + Pages.HIV.Encounter.Fetch.fetch id db + ++ (if activity == Diagnostics then + fetchForDiagnostics id db + + else + [] + ) + + +{-| For Diagnostics activity, we need to know if patient has ever tested positive to HIV. +For this, we need to fetch all measurements of all NCD and Prenatal encounters. +-} +fetchForDiagnostics : HIVEncounterId -> ModelIndexedDb -> List MsgIndexedDb +fetchForDiagnostics id db = + let + participantId = + Dict.get id db.hivEncounters + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.map .participant + in + Maybe.andThen (\id_ -> Dict.get id_ db.individualParticipants) participantId + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.map + (\participant -> + let + personId = + participant.person + + ncdParticipantsIds = + resolveIndividualParticipantsForPerson personId NCDEncounter db + + prenatalParticipantsIds = + resolveIndividualParticipantsForPerson personId AntenatalEncounter db + + ncdEncountersIds = + List.map (getNCDEncountersForParticipant db >> List.map Tuple.first) ncdParticipantsIds + |> List.concat + + prenatalEncountersIds = + List.map (getPrenatalEncountersForParticipant db >> List.map Tuple.first) prenatalParticipantsIds + |> List.concat + + fetchNCDMeasurementsMsgs = + List.map Backend.Model.FetchNCDMeasurements ncdEncountersIds + + fetchPrenatalMeasurementsMsgs = + List.map Backend.Model.FetchPrenatalMeasurements prenatalEncountersIds + in + [ Backend.Model.FetchIndividualEncounterParticipantsForPerson personId + , Backend.Model.FetchNCDEncountersForParticipants ncdParticipantsIds + , Backend.Model.FetchPrenatalEncountersForParticipants prenatalParticipantsIds + ] + ++ fetchNCDMeasurementsMsgs + ++ fetchPrenatalMeasurementsMsgs + ) + |> Maybe.withDefault [] diff --git a/client/src/elm/Pages/HIV/Activity/Model.elm b/client/src/elm/Pages/HIV/Activity/Model.elm new file mode 100644 index 0000000000..f9a74691dd --- /dev/null +++ b/client/src/elm/Pages/HIV/Activity/Model.elm @@ -0,0 +1,199 @@ +module Pages.HIV.Activity.Model exposing (..) + +import Backend.Entities exposing (..) +import Backend.Measurement.Model exposing (..) +import Date exposing (Date) +import DateSelector.Model exposing (DateSelectorConfig) +import Gizra.NominalDate exposing (NominalDate) +import Measurement.Model + exposing + ( FollowUpForm + , OngoingTreatmentReviewForm + , SendToHCForm + , emptyFollowUpForm + , emptyOngoingTreatmentReviewForm + , emptySendToHCForm + ) +import Pages.Page exposing (Page) + + +type alias Model = + { diagnosticsData : DiagnosticsData + , medicationData : MedicationData + , symptomReviewData : SymptomReviewData + , nextStepsData : NextStepsData + } + + +emptyModel : Model +emptyModel = + { diagnosticsData = emptyDiagnosticsData + , medicationData = emptyMedicationData + , symptomReviewData = emptySymptomReviewData + , nextStepsData = emptyNextStepsData + } + + +type alias DiagnosticsData = + { form : DiagnosticsForm + } + + +emptyDiagnosticsData : DiagnosticsData +emptyDiagnosticsData = + { form = emptyDiagnosticsForm + } + + +type alias DiagnosticsForm = + { -- Used in case we don't have info of positive HIV test result + -- for this patient (HIV test is done at Prenatal and NCD). + resultPositive : Maybe Bool + , -- Used in case we have info of positive HIV test result + -- for this patient (HIV test is done at Prenatal and NCD). + resultDateCorrect : Maybe Bool + , positiveResultDate : Maybe Date + , positiveResultDateDirty : Bool + , positiveResultDateEstimated : Maybe Bool + , positiveResultDateEstimatedDirty : Bool + , dateSelectorPopupState : Maybe (DateSelectorConfig Msg) + } + + +emptyDiagnosticsForm : DiagnosticsForm +emptyDiagnosticsForm = + { resultPositive = Nothing + , resultDateCorrect = Nothing + , positiveResultDate = Nothing + , positiveResultDateDirty = False + , positiveResultDateEstimated = Nothing + , positiveResultDateEstimatedDirty = False + , dateSelectorPopupState = Nothing + } + + +type alias MedicationData = + { prescribedMedicationForm : PrescribedMedicationForm + , treatmentReviewForm : OngoingTreatmentReviewForm + , activeTask : Maybe MedicationTask + } + + +emptyMedicationData : MedicationData +emptyMedicationData = + { prescribedMedicationForm = emptyPrescribedMedicationForm + , treatmentReviewForm = emptyOngoingTreatmentReviewForm + , activeTask = Nothing + } + + +type alias PrescribedMedicationForm = + { medications : Maybe (List HIVPrescribedMedication) + } + + +emptyPrescribedMedicationForm : PrescribedMedicationForm +emptyPrescribedMedicationForm = + { medications = Nothing + } + + +type MedicationTask + = TaskPrescribedMedication + | TaskTreatmentReview + + +type alias SymptomReviewData = + { form : SymptomReviewForm + } + + +emptySymptomReviewData : SymptomReviewData +emptySymptomReviewData = + { form = emptySymptomReviewForm + } + + +type alias SymptomReviewForm = + { symptoms : Maybe (List HIVSymptom) + , symptomsDirty : Bool + } + + +emptySymptomReviewForm : SymptomReviewForm +emptySymptomReviewForm = + { symptoms = Nothing + , symptomsDirty = False + } + + +type alias NextStepsData = + { sendToHCForm : SendToHCForm + , healthEducationForm : HealthEducationForm + , followUpForm : FollowUpForm + , activeTask : Maybe NextStepsTask + } + + +emptyNextStepsData : NextStepsData +emptyNextStepsData = + { sendToHCForm = emptySendToHCForm + , healthEducationForm = emptyHealthEducationForm + , followUpForm = emptyFollowUpForm + , activeTask = Nothing + } + + +type alias HealthEducationForm = + { positiveResult : Maybe Bool + , saferSexPractices : Maybe Bool + , encouragedPartnerTesting : Maybe Bool + , familyPlanningOptions : Maybe Bool + } + + +emptyHealthEducationForm : HealthEducationForm +emptyHealthEducationForm = + { positiveResult = Nothing + , saferSexPractices = Nothing + , encouragedPartnerTesting = Nothing + , familyPlanningOptions = Nothing + } + + +type NextStepsTask + = TaskReferral + | TaskHealthEducation + | TaskFollowUp + + +type Msg + = SetActivePage Page + -- DIAGNOSTICS + | SetDiagnosticsBoolInput (Bool -> DiagnosticsForm -> DiagnosticsForm) Bool + | ConfirmPositiveResultDate Date Bool + | SetPositiveResultDate Date + | SetDateSelectorState (Maybe (DateSelectorConfig Msg)) + | SaveDiagnostics PersonId IndividualEncounterParticipantId Bool (Maybe ( HIVDiagnosticsId, HIVDiagnostics )) + -- MEDICATION + | SetActiveMedicationTask MedicationTask + | SetPrescribedMedication HIVPrescribedMedication + | SavePrescribedMedication PersonId (Maybe ( HIVMedicationId, HIVMedication )) (Maybe MedicationTask) + | SetTreatmentReviewBoolInput (Bool -> OngoingTreatmentReviewForm -> OngoingTreatmentReviewForm) Bool + | SetReasonForNotTaking ReasonForNotTaking + | SetTotalMissedDoses String + | SetAdverseEvent AdverseEvent + | SaveTreatmentReview PersonId (Maybe ( HIVTreatmentReviewId, HIVTreatmentReview )) (Maybe MedicationTask) + -- SYMPTOM REVIEW + | SetSymptom HIVSymptom + | SaveSymptomReview PersonId (Maybe ( HIVSymptomReviewId, HIVSymptomReview )) + -- NEXT STEPS + | SetActiveNextStepsTask NextStepsTask + | SetHealthEducationBoolInput (Bool -> HealthEducationForm -> HealthEducationForm) Bool + | SaveHealthEducation PersonId (Maybe ( HIVHealthEducationId, HIVHealthEducation )) (Maybe NextStepsTask) + | SetFollowUpOption FollowUpOption + | SaveFollowUp PersonId (Maybe ( HIVFollowUpId, HIVFollowUp )) (Maybe NextStepsTask) + | SetReferToHealthCenter Bool + | SetHandReferralForm Bool + | SetReasonForNonReferral ReasonForNonReferral + | SaveReferral PersonId (Maybe ( HIVReferralId, HIVReferral )) (Maybe NextStepsTask) diff --git a/client/src/elm/Pages/HIV/Activity/Update.elm b/client/src/elm/Pages/HIV/Activity/Update.elm new file mode 100644 index 0000000000..ad276d9ebd --- /dev/null +++ b/client/src/elm/Pages/HIV/Activity/Update.elm @@ -0,0 +1,560 @@ +module Pages.HIV.Activity.Update exposing (update) + +import App.Model +import App.Utils exposing (focusOnCalendarMsg) +import AssocList as Dict +import Backend.Entities exposing (..) +import Backend.HIVEncounter.Model +import Backend.IndividualEncounterParticipant.Model exposing (HIVOutcome(..)) +import Backend.Measurement.Model exposing (AdverseEvent(..), HIVPrescribedMedication(..), HIVSymptom(..)) +import Backend.Measurement.Utils exposing (getMeasurementValueFunc) +import Backend.Model exposing (ModelIndexedDb) +import Date +import EverySet +import Gizra.NominalDate exposing (NominalDate) +import Gizra.Update exposing (sequenceExtra) +import Maybe.Extra exposing (unwrap) +import Measurement.Utils + exposing + ( ongoingTreatmentReviewFormWithDefault + , toFollowUpValueWithDefault + , toOngoingTreatmentReviewValueWithDefault + , toSendToHCValueWithDefault + ) +import Pages.HIV.Activity.Model exposing (..) +import Pages.HIV.Activity.Utils exposing (..) +import Pages.Page exposing (Page(..), UserPage(..)) +import Pages.Utils exposing (setMultiSelectInputValue) +import RemoteData exposing (RemoteData(..)) + + +update : NominalDate -> HIVEncounterId -> ModelIndexedDb -> Msg -> Model -> ( Model, Cmd Msg, List App.Model.Msg ) +update currentDate id db msg model = + let + resolveFormWithDefaults getMeasurementFunc formWithDefaultsFunc form = + Dict.get id db.hivMeasurements + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.map + (getMeasurementFunc + >> getMeasurementValueFunc + >> formWithDefaultsFunc form + ) + |> Maybe.withDefault form + + diagnosticsForm = + resolveFormWithDefaults .diagnostics diagnosticsFormWithDefault model.diagnosticsData.form + + medicationForm = + resolveFormWithDefaults .medication prescribedMedicationFormWithDefault model.medicationData.prescribedMedicationForm + + treatmentReviewForm = + resolveFormWithDefaults .treatmentReview ongoingTreatmentReviewFormWithDefault model.medicationData.treatmentReviewForm + + symptomReviewForm = + resolveFormWithDefaults .symptomReview symptomReviewFormWithDefault model.symptomReviewData.form + + generateMedicationMsgs nextTask = + Maybe.map (\task -> [ SetActiveMedicationTask task ]) nextTask + |> Maybe.withDefault [ SetActivePage <| UserPage <| HIVEncounterPage id ] + + generateNextStepsMsgs nextTask = + Maybe.map (\task -> [ SetActiveNextStepsTask task ]) nextTask + |> Maybe.withDefault [ SetActivePage <| UserPage <| HIVEncounterPage id ] + in + case msg of + SetActivePage page -> + ( model + , Cmd.none + , [ App.Model.SetActivePage page ] + ) + + SetDiagnosticsBoolInput formUpdateFunc value -> + let + updatedForm = + formUpdateFunc value diagnosticsForm + + updatedData = + model.diagnosticsData + |> (\data -> { data | form = updatedForm }) + in + ( { model | diagnosticsData = updatedData } + , Cmd.none + , [] + ) + + ConfirmPositiveResultDate date confirmed -> + let + updatedForm = + { diagnosticsForm + | resultDateCorrect = Just confirmed + , positiveResultDate = Nothing + , positiveResultDateDirty = True + , positiveResultDateEstimated = Nothing + , positiveResultDateEstimatedDirty = True + } + + updatedData = + model.diagnosticsData + |> (\data -> { data | form = updatedForm }) + + setPositiveResultDateMsg = + if confirmed then + [ SetPositiveResultDate date ] + + else + [] + in + ( { model | diagnosticsData = updatedData } + , Cmd.none + , [] + ) + |> sequenceExtra (update currentDate id db) setPositiveResultDateMsg + + SetPositiveResultDate value -> + let + updatedForm = + { diagnosticsForm + | positiveResultDate = Just value + , positiveResultDateDirty = True + , positiveResultDateEstimated = Nothing + , positiveResultDateEstimatedDirty = True + } + + updatedData = + model.diagnosticsData + |> (\data -> { data | form = updatedForm }) + in + ( { model | diagnosticsData = updatedData } + , Cmd.none + , [] + ) + + SetDateSelectorState state -> + let + updatedForm = + { diagnosticsForm | dateSelectorPopupState = state } + + updatedData = + model.diagnosticsData + |> (\data -> { data | form = updatedForm }) + in + ( { model | diagnosticsData = updatedData } + , Cmd.none + , [ focusOnCalendarMsg ] + ) + + SaveDiagnostics personId particpantId positiveResultRecorded saved -> + let + measurementId = + Maybe.map Tuple.first saved + + measurement = + getMeasurementValueFunc saved + + appMsgs = + model.diagnosticsData.form + |> toDiagnosticsValueWithDefault positiveResultRecorded measurement + |> unwrap + [] + (\value -> + let + saveMsg = + Backend.HIVEncounter.Model.SaveDiagnostics personId measurementId value + |> Backend.Model.MsgHIVEncounter id + |> App.Model.MsgIndexedDb + + additionalMsgs = + if not positiveResultRecorded && diagnosticsForm.resultPositive == Just False then + [ Backend.IndividualEncounterParticipant.Model.CloseHIVSession HIVOutcomeNotDiagnosed + |> Backend.Model.MsgIndividualEncounterParticipant particpantId + |> App.Model.MsgIndexedDb + , App.Model.SetActivePage PinCodePage + ] + + else + [ App.Model.SetActivePage <| UserPage <| HIVEncounterPage id ] + in + saveMsg :: additionalMsgs + ) + in + ( model + , Cmd.none + , appMsgs + ) + + SetActiveMedicationTask task -> + let + updatedData = + model.medicationData + |> (\data -> { data | activeTask = Just task }) + in + ( { model | medicationData = updatedData } + , Cmd.none + , [] + ) + + SetPrescribedMedication medication -> + let + form = + medicationForm + + updatedForm = + setMultiSelectInputValue .medications + (\medications -> { form | medications = medications }) + NoHIVPrescribedMedications + medication + form + + updatedData = + model.medicationData + |> (\data -> { data | prescribedMedicationForm = updatedForm }) + in + ( { model | medicationData = updatedData } + , Cmd.none + , [] + ) + + SavePrescribedMedication personId saved nextTask -> + let + measurementId = + Maybe.map Tuple.first saved + + measurement = + getMeasurementValueFunc saved + + extraMsgs = + generateMedicationMsgs nextTask + + appMsgs = + toPrescribedMedicationValueWithDefault measurement model.medicationData.prescribedMedicationForm + |> Maybe.map + (Backend.HIVEncounter.Model.SavePrescribedMedication personId measurementId + >> Backend.Model.MsgHIVEncounter id + >> App.Model.MsgIndexedDb + >> List.singleton + ) + |> Maybe.withDefault [] + in + ( model + , Cmd.none + , appMsgs + ) + |> sequenceExtra (update currentDate id db) extraMsgs + + SetTreatmentReviewBoolInput formUpdateFunc value -> + let + updatedData = + let + updatedForm = + formUpdateFunc value treatmentReviewForm + in + model.medicationData + |> (\data -> { data | treatmentReviewForm = updatedForm }) + in + ( { model | medicationData = updatedData } + , Cmd.none + , [] + ) + + SetReasonForNotTaking value -> + let + form = + treatmentReviewForm + + updatedForm = + { form | reasonForNotTaking = Just value, reasonForNotTakingDirty = True } + + updatedData = + model.medicationData + |> (\data -> { data | treatmentReviewForm = updatedForm }) + in + ( { model | medicationData = updatedData } + , Cmd.none + , [] + ) + + SetTotalMissedDoses value -> + let + form = + treatmentReviewForm + + updatedForm = + { form | totalMissedDoses = String.toInt value, totalMissedDosesDirty = True } + + updatedData = + model.medicationData + |> (\data -> { data | treatmentReviewForm = updatedForm }) + in + ( { model | medicationData = updatedData } + , Cmd.none + , [] + ) + + SetAdverseEvent event -> + let + form = + treatmentReviewForm + + updatedForm = + setMultiSelectInputValue .adverseEvents + (\events -> { form | adverseEvents = events, adverseEventsDirty = True }) + NoAdverseEvent + event + form + + updatedData = + model.medicationData + |> (\data -> { data | treatmentReviewForm = updatedForm }) + in + ( { model | medicationData = updatedData } + , Cmd.none + , [] + ) + + SaveTreatmentReview personId saved nextTask -> + let + measurementId = + Maybe.map Tuple.first saved + + measurement = + getMeasurementValueFunc saved + + extraMsgs = + generateMedicationMsgs nextTask + + appMsgs = + toOngoingTreatmentReviewValueWithDefault measurement model.medicationData.treatmentReviewForm + |> Maybe.map + (Backend.HIVEncounter.Model.SaveTreatmentReview personId measurementId + >> Backend.Model.MsgHIVEncounter id + >> App.Model.MsgIndexedDb + >> List.singleton + ) + |> Maybe.withDefault [] + in + ( model + , Cmd.none + , appMsgs + ) + |> sequenceExtra (update currentDate id db) extraMsgs + + SetSymptom symptom -> + let + form = + symptomReviewForm + + updatedForm = + setMultiSelectInputValue .symptoms + (\symptoms -> { form | symptoms = symptoms, symptomsDirty = True }) + NoHIVSymptoms + symptom + form + + updatedData = + model.symptomReviewData + |> (\data -> { data | form = updatedForm }) + in + ( { model | symptomReviewData = updatedData } + , Cmd.none + , [] + ) + + SaveSymptomReview personId saved -> + let + measurementId = + Maybe.map Tuple.first saved + + measurement = + getMeasurementValueFunc saved + + appMsgs = + model.symptomReviewData.form + |> toSymptomReviewValueWithDefault measurement + |> unwrap + [] + (\value -> + [ Backend.HIVEncounter.Model.SaveSymptomReview personId measurementId value + |> Backend.Model.MsgHIVEncounter id + |> App.Model.MsgIndexedDb + , App.Model.SetActivePage <| UserPage <| HIVEncounterPage id + ] + ) + in + ( model + , Cmd.none + , appMsgs + ) + + SetActiveNextStepsTask task -> + let + updatedData = + model.nextStepsData + |> (\data -> { data | activeTask = Just task }) + in + ( { model | nextStepsData = updatedData } + , Cmd.none + , [] + ) + + SetHealthEducationBoolInput formUpdateFunc value -> + let + updatedForm = + formUpdateFunc value model.nextStepsData.healthEducationForm + + updatedData = + model.nextStepsData + |> (\data -> { data | healthEducationForm = updatedForm }) + in + ( { model | nextStepsData = updatedData } + , Cmd.none + , [] + ) + + SaveHealthEducation personId saved nextTask -> + let + measurementId = + Maybe.map Tuple.first saved + + measurement = + getMeasurementValueFunc saved + + extraMsgs = + generateNextStepsMsgs nextTask + + appMsgs = + toHealthEducationValueWithDefault measurement model.nextStepsData.healthEducationForm + |> Maybe.map + (Backend.HIVEncounter.Model.SaveHealthEducation personId measurementId + >> Backend.Model.MsgHIVEncounter id + >> App.Model.MsgIndexedDb + >> List.singleton + ) + |> Maybe.withDefault [] + in + ( model + , Cmd.none + , appMsgs + ) + |> sequenceExtra (update currentDate id db) extraMsgs + + SetFollowUpOption option -> + let + form = + model.nextStepsData.followUpForm + + updatedForm = + { form | option = Just option } + + updatedData = + model.nextStepsData + |> (\data -> { data | followUpForm = updatedForm }) + in + ( { model | nextStepsData = updatedData } + , Cmd.none + , [] + ) + + SaveFollowUp personId saved nextTask -> + let + measurementId = + Maybe.map Tuple.first saved + + measurement = + getMeasurementValueFunc saved + + extraMsgs = + generateNextStepsMsgs nextTask + + appMsgs = + toFollowUpValueWithDefault measurement model.nextStepsData.followUpForm + |> Maybe.map + (Backend.HIVEncounter.Model.SaveFollowUp personId measurementId + >> Backend.Model.MsgHIVEncounter id + >> App.Model.MsgIndexedDb + >> List.singleton + ) + |> Maybe.withDefault [] + in + ( model + , Cmd.none + , appMsgs + ) + |> sequenceExtra (update currentDate id db) extraMsgs + + SetReferToHealthCenter value -> + let + form = + model.nextStepsData.sendToHCForm + + updatedForm = + { form | referToHealthCenter = Just value, reasonForNotSendingToHC = Nothing } + + updatedData = + model.nextStepsData + |> (\data -> { data | sendToHCForm = updatedForm }) + in + ( { model | nextStepsData = updatedData } + , Cmd.none + , [] + ) + + SetHandReferralForm value -> + let + form = + model.nextStepsData.sendToHCForm + + updatedForm = + { form | handReferralForm = Just value } + + updatedData = + model.nextStepsData + |> (\data -> { data | sendToHCForm = updatedForm }) + in + ( { model | nextStepsData = updatedData } + , Cmd.none + , [] + ) + + SetReasonForNonReferral value -> + let + form = + model.nextStepsData.sendToHCForm + + updatedForm = + { form | reasonForNotSendingToHC = Just value } + + updatedData = + model.nextStepsData + |> (\data -> { data | sendToHCForm = updatedForm }) + in + ( { model | nextStepsData = updatedData } + , Cmd.none + , [] + ) + + SaveReferral personId saved nextTask -> + let + measurementId = + Maybe.map Tuple.first saved + + measurement = + getMeasurementValueFunc saved + + extraMsgs = + generateNextStepsMsgs nextTask + + appMsgs = + toSendToHCValueWithDefault measurement model.nextStepsData.sendToHCForm + |> Maybe.map + (Backend.HIVEncounter.Model.SaveReferral personId measurementId + >> Backend.Model.MsgHIVEncounter id + >> App.Model.MsgIndexedDb + >> List.singleton + ) + |> Maybe.withDefault [] + in + ( model + , Cmd.none + , appMsgs + ) + |> sequenceExtra (update currentDate id db) extraMsgs diff --git a/client/src/elm/Pages/HIV/Activity/Utils.elm b/client/src/elm/Pages/HIV/Activity/Utils.elm new file mode 100644 index 0000000000..32367998c7 --- /dev/null +++ b/client/src/elm/Pages/HIV/Activity/Utils.elm @@ -0,0 +1,506 @@ +module Pages.HIV.Activity.Utils exposing (..) + +import AssocList as Dict exposing (Dict) +import Backend.HIVActivity.Model exposing (HIVActivity(..)) +import Backend.HIVActivity.Utils exposing (allActivities) +import Backend.Measurement.Model exposing (..) +import Backend.Measurement.Utils exposing (getMeasurementValueFunc) +import Date +import EverySet exposing (EverySet) +import Gizra.Html exposing (emptyNode) +import Gizra.NominalDate exposing (NominalDate) +import Html exposing (..) +import Html.Attributes exposing (..) +import Maybe.Extra exposing (andMap, isJust, or, unwrap) +import Measurement.Utils + exposing + ( followUpFormWithDefault + , ongoingTreatmentReviewFormWithDefault + , sendToHCFormWithDefault + , treatmentReviewInputsAndTasks + ) +import Pages.HIV.Activity.Model exposing (..) +import Pages.HIV.Encounter.Model exposing (AssembledData) +import Pages.Utils + exposing + ( ifEverySetEmpty + , ifNullableTrue + , ifTrue + , maybeToBoolTask + , maybeValueConsideringIsDirtyField + , taskCompleted + , viewBoolInput + , viewCheckBoxMultipleSelectInput + , viewCheckBoxSelectInput + , viewCustomLabel + , viewNumberInput + , viewQuestionLabel + ) +import Translate exposing (translate) +import Translate.Model exposing (Language(..)) + + +expectActivity : NominalDate -> AssembledData -> HIVActivity -> Bool +expectActivity currentDate assembled activity = + case activity of + Diagnostics -> + assembled.initialEncounter + + Medication -> + resolveMedicationTasks currentDate assembled + |> List.isEmpty + |> not + + SymptomReview -> + not assembled.initialEncounter + + NextSteps -> + mandatoryActivitiesForNextStepsCompleted currentDate assembled + && (resolveNextStepsTasks currentDate assembled + |> List.isEmpty + |> not + ) + + +activityCompleted : NominalDate -> AssembledData -> HIVActivity -> Bool +activityCompleted currentDate assembled activity = + let + notExpected activityToCheck = + not <| expectActivity currentDate assembled activityToCheck + in + case activity of + Diagnostics -> + notExpected Diagnostics + || isJust assembled.measurements.diagnostics + + Medication -> + notExpected Medication + || (resolveMedicationTasks currentDate assembled + |> List.all (medicationTaskCompleted assembled) + ) + + SymptomReview -> + notExpected SymptomReview + || isJust assembled.measurements.symptomReview + + NextSteps -> + notExpected NextSteps + || (resolveNextStepsTasks currentDate assembled + |> List.all (nextStepsTaskCompleted assembled) + ) + + +medicationTasks : List MedicationTask +medicationTasks = + [ TaskPrescribedMedication, TaskTreatmentReview ] + + +resolveMedicationTasks : NominalDate -> AssembledData -> List MedicationTask +resolveMedicationTasks currentDate assembled = + List.filter (expectMedicationTask currentDate assembled) medicationTasks + + +expectMedicationTask : NominalDate -> AssembledData -> MedicationTask -> Bool +expectMedicationTask currentDate assembled task = + case task of + TaskPrescribedMedication -> + assembled.initialEncounter + + TaskTreatmentReview -> + not assembled.initialEncounter + || isJust assembled.measurements.medication + + +medicationTaskCompleted : AssembledData -> MedicationTask -> Bool +medicationTaskCompleted assembled task = + case task of + TaskPrescribedMedication -> + isJust assembled.measurements.medication + + TaskTreatmentReview -> + isJust assembled.measurements.treatmentReview + + +medicationTasksCompletedFromTotal : Language -> NominalDate -> AssembledData -> MedicationData -> MedicationTask -> ( Int, Int ) +medicationTasksCompletedFromTotal language currentDate assembled data task = + case task of + TaskPrescribedMedication -> + let + form = + getMeasurementValueFunc assembled.measurements.medication + |> prescribedMedicationFormWithDefault data.prescribedMedicationForm + + isCompleted = + let + mandatoryGroup = + mostCommonAntiRetroviralMedications ++ lessCommonAntiRetroviralMedications + in + Maybe.map + (\medications -> + if List.any (\medication -> List.member medication medications) mandatoryGroup then + 1 + + else + 0 + ) + form.medications + |> Maybe.withDefault 0 + in + ( isCompleted + , 1 + ) + + TaskTreatmentReview -> + let + form = + getMeasurementValueFunc assembled.measurements.treatmentReview + |> ongoingTreatmentReviewFormWithDefault data.treatmentReviewForm + + ( _, tasks ) = + treatmentReviewInputsAndTasks language + currentDate + SetTreatmentReviewBoolInput + SetReasonForNotTaking + SetTotalMissedDoses + SetAdverseEvent + form + in + ( Maybe.Extra.values tasks + |> List.length + , List.length tasks + ) + + +nextStepsTasks : List NextStepsTask +nextStepsTasks = + [ TaskReferral, TaskHealthEducation, TaskFollowUp ] + + +resolveNextStepsTasks : NominalDate -> AssembledData -> List NextStepsTask +resolveNextStepsTasks currentDate assembled = + List.filter (expectNextStepsTask currentDate assembled) nextStepsTasks + + +expectNextStepsTask : NominalDate -> AssembledData -> NextStepsTask -> Bool +expectNextStepsTask currentDate assembled task = + case task of + TaskReferral -> + adverseEventReported assembled.measurements + || symptomReported assembled.measurements + + TaskHealthEducation -> + -- Always provide health education. + True + + TaskFollowUp -> + -- Always schedule follow up. + True + + +adverseEventReported : HIVMeasurements -> Bool +adverseEventReported measurements = + getMeasurementValueFunc measurements.treatmentReview + |> Maybe.map + (\value -> + case EverySet.toList value.adverseEvents of + [] -> + False + + [ NoAdverseEvent ] -> + False + + _ -> + True + ) + |> Maybe.withDefault False + + +symptomReported : HIVMeasurements -> Bool +symptomReported measurements = + getMeasurementValueFunc measurements.symptomReview + |> Maybe.map + (\value -> + case EverySet.toList value of + [] -> + False + + [ NoHIVSymptoms ] -> + False + + _ -> + True + ) + |> Maybe.withDefault False + + +nextStepsTaskCompleted : AssembledData -> NextStepsTask -> Bool +nextStepsTaskCompleted assembled task = + case task of + TaskReferral -> + isJust assembled.measurements.referral + + TaskHealthEducation -> + isJust assembled.measurements.healthEducation + + TaskFollowUp -> + isJust assembled.measurements.followUp + + +nextStepsTasksCompletedFromTotal : HIVMeasurements -> NextStepsData -> NextStepsTask -> ( Int, Int ) +nextStepsTasksCompletedFromTotal measurements data task = + case task of + TaskHealthEducation -> + let + form = + getMeasurementValueFunc measurements.healthEducation + |> healthEducationFormWithDefault data.healthEducationForm + in + ( taskCompleted form.positiveResult + + taskCompleted form.saferSexPractices + + taskCompleted form.encouragedPartnerTesting + + taskCompleted form.familyPlanningOptions + , 4 + ) + + TaskFollowUp -> + let + form = + getMeasurementValueFunc measurements.followUp + |> followUpFormWithDefault data.followUpForm + in + ( taskCompleted form.option + , 1 + ) + + TaskReferral -> + let + form = + getMeasurementValueFunc measurements.referral + |> sendToHCFormWithDefault data.sendToHCForm + + ( reasonForNotSentActive, reasonForNotSentCompleted ) = + form.referToHealthCenter + |> Maybe.map + (\sentToHC -> + if not sentToHC then + if isJust form.reasonForNotSendingToHC then + ( 2, 2 ) + + else + ( 1, 2 ) + + else + ( 1, 1 ) + ) + |> Maybe.withDefault ( 0, 1 ) + in + ( reasonForNotSentActive + taskCompleted form.handReferralForm + , reasonForNotSentCompleted + 1 + ) + + +mandatoryActivitiesForNextStepsCompleted : NominalDate -> AssembledData -> Bool +mandatoryActivitiesForNextStepsCompleted currentDate assembled = + List.all (activityCompleted currentDate assembled) + [ Diagnostics, Medication, SymptomReview ] + + +diagnosticsFormWithDefault : DiagnosticsForm -> Maybe HIVDiagnosticsValue -> DiagnosticsForm +diagnosticsFormWithDefault form saved = + saved + |> unwrap + form + (\value -> + let + positiveResultDateEstimatedByValue = + EverySet.member HIVResultDateEstimated value.signs + in + { resultPositive = or form.resultPositive (EverySet.member HIVResultPositiveReported value.signs |> Just) + , resultDateCorrect = or form.resultDateCorrect (EverySet.member HIVResultPositiveKnown value.signs |> Just) + , positiveResultDate = + maybeValueConsideringIsDirtyField form.positiveResultDateDirty + form.positiveResultDate + value.positiveResultDate + , positiveResultDateDirty = form.positiveResultDateDirty + , positiveResultDateEstimated = + maybeValueConsideringIsDirtyField form.positiveResultDateEstimatedDirty + form.positiveResultDateEstimated + (Just positiveResultDateEstimatedByValue) + , positiveResultDateEstimatedDirty = form.positiveResultDateEstimatedDirty + , dateSelectorPopupState = form.dateSelectorPopupState + } + ) + + +toDiagnosticsValueWithDefault : Bool -> Maybe HIVDiagnosticsValue -> DiagnosticsForm -> Maybe HIVDiagnosticsValue +toDiagnosticsValueWithDefault positiveResultRecorded saved form = + diagnosticsFormWithDefault form saved + |> toDiagnosticsValue positiveResultRecorded + + +toDiagnosticsValue : Bool -> DiagnosticsForm -> Maybe HIVDiagnosticsValue +toDiagnosticsValue positiveResultRecorded form = + let + esitmatedSign = + if form.positiveResultDateEstimated == Just True then + [ HIVResultDateEstimated ] + + else + [] + in + if positiveResultRecorded then + Maybe.map + (\resultDateCorrect -> + let + mainSign = + if resultDateCorrect then + [ HIVResultPositiveKnown ] + + else + [] + in + { signs = EverySet.fromList <| mainSign ++ esitmatedSign + , positiveResultDate = form.positiveResultDate + } + ) + form.resultDateCorrect + + else + Maybe.map + (\resultPositive -> + let + mainSign = + if resultPositive then + [ HIVResultPositiveReported ] + + else + [] + in + { signs = EverySet.fromList <| mainSign ++ esitmatedSign + , positiveResultDate = form.positiveResultDate + } + ) + form.resultPositive + + +toPrescribedMedicationValueWithDefault : Maybe HIVMedicationValue -> PrescribedMedicationForm -> Maybe HIVMedicationValue +toPrescribedMedicationValueWithDefault saved form = + prescribedMedicationFormWithDefault form saved + |> toPrescribedMedicationValue + + +prescribedMedicationFormWithDefault : + PrescribedMedicationForm + -> Maybe HIVMedicationValue + -> PrescribedMedicationForm +prescribedMedicationFormWithDefault form saved = + saved + |> unwrap + form + (\value -> + { medications = or form.medications (Just <| EverySet.toList value) } + ) + + +toPrescribedMedicationValue : PrescribedMedicationForm -> Maybe HIVMedicationValue +toPrescribedMedicationValue form = + Maybe.map EverySet.fromList form.medications + + +toSymptomReviewValueWithDefault : Maybe HIVSymptomReviewValue -> SymptomReviewForm -> Maybe HIVSymptomReviewValue +toSymptomReviewValueWithDefault saved form = + symptomReviewFormWithDefault form saved + |> toSymptomReviewValue + + +symptomReviewFormWithDefault : + SymptomReviewForm + -> Maybe HIVSymptomReviewValue + -> SymptomReviewForm +symptomReviewFormWithDefault form saved = + saved + |> unwrap + form + (\value -> + { symptoms = or form.symptoms (Just <| EverySet.toList value) + , symptomsDirty = form.symptomsDirty + } + ) + + +toSymptomReviewValue : SymptomReviewForm -> Maybe HIVSymptomReviewValue +toSymptomReviewValue form = + Maybe.map EverySet.fromList form.symptoms + + +toHealthEducationValueWithDefault : Maybe HIVHealthEducationValue -> HealthEducationForm -> Maybe HIVHealthEducationValue +toHealthEducationValueWithDefault saved form = + healthEducationFormWithDefault form saved + |> toHealthEducationValue + + +healthEducationFormWithDefault : + HealthEducationForm + -> Maybe HIVHealthEducationValue + -> HealthEducationForm +healthEducationFormWithDefault form saved = + saved + |> unwrap + form + (\value -> + { positiveResult = or form.positiveResult (EverySet.member EducationPositiveResult value |> Just) + , saferSexPractices = or form.saferSexPractices (EverySet.member EducationSaferSexPractices value |> Just) + , encouragedPartnerTesting = or form.encouragedPartnerTesting (EverySet.member EducationEncouragedPartnerTesting value |> Just) + , familyPlanningOptions = or form.familyPlanningOptions (EverySet.member EducationFamilyPlanningOptions value |> Just) + } + ) + + +toHealthEducationValue : HealthEducationForm -> Maybe HIVHealthEducationValue +toHealthEducationValue form = + [ ifNullableTrue EducationPositiveResult form.positiveResult + , ifNullableTrue EducationSaferSexPractices form.saferSexPractices + , ifNullableTrue EducationEncouragedPartnerTesting form.encouragedPartnerTesting + , ifNullableTrue EducationFamilyPlanningOptions form.familyPlanningOptions + ] + |> Maybe.Extra.combine + |> Maybe.map (List.foldl EverySet.union EverySet.empty >> ifEverySetEmpty NoHIVHealthEducationSigns) + + +mostCommonAntiRetroviralMedications : List HIVPrescribedMedication +mostCommonAntiRetroviralMedications = + [ HIVMedicationDolutegravirLamivudineTenofovir + , HIVMedicationAtazanavirRitonavir + , HIVMedicationDolutegravir + , HIVMedicationAbacavirLamivudine + , HIVMedicationLamivudineTenofovir + , HIVMedicationZidovudine + ] + + +lessCommonAntiRetroviralMedications : List HIVPrescribedMedication +lessCommonAntiRetroviralMedications = + [ HIVMedicationLamivudineZidovudineNevirapine + , HIVMedicationEfavirenzLamivudineTenofovir + , HIVMedicationLamivudineZidovudine + , HIVMedicationLopinavirRitonavir + , HIVMedicationDarunavirRitonavir + , HIVMedicationDarunavirCobicistat + , HIVMedicationRaltegravir + , HIVMedicationEfavirenz + , HIVMedicationNevirapine + , HIVMedicationEtravirine + , HIVMedicationTenofovir + , HIVMedicationLamivudine + , HIVMedicationAbacavir + ] + + +prophylaxisMedications : List HIVPrescribedMedication +prophylaxisMedications = + [ HIVMedicationBactrim + , HIVMedicationDapsone + , HIVMedicationIsoniazid + , HIVMedicationFluconazole + , HIVMedicationAzithromycin + ] diff --git a/client/src/elm/Pages/HIV/Activity/View.elm b/client/src/elm/Pages/HIV/Activity/View.elm new file mode 100644 index 0000000000..78a2c028d6 --- /dev/null +++ b/client/src/elm/Pages/HIV/Activity/View.elm @@ -0,0 +1,703 @@ +module Pages.HIV.Activity.View exposing (view) + +import AssocList as Dict +import Backend.Entities exposing (..) +import Backend.HIVActivity.Model exposing (HIVActivity(..)) +import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterType(..)) +import Backend.Measurement.Model exposing (..) +import Backend.Measurement.Utils exposing (getMeasurementValueFunc) +import Backend.Model exposing (ModelIndexedDb) +import Backend.NutritionEncounter.Utils exposing (getNCDEncountersForParticipant, getPrenatalEncountersForParticipant) +import Backend.Utils exposing (resolveIndividualParticipantsForPerson) +import Date exposing (Unit(..)) +import DateSelector.SelectorPopup exposing (viewCalendarPopup) +import EverySet +import Gizra.Html exposing (emptyNode, showIf) +import Gizra.NominalDate exposing (NominalDate, formatDDMMYYYY) +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import List.Extra +import Maybe.Extra exposing (isJust) +import Measurement.Model exposing (OngoingTreatmentReviewForm) +import Measurement.Utils + exposing + ( followUpFormWithDefault + , ongoingTreatmentReviewFormWithDefault + , sendToHCFormWithDefault + , treatmentReviewInputsAndTasks + ) +import Measurement.View + exposing + ( viewFollowUpForm + , viewSendToHealthCenterForm + ) +import Pages.HIV.Activity.Model exposing (..) +import Pages.HIV.Activity.Utils exposing (..) +import Pages.HIV.Encounter.Model exposing (AssembledData) +import Pages.HIV.Encounter.Utils exposing (generateAssembledData) +import Pages.Page exposing (Page(..), UserPage(..)) +import Pages.Utils + exposing + ( isTaskCompleted + , maybeToBoolTask + , resolveActiveTask + , saveButton + , taskCompleted + , tasksBarId + , viewBoolInput + , viewCheckBoxMultipleSelectInput + , viewCheckBoxMultipleSelectSectionsInput + , viewCustomBoolInput + , viewLabel + , viewPersonDetailsExtended + , viewQuestionLabel + , viewSaveAction + ) +import RemoteData +import SyncManager.Model exposing (Site) +import Translate exposing (Language, translate) +import Utils.Html exposing (viewModal) +import Utils.WebData exposing (viewWebData) + + +view : + Language + -> NominalDate + -> HIVEncounterId + -> HIVActivity + -> ModelIndexedDb + -> Model + -> Html Msg +view language currentDate id activity db model = + let + assembled = + generateAssembledData id db + in + viewWebData language (viewHeaderAndContent language currentDate id activity db model) identity assembled + + +viewHeaderAndContent : Language -> NominalDate -> HIVEncounterId -> HIVActivity -> ModelIndexedDb -> Model -> AssembledData -> Html Msg +viewHeaderAndContent language currentDate id activity db model assembled = + div [ class "page-activity hiv" ] <| + [ viewHeader language id activity + , viewContent language currentDate activity db model assembled + ] + + +viewHeader : Language -> HIVEncounterId -> HIVActivity -> Html Msg +viewHeader language id activity = + div + [ class "ui basic segment head" ] + [ h1 + [ class "ui header" ] + [ text <| translate language <| Translate.HIVActivityTitle activity ] + , span + [ class "link-back" + , onClick <| SetActivePage <| UserPage <| HIVEncounterPage id + ] + [ span [ class "icon-back" ] [] ] + ] + + +viewContent : Language -> NominalDate -> HIVActivity -> ModelIndexedDb -> Model -> AssembledData -> Html Msg +viewContent language currentDate activity db model assembled = + div [ class "ui unstackable items" ] <| + ((viewPersonDetailsExtended language currentDate assembled.person |> div [ class "item" ]) + :: viewActivity language currentDate activity assembled db model + ) + + +viewActivity : Language -> NominalDate -> HIVActivity -> AssembledData -> ModelIndexedDb -> Model -> List (Html Msg) +viewActivity language currentDate activity assembled db model = + case activity of + Diagnostics -> + viewDiagnosticsContent language currentDate assembled db model.diagnosticsData + + Medication -> + viewMedicationContent language currentDate assembled model.medicationData + + SymptomReview -> + viewSymptomReviewContent language currentDate assembled model.symptomReviewData + + NextSteps -> + viewNextStepsContent language currentDate assembled model.nextStepsData + + +viewDiagnosticsContent : Language -> NominalDate -> AssembledData -> ModelIndexedDb -> DiagnosticsData -> List (Html Msg) +viewDiagnosticsContent language currentDate assembled db data = + let + form = + assembled.measurements.diagnostics + |> getMeasurementValueFunc + |> diagnosticsFormWithDefault data.form + + personId = + assembled.participant.person + + ncdParticipantsIds = + resolveIndividualParticipantsForPerson personId NCDEncounter db + + prenatalParticipantsIds = + resolveIndividualParticipantsForPerson personId AntenatalEncounter db + + ncdEncountersIds = + List.map (getNCDEncountersForParticipant db >> List.map Tuple.first) ncdParticipantsIds + |> List.concat + + prenatalEncountersIds = + List.map (getPrenatalEncountersForParticipant db >> List.map Tuple.first) prenatalParticipantsIds + |> List.concat + + resolvePositiveHIVResultDates getMeasurementsFunc = + List.filterMap + (\encounterId -> + getMeasurementsFunc db + |> Dict.get encounterId + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.andThen .hivTest + |> getMeasurementValueFunc + |> Maybe.andThen + (\value -> + if value.testResult == Just TestPositive then + value.executionDate + + else + Nothing + ) + ) + + positiveHIVResultDatesFromNCD = + resolvePositiveHIVResultDates .ncdMeasurements ncdEncountersIds + + positiveHIVResultDatesFromPrenatal = + resolvePositiveHIVResultDates .prenatalMeasurements prenatalEncountersIds + + mPositiveHIVResultDate = + positiveHIVResultDatesFromNCD + ++ positiveHIVResultDatesFromPrenatal + |> List.sortWith Date.compare + |> List.head + + ( inputs, tasksCompleted, totalTasks ) = + Maybe.map (resolveInputsAndTasksForExistingPositiveHIVResult language currentDate form) mPositiveHIVResultDate + |> Maybe.withDefault (resolveInputsAndTasksForNonExistingPositiveHIVResult language currentDate form) + in + [ div [ class "tasks-count" ] [ text <| translate language <| Translate.TasksCompleted tasksCompleted totalTasks ] + , div [ class "ui full segment" ] + [ div [ class "full content" ] + [ div [ class "ui form danger-signs" ] inputs + ] + , div [ class "actions" ] + [ saveButton language + (tasksCompleted == totalTasks) + (SaveDiagnostics assembled.participant.person + assembled.encounter.participant + (isJust mPositiveHIVResultDate) + assembled.measurements.diagnostics + ) + ] + ] + ] + + +resolveInputsAndTasksForExistingPositiveHIVResult : Language -> NominalDate -> DiagnosticsForm -> NominalDate -> ( List (Html Msg), Int, Int ) +resolveInputsAndTasksForExistingPositiveHIVResult language currentDate form positiveHIVResultDate = + let + ( derivedInputs, derivedTasksCompleted, derivedTotalTasks ) = + Maybe.map + (\resultDateCorrect -> + if not resultDateCorrect then + resolveInputsAndTasksForPositiveHIVDate language currentDate form + + else + ( [], 0, 0 ) + ) + form.resultDateCorrect + |> Maybe.withDefault ( [], 0, 0 ) + in + ( [ viewQuestionLabel language <| Translate.HIVPositiveDateCorrectQuestion positiveHIVResultDate + , viewBoolInput + language + form.resultDateCorrect + (ConfirmPositiveResultDate positiveHIVResultDate) + "result-date-correct" + Nothing + ] + ++ derivedInputs + , taskCompleted form.resultDateCorrect + derivedTasksCompleted + , 1 + derivedTotalTasks + ) + + +resolveInputsAndTasksForNonExistingPositiveHIVResult : Language -> NominalDate -> DiagnosticsForm -> ( List (Html Msg), Int, Int ) +resolveInputsAndTasksForNonExistingPositiveHIVResult language currentDate form = + let + ( derivedInputs, derivedTasksCompleted, derivedTotalTasks ) = + Maybe.map + (\resultPositive -> + if resultPositive then + resolveInputsAndTasksForPositiveHIVDate language currentDate form + + else + ( [], 0, 0 ) + ) + form.resultPositive + |> Maybe.withDefault ( [], 0, 0 ) + in + ( [ viewQuestionLabel language Translate.HIVPositiveDiagnosedQuestion + , viewBoolInput + language + form.resultPositive + (SetDiagnosticsBoolInput + (\value form_ -> + { form_ + | resultPositive = Just value + , positiveResultDate = Nothing + , positiveResultDateDirty = True + , positiveResultDateEstimated = Nothing + , positiveResultDateEstimatedDirty = True + } + ) + ) + "result-positive" + Nothing + ] + ++ derivedInputs + , taskCompleted form.resultPositive + derivedTasksCompleted + , 1 + derivedTotalTasks + ) + + +resolveInputsAndTasksForPositiveHIVDate : Language -> NominalDate -> DiagnosticsForm -> ( List (Html Msg), Int, Int ) +resolveInputsAndTasksForPositiveHIVDate language currentDate form = + let + dateForView = + Maybe.map formatDDMMYYYY form.positiveResultDate + |> Maybe.withDefault "" + + estimatedChecked = + Maybe.withDefault False form.positiveResultDateEstimated + + dateSelectorConfig = + { select = SetPositiveResultDate + , close = SetDateSelectorState Nothing + , dateFrom = Date.add Years -120 currentDate + , dateTo = currentDate + , dateDefault = Nothing + } + in + ( [ div [ class "ui grid" ] + [ div [ class "twelve wide column required" ] + [ viewQuestionLabel language Translate.HIVPositiveTestDateQuestion + , div + [ class "form-input date" + , onClick <| SetDateSelectorState (Just dateSelectorConfig) + ] + [ text dateForView ] + ] + , div + [ class "three wide column" ] + [ viewLabel language Translate.Estimated + , input + [ type_ "checkbox" + , onClick + (SetDiagnosticsBoolInput + (\value form_ -> + { form_ + | positiveResultDateEstimated = Just value + , positiveResultDateEstimatedDirty = True + } + ) + (not estimatedChecked) + ) + , checked estimatedChecked + , classList + [ ( "checkbox", True ) + , ( "checked", estimatedChecked ) + ] + ] + [] + ] + , viewModal <| viewCalendarPopup language form.dateSelectorPopupState form.positiveResultDate + ] + ] + , taskCompleted form.positiveResultDate + , 1 + ) + + +viewMedicationContent : Language -> NominalDate -> AssembledData -> MedicationData -> List (Html Msg) +viewMedicationContent language currentDate assembled data = + let + measurements = + assembled.measurements + + tasks = + List.filter (expectMedicationTask currentDate assembled) medicationTasks + + activeTask = + resolveActiveTask tasks data.activeTask + + viewTask task = + let + isCompleted = + medicationTaskCompleted assembled task + + iconClass = + case task of + TaskPrescribedMedication -> + "medication" + + TaskTreatmentReview -> + "treatment-review" + + isActive = + activeTask == Just task + + attributes = + classList [ ( "link-section", True ), ( "active", isActive ), ( "completed", not isActive && isCompleted ) ] + :: (if isActive then + [] + + else + [ onClick <| SetActiveMedicationTask task ] + ) + in + div [ class "column" ] + [ div attributes + [ span [ class <| "icon-activity-task icon-" ++ iconClass ] [] + , text <| translate language (Translate.HIVMedicationTask task) + ] + ] + + tasksCompletedFromTotalDict = + List.map (\task -> ( task, medicationTasksCompletedFromTotal language currentDate assembled data task )) tasks + |> Dict.fromList + + ( tasksCompleted, totalTasks ) = + Maybe.andThen (\task -> Dict.get task tasksCompletedFromTotalDict) activeTask + |> Maybe.withDefault ( 0, 0 ) + + viewForm = + case activeTask of + Just TaskPrescribedMedication -> + getMeasurementValueFunc measurements.medication + |> prescribedMedicationFormWithDefault data.prescribedMedicationForm + |> viewPrescribedMedicationForm language currentDate + |> List.singleton + + Just TaskTreatmentReview -> + getMeasurementValueFunc measurements.treatmentReview + |> ongoingTreatmentReviewFormWithDefault data.treatmentReviewForm + |> viewTreatmentReviewForm language currentDate + |> List.singleton + + Nothing -> + [] + + nextTask = + let + tasksAfterSave = + case activeTask of + Just TaskPrescribedMedication -> + -- DOT and Treatment Review review appear only after + -- Prescribed Medication task is saved. + [ TaskPrescribedMedication, TaskTreatmentReview ] + + _ -> + tasks + in + List.filter + (\task -> + (Just task /= activeTask) + && (not <| isTaskCompleted tasksCompletedFromTotalDict task) + ) + tasksAfterSave + |> List.head + + actions = + Maybe.map + (\task -> + let + personId = + assembled.participant.person + + saveMsg = + case task of + TaskPrescribedMedication -> + SavePrescribedMedication personId measurements.medication nextTask + + TaskTreatmentReview -> + SaveTreatmentReview personId measurements.treatmentReview nextTask + + disabled = + tasksCompleted /= totalTasks + in + viewSaveAction language saveMsg disabled + ) + activeTask + |> Maybe.withDefault emptyNode + in + [ div [ class "ui task segment blue", Html.Attributes.id tasksBarId ] + [ div [ class "ui five column grid" ] <| + List.map viewTask tasks + ] + , div [ class "tasks-count" ] [ text <| translate language <| Translate.TasksCompleted tasksCompleted totalTasks ] + , div [ class "ui full segment" ] + [ div [ class "full content" ] <| + (viewForm ++ [ actions ]) + ] + ] + + +viewPrescribedMedicationForm : Language -> NominalDate -> PrescribedMedicationForm -> Html Msg +viewPrescribedMedicationForm language currentDate form = + div [ class "ui form prescribed-medication" ] + [ viewQuestionLabel language Translate.HIVPrescribedMedicationsQuestion + , viewCheckBoxMultipleSelectSectionsInput language + [ ( Translate.MostCommonAntiRetroviralMedications, mostCommonAntiRetroviralMedications ) + , ( Translate.LessCommonAntiRetroviralMedications, lessCommonAntiRetroviralMedications ) + , ( Translate.ProphylaxisMedications, prophylaxisMedications ) + ] + (Maybe.withDefault [] form.medications) + SetPrescribedMedication + Translate.HIVPrescribedMedication + ] + + +viewTreatmentReviewForm : Language -> NominalDate -> OngoingTreatmentReviewForm -> Html Msg +viewTreatmentReviewForm language currentDate form = + let + ( inputs, _ ) = + treatmentReviewInputsAndTasks language + currentDate + SetTreatmentReviewBoolInput + SetReasonForNotTaking + SetTotalMissedDoses + SetAdverseEvent + form + in + div [ class "ui form treatment-review" ] + inputs + + +viewSymptomReviewContent : Language -> NominalDate -> AssembledData -> SymptomReviewData -> List (Html Msg) +viewSymptomReviewContent language currentDate assembled data = + let + form = + assembled.measurements.symptomReview + |> getMeasurementValueFunc + |> symptomReviewFormWithDefault data.form + + ( inputs, tasksCompleted, totalTasks ) = + ( [ viewQuestionLabel language Translate.HIVSymptomReviewQuestion + , viewCheckBoxMultipleSelectInput language + [ HIVSymptomFever + , HIVSymptomFatigue + , HIVSymptomSwollenLymphNodes + , HIVSymptomSoreThroat + , HIVSymptomRash + , HIVSymptomMuscleJointPain + , HIVSymptomHeadache + , HIVSymptomSevereAbdominalPain + ] + [ HIVSymptomNightSweats + , HIVSymptomDiarrhea + , HIVSymptomWeightLoss + , HIVSymptomCoughingUpBlood + , HIVSymptomHairLoss + , HIVSymptomMouthUlcers + , HIVSymptomDifficultyBreathing + , HIVSymptomVomiting + ] + (Maybe.withDefault [] form.symptoms) + (Just NoHIVSymptoms) + SetSymptom + Translate.HIVSymptom + ] + , taskCompleted form.symptoms + , 1 + ) + in + [ div [ class "tasks-count" ] [ text <| translate language <| Translate.TasksCompleted tasksCompleted totalTasks ] + , div [ class "ui full segment" ] + [ div [ class "full content" ] + [ div [ class "ui form symptom-review" ] inputs + ] + , div [ class "actions" ] + [ saveButton language + (tasksCompleted == totalTasks) + (SaveSymptomReview assembled.participant.person assembled.measurements.symptomReview) + ] + ] + ] + + +viewNextStepsContent : Language -> NominalDate -> AssembledData -> NextStepsData -> List (Html Msg) +viewNextStepsContent language currentDate assembled data = + let + measurements = + assembled.measurements + + tasks = + List.filter (expectNextStepsTask currentDate assembled) nextStepsTasks + + activeTask = + resolveActiveTask tasks data.activeTask + + viewTask task = + let + isCompleted = + nextStepsTaskCompleted assembled task + + iconClass = + case task of + TaskHealthEducation -> + "next-steps-health-education" + + TaskFollowUp -> + "next-steps-follow-up" + + TaskReferral -> + "next-steps-send-to-hc" + + isActive = + activeTask == Just task + + attributes = + classList [ ( "link-section", True ), ( "active", isActive ), ( "completed", not isActive && isCompleted ) ] + :: (if isActive then + [] + + else + [ onClick <| SetActiveNextStepsTask task ] + ) + in + div [ class "column" ] + [ div attributes + [ span [ class <| "icon-activity-task icon-" ++ iconClass ] [] + , text <| translate language (Translate.HIVNextStepsTask task) + ] + ] + + tasksCompletedFromTotalDict = + List.map (\task -> ( task, nextStepsTasksCompletedFromTotal measurements data task )) tasks + |> Dict.fromList + + ( tasksCompleted, totalTasks ) = + Maybe.andThen (\task -> Dict.get task tasksCompletedFromTotalDict) activeTask + |> Maybe.withDefault ( 0, 0 ) + + viewForm = + case activeTask of + Just TaskHealthEducation -> + getMeasurementValueFunc measurements.healthEducation + |> healthEducationFormWithDefault data.healthEducationForm + |> viewHealthEducationForm language + currentDate + assembled + |> List.singleton + + Just TaskFollowUp -> + getMeasurementValueFunc measurements.followUp + |> followUpFormWithDefault data.followUpForm + |> viewFollowUpForm language + currentDate + [ OneDay, OneWeek, OneMonth ] + SetFollowUpOption + |> List.singleton + + Just TaskReferral -> + getMeasurementValueFunc measurements.referral + |> sendToHCFormWithDefault data.sendToHCForm + |> viewSendToHealthCenterForm language + currentDate + SetReferToHealthCenter + SetReasonForNonReferral + SetHandReferralForm + Nothing + |> List.singleton + + Nothing -> + [] + + nextTask = + List.filter + (\task -> + (Just task /= activeTask) + && (not <| isTaskCompleted tasksCompletedFromTotalDict task) + ) + tasks + |> List.head + + actions = + activeTask + |> Maybe.map + (\task -> + let + personId = + assembled.participant.person + + saveMsg = + case task of + TaskHealthEducation -> + SaveHealthEducation personId measurements.healthEducation nextTask + + TaskFollowUp -> + SaveFollowUp personId measurements.followUp nextTask + + TaskReferral -> + SaveReferral personId measurements.referral nextTask + + disabled = + tasksCompleted /= totalTasks + in + viewSaveAction language saveMsg disabled + ) + |> Maybe.withDefault emptyNode + in + [ div [ class "ui task segment blue", Html.Attributes.id tasksBarId ] + [ div [ class "ui five column grid" ] <| + List.map viewTask tasks + ] + , div [ class "tasks-count" ] [ text <| translate language <| Translate.TasksCompleted tasksCompleted totalTasks ] + , div [ class "ui full segment" ] + [ div [ class "full content" ] <| + (viewForm ++ [ actions ]) + ] + ] + + +viewHealthEducationForm : Language -> NominalDate -> AssembledData -> HealthEducationForm -> Html Msg +viewHealthEducationForm language currentDate assembled form = + div [ class "ui form health-education" ] + [ viewQuestionLabel language <| Translate.HIVHealthEducationQuestion EducationPositiveResult + , viewBoolInput + language + form.positiveResult + (SetHealthEducationBoolInput (\value form_ -> { form_ | positiveResult = Just value })) + "positive-result" + Nothing + , viewQuestionLabel language <| Translate.HIVHealthEducationQuestion EducationSaferSexPractices + , viewBoolInput + language + form.saferSexPractices + (SetHealthEducationBoolInput (\value form_ -> { form_ | saferSexPractices = Just value })) + "safer-sex-practices" + Nothing + , viewQuestionLabel language <| Translate.HIVHealthEducationQuestion EducationEncouragedPartnerTesting + , viewBoolInput + language + form.encouragedPartnerTesting + (SetHealthEducationBoolInput (\value form_ -> { form_ | encouragedPartnerTesting = Just value })) + "encouraged-partner-testing" + Nothing + , viewQuestionLabel language <| Translate.HIVHealthEducationQuestion EducationFamilyPlanningOptions + , viewBoolInput + language + form.familyPlanningOptions + (SetHealthEducationBoolInput (\value form_ -> { form_ | familyPlanningOptions = Just value })) + "family-planning-options" + Nothing + ] diff --git a/client/src/elm/Pages/HIV/Encounter/Fetch.elm b/client/src/elm/Pages/HIV/Encounter/Fetch.elm new file mode 100644 index 0000000000..3b3f41fe99 --- /dev/null +++ b/client/src/elm/Pages/HIV/Encounter/Fetch.elm @@ -0,0 +1,39 @@ +module Pages.HIV.Encounter.Fetch exposing (fetch) + +import AssocList as Dict +import Backend.Entities exposing (..) +import Backend.Model exposing (ModelIndexedDb, MsgIndexedDb(..)) +import Backend.NutritionEncounter.Fetch +import Backend.NutritionEncounter.Utils exposing (getHIVEncountersForParticipant) +import Maybe.Extra +import RemoteData + + +fetch : HIVEncounterId -> ModelIndexedDb -> List MsgIndexedDb +fetch id db = + let + participantId = + Dict.get id db.hivEncounters + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.map .participant + + personId = + Maybe.andThen (\id_ -> Dict.get id_ db.individualParticipants) participantId + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.map .person + + encountersIds = + Maybe.map (getHIVEncountersForParticipant db >> List.map Tuple.first) participantId + |> Maybe.withDefault [] + + -- We fetch measurements of all encounters. + fetchMeasurementsMsgs = + List.map FetchHIVMeasurements encountersIds + in + Maybe.Extra.values + [ Maybe.map FetchIndividualEncounterParticipant participantId + , Maybe.map FetchPerson personId + , Maybe.map FetchHIVEncountersForParticipant participantId + , Just <| FetchHIVEncounter id + ] + ++ fetchMeasurementsMsgs diff --git a/client/src/elm/Pages/HIV/Encounter/Model.elm b/client/src/elm/Pages/HIV/Encounter/Model.elm new file mode 100644 index 0000000000..d27975121b --- /dev/null +++ b/client/src/elm/Pages/HIV/Encounter/Model.elm @@ -0,0 +1,55 @@ +module Pages.HIV.Encounter.Model exposing (..) + +import Backend.Entities exposing (..) +import Backend.HIVEncounter.Model exposing (..) +import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterParticipant) +import Backend.Measurement.Model exposing (HIVMeasurements) +import Backend.Person.Model exposing (Person) +import Gizra.NominalDate exposing (NominalDate) +import Pages.Page exposing (Page) + + +type alias Model = + { selectedTab : Tab + , showEndEncounterDialog : Bool + } + + +emptyModel : Model +emptyModel = + { selectedTab = Pending + , showEndEncounterDialog = False + } + + +type Tab + = Completed + | Pending + | Reports + + +type alias AssembledData = + { id : HIVEncounterId + , encounter : HIVEncounter + , participant : IndividualEncounterParticipant + , person : Person + , measurements : HIVMeasurements + , previousEncountersData : List PreviousEncounterData + + -- Intial encounter is the one where initial diagnosis is made. + , initialEncounter : Bool + } + + +type alias PreviousEncounterData = + { id : HIVEncounterId + , startDate : NominalDate + , measurements : HIVMeasurements + } + + +type Msg + = CloseEncounter HIVEncounterId + | SetActivePage Page + | SetSelectedTab Tab + | SetEndEncounterDialogState Bool diff --git a/client/src/elm/Pages/HIV/Encounter/Update.elm b/client/src/elm/Pages/HIV/Encounter/Update.elm new file mode 100644 index 0000000000..12d55d9b10 --- /dev/null +++ b/client/src/elm/Pages/HIV/Encounter/Update.elm @@ -0,0 +1,35 @@ +module Pages.HIV.Encounter.Update exposing (update) + +import App.Model +import Backend.HIVEncounter.Model +import Backend.IndividualEncounterParticipant.Model exposing (IndividualParticipantInitiator(..)) +import Backend.Model +import Gizra.Update exposing (sequenceExtra) +import Pages.HIV.Encounter.Model exposing (..) +import Pages.Page exposing (Page(..), UserPage(..)) + + +update : Msg -> Model -> ( Model, Cmd Msg, List App.Model.Msg ) +update msg model = + case msg of + CloseEncounter id -> + ( model + , Cmd.none + , [ Backend.HIVEncounter.Model.CloseHIVEncounter + |> Backend.Model.MsgHIVEncounter id + |> App.Model.MsgIndexedDb + , App.Model.SetActivePage PinCodePage + ] + ) + + SetActivePage page -> + ( model + , Cmd.none + , [ App.Model.SetActivePage page ] + ) + + SetSelectedTab tab -> + ( { model | selectedTab = tab }, Cmd.none, [] ) + + SetEndEncounterDialogState isOpen -> + ( { model | showEndEncounterDialog = isOpen }, Cmd.none, [] ) diff --git a/client/src/elm/Pages/HIV/Encounter/Utils.elm b/client/src/elm/Pages/HIV/Encounter/Utils.elm new file mode 100644 index 0000000000..c8dd2bf2f5 --- /dev/null +++ b/client/src/elm/Pages/HIV/Encounter/Utils.elm @@ -0,0 +1,102 @@ +module Pages.HIV.Encounter.Utils exposing (..) + +import AssocList as Dict +import Backend.Entities exposing (..) +import Backend.Measurement.Model exposing (..) +import Backend.Measurement.Utils exposing (diabetesBySugarCount, diabetesByUrineGlucose, getCurrentReasonForNonReferral, getMeasurementValueFunc) +import Backend.Model exposing (ModelIndexedDb) +import Backend.NutritionEncounter.Utils exposing (getHIVEncountersForParticipant) +import Date +import EverySet exposing (EverySet) +import Gizra.NominalDate exposing (NominalDate) +import Html exposing (..) +import Html.Attributes exposing (..) +import Maybe.Extra exposing (andMap, isJust, or, unwrap) +import Pages.HIV.Encounter.Model exposing (..) +import Pages.Utils + exposing + ( ifEverySetEmpty + , ifNullableTrue + , maybeToBoolTask + , taskCompleted + , viewBoolInput + , viewCheckBoxMultipleSelectCustomInput + , viewCheckBoxSelectCustomInput + , viewCheckBoxSelectInput + , viewCustomLabel + , viewInstructionsLabel + , viewQuestionLabel + ) +import RemoteData exposing (RemoteData(..), WebData) +import Translate exposing (Language, translate) +import Utils.NominalDate exposing (sortByStartDateDesc) + + +generateAssembledData : HIVEncounterId -> ModelIndexedDb -> WebData AssembledData +generateAssembledData id db = + let + encounter = + Dict.get id db.hivEncounters + |> Maybe.withDefault NotAsked + + measurements = + Dict.get id db.hivMeasurements + |> Maybe.withDefault NotAsked + + participant = + encounter + |> RemoteData.andThen + (\encounter_ -> + Dict.get encounter_.participant db.individualParticipants + |> Maybe.withDefault NotAsked + ) + + person = + participant + |> RemoteData.andThen + (\participant_ -> + Dict.get participant_.person db.people + |> Maybe.withDefault NotAsked + ) + + previousEncountersData = + RemoteData.toMaybe encounter + |> Maybe.map (\encounter_ -> generatePreviousEncountersData (Just id) encounter_.participant db) + |> Maybe.withDefault [] + + initialEncounter = + List.isEmpty previousEncountersData + in + RemoteData.map AssembledData (Success id) + |> RemoteData.andMap encounter + |> RemoteData.andMap participant + |> RemoteData.andMap person + |> RemoteData.andMap measurements + |> RemoteData.andMap (Success previousEncountersData) + |> RemoteData.andMap (Success initialEncounter) + + +generatePreviousEncountersData : Maybe HIVEncounterId -> IndividualEncounterParticipantId -> ModelIndexedDb -> List PreviousEncounterData +generatePreviousEncountersData currentEncounterId participantId db = + getHIVEncountersForParticipant db participantId + |> List.filterMap + (\( encounterId, encounter ) -> + -- If the ID of current encounter was provided, + -- we do not want to get its data. + if currentEncounterId == Just encounterId then + Nothing + + else + case Dict.get encounterId db.hivMeasurements of + Just (Success measurements) -> + Just + { id = encounterId + , startDate = encounter.startDate + , measurements = measurements + } + + _ -> + Nothing + ) + -- Most recent date to least recent date. + |> List.sortWith sortByStartDateDesc diff --git a/client/src/elm/Pages/HIV/Encounter/View.elm b/client/src/elm/Pages/HIV/Encounter/View.elm new file mode 100644 index 0000000000..600569c091 --- /dev/null +++ b/client/src/elm/Pages/HIV/Encounter/View.elm @@ -0,0 +1,176 @@ +module Pages.HIV.Encounter.View exposing (view) + +import Backend.Entities exposing (..) +import Backend.HIVActivity.Model exposing (HIVActivity) +import Backend.HIVActivity.Utils exposing (allActivities, getActivityIcon) +import Backend.IndividualEncounterParticipant.Model +import Backend.Measurement.Utils exposing (getMeasurementValueFunc) +import Backend.Model exposing (ModelIndexedDb) +import EverySet +import Gizra.NominalDate exposing (NominalDate) +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import Pages.HIV.Activity.Utils exposing (activityCompleted, expectActivity) +import Pages.HIV.Encounter.Model exposing (..) +import Pages.HIV.Encounter.Utils exposing (generateAssembledData) +import Pages.Page exposing (Page(..), UserPage(..)) +import Pages.Utils + exposing + ( viewEndEncounterButton + , viewEndEncounterDialog + , viewPersonDetailsExtended + , viewReportLink + ) +import SyncManager.Model exposing (Site) +import Translate exposing (Language, translate) +import Utils.Html exposing (activityCard, tabItem, viewModal) +import Utils.WebData exposing (viewWebData) + + +view : Language -> NominalDate -> Site -> HIVEncounterId -> ModelIndexedDb -> Model -> Html Msg +view language currentDate site id db model = + let + assembled = + generateAssembledData id db + in + viewWebData language (viewHeaderAndContent language currentDate db model) identity assembled + + +viewHeaderAndContent : Language -> NominalDate -> ModelIndexedDb -> Model -> AssembledData -> Html Msg +viewHeaderAndContent language currentDate db model assembled = + let + header = + viewHeader language assembled + + content = + viewContent language currentDate db model assembled + + endEncounterDialog = + if model.showEndEncounterDialog then + Just <| + viewEndEncounterDialog language + Translate.EndEncounterQuestion + Translate.OnceYouEndTheEncounter + (CloseEncounter assembled.id) + (SetEndEncounterDialogState False) + + else + Nothing + in + div [ class "page-encounter hiv" ] + [ header + , content + , viewModal endEncounterDialog + ] + + +viewHeader : Language -> AssembledData -> Html Msg +viewHeader language assembled = + div + [ class "ui basic segment head" ] + [ h1 + [ class "ui header" ] + [ text <| + translate language <| + Translate.IndividualEncounterLabel + Backend.IndividualEncounterParticipant.Model.HIVEncounter + False + ] + , span + [ class "link-back" + , onClick <| SetActivePage <| UserPage <| HIVParticipantPage assembled.participant.person + ] + [ span [ class "icon-back" ] [] ] + ] + + +viewContent : Language -> NominalDate -> ModelIndexedDb -> Model -> AssembledData -> Html Msg +viewContent language currentDate db model assembled = + ((viewPersonDetailsExtended language currentDate assembled.person |> div [ class "item" ]) + :: viewMainPageContent language currentDate db assembled model + ) + |> div [ class "ui unstackable items" ] + + +viewMainPageContent : Language -> NominalDate -> ModelIndexedDb -> AssembledData -> Model -> List (Html Msg) +viewMainPageContent language currentDate db assembled model = + let + ( completedActivities, pendingActivities ) = + List.filter (expectActivity currentDate assembled) allActivities + |> List.partition (activityCompleted currentDate assembled) + + pendingTabTitle = + translate language <| Translate.ActivitiesToComplete <| List.length pendingActivities + + completedTabTitle = + translate language <| Translate.ActivitiesCompleted <| List.length completedActivities + + reportsTabTitle = + translate language Translate.ProgressReport + + tabs = + div [ class "ui tabular menu" ] + [ tabItem pendingTabTitle (model.selectedTab == Pending) "pending" (SetSelectedTab Pending) + , tabItem completedTabTitle (model.selectedTab == Completed) "completed" (SetSelectedTab Completed) + , tabItem reportsTabTitle (model.selectedTab == Reports) "reports" (SetSelectedTab Reports) + ] + + viewCard activity = + activityCard language + (Translate.HIVActivityTitle activity) + (getActivityIcon activity) + (SetActivePage <| UserPage <| HIVActivityPage assembled.id activity) + + ( selectedActivities, emptySectionMessage ) = + case model.selectedTab of + Pending -> + ( pendingActivities, translate language Translate.NoActivitiesPending ) + + Completed -> + ( completedActivities, translate language Translate.NoActivitiesCompleted ) + + Reports -> + ( [], "" ) + + innerContent = + if model.selectedTab == Reports then + div [ class "reports-wrapper" ] + [-- @todo: + -- viewReportLink language + -- Translate.ProgressReport + -- (SetActivePage <| + -- UserPage <| + -- HIVProgressReportPage (InitiatorEncounterPage assembled.id) + -- ) + ] + + else + div [ class "full content" ] + [ div [ class "wrap-cards" ] + [ div [ class "ui four cards" ] <| + if List.isEmpty selectedActivities then + [ span [] [ text emptySectionMessage ] ] + + else + List.map viewCard selectedActivities + ] + ] + + allowEndEncounter = + allowEndingEcounter pendingActivities + + content = + div [ class "ui full segment" ] + [ innerContent + , viewEndEncounterButton language allowEndEncounter (SetEndEncounterDialogState True) + ] + in + [ tabs + , content + ] + + +allowEndingEcounter : List HIVActivity -> Bool +allowEndingEcounter pendingActivities = + List.isEmpty pendingActivities diff --git a/client/src/elm/Pages/HIV/Participant/Fetch.elm b/client/src/elm/Pages/HIV/Participant/Fetch.elm new file mode 100644 index 0000000000..0d4b85de58 --- /dev/null +++ b/client/src/elm/Pages/HIV/Participant/Fetch.elm @@ -0,0 +1,19 @@ +module Pages.HIV.Participant.Fetch exposing (fetch) + +import Backend.Entities exposing (..) +import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterType(..)) +import Backend.Model exposing (ModelIndexedDb, MsgIndexedDb(..)) +import Backend.Utils exposing (resolveIndividualParticipantsForPerson) + + +fetch : PersonId -> ModelIndexedDb -> List MsgIndexedDb +fetch id db = + let + fetchHIVEncounters = + resolveIndividualParticipantsForPerson id HIVEncounter db + |> FetchHIVEncountersForParticipants + in + [ FetchPerson id + , FetchIndividualEncounterParticipantsForPerson id + , fetchHIVEncounters + ] diff --git a/client/src/elm/Pages/HIV/Participant/View.elm b/client/src/elm/Pages/HIV/Participant/View.elm new file mode 100644 index 0000000000..01285498c4 --- /dev/null +++ b/client/src/elm/Pages/HIV/Participant/View.elm @@ -0,0 +1,176 @@ +module Pages.HIV.Participant.View exposing (view) + +import App.Model +import AssocList as Dict exposing (Dict) +import Backend.Entities exposing (..) +import Backend.HIVEncounter.Model +import Backend.IndividualEncounterParticipant.Model + exposing + ( IndividualEncounterParticipant + , emptyIndividualEncounterParticipant + ) +import Backend.IndividualEncounterParticipant.Utils exposing (isDailyEncounterActive) +import Backend.Model exposing (ModelIndexedDb) +import Backend.NutritionEncounter.Utils exposing (getHIVEncountersForParticipant) +import Gizra.NominalDate exposing (NominalDate) +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (..) +import Maybe.Extra exposing (isNothing) +import Pages.Page exposing (Page(..), UserPage(..)) +import RemoteData exposing (RemoteData(..)) +import Translate exposing (Language, translate) +import Utils.WebData exposing (viewWebData) + + +view : Language -> NominalDate -> HealthCenterId -> PersonId -> ModelIndexedDb -> Html App.Model.Msg +view language currentDate selectedHealthCenter id db = + let + sessions = + Dict.get id db.individualParticipantsByPerson + |> Maybe.withDefault NotAsked + in + div + [ class "wrap wrap-alt-2 page-participant individual hiv" ] + [ viewHeader language + , div + [ class "ui full segment" ] + [ viewWebData language (viewActions language currentDate selectedHealthCenter id db) identity sessions + ] + ] + + +viewHeader : Language -> Html App.Model.Msg +viewHeader language = + div + [ class "ui basic segment head" ] + [ h1 + [ class "ui header" ] + [ text <| + translate language <| + Translate.IndividualEncounterLabel + Backend.IndividualEncounterParticipant.Model.HIVEncounter + True + ] + , span + [ class "link-back" + , onClick <| + App.Model.SetActivePage <| + UserPage <| + IndividualEncounterParticipantsPage + Backend.IndividualEncounterParticipant.Model.HIVEncounter + ] + [ span [ class "icon-back" ] [] ] + ] + + +viewActions : + Language + -> NominalDate + -> HealthCenterId + -> PersonId + -> ModelIndexedDb + -> Dict IndividualEncounterParticipantId IndividualEncounterParticipant + -> Html App.Model.Msg +viewActions language currentDate selectedHealthCenter id db sessions = + div [] + [ p [ class "label-visit" ] + [ text <| + translate language <| + Translate.IndividualEncounterSelectVisit + Backend.IndividualEncounterParticipant.Model.HIVEncounter + True + ] + , viewHIVAction language currentDate selectedHealthCenter id db sessions + ] + + +viewHIVAction : + Language + -> NominalDate + -> HealthCenterId + -> PersonId + -> ModelIndexedDb + -> Dict IndividualEncounterParticipantId IndividualEncounterParticipant + -> Html App.Model.Msg +viewHIVAction language currentDate selectedHealthCenter id db sessions = + let + maybeSessionId = + Dict.toList sessions + |> List.filter + (\( _, session ) -> + (session.encounterType == Backend.IndividualEncounterParticipant.Model.HIVEncounter) + && isNothing session.endDate + ) + |> List.head + |> Maybe.map Tuple.first + + -- Resolve active encounter for person. There should not be more than one. + -- We also want to know if there's an encounter that was completed today, + -- (started and ended on the same day), as we do not want to allow creating new encounter + -- at same day, previous one has ended. + ( maybeActiveEncounterId, encounterWasCompletedToday ) = + Maybe.map + (getHIVEncountersForParticipant db + >> (\list -> + ( List.filter (Tuple.second >> isDailyEncounterActive currentDate) list + |> List.head + |> Maybe.map Tuple.first + , List.filter + (\( _, encounter ) -> + encounter.startDate == currentDate && encounter.endDate == Just currentDate + ) + list + |> List.isEmpty + |> not + ) + ) + ) + maybeSessionId + |> Maybe.withDefault ( Nothing, False ) + + action = + Maybe.map navigateToEncounterAction maybeActiveEncounterId + |> Maybe.withDefault + (maybeSessionId + |> Maybe.map + -- If HIV session exists, create new encounter for it. + (\sessionId -> + [ Backend.HIVEncounter.Model.emptyHIVEncounter sessionId currentDate (Just selectedHealthCenter) + |> Backend.Model.PostHIVEncounter + |> App.Model.MsgIndexedDb + |> onClick + ] + ) + -- If hiv session does not exist, create it. + |> Maybe.withDefault + [ emptyIndividualEncounterParticipant currentDate id Backend.IndividualEncounterParticipant.Model.HIVEncounter selectedHealthCenter + |> Backend.Model.PostIndividualEncounterParticipant Backend.IndividualEncounterParticipant.Model.NoIndividualParticipantExtraData + |> App.Model.MsgIndexedDb + |> onClick + ] + ) + + navigateToEncounterAction id_ = + [ Pages.Page.HIVEncounterPage id_ + |> UserPage + |> App.Model.SetActivePage + |> onClick + ] + in + div + (classList + [ ( "ui primary button", True ) + , ( "disabled", encounterWasCompletedToday ) + ] + :: action + ) + [ div [ class "button-label" ] + [ text <| + translate language <| + Translate.IndividualEncounterLabel + Backend.IndividualEncounterParticipant.Model.HIVEncounter + True + ] + , div [ class "icon-back" ] [] + ] diff --git a/client/src/elm/Pages/IndividualEncounterParticipants/View.elm b/client/src/elm/Pages/IndividualEncounterParticipants/View.elm index 5f8b2b3566..e4cfd64de6 100644 --- a/client/src/elm/Pages/IndividualEncounterParticipants/View.elm +++ b/client/src/elm/Pages/IndividualEncounterParticipants/View.elm @@ -89,36 +89,39 @@ viewSearchForm language currentDate ( healthCenterId, maybeVillageId ) isChw enc AntenatalEncounter -> isPersonAFertileWoman currentDate person - NutritionEncounter -> - isPersonAnAdult currentDate person - |> Maybe.map not - |> Maybe.withDefault False + ChildScoreboardEncounter -> + isChw && isChildUnderAgeOf2 currentDate person - WellChildEncounter -> - isPersonAnAdult currentDate person - |> Maybe.map not - |> Maybe.withDefault False + HIVEncounter -> + isChw HomeVisitEncounter -> -- We do not have direct access to Home Visit encounter. False - InmmunizationEncounter -> - -- Not in use (possibly future development). - False - NCDEncounter -> -- Patient is 12 years old or above. Maybe.map (\birthDate -> diffYears birthDate currentDate >= 12) person.birthDate |> Maybe.withDefault False - ChildScoreboardEncounter -> - isChw && isChildUnderAgeOf2 currentDate person + NutritionEncounter -> + isPersonAnAdult currentDate person + |> Maybe.map not + |> Maybe.withDefault False TuberculosisEncounter -> isChw + WellChildEncounter -> + isPersonAnAdult currentDate person + |> Maybe.map not + |> Maybe.withDefault False + + InmmunizationEncounter -> + -- Not in use (possibly future development). + False + -- For CHW nurse, we present people only from the village that was selected. chwCondition person = if isChw then @@ -214,29 +217,32 @@ viewParticipant language currentDate encounterType db id person = AntenatalEncounter -> [ onClick <| SetActivePage <| UserPage <| PrenatalParticipantPage InitiatorParticipantsPage id ] - NutritionEncounter -> - [ onClick <| SetActivePage <| UserPage <| NutritionParticipantPage InitiatorParticipantsPage id ] + ChildScoreboardEncounter -> + [ onClick <| SetActivePage <| UserPage <| ChildScoreboardParticipantPage id ] - WellChildEncounter -> - [ onClick <| SetActivePage <| UserPage <| WellChildParticipantPage InitiatorParticipantsPage id ] + HIVEncounter -> + [ onClick <| SetActivePage <| UserPage <| HIVParticipantPage id ] HomeVisitEncounter -> -- We do not have direct access to Home Visit encounter. [] - InmmunizationEncounter -> - -- Not in use (possibly future development). - [] - NCDEncounter -> [ onClick <| SetActivePage <| UserPage <| NCDParticipantPage InitiatorParticipantsPage id ] - ChildScoreboardEncounter -> - [ onClick <| SetActivePage <| UserPage <| ChildScoreboardParticipantPage id ] + NutritionEncounter -> + [ onClick <| SetActivePage <| UserPage <| NutritionParticipantPage InitiatorParticipantsPage id ] TuberculosisEncounter -> [ onClick <| SetActivePage <| UserPage <| TuberculosisParticipantPage id ] + WellChildEncounter -> + [ onClick <| SetActivePage <| UserPage <| WellChildParticipantPage InitiatorParticipantsPage id ] + + InmmunizationEncounter -> + -- Not implemented (possibly future development). + [] + viewAction = div [ class "action" ] [ div [ class "action-icon-wrapper" ] diff --git a/client/src/elm/Pages/IndividualEncounterTypes/View.elm b/client/src/elm/Pages/IndividualEncounterTypes/View.elm index 8e43b5f75f..73eefed999 100644 --- a/client/src/elm/Pages/IndividualEncounterTypes/View.elm +++ b/client/src/elm/Pages/IndividualEncounterTypes/View.elm @@ -3,7 +3,7 @@ module Pages.IndividualEncounterTypes.View exposing (view) import App.Model exposing (Msg(..)) import Backend.Entities exposing (..) import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterType(..)) -import Backend.Utils exposing (ncdaEnabled, tuberculosisManagementEnabled) +import Backend.Utils exposing (hivManagementEnabled, ncdaEnabled, tuberculosisManagementEnabled) import EverySet exposing (EverySet) import Gizra.Html exposing (emptyNode) import Gizra.NominalDate exposing (NominalDate) @@ -62,19 +62,27 @@ viewContent language currentDate features healthCenterId isChw model = else emptyNode - tuberculosiskManagementButton = + tuberculosisManagementButton = if tuberculosisManagementEnabled features then encounterButton TuberculosisEncounter else emptyNode + + hivManagementButton = + if hivManagementEnabled features then + encounterButton HIVEncounter + + else + emptyNode in [ encounterButton AcuteIllnessEncounter , encounterButton AntenatalEncounter , encounterButton NutritionEncounter , encounterButton WellChildEncounter , childScoreboardButton - , tuberculosiskManagementButton + , tuberculosisManagementButton + , hivManagementButton ] else diff --git a/client/src/elm/Pages/NCD/Participant/Fetch.elm b/client/src/elm/Pages/NCD/Participant/Fetch.elm index af26556efe..02e2658dfd 100644 --- a/client/src/elm/Pages/NCD/Participant/Fetch.elm +++ b/client/src/elm/Pages/NCD/Participant/Fetch.elm @@ -11,9 +11,9 @@ fetch id db = let fetchNCDEncounters = resolveIndividualParticipantsForPerson id NCDEncounter db - |> List.map FetchNCDEncountersForParticipant + |> FetchNCDEncountersForParticipants in [ FetchPerson id , FetchIndividualEncounterParticipantsForPerson id + , fetchNCDEncounters ] - ++ fetchNCDEncounters diff --git a/client/src/elm/Pages/NCD/Participant/View.elm b/client/src/elm/Pages/NCD/Participant/View.elm index b78e0e4c3d..5a4cc39f92 100644 --- a/client/src/elm/Pages/NCD/Participant/View.elm +++ b/client/src/elm/Pages/NCD/Participant/View.elm @@ -31,7 +31,7 @@ view language currentDate selectedHealthCenter id initiator db = |> Maybe.withDefault NotAsked in div - [ class "wrap wrap-alt-2 page-participant ncd" ] + [ class "wrap wrap-alt-2 page-participant individual ncd" ] [ viewHeader language initiator , div [ class "ui full segment" ] diff --git a/client/src/elm/Pages/Nutrition/Participant/View.elm b/client/src/elm/Pages/Nutrition/Participant/View.elm index d751f07f53..366f4aebf7 100644 --- a/client/src/elm/Pages/Nutrition/Participant/View.elm +++ b/client/src/elm/Pages/Nutrition/Participant/View.elm @@ -28,7 +28,7 @@ view language currentDate selectedHealthCenter id isChw initiator db = |> Maybe.withDefault NotAsked in div - [ class "wrap wrap-alt-2 page-participant nutrition" ] + [ class "wrap wrap-alt-2 page-participant individual nutrition" ] [ viewHeader language isChw initiator , div [ class "ui full segment" ] diff --git a/client/src/elm/Pages/Page.elm b/client/src/elm/Pages/Page.elm index 7b5e102f9e..4bd9010096 100644 --- a/client/src/elm/Pages/Page.elm +++ b/client/src/elm/Pages/Page.elm @@ -45,6 +45,7 @@ import Backend.AcuteIllnessActivity.Model exposing (AcuteIllnessActivity) import Backend.AcuteIllnessEncounter.Types exposing (AcuteIllnessProgressReportInitiator) import Backend.ChildScoreboardActivity.Model exposing (ChildScoreboardActivity) import Backend.Entities exposing (..) +import Backend.HIVActivity.Model exposing (HIVActivity) import Backend.HomeVisitActivity.Model exposing (HomeVisitActivity) import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterType, IndividualParticipantInitiator) import Backend.Measurement.Model exposing (LaboratoryTest) @@ -193,9 +194,12 @@ type UserPage | ChildScoreboardActivityPage ChildScoreboardEncounterId ChildScoreboardActivity -- record Child Scoreboard activity. | ChildScoreboardProgressReportPage ChildScoreboardEncounterId -- Scorecard. | TuberculosisParticipantPage PersonId - | TuberculosisEncounterPage TuberculosisEncounterId -- Child Scoreboard activities index. - | TuberculosisActivityPage TuberculosisEncounterId TuberculosisActivity -- record Child Scoreboard activity. + | TuberculosisEncounterPage TuberculosisEncounterId -- Tuberculosis activities index. + | TuberculosisActivityPage TuberculosisEncounterId TuberculosisActivity -- record Tuberculosis activity. | EducationSessionPage EducationSessionId -- Education Session page. + | HIVParticipantPage PersonId + | HIVEncounterPage HIVEncounterId -- HIV activities index. + | HIVActivityPage HIVEncounterId HIVActivity -- record HIV activity. | TraceContactPage AcuteIllnessTraceContactId | PatientRecordPage PatientRecordInitiator PersonId | MessagingCenterPage @@ -210,6 +214,7 @@ type DashboardPage | PagePrenatal | PageNCD NCDSubPage | PageChildWellness ChildWellnessSubPage + | PageGroupEducation type NutritionSubPage diff --git a/client/src/elm/Pages/PatientRecord/Fetch.elm b/client/src/elm/Pages/PatientRecord/Fetch.elm index 0120f2e050..f3664d9769 100644 --- a/client/src/elm/Pages/PatientRecord/Fetch.elm +++ b/client/src/elm/Pages/PatientRecord/Fetch.elm @@ -31,6 +31,7 @@ fetch currentDate personId db = in [ FetchPerson personId , FetchRelationshipsForPerson personId + , FetchEducationSessionsForPerson personId ] ++ msgsByAge diff --git a/client/src/elm/Pages/PatientRecord/Model.elm b/client/src/elm/Pages/PatientRecord/Model.elm index 0cb347529f..08555e64f8 100644 --- a/client/src/elm/Pages/PatientRecord/Model.elm +++ b/client/src/elm/Pages/PatientRecord/Model.elm @@ -48,5 +48,6 @@ type PatientType type PatientRecordFilter = FilterAcuteIllness | FilterAntenatal - | FilterFamilyPlanning | FilterDemographics + | FilterFamilyPlanning + | FilterGroupEducation diff --git a/client/src/elm/Pages/PatientRecord/View.elm b/client/src/elm/Pages/PatientRecord/View.elm index 63d73f9176..6cb823a015 100644 --- a/client/src/elm/Pages/PatientRecord/View.elm +++ b/client/src/elm/Pages/PatientRecord/View.elm @@ -1,8 +1,9 @@ module Pages.PatientRecord.View exposing (view) -import AssocList as Dict +import AssocList as Dict exposing (Dict) import Backend.AcuteIllnessEncounter.Model import Backend.AcuteIllnessEncounter.Types +import Backend.EducationSession.Model exposing (EducationSession) import Backend.Entities exposing (..) import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterParticipant, IndividualEncounterType(..)) import Backend.Measurement.Model exposing (FamilyPlanningSign, Gender(..)) @@ -13,6 +14,7 @@ import Backend.Person.Utils exposing (ageInYears, isPersonAnAdult) import Backend.PrenatalEncounter.Model import Backend.PrenatalEncounter.Utils exposing (eddToLmpDate) import Backend.Relationship.Model exposing (MyRelatedBy(..)) +import Backend.Utils exposing (groupEducationEnabled) import EverySet exposing (EverySet) import Gizra.Html exposing (emptyNode, showIf) import Gizra.NominalDate exposing (NominalDate, formatDDMMYYYY) @@ -38,7 +40,7 @@ import RemoteData import SyncManager.Model exposing (Site(..), SiteFeature) import Translate exposing (Language, translate, translateText) import Utils.Html exposing (spinner, thumbnailImage) -import Utils.NominalDate exposing (sortByDate, sortTuplesByDateDesc) +import Utils.NominalDate exposing (sortByDate, sortByDateDesc, sortTuplesByDateDesc) import ZScore.Model @@ -81,7 +83,7 @@ view language currentDate zscores site features id isChw initiator db model = viewContentForChild language currentDate zscores site features id person isChw initiator db model else - viewContentForOther language currentDate site isChw id person patientType initiator db model + viewContentForOther language currentDate site features isChw id person patientType initiator db model ) |> Maybe.withDefault spinner @@ -199,8 +201,20 @@ viewContentForChild language currentDate zscores site features childId child isC ( childId, child ) -viewContentForOther : Language -> NominalDate -> Site -> Bool -> PersonId -> Person -> PatientType -> PatientRecordInitiator -> ModelIndexedDb -> Model -> Html Msg -viewContentForOther language currentDate site isChw personId person patientType initiator db model = +viewContentForOther : + Language + -> NominalDate + -> Site + -> EverySet SiteFeature + -> Bool + -> PersonId + -> Person + -> PatientType + -> PatientRecordInitiator + -> ModelIndexedDb + -> Model + -> Html Msg +viewContentForOther language currentDate site features isChw personId person patientType initiator db model = let individualParticipants = Dict.get personId db.individualParticipantsByPerson @@ -208,13 +222,6 @@ viewContentForOther language currentDate site isChw personId person patientType |> Maybe.map Dict.toList |> Maybe.withDefault [] - acuteIllnesses = - List.filter - (\( _, participant ) -> - participant.encounterType == Backend.IndividualEncounterParticipant.Model.AcuteIllnessEncounter - ) - individualParticipants - pregnancies = List.filter (\( _, participant ) -> @@ -225,6 +232,14 @@ viewContentForOther language currentDate site isChw personId person patientType selectedPane = case model.filter of FilterAcuteIllness -> + let + acuteIllnesses = + List.filter + (\( _, participant ) -> + participant.encounterType == Backend.IndividualEncounterParticipant.Model.AcuteIllnessEncounter + ) + individualParticipants + in viewAcuteIllnessPane language currentDate personId initiator acuteIllnesses db FilterAntenatal -> @@ -233,6 +248,13 @@ viewContentForOther language currentDate site isChw personId person patientType FilterFamilyPlanning -> viewFamilyPlanningPane language currentDate personId (List.map Tuple.first pregnancies) db + FilterGroupEducation -> + Dict.get personId db.educationSessionsByPerson + |> Maybe.andThen RemoteData.toMaybe + |> Maybe.map Dict.values + |> Maybe.withDefault [] + |> viewGroupEducationPane language currentDate + FilterDemographics -> -- Demographics report got dedicated page. emptyNode @@ -251,7 +273,7 @@ viewContentForOther language currentDate site isChw personId person patientType , div [ class "pane progress-reports" ] [ div [ class "pane-heading" ] [ text <| translate language Translate.ProgressReports ] - , viewFilters language person patientType model + , viewFilters language features person patientType model ] , selectedPane , viewStartEncounterButton language (SetViewMode ViewStartEncounter) @@ -377,8 +399,8 @@ thumbnailDimensions = } -viewFilters : Language -> Person -> PatientType -> Model -> Html Msg -viewFilters language person patientType model = +viewFilters : Language -> EverySet SiteFeature -> Person -> PatientType -> Model -> Html Msg +viewFilters language features person patientType model = let renderButton filter = button @@ -396,18 +418,30 @@ viewFilters language person patientType model = [] PatientAdult -> + let + filterGroupEducation = + if groupEducationEnabled features then + Just FilterGroupEducation + + else + Nothing + in case person.gender of Male -> - [ FilterAcuteIllness - , FilterDemographics + [ Just FilterAcuteIllness + , filterGroupEducation + , Just FilterDemographics ] + |> Maybe.Extra.values Female -> - [ FilterAcuteIllness - , FilterAntenatal - , FilterFamilyPlanning - , FilterDemographics + [ Just FilterAcuteIllness + , Just FilterAntenatal + , Just FilterFamilyPlanning + , filterGroupEducation + , Just FilterDemographics ] + |> Maybe.Extra.values PatientUnknown -> [ FilterAcuteIllness @@ -568,7 +602,7 @@ viewFamilyPlanningPane language currentDate personId prenatalParticipantsIds db , div [ class "signs" ] [ text <| translate language Translate.SelectedFamilyPlanningMethod ] ] - content = + entries = groupFamilyPlannings ++ prenatalFamilyPlannings |> List.sortWith sortTuplesByDateDesc @@ -604,7 +638,7 @@ viewFamilyPlanningPane language currentDate personId prenatalParticipantsIds db [ viewPaneHeading language <| Translate.PatientRecordFilter FilterFamilyPlanning , div [ class "pane-content" ] <| entriesHeading - :: content + :: viewEntries language entries ] @@ -619,3 +653,38 @@ viewFamilyPlanningEntry language ( date, signs ) = |> text ] ] + + +viewGroupEducationPane : Language -> NominalDate -> List EducationSession -> Html Msg +viewGroupEducationPane language currentDate sessions = + let + entriesHeading = + div [ class "heading group-education" ] + [ div [ class "topics" ] [ text <| translate language Translate.Topics ] + , div [ class "date" ] [ text <| translate language Translate.Date ] + ] + + entries = + List.sortWith (sortByDateDesc .startDate) sessions + |> List.map (viewGroupEducationEntry language) + in + div [ class "pane group-education" ] + [ viewPaneHeading language <| Translate.PatientRecordFilter FilterGroupEducation + , div [ class "pane-content" ] <| + entriesHeading + :: viewEntries language entries + ] + + +viewGroupEducationEntry : Language -> EducationSession -> Html Msg +viewGroupEducationEntry language session = + let + topics = + EverySet.toList session.topics + |> List.map (\topic -> li [] [ text <| translate language <| Translate.EducationTopic topic ]) + |> ul [ class "topics" ] + in + div [ class "entry group-education" ] + [ topics + , div [ class "date" ] [ text <| formatDDMMYYYY session.startDate ] + ] diff --git a/client/src/elm/Pages/Person/View.elm b/client/src/elm/Pages/Person/View.elm index 08bb64be6b..cb9add7388 100644 --- a/client/src/elm/Pages/Person/View.elm +++ b/client/src/elm/Pages/Person/View.elm @@ -573,20 +573,20 @@ viewCreateEditForm language currentDate site geoInfo reverseGeoInfo maybeVillage , title = Translate.People } - NutritionEncounter -> - { goBackPage = UserPage (IndividualEncounterParticipantsPage NutritionEncounter) + ChildScoreboardEncounter -> + { goBackPage = UserPage (IndividualEncounterParticipantsPage ChildScoreboardEncounter) , expectedAge = ExpectChild , expectedGender = ExpectMaleOrFemale - , birthDateSelectorFrom = Date.add Years -5 today - , birthDateSelectorTo = today + , birthDateSelectorFrom = Date.add Years -2 today + , birthDateSelectorTo = Date.add Days -1 today , title = Translate.People } - WellChildEncounter -> - { goBackPage = UserPage (IndividualEncounterParticipantsPage WellChildEncounter) - , expectedAge = ExpectChild + HIVEncounter -> + { goBackPage = UserPage (IndividualEncounterParticipantsPage HIVEncounter) + , expectedAge = ExpectAdultOrChild , expectedGender = ExpectMaleOrFemale - , birthDateSelectorFrom = Date.add Years -13 today + , birthDateSelectorFrom = Date.add Years -120 today , birthDateSelectorTo = today , title = Translate.People } @@ -616,12 +616,12 @@ viewCreateEditForm language currentDate site geoInfo reverseGeoInfo maybeVillage , title = Translate.People } - ChildScoreboardEncounter -> - { goBackPage = UserPage (IndividualEncounterParticipantsPage ChildScoreboardEncounter) + NutritionEncounter -> + { goBackPage = UserPage (IndividualEncounterParticipantsPage NutritionEncounter) , expectedAge = ExpectChild , expectedGender = ExpectMaleOrFemale - , birthDateSelectorFrom = Date.add Years -2 today - , birthDateSelectorTo = Date.add Days -1 today + , birthDateSelectorFrom = Date.add Years -5 today + , birthDateSelectorTo = today , title = Translate.People } @@ -634,6 +634,15 @@ viewCreateEditForm language currentDate site geoInfo reverseGeoInfo maybeVillage , title = Translate.People } + WellChildEncounter -> + { goBackPage = UserPage (IndividualEncounterParticipantsPage WellChildEncounter) + , expectedAge = ExpectChild + , expectedGender = ExpectMaleOrFemale + , birthDateSelectorFrom = Date.add Years -13 today + , birthDateSelectorTo = today + , title = Translate.People + } + -- Note yet implemented. Providing 'default' -- values, to satisfy compiler. InmmunizationEncounter -> diff --git a/client/src/elm/Pages/Prenatal/Participant/View.elm b/client/src/elm/Pages/Prenatal/Participant/View.elm index 17273848af..b96cfc0968 100644 --- a/client/src/elm/Pages/Prenatal/Participant/View.elm +++ b/client/src/elm/Pages/Prenatal/Participant/View.elm @@ -38,7 +38,7 @@ view language currentDate selectedHealthCenter id isChw initiator db model = |> Maybe.withDefault NotAsked in div - [ class "wrap wrap-alt-2 page-participant prenatal" ] + [ class "wrap wrap-alt-2 page-participant individual prenatal" ] [ viewHeader language isChw initiator , div [ class "ui full segment" ] diff --git a/client/src/elm/Pages/Router.elm b/client/src/elm/Pages/Router.elm index fc21faeaca..c309c5cbfc 100644 --- a/client/src/elm/Pages/Router.elm +++ b/client/src/elm/Pages/Router.elm @@ -8,6 +8,8 @@ import Backend.AcuteIllnessEncounter.Types exposing (AcuteIllnessProgressReportI import Backend.AcuteIllnessEncounter.Utils import Backend.ChildScoreboardActivity.Model exposing (ChildScoreboardActivity) import Backend.ChildScoreboardActivity.Utils +import Backend.HIVActivity.Model exposing (HIVActivity) +import Backend.HIVActivity.Utils import Backend.HomeVisitActivity.Model exposing (HomeVisitActivity) import Backend.HomeVisitActivity.Utils import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterType, IndividualParticipantInitiator) @@ -123,6 +125,9 @@ pageToFragment current = PageChildWellnessNutrition -> "child-wellness-nutrition" + + PageGroupEducation -> + "group-education" in Just ("dashboard/" ++ url) @@ -196,6 +201,9 @@ pageToFragment current = TuberculosisParticipantPage id -> Just <| "tuberculosis-participant/" ++ fromEntityUuid id + HIVParticipantPage id -> + Just <| "hiv-participant/" ++ fromEntityUuid id + IndividualEncounterParticipantsPage encounterType -> Just <| "individual-participants/" ++ individualEncounterTypeToString encounterType @@ -349,6 +357,12 @@ pageToFragment current = EducationSessionPage id -> Just <| "education-session/" ++ fromEntityUuid id + HIVEncounterPage id -> + Just <| "hiv-encounter/" ++ fromEntityUuid id + + HIVActivityPage id activity -> + Just <| "hiv-activity/" ++ fromEntityUuid id ++ "/" ++ Backend.HIVActivity.Utils.activityToString activity + TraceContactPage id -> Just <| "trace-contact/" ++ fromEntityUuid id @@ -393,6 +407,7 @@ parser = , map (\id initiator -> UserPage <| WellChildParticipantPage initiator id) (s "well-child-participant" parseUuid parseIndividualParticipantInitiator) , map (\id initiator -> UserPage <| NCDParticipantPage initiator id) (s "ncd-participant" parseUuid parseIndividualParticipantInitiator) , map (\id -> UserPage <| ChildScoreboardParticipantPage id) (s "child-scoreboard-participant" parseUuid) + , map (\id -> UserPage <| HIVParticipantPage id) (s "hiv-participant" parseUuid) , map (\id -> UserPage <| TuberculosisParticipantPage id) (s "tuberculosis-participant" parseUuid) , map (\id1 id2 origin -> UserPage <| RelationshipPage id1 id2 origin) (s "relationship" parseUuid parseUuid parseOrigin) , map (\id -> UserPage <| PrenatalEncounterPage id) (s "prenatal-encounter" parseUuid) @@ -429,6 +444,8 @@ parser = , map (\id -> UserPage <| TuberculosisEncounterPage id) (s "tuberculosis-encounter" parseUuid) , map (\id activity -> UserPage <| TuberculosisActivityPage id activity) (s "tuberculosis-activity" parseUuid parseTuberculosisActivity) , map (\id -> UserPage <| EducationSessionPage id) (s "education-session" parseUuid) + , map (\id -> UserPage <| HIVEncounterPage id) (s "hiv-encounter" parseUuid) + , map (\id activity -> UserPage <| HIVActivityPage id activity) (s "hiv-activity" parseUuid parseHIVActivity) , map (\id -> UserPage <| TraceContactPage id) (s "trace-contact" parseUuid) , map (\id initiator -> UserPage <| PatientRecordPage initiator id) (s "patient-record" parseUuid parsePatientRecordInitiator) , map (UserPage MessagingCenterPage) (s "messaging-center") @@ -457,6 +474,7 @@ parseDashboardPage = , map (PageNCD PageDiabetes) (s "diabetes") , map (PageChildWellness PageChildWellnessOverview) (s "child-wellness") , map (PageChildWellness PageChildWellnessNutrition) (s "child-wellness-nutrition") + , map PageGroupEducation (s "group-education") ] @@ -539,6 +557,11 @@ parseTuberculosisActivity = custom "TuberculosisActivity" Backend.TuberculosisActivity.Utils.activityFromString +parseHIVActivity : Parser (HIVActivity -> c) c +parseHIVActivity = + custom "HIVActivity" Backend.HIVActivity.Utils.activityFromString + + parseIndividualEncounterType : Parser (IndividualEncounterType -> c) c parseIndividualEncounterType = custom "IndividualEncounterType" individualEncounterTypeFromString diff --git a/client/src/elm/Pages/Tuberculosis/Activity/Update.elm b/client/src/elm/Pages/Tuberculosis/Activity/Update.elm index 84c8ad3e44..2b1634af9a 100644 --- a/client/src/elm/Pages/Tuberculosis/Activity/Update.elm +++ b/client/src/elm/Pages/Tuberculosis/Activity/Update.elm @@ -97,7 +97,7 @@ update currentDate id db msg model = additionalMsgs = if diagnosticsForm.diagnosed == Just False then - [ Backend.IndividualEncounterParticipant.Model.CloseTuberculosisSession OutcomeNotDiagnosed + [ Backend.IndividualEncounterParticipant.Model.CloseTuberculosisSession TuberculosisOutcomeNotDiagnosed |> Backend.Model.MsgIndividualEncounterParticipant particpantId |> App.Model.MsgIndexedDb , App.Model.SetActivePage PinCodePage diff --git a/client/src/elm/Pages/Tuberculosis/Activity/Utils.elm b/client/src/elm/Pages/Tuberculosis/Activity/Utils.elm index 12433ddbf0..5b43f83ae5 100644 --- a/client/src/elm/Pages/Tuberculosis/Activity/Utils.elm +++ b/client/src/elm/Pages/Tuberculosis/Activity/Utils.elm @@ -367,10 +367,10 @@ symptomReviewFormWithDefault form saved = |> unwrap form (\value -> - { nightSweats = or form.nightSweats (EverySet.member SymptomNightSweats value |> Just) - , bloodInSputum = or form.bloodInSputum (EverySet.member SymptomBloodInSputum value |> Just) - , weightLoss = or form.weightLoss (EverySet.member SymptomWeightLoss value |> Just) - , severeFatigue = or form.severeFatigue (EverySet.member SymptomSevereFatigue value |> Just) + { nightSweats = or form.nightSweats (EverySet.member TuberculosisSymptomNightSweats value |> Just) + , bloodInSputum = or form.bloodInSputum (EverySet.member TuberculosisSymptomBloodInSputum value |> Just) + , weightLoss = or form.weightLoss (EverySet.member TuberculosisSymptomWeightLoss value |> Just) + , severeFatigue = or form.severeFatigue (EverySet.member TuberculosisSymptomSevereFatigue value |> Just) } ) @@ -383,10 +383,10 @@ toSymptomReviewValueWithDefault saved form = toSymptomReviewValue : SymptomReviewForm -> Maybe TuberculosisSymptomReviewValue toSymptomReviewValue form = - [ ifNullableTrue SymptomNightSweats form.nightSweats - , ifNullableTrue SymptomBloodInSputum form.bloodInSputum - , ifNullableTrue SymptomWeightLoss form.weightLoss - , ifNullableTrue SymptomSevereFatigue form.severeFatigue + [ ifNullableTrue TuberculosisSymptomNightSweats form.nightSweats + , ifNullableTrue TuberculosisSymptomBloodInSputum form.bloodInSputum + , ifNullableTrue TuberculosisSymptomWeightLoss form.weightLoss + , ifNullableTrue TuberculosisSymptomSevereFatigue form.severeFatigue ] |> Maybe.Extra.combine |> Maybe.map (List.foldl EverySet.union EverySet.empty >> ifEverySetEmpty NoTuberculosisSymptoms) diff --git a/client/src/elm/Pages/Tuberculosis/Activity/View.elm b/client/src/elm/Pages/Tuberculosis/Activity/View.elm index a7de211d34..be769f8564 100644 --- a/client/src/elm/Pages/Tuberculosis/Activity/View.elm +++ b/client/src/elm/Pages/Tuberculosis/Activity/View.elm @@ -381,7 +381,7 @@ viewSymptomReviewContent language currentDate assembled data = |> symptomReviewFormWithDefault data.form ( inputs, tasksCompleted, totalTasks ) = - ( [ viewQuestionLabel language <| Translate.TuberculosisSymptomQuestion SymptomNightSweats + ( [ viewQuestionLabel language <| Translate.TuberculosisSymptomQuestion TuberculosisSymptomNightSweats , viewBoolInput language form.nightSweats @@ -392,7 +392,7 @@ viewSymptomReviewContent language currentDate assembled data = ) "night-sweats" Nothing - , viewQuestionLabel language <| Translate.TuberculosisSymptomQuestion SymptomBloodInSputum + , viewQuestionLabel language <| Translate.TuberculosisSymptomQuestion TuberculosisSymptomBloodInSputum , viewBoolInput language form.bloodInSputum @@ -403,7 +403,7 @@ viewSymptomReviewContent language currentDate assembled data = ) "blood-in-Sputum" Nothing - , viewQuestionLabel language <| Translate.TuberculosisSymptomQuestion SymptomWeightLoss + , viewQuestionLabel language <| Translate.TuberculosisSymptomQuestion TuberculosisSymptomWeightLoss , viewBoolInput language form.weightLoss @@ -414,7 +414,7 @@ viewSymptomReviewContent language currentDate assembled data = ) "weight-loss" Nothing - , viewQuestionLabel language <| Translate.TuberculosisSymptomQuestion SymptomSevereFatigue + , viewQuestionLabel language <| Translate.TuberculosisSymptomQuestion TuberculosisSymptomSevereFatigue , viewBoolInput language form.severeFatigue @@ -436,7 +436,7 @@ viewSymptomReviewContent language currentDate assembled data = [ div [ class "tasks-count" ] [ text <| translate language <| Translate.TasksCompleted tasksCompleted totalTasks ] , div [ class "ui full segment" ] [ div [ class "full content" ] - [ div [ class "ui form danger-signs" ] inputs + [ div [ class "ui form symptom-review" ] inputs ] , div [ class "actions" ] [ saveButton language diff --git a/client/src/elm/Pages/Tuberculosis/Participant/Fetch.elm b/client/src/elm/Pages/Tuberculosis/Participant/Fetch.elm index b26723f215..06b07a06b1 100644 --- a/client/src/elm/Pages/Tuberculosis/Participant/Fetch.elm +++ b/client/src/elm/Pages/Tuberculosis/Participant/Fetch.elm @@ -11,9 +11,9 @@ fetch id db = let fetchTuberculosisEncounters = resolveIndividualParticipantsForPerson id TuberculosisEncounter db - |> List.map FetchTuberculosisEncountersForParticipant + |> FetchTuberculosisEncountersForParticipants in [ FetchPerson id , FetchIndividualEncounterParticipantsForPerson id + , fetchTuberculosisEncounters ] - ++ fetchTuberculosisEncounters diff --git a/client/src/elm/Pages/Tuberculosis/Participant/View.elm b/client/src/elm/Pages/Tuberculosis/Participant/View.elm index 6b2f0cb69a..e07ac52493 100644 --- a/client/src/elm/Pages/Tuberculosis/Participant/View.elm +++ b/client/src/elm/Pages/Tuberculosis/Participant/View.elm @@ -31,7 +31,7 @@ view language currentDate selectedHealthCenter id db = |> Maybe.withDefault NotAsked in div - [ class "wrap wrap-alt-2 page-participant ncd" ] + [ class "wrap wrap-alt-2 page-participant individual tuberculosis" ] [ viewHeader language , div [ class "ui full segment" ] diff --git a/client/src/elm/Pages/Utils.elm b/client/src/elm/Pages/Utils.elm index fe54fa4931..51be6fc292 100644 --- a/client/src/elm/Pages/Utils.elm +++ b/client/src/elm/Pages/Utils.elm @@ -578,8 +578,7 @@ viewCheckBoxMultipleSelectInput : Language -> List a -> List a -> List a -> Mayb viewCheckBoxMultipleSelectInput language leftOptions rightOptions checkedOptions noneOption setMsg translateFunc = let viewOptionFunc option = - label [] - [ translateFunc option |> translate language |> text ] + label [] [ translateFunc option |> translate language |> text ] in viewCheckBoxMultipleSelectCustomInput language leftOptions rightOptions checkedOptions noneOption setMsg viewOptionFunc @@ -618,6 +617,26 @@ viewCheckBoxMultipleSelectCustomInput language leftOptions rightOptions checkedO :: noneSection +viewCheckBoxMultipleSelectSectionsInput : Language -> List ( TranslationId, List a ) -> List a -> (a -> msg) -> (a -> TranslationId) -> Html msg +viewCheckBoxMultipleSelectSectionsInput language sections checkedOptions setMsg translateFunc = + let + viewSection ( labelTransId, options ) = + let + viewOptionFunc option = + label [] [ translateFunc option |> translate language |> text ] + in + div [ class "section" ] <| + viewLabel language labelTransId + :: List.map (viewCheckBoxSelectInputItem language checkedOptions setMsg viewOptionFunc) options + in + div [ class "checkbox-select-input" ] + [ div [ class "ui grid" ] + [ List.map viewSection sections + |> div [ class "sixteen wide column" ] + ] + ] + + viewCheckBoxSelectInputItem : Language -> List a -> (a -> msg) -> (a -> Html msg) -> a -> Html msg viewCheckBoxSelectInputItem language checkedOptions setMsg viewOptionFunc option = let diff --git a/client/src/elm/Pages/WellChild/Participant/View.elm b/client/src/elm/Pages/WellChild/Participant/View.elm index a0fcc2f531..66854a3970 100644 --- a/client/src/elm/Pages/WellChild/Participant/View.elm +++ b/client/src/elm/Pages/WellChild/Participant/View.elm @@ -27,7 +27,7 @@ view language currentDate selectedHealthCenter id isChw initiator db = |> Maybe.withDefault NotAsked in div - [ class "wrap wrap-alt-2 page-participant well-child" ] + [ class "wrap wrap-alt-2 page-participant individual well-child" ] [ viewHeader language isChw initiator , div [ class "ui full segment" ] diff --git a/client/src/elm/SyncManager/Decoder.elm b/client/src/elm/SyncManager/Decoder.elm index 190aa2d006..6054e9f327 100644 --- a/client/src/elm/SyncManager/Decoder.elm +++ b/client/src/elm/SyncManager/Decoder.elm @@ -13,6 +13,7 @@ import Backend.Clinic.Decoder import Backend.Counseling.Decoder import Backend.Dashboard.Decoder import Backend.EducationSession.Decoder +import Backend.HIVEncounter.Decoder import Backend.HealthCenter.Decoder import Backend.HomeVisitEncounter.Decoder import Backend.IndividualEncounterParticipant.Decoder @@ -83,6 +84,10 @@ decodeIndexDbQueryTypeResult = field "data" decodeInt |> andThen (\val -> succeed (IndexDbQueryGetTotalEntriesToUploadResult val)) + "IndexDbQueryGetShardsEntityByUuidResult" -> + field "data" string + |> andThen (\val -> succeed (IndexDbQueryGetShardsEntityByUuidResult val)) + _ -> fail <| queryType ++ " is not a recognized IndexDbQueryTypeResult" ) @@ -637,6 +642,46 @@ decodeBackendAuthorityEntity uuidDecoder identifierDecoder = Backend.Measurement.Decoder.decodeHeight BackendAuthorityHeight + "hiv_diagnostics" -> + doDecode + Backend.Measurement.Decoder.decodeHIVDiagnostics + BackendAuthorityHIVDiagnostics + + "hiv_encounter" -> + doDecode + Backend.HIVEncounter.Decoder.decodeHIVEncounter + BackendAuthorityHIVEncounter + + "hiv_follow_up" -> + doDecode + Backend.Measurement.Decoder.decodeHIVFollowUp + BackendAuthorityHIVFollowUp + + "hiv_health_education" -> + doDecode + Backend.Measurement.Decoder.decodeHIVHealthEducation + BackendAuthorityHIVHealthEducation + + "hiv_medication" -> + doDecode + Backend.Measurement.Decoder.decodeHIVMedication + BackendAuthorityHIVMedication + + "hiv_referral" -> + doDecode + Backend.Measurement.Decoder.decodeHIVReferral + BackendAuthorityHIVReferral + + "hiv_symptom_review" -> + doDecode + Backend.Measurement.Decoder.decodeHIVSymptomReview + BackendAuthorityHIVSymptomReview + + "hiv_treatment_review" -> + doDecode + Backend.Measurement.Decoder.decodeHIVTreatmentReview + BackendAuthorityHIVTreatmentReview + "home_visit_encounter" -> doDecode Backend.HomeVisitEncounter.Decoder.decodeHomeVisitEncounter diff --git a/client/src/elm/SyncManager/Encoder.elm b/client/src/elm/SyncManager/Encoder.elm index cde8d4dccc..814d9e3b2b 100644 --- a/client/src/elm/SyncManager/Encoder.elm +++ b/client/src/elm/SyncManager/Encoder.elm @@ -1,6 +1,7 @@ module SyncManager.Encoder exposing ( encodeDataForDeferredPhotos , encodeDeviceStateReport + , encodeIncidentDetails , encodeIndexDbQueryUploadAuthorityResultRecord , encodeIndexDbQueryUploadGeneralResultRecord , encodeIndexDbQueryUploadWhatsAppResultRecord @@ -218,3 +219,8 @@ encodeUploadMethod uploadMethod = UploadMethodUpdate -> string "PATCH" + + +encodeIncidentDetails : String -> List ( String, Value ) +encodeIncidentDetails details = + [ ( "incident_details", string details ) ] diff --git a/client/src/elm/SyncManager/Model.elm b/client/src/elm/SyncManager/Model.elm index 316efd4a76..ba2bc3813b 100644 --- a/client/src/elm/SyncManager/Model.elm +++ b/client/src/elm/SyncManager/Model.elm @@ -8,6 +8,7 @@ import Backend.Counseling.Model exposing (CounselingSchedule, CounselingTopic) import Backend.Dashboard.Model exposing (DashboardStatsRaw) import Backend.EducationSession.Model exposing (EducationSession) import Backend.Entities exposing (HealthCenterId) +import Backend.HIVEncounter.Model exposing (HIVEncounter) import Backend.HealthCenter.Model exposing (CatchmentArea, HealthCenter) import Backend.HomeVisitEncounter.Model exposing (HomeVisitEncounter) import Backend.IndividualEncounterParticipant.Model exposing (IndividualEncounterParticipant) @@ -103,6 +104,14 @@ type BackendAuthorityEntity | BackendAuthorityHealthEducation (BackendEntity HealthEducation) | BackendAuthorityHCContact (BackendEntity HCContact) | BackendAuthorityHeight (BackendEntity Height) + | BackendAuthorityHIVDiagnostics (BackendEntity HIVDiagnostics) + | BackendAuthorityHIVEncounter (BackendEntity HIVEncounter) + | BackendAuthorityHIVFollowUp (BackendEntity HIVFollowUp) + | BackendAuthorityHIVHealthEducation (BackendEntity HIVHealthEducation) + | BackendAuthorityHIVMedication (BackendEntity HIVMedication) + | BackendAuthorityHIVReferral (BackendEntity HIVReferral) + | BackendAuthorityHIVSymptomReview (BackendEntity HIVSymptomReview) + | BackendAuthorityHIVTreatmentReview (BackendEntity HIVTreatmentReview) | BackendAuthorityHomeVisitEncounter (BackendEntity HomeVisitEncounter) | BackendAuthorityIndividualParticipant (BackendEntity IndividualEncounterParticipant) | BackendAuthorityIsolation (BackendEntity Isolation) @@ -566,6 +575,9 @@ type IndexDbQueryType | IndexDbQueryRemoveUploadPhotos (List Int) -- Reports the number of entries at shardChanges table. | IndexDbQueryGetTotalEntriesToUpload + -- Pulls Entity from Shards table by UUID. We use so we can reslove + -- `Could not find UUID` error without performing remote debug on device. + | IndexDbQueryGetShardsEntityByUuid String type IndexDbQueryTypeResult @@ -579,6 +591,8 @@ type IndexDbQueryTypeResult -- A single deferred photo, if exists. | IndexDbQueryDeferredPhotoResult (Maybe IndexDbQueryDeferredPhotoResultRecord) | IndexDbQueryGetTotalEntriesToUploadResult Int + -- JSON.stringify representation of pulled entity. + | IndexDbQueryGetShardsEntityByUuidResult String type UploadFileError @@ -706,11 +720,12 @@ type Site type SiteFeature - = FeatureNCDA + = FeatureGroupEducation + | FeatureHIVManagement + | FeatureNCDA | FeatureReportToWhatsApp | FeatureStockManagement | FeatureTuberculosisManagement - | FeatureGroupEducation type Msg @@ -749,6 +764,7 @@ type Msg | BackendUploadPhotoHandle (RemoteData UploadFileError (Maybe IndexDbQueryUploadPhotoResultRecord)) | BackendUploadScreenshotHandle (RemoteData UploadFileError (Maybe IndexDbQueryUploadFileResultRecord)) | BackendReportState Int + | BackendReportIncidentDetails String | BackendReportSyncIncident SyncIncidentType | QueryIndexDb IndexDbQueryType | QueryIndexDbHandle Value diff --git a/client/src/elm/SyncManager/Update.elm b/client/src/elm/SyncManager/Update.elm index 3aff229b23..40ed4e7ea0 100644 --- a/client/src/elm/SyncManager/Update.elm +++ b/client/src/elm/SyncManager/Update.elm @@ -12,7 +12,8 @@ import Editable import Error.Utils exposing (decoderError, maybeHttpError, noError) import GeoLocation.Utils exposing (getGeoInfo, getReverseGeoInfo) import Gizra.NominalDate exposing (NominalDate) -import HttpBuilder exposing (withExpectJson, withJsonBody, withQueryParams) +import Http exposing (Error(..)) +import HttpBuilder exposing (..) import Json.Decode exposing (Value, decodeValue) import Json.Encode import List.Zipper as Zipper @@ -29,6 +30,7 @@ import SyncManager.Utils , backendGeneralEntityToRevision , getDownloadPhotosSpeedForSubscriptions , getSyncSpeedForSubscriptions + , resolveIncidentDetailsMsg , syncInfoAuthorityForPort , syncInfoGeneralForPort ) @@ -895,6 +897,20 @@ update currentDate currentTime activePage dbVersion device msg model = noError [] + BackendReportIncidentDetails details -> + let + cmd = + HttpBuilder.post (device.backendUrl ++ "/api/report-incident-details") + |> withQueryParams [ ( "access_token", device.accessToken ) ] + |> withJsonBody (Json.Encode.object <| SyncManager.Encoder.encodeIncidentDetails details) + |> HttpBuilder.send (always NoOp) + in + SubModelReturn + model + cmd + noError + [] + BackendReportSyncIncident incidentType -> let cmd = @@ -1250,12 +1266,20 @@ update currentDate currentTime activePage dbVersion device msg model = ( Just zipperUpdated, sendSyncInfoAuthoritiesCmd zipperUpdated ) ) |> Maybe.withDefault ( model.syncInfoAuthorities, Cmd.none ) + + incidentDetailsMsg = + resolveIncidentDetailsMsg error in SubModelReturn - (SyncManager.Utils.determineSyncStatus activePage { model | syncStatus = syncStatus, syncInfoAuthorities = syncInfoAuthorities }) + (SyncManager.Utils.determineSyncStatus activePage + { model | syncStatus = syncStatus, syncInfoAuthorities = syncInfoAuthorities } + ) setSyncInfoAurhoritiesCmd (maybeHttpError webData "Backend.SyncManager.Update" "BackendUploadAuthorityHandle") [] + |> sequenceSubModelReturn + (update currentDate currentTime activePage dbVersion device) + incidentDetailsMsg RemoteData.Success _ -> let @@ -1321,8 +1345,7 @@ update currentDate currentTime activePage dbVersion device msg model = subModelReturn |> sequenceSubModelReturn (update currentDate currentTime activePage dbVersion device) - [ QueryIndexDb <| IndexDbQueryRemoveUploadPhotos uploadPhotosToDelete - ] + [ QueryIndexDb <| IndexDbQueryRemoveUploadPhotos uploadPhotosToDelete ] _ -> -- Satisfy the compiler. @@ -1421,12 +1444,18 @@ update currentDate currentTime activePage dbVersion device msg model = setSyncInfoGeneralCmd = sendSyncInfoGeneralCmd syncInfoGeneral + + incidentDetailsMsg = + resolveIncidentDetailsMsg error in SubModelReturn (SyncManager.Utils.determineSyncStatus activePage { model | syncStatus = syncStatus, syncInfoGeneral = syncInfoGeneral }) setSyncInfoGeneralCmd (maybeHttpError webData "Backend.SyncManager.Update" "BackendUploadGeneralHandle") [] + |> sequenceSubModelReturn + (update currentDate currentTime activePage dbVersion device) + incidentDetailsMsg RemoteData.Success _ -> let @@ -1566,12 +1595,20 @@ update currentDate currentTime activePage dbVersion device msg model = setSyncInfoGeneralCmd = sendSyncInfoGeneralCmd syncInfoGeneral + + incidentDetailsMsg = + resolveIncidentDetailsMsg error in SubModelReturn - (SyncManager.Utils.determineSyncStatus activePage { model | syncStatus = syncStatus, syncInfoGeneral = syncInfoGeneral }) + (SyncManager.Utils.determineSyncStatus activePage + { model | syncStatus = syncStatus, syncInfoGeneral = syncInfoGeneral } + ) setSyncInfoGeneralCmd (maybeHttpError webData "Backend.SyncManager.Update" "BackendUploadWhatsAppHandle") [] + |> sequenceSubModelReturn + (update currentDate currentTime activePage dbVersion device) + incidentDetailsMsg RemoteData.Success _ -> let @@ -1858,6 +1895,11 @@ update currentDate currentTime activePage dbVersion device msg model = { queryType = "IndexDbQueryGetTotalEntriesToUpload" , data = Nothing } + + IndexDbQueryGetShardsEntityByUuid uuidsAsString -> + { queryType = "IndexDbQueryGetShardsEntityByUuid" + , data = Just uuidsAsString + } in SubModelReturn model @@ -1939,6 +1981,16 @@ update currentDate currentTime activePage dbVersion device msg model = (BackendReportState result) model + IndexDbQueryGetShardsEntityByUuidResult result -> + update + currentDate + currentTime + activePage + dbVersion + device + (BackendReportIncidentDetails result) + model + Err error -> let location = @@ -2017,7 +2069,7 @@ update currentDate currentTime activePage dbVersion device msg model = syncSpeed = Editable.value model.syncSpeed - -- Safe guard against to0 low values. + -- Safe guard against too low values. syncSpeedUpdated = { syncSpeed | idle = diff --git a/client/src/elm/SyncManager/Utils.elm b/client/src/elm/SyncManager/Utils.elm index 3e0187f80e..57b656e70d 100644 --- a/client/src/elm/SyncManager/Utils.elm +++ b/client/src/elm/SyncManager/Utils.elm @@ -7,6 +7,7 @@ import Backend.Clinic.Encoder import Backend.Counseling.Encoder import Backend.Dashboard.Encoder import Backend.EducationSession.Encoder +import Backend.HIVEncounter.Encoder import Backend.HealthCenter.Encoder import Backend.HomeVisitEncounter.Encoder import Backend.IndividualEncounterParticipant.Encoder @@ -30,6 +31,8 @@ import Backend.Village.Encoder import Backend.WellChildEncounter.Encoder import Editable import EverySet exposing (EverySet) +import Http +import Json.Decode import Json.Encode exposing (Value, object) import List.Zipper as Zipper import Maybe.Extra @@ -584,6 +587,30 @@ getBackendAuthorityEntityIdentifier backendAuthorityEntity = BackendAuthorityHeight identifier -> getIdentifier identifier "height" + BackendAuthorityHIVDiagnostics identifier -> + getIdentifier identifier "hiv_diagnostics" + + BackendAuthorityHIVEncounter identifier -> + getIdentifier identifier "hiv_encounter" + + BackendAuthorityHIVFollowUp identifier -> + getIdentifier identifier "hiv_follow_up" + + BackendAuthorityHIVHealthEducation identifier -> + getIdentifier identifier "hiv_health_education" + + BackendAuthorityHIVMedication identifier -> + getIdentifier identifier "hiv_medication" + + BackendAuthorityHIVReferral identifier -> + getIdentifier identifier "hiv_referral" + + BackendAuthorityHIVSymptomReview identifier -> + getIdentifier identifier "hiv_symptom_review" + + BackendAuthorityHIVTreatmentReview identifier -> + getIdentifier identifier "hiv_treatment_review" + BackendAuthorityHomeVisitEncounter identifier -> getIdentifier identifier "home_visit_encounter" @@ -1084,6 +1111,9 @@ getSyncSpeedForSubscriptions model = SyncUploadGeneral record -> checkWebData record.backendRemoteData + SyncUploadWhatsApp record -> + checkWebData record.backendRemoteData + SyncUploadAuthority record -> checkWebData record.backendRemoteData @@ -1325,6 +1355,30 @@ encodeBackendAuthorityEntity entity = BackendAuthorityHeight identifier -> encode Backend.Measurement.Encoder.encodeHeight identifier + BackendAuthorityHIVDiagnostics identifier -> + encode Backend.Measurement.Encoder.encodeHIVDiagnostics identifier + + BackendAuthorityHIVEncounter identifier -> + encode Backend.HIVEncounter.Encoder.encodeHIVEncounter identifier + + BackendAuthorityHIVFollowUp identifier -> + encode Backend.Measurement.Encoder.encodeHIVFollowUp identifier + + BackendAuthorityHIVHealthEducation identifier -> + encode Backend.Measurement.Encoder.encodeHIVHealthEducation identifier + + BackendAuthorityHIVMedication identifier -> + encode Backend.Measurement.Encoder.encodeHIVMedication identifier + + BackendAuthorityHIVReferral identifier -> + encode Backend.Measurement.Encoder.encodeHIVReferral identifier + + BackendAuthorityHIVSymptomReview identifier -> + encode Backend.Measurement.Encoder.encodeHIVSymptomReview identifier + + BackendAuthorityHIVTreatmentReview identifier -> + encode Backend.Measurement.Encoder.encodeHIVTreatmentReview identifier + BackendAuthorityHomeVisitEncounter identifier -> encode Backend.HomeVisitEncounter.Encoder.encodeHomeVisitEncounter identifier @@ -1870,6 +1924,9 @@ siteFeatureFromString str = "group_education" -> Just FeatureGroupEducation + "hiv_management" -> + Just FeatureHIVManagement + _ -> Nothing @@ -1892,6 +1949,9 @@ siteFeatureToString feature = FeatureGroupEducation -> "group_education" + FeatureHIVManagement -> + "hiv_management" + siteFeaturesFromString : String -> EverySet SiteFeature siteFeaturesFromString str = @@ -2123,6 +2183,30 @@ backendAuthorityEntityToRevision backendAuthorityEntity = BackendAuthorityHeight identifier -> HeightRevision (toEntityUuid identifier.uuid) identifier.entity + BackendAuthorityHIVDiagnostics identifier -> + HIVDiagnosticsRevision (toEntityUuid identifier.uuid) identifier.entity + + BackendAuthorityHIVEncounter identifier -> + HIVEncounterRevision (toEntityUuid identifier.uuid) identifier.entity + + BackendAuthorityHIVFollowUp identifier -> + HIVFollowUpRevision (toEntityUuid identifier.uuid) identifier.entity + + BackendAuthorityHIVHealthEducation identifier -> + HIVHealthEducationRevision (toEntityUuid identifier.uuid) identifier.entity + + BackendAuthorityHIVMedication identifier -> + HIVMedicationRevision (toEntityUuid identifier.uuid) identifier.entity + + BackendAuthorityHIVReferral identifier -> + HIVReferralRevision (toEntityUuid identifier.uuid) identifier.entity + + BackendAuthorityHIVSymptomReview identifier -> + HIVSymptomReviewRevision (toEntityUuid identifier.uuid) identifier.entity + + BackendAuthorityHIVTreatmentReview identifier -> + HIVTreatmentReviewRevision (toEntityUuid identifier.uuid) identifier.entity + BackendAuthorityHomeVisitEncounter identifier -> HomeVisitEncounterRevision (toEntityUuid identifier.uuid) identifier.entity @@ -2544,6 +2628,29 @@ backendAuthorityEntityToRevision backendAuthorityEntity = WellChildWeightRevision (toEntityUuid identifier.uuid) identifier.entity +resolveIncidentDetailsMsg : Http.Error -> List Msg +resolveIncidentDetailsMsg error = + case error of + Http.BadStatus response -> + case Json.Decode.decodeString Utils.WebData.decodeDrupalError response.body of + Ok decoded -> + if String.startsWith "Could not find UUID" decoded.title then + let + uuidAsString = + String.dropLeft 21 decoded.title + in + [ QueryIndexDb <| IndexDbQueryGetShardsEntityByUuid uuidAsString ] + + else + [] + + Err _ -> + [] + + _ -> + [] + + fileUploadFailureThreshold : Int fileUploadFailureThreshold = 5 diff --git a/client/src/elm/SyncManager/View.elm b/client/src/elm/SyncManager/View.elm index 8dabdf0fbd..d749340826 100644 --- a/client/src/elm/SyncManager/View.elm +++ b/client/src/elm/SyncManager/View.elm @@ -449,8 +449,32 @@ viewAuthorityEntity backendAuthorityEntity = BackendAuthorityHeight identifier -> viewMeasurement identifier "Height" + BackendAuthorityHIVDiagnostics identifier -> + viewMeasurement identifier "HIV Diagnostics" + + BackendAuthorityHIVEncounter identifier -> + text ("HIV Encounter for participant ID " ++ fromEntityUuid identifier.entity.participant) + + BackendAuthorityHIVFollowUp identifier -> + viewMeasurement identifier "HIV Follow Up" + + BackendAuthorityHIVHealthEducation identifier -> + viewMeasurement identifier "HIV Health Education" + + BackendAuthorityHIVMedication identifier -> + viewMeasurement identifier "HIV Medication" + + BackendAuthorityHIVReferral identifier -> + viewMeasurement identifier "HIV Referral" + + BackendAuthorityHIVSymptomReview identifier -> + viewMeasurement identifier "HIV Symptom Review" + + BackendAuthorityHIVTreatmentReview identifier -> + viewMeasurement identifier "HIV Treatment Review" + BackendAuthorityHomeVisitEncounter identifier -> - text ("HomeVisitEncounter for participant ID " ++ fromEntityUuid identifier.entity.participant) + text ("Home Visit Encounter for participant ID " ++ fromEntityUuid identifier.entity.participant) BackendAuthorityIndividualParticipant identifier -> text <| "Individual Participant for person ID " ++ fromEntityUuid identifier.entity.person @@ -738,31 +762,31 @@ viewAuthorityEntity backendAuthorityEntity = viewMeasurement identifier "Treatment Review" BackendAuthorityTuberculosisDiagnostics identifier -> - viewMeasurement identifier "TuberculosisDiagnostics" + viewMeasurement identifier "Tuberculosis Diagnostics" BackendAuthorityTuberculosisDOT identifier -> - viewMeasurement identifier "TuberculosisDOT" + viewMeasurement identifier "Tuberculosis DOT" BackendAuthorityTuberculosisEncounter identifier -> text ("Tuberculosis Encounter for participant ID " ++ fromEntityUuid identifier.entity.participant) BackendAuthorityTuberculosisFollowUp identifier -> - viewMeasurement identifier "TuberculosisFollowUp" + viewMeasurement identifier "Tuberculosis Follow Up" BackendAuthorityTuberculosisHealthEducation identifier -> - viewMeasurement identifier "TuberculosisHealthEducation" + viewMeasurement identifier "Tuberculosis Health Education" BackendAuthorityTuberculosisMedication identifier -> - viewMeasurement identifier "TuberculosisMedication" + viewMeasurement identifier "Tuberculosis Medication" BackendAuthorityTuberculosisReferral identifier -> - viewMeasurement identifier "TuberculosisReferral" + viewMeasurement identifier "Tuberculosis Referral" BackendAuthorityTuberculosisSymptomReview identifier -> - viewMeasurement identifier "TuberculosisSymptomReview" + viewMeasurement identifier "Tuberculosis Symptom Review" BackendAuthorityTuberculosisTreatmentReview identifier -> - viewMeasurement identifier "TuberculosisTreatmentReview" + viewMeasurement identifier "Tuberculosis Treatment Review" BackendAuthorityVitals identifier -> viewMeasurement identifier "Vitals" diff --git a/client/src/elm/Translate.elm b/client/src/elm/Translate.elm index 4e659b3f0a..ed41569f1f 100644 --- a/client/src/elm/Translate.elm +++ b/client/src/elm/Translate.elm @@ -22,6 +22,7 @@ import Backend.Clinic.Model exposing (ClinicType(..)) import Backend.Counseling.Model exposing (CounselingTopic) import Backend.EducationSession.Model exposing (EducationTopic(..)) import Backend.Entities exposing (..) +import Backend.HIVActivity.Model exposing (HIVActivity) import Backend.HomeVisitActivity.Model exposing (HomeVisitActivity(..)) import Backend.IndividualEncounterParticipant.Model exposing (AcuteIllnessOutcome(..), IndividualEncounterType(..), PregnancyOutcome(..)) import Backend.Measurement.Model exposing (..) @@ -105,6 +106,7 @@ import Pages.Dashboard.Model as Dashboard import Pages.EducationSession.Model import Pages.GlobalCaseManagement.Model exposing (CaseManagementFilter(..), FollowUpDueOption(..), LabsEntryState(..)) import Pages.GroupEncounterTypes.Model exposing (GroupEncounterType(..)) +import Pages.HIV.Activity.Model import Pages.MessagingCenter.Model exposing (MessagingTab(..)) import Pages.NCD.Activity.Types exposing (ExaminationTask(..), MedicalHistoryTask(..)) import Pages.NCD.ProgressReport.Model exposing (NCDRiskFactor(..)) @@ -290,6 +292,7 @@ type Dashboard | NumberOfCephaly | NumberOfChildrenSeen | NumberOfDiagnosedMalnourished + | NumberOfGroupSessions | NumberOfStunting | PatientsManagedAtHome | PatientCurrentlyUnderCare @@ -308,11 +311,13 @@ type Dashboard | TotalMalnourished | TotalEncountersLabel | TotalAssessment + | TotalAttendees | TotalCases | TotalDiabeticCases | UncomplicatedMalariaByChws | UncomplicatedMalariaInPregnancyReferredToHc | UncomplicatedGIInfectionByCHWS + | UniquePatients | UseFamilyPlanning | Within4MonthsOfDueDate | WithDangerSigns @@ -587,7 +592,10 @@ type TranslationId | DiagnosedOn | Diagnosis | DiagnosisDate + | Diagnostics + | Diarrhea | DifferenceBetweenDueAndDeliveryDates + | DifficultyBreathingLabel | Disabled | DistributionNotice DistributionNotice | District @@ -654,6 +662,7 @@ type TranslationId | FamilyUbudehe | FatherOrChiefId | FatherOrChiefName + | Fatigue | FavoriteToggle Bool | FbfDistribution ClinicType | Feeding @@ -661,6 +670,7 @@ type TranslationId | FetalMovement | FetalPresentationLabel | FetalPresentation FetalPresentation + | Fever | FillTheBlanks | FilterByName | Finish @@ -693,6 +703,7 @@ type TranslationId | GroupAssessment | Grams | Gravida + | GroupEducation | GroupEncounterType GroupEncounterType | GroupOfFoods GroupOfFoods | Growth @@ -707,6 +718,7 @@ type TranslationId | HCRecommendation HCRecommendation | HCResponseQuestion | HCResponsePeriodQuestion + | HeadacheLabel | HeadCircumferenceHelper | HeadCircumferenceNotTakenLabel | HeadHair @@ -737,9 +749,21 @@ type TranslationId | History | HistoryTask HistoryTask | HIV + | HIVActivityTitle HIVActivity + | HIVHealthEducationQuestion HIVHealthEducationSign + | HIVFollowUpLabel + | HIVMedicationTask Pages.HIV.Activity.Model.MedicationTask + | HIVNextStepsTask Pages.HIV.Activity.Model.NextStepsTask | HIVPCRResult HIVPCRResult + | HIVPositiveDateCorrectQuestion NominalDate + | HIVPositiveDiagnosedQuestion + | HIVPositiveTestDateQuestion + | HIVPrescribedMedication HIVPrescribedMedication + | HIVPrescribedMedicationsQuestion | HIVStatus HIVStatus | HIVStatusLabel + | HIVSymptom HIVSymptom + | HIVSymptomReviewQuestion | HIVTreatmentSign HIVTreatmentSign | Home | HomeVisit @@ -873,6 +897,7 @@ type TranslationId | LegRight | Legs | LegsCPESign LegsCPESign + | LessCommonAntiRetroviralMedications | LevelOfEducationLabel | LevelOfEducation EducationLevel | LevelOfEducationForResilience EducationLevel @@ -969,6 +994,7 @@ type TranslationId | MonthlySurveyScoreInterpretation Int | MonthSinglePlural Int | MonthsOfStock + | MostCommonAntiRetroviralMedications | MotherId | MotherName String | MotherNameLabel @@ -1032,6 +1058,7 @@ type TranslationId | NextPediatricVisit Bool | NextSteps | NextStepsTask Bool Pages.AcuteIllness.Activity.Types.NextStepsTask + | NightSweatsLabel | NightSweatsQuestion | No | NoActivitiesCompleted @@ -1057,6 +1084,7 @@ type TranslationId | NoReferralRecorded | Normal | NoChildrenRegisteredInTheSystem + | NoneOfThese | NotAvailable | NotFollowingRecommendationQuestion | NotIndicated @@ -1213,6 +1241,7 @@ type TranslationId | PrenatalNCDProgramHeaderSuffix | PrenatalNCDProgramInstructions | PrenatalNextStepsTask Bool Pages.Prenatal.Activity.Types.NextStepsTask + | PrescribedMedication | OutsideCareSignQuestion OutsideCareSign | OutsideCareMedicationLabel OutsideCareMedication | OutsideCareMedicationDosage OutsideCareMedication @@ -1242,6 +1271,7 @@ type TranslationId | ProgressReports | ProgressTimeline | ProgressTrends + | ProphylaxisMedications | ProvideHealthEducationAndInstructToIsolate | PreTermPregnancy | PriorDiagnosis @@ -1549,6 +1579,7 @@ type TranslationId | SelectedHCSyncing | Send | SendToHC + | SevereAbdominalPainLabel | SevereFatigueQuestion | ReportToWhatsApp | ReportToWhatsAppComponentsSelectionHeader Components.ReportToWhatsAppDialog.Model.ReportType @@ -1591,6 +1622,7 @@ type TranslationId | SkipNCDADialogConfirm | SkipNCDADialogQuestion | SkipNCDADialogReject + | SoreThroatLabel | SpecialityCareHeaderPrefix | SpecialityCareHeaderSuffix | SpecialityCareSignQuestion SpecialityCareSign @@ -1674,6 +1706,7 @@ type TranslationId | ThisGroupHasNoMothers | Time | To + | Topics | TotalHighRiskPregnancies | ToThePatient | TransportationPlanQuestion @@ -1762,6 +1795,7 @@ type TranslationId | ViewProgressReport | Village | VitaminAWarningPopupMessage + | VomitingLabel | WaitForVitalsRecheckHelper | WaitForLabsResultsHelper | WaitInstructions @@ -1769,6 +1803,7 @@ type TranslationId | WasFbfDistirbuted Activity | WeekSinglePlural Int | Weight + | WeightLossLabel | WeightLossQuestion | WelcomeUser String | Wellbeing @@ -2033,28 +2068,16 @@ translationSet trans = } AdverseEventFever -> - { english = "Fever" - , kinyarwanda = Just "Umuriro" - , kirundi = Just "Ubushuhe" - } + translationSet Fever AdverseEventDiarrhea -> - { english = "Diarrhea" - , kinyarwanda = Just "Impiswi" - , kirundi = Just "Uguhitwa" - } + translationSet Diarrhea AdverseEventVomiting -> - { english = "Vomiting" - , kinyarwanda = Just "Kuruka" - , kirundi = Just "Ukudahwa" - } + translationSet VomitingLabel AdverseEventFatigue -> - { english = "Fatigue" - , kinyarwanda = Just "umunaniro" - , kirundi = Just "Uburuhe" - } + translationSet Fatigue AdverseEventOther -> { english = "Other" @@ -2089,10 +2112,7 @@ translationSet trans = } DangerSignVomiting -> - { english = "Vomiting" - , kinyarwanda = Just "Araruka" - , kirundi = Just "Ukudahwa" - } + translationSet VomitingLabel DangerSignConvulsions -> { english = "Convulsions" @@ -3731,6 +3751,9 @@ translationSet trans = FilterTuberculosis -> translationSet Tuberculosis + FilterHIV -> + translationSet HIV + CaseManagementPaneHeader encounterType -> case encounterType of Pages.GlobalCaseManagement.Model.FilterAcuteIllness -> @@ -3772,6 +3795,9 @@ translationSet trans = FilterTuberculosis -> translationSet Tuberculosis + FilterHIV -> + translationSet HIV + Celsius -> { english = "Celsius" , kinyarwanda = Just "Serisiyusi" @@ -3862,10 +3888,7 @@ translationSet trans = translationSet Edema NormalChildNutrition -> - { english = "None of these" - , kinyarwanda = Just "Nta bimenyetso" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese PoorAppetite -> { english = "Poor Appetite" @@ -4243,10 +4266,7 @@ translationSet trans = } NoContributingFactorsSign -> - { english = "None of these" - , kinyarwanda = Just "Nta kimenyetso na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese ContributingFactorsQuestion -> { english = "Has patient or patient’s mother experienced any of the following" @@ -4343,10 +4363,7 @@ translationSet trans = } NoDeliveryComplications -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese DeliveryComplicationsPresentQuestion -> { english = "Were there any complications with the delivery" @@ -4549,22 +4566,13 @@ translationSet trans = } AbdominalPain -> - { english = "Severe Abdominal pain" - , kinyarwanda = Just "Kuribwa mu nda bikabije" - , kirundi = Just "Kurimba cane mu bwena" - } + translationSet SevereAbdominalPainLabel DifficultyBreathing -> - { english = "Difficulty breathing" - , kinyarwanda = Just "Guhumeka nabi" - , kirundi = Just "Guhema nabi" - } + translationSet DifficultyBreathingLabel Backend.Measurement.Model.Fever -> - { english = "Fever" - , kinyarwanda = Just "Umuriro" - , kirundi = Just "Ubushuhe" - } + translationSet Fever ExtremeWeakness -> { english = "Extreme weakness" @@ -4615,10 +4623,7 @@ translationSet trans = } NoDangerSign -> - { english = "None of these" - , kinyarwanda = Just "Nta bimenyetso/nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese DangerSigns -> { english = "Danger Signs" @@ -4809,12 +4814,30 @@ translationSet trans = , kirundi = Just "Itarike yo gusuzuma" } + Diagnostics -> + { english = "Diagnostics" + , kinyarwanda = Just "Gusuzuma uburwayi" + , kirundi = Nothing + } + + Diarrhea -> + { english = "Diarrhea" + , kinyarwanda = Just "Impiswi" + , kirundi = Just "Uguhitwa" + } + DifferenceBetweenDueAndDeliveryDates -> { english = "Difference between due date and delivery date" , kinyarwanda = Just "Ikinyuranyo kiri hagati y'amatariki" , kirundi = Just "Itandukanirizo riri hagati y'itarike itegekanijwe kuvyara niy'umunsi avyariyeko" } + DifficultyBreathingLabel -> + { english = "Difficulty breathing" + , kinyarwanda = Just "Guhumeka nabi" + , kirundi = Just "Guhema nabi" + } + Disabled -> { english = "Disabled" , kinyarwanda = Nothing @@ -5366,6 +5389,12 @@ translationSet trans = ChildScoreboardEncounter -> translationSet EmptyString + HIVEncounter -> + { english = "Do you want to start a HIV Management encounter for" + , kinyarwanda = Nothing + , kirundi = Nothing + } + HomeVisitEncounter -> { english = "Do you want to start a Home Visit assessment for" , kinyarwanda = Just "Urashaka gutangira igikorwa cyo gusura mu rugo" @@ -5446,6 +5475,9 @@ translationSet trans = PageChildWellnessNutrition -> translationSet Nutrition + PageGroupEducation -> + translationSet GroupEducation + EncounterWarningForDiagnosisPane warning suffix -> let suffix_ = @@ -5779,10 +5811,7 @@ translationSet trans = } NoFamilyPlanning -> - { english = "None of these" - , kinyarwanda = Just "Nta buryo bwo kuboneza urubyaro yahisemo" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese OralContraceptives -> { english = "Oral contraceptives" @@ -5846,6 +5875,12 @@ translationSet trans = , kirundi = Just "Amazina ya Serugo canke Umukuru w'umuryango" } + Fatigue -> + { english = "Fatigue" + , kinyarwanda = Just "umunaniro" + , kirundi = Just "Uburuhe" + } + FavoriteToggle isFavorite -> if isFavorite then { english = "Unfavorite" @@ -5909,6 +5944,12 @@ translationSet trans = , kirundi = Just "Bitazwi" } + Fever -> + { english = "Fever" + , kinyarwanda = Just "Umuriro" + , kirundi = Just "Ubushuhe" + } + FillTheBlanks -> { english = "Nutrition Information" , kinyarwanda = Just "Amakuru ku Mirire" @@ -6237,6 +6278,12 @@ translationSet trans = , kirundi = Just "Inday ya" } + GroupEducation -> + { english = "Group Education" + , kinyarwanda = Nothing + , kirundi = Nothing + } + GroupEncounterType encounterType -> case encounterType of GroupEncounterNutrition -> @@ -6339,6 +6386,12 @@ translationSet trans = , kirundi = Just "Mbega Ivuriro ryafashe umanye ungana gute ngo bishure" } + HeadacheLabel -> + { english = "Headache" + , kinyarwanda = Just "Kubabara umutwe" + , kirundi = Just "Kumeneka umutwe" + } + HeadCircumferenceHelper -> { english = "Using a tape measure, wrap the tape around the widest possible circumference; above the ears and midway between the eyebrows and the hairline to the occipital prominence on the back of the head." , kinyarwanda = Just "Wifashishije metero bushumi kandi umwana aryamye agaramye, zengurutsa iyo metero ku mutwe w'umwana hejuru y'amatwi uhereye inyuma, izenguruke ku gahanga kugeza ugeze aho watangiriye." @@ -6604,6 +6657,74 @@ translationSet trans = , kirundi = Just "Umugera wa SIDA" } + HIVActivityTitle activity -> + case activity of + Backend.HIVActivity.Model.Diagnostics -> + translationSet Diagnostics + + Backend.HIVActivity.Model.Medication -> + translationSet Medication + + Backend.HIVActivity.Model.SymptomReview -> + translationSet SymptomReview + + Backend.HIVActivity.Model.NextSteps -> + translationSet NextSteps + + HIVHealthEducationQuestion sign -> + case sign of + EducationPositiveResult -> + { english = "Have you counseled patient on positive HIV test meaning" + , kinyarwanda = Just "Waba wasobanuriye umurwayi (umubyeyi) icyo bisibanuye kugira ibisubizo biri positifu ku bwandu bw'agakoko gatera SIDA" + , kirundi = Just "Mbega warahanuye wongera urabwira umugwayi iciza c'igipimo c'umugera wa SIDA" + } + + EducationSaferSexPractices -> + { english = "Have you counseled patient on safer sex practices" + , kinyarwanda = Just "Wagiriye inama umubyeyi ku bijyanye no gukora imibonano mpuzabitsina ikingiye" + , kirundi = Just "Mbega warahanuye umugwayi kuvyerekeye iciza co kwikingira mu gihe c'imibonano mpuza ibitsina" + } + + EducationEncouragedPartnerTesting -> + { english = "Have you encouraged the patient’s partner to get tested" + , kinyarwanda = Just "Waba washishikarije umubyueyi kubwira uwo babana kwipimisha" + , kirundi = Just "Mbega wateye inguvu umufasha w'umugwayi kugira yipimishe" + } + + EducationFamilyPlanningOptions -> + { english = "Have you counseled the patient on family planning options" + , kinyarwanda = Just "Waba wagiriye inama umurwayi (umubyeyi) uburyo bwo kuboneza urubyaro" + , kirundi = Just "Mbega warahanuye umugwayi kuvyerekeye uburyo bwo kuvyara k'urugero" + } + + NoHIVHealthEducationSigns -> + translationSet EmptyString + + HIVFollowUpLabel -> + { english = "HIV Follow up" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationTask task -> + case task of + Pages.HIV.Activity.Model.TaskPrescribedMedication -> + translationSet PrescribedMedication + + Pages.HIV.Activity.Model.TaskTreatmentReview -> + translationSet TreatmentReview + + HIVNextStepsTask task -> + case task of + Pages.HIV.Activity.Model.TaskHealthEducation -> + translationSet HealthEducation + + Pages.HIV.Activity.Model.TaskReferral -> + translationSet SendToHC + + Pages.HIV.Activity.Model.TaskFollowUp -> + translationSet FollowUp + HIVPCRResult result -> case result of ResultSuppressedViralLoad -> @@ -6618,6 +6739,179 @@ translationSet trans = , kirundi = Nothing } + HIVPositiveDateCorrectQuestion date -> + { english = "The patient tested positive for HIV on " ++ formatDDMMYYYY date ++ ". Is this date correct" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVPositiveDiagnosedQuestion -> + { english = "Was this person diagnosed with HIV" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVPositiveTestDateQuestion -> + { english = "When was the positive test date" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVPrescribedMedication medication -> + case medication of + HIVMedicationDolutegravirLamivudineTenofovir -> + { english = "Dolutegravir + Lamivudine + Tenofovir (DTG-3TC-TDF)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationAtazanavirRitonavir -> + { english = "Atazanavir + Ritonavir (ATZ/r)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationDolutegravir -> + { english = "Dolutegravir (DTG)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationAbacavirLamivudine -> + { english = "Abacavir + Lamivudine (ABC-3TC)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationLamivudineTenofovir -> + { english = "Lamivudine + Tenofovir (3TC-TDF)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationZidovudine -> + { english = "Zidovudine (liquid) (AZT)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationLamivudineZidovudineNevirapine -> + { english = "Lamivudine + Zidovudine + Nevirapine (3TC-AZT-NVP)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationEfavirenzLamivudineTenofovir -> + { english = "Efavirenz + Lamivudine + Tenofovir (EFV-3TC-TDF)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationLamivudineZidovudine -> + { english = "Lamivudine + Zidovudine (3TC-AZT)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationLopinavirRitonavir -> + { english = "Lopinavir + Ritonavir (LPV/r)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationDarunavirRitonavir -> + { english = "Darunavir + Ritonavir (DRV/r)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationDarunavirCobicistat -> + { english = "Darunavir + Cobicistat (DRV/c)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationRaltegravir -> + { english = "Raltegravir (RAL)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationEfavirenz -> + { english = "Efavirenz (EFV)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationNevirapine -> + { english = "Nevirapine (tablet or liquid) (NVP)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationEtravirine -> + { english = "Etravirine (ETR)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationTenofovir -> + { english = "Tenofovir (TDF)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationLamivudine -> + { english = "Lamivudine (3TC)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationAbacavir -> + { english = "Abacavir (ABC)" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationBactrim -> + { english = "Bactrim" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationDapsone -> + { english = "Dapsone" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationIsoniazid -> + { english = "Isoniazid" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationFluconazole -> + { english = "Fluconazole" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVMedicationAzithromycin -> + { english = "Azithromycin" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + NoHIVPrescribedMedications -> + translationSet EmptyString + + HIVPrescribedMedicationsQuestion -> + { english = "What are the medications that were prescribed" + , kinyarwanda = Just "Ni iyihe miti yatanzwe" + , kirundi = Nothing + } + HIVStatus status -> case status of HIVExposedInfant -> @@ -6653,6 +6947,83 @@ translationSet trans = , kirundi = Just "Ivyerekeye umugera wa SIDA" } + HIVSymptom symptom -> + case symptom of + HIVSymptomFever -> + translationSet Fever + + HIVSymptomFatigue -> + translationSet Fatigue + + HIVSymptomSwollenLymphNodes -> + { english = "Swollen lymph nodes" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVSymptomSoreThroat -> + translationSet SoreThroatLabel + + HIVSymptomRash -> + { english = "Rash" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVSymptomMuscleJointPain -> + { english = "Muscle and joint pain" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVSymptomHeadache -> + translationSet HeadacheLabel + + HIVSymptomSevereAbdominalPain -> + translationSet SevereAbdominalPainLabel + + HIVSymptomNightSweats -> + translationSet NightSweatsLabel + + HIVSymptomDiarrhea -> + translationSet Diarrhea + + HIVSymptomWeightLoss -> + translationSet WeightLossLabel + + HIVSymptomCoughingUpBlood -> + { english = "Coughing up blood" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVSymptomHairLoss -> + { english = "Hair loss" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVSymptomMouthUlcers -> + { english = "Mouth ulcers" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVSymptomDifficultyBreathing -> + translationSet DifficultyBreathingLabel + + HIVSymptomVomiting -> + translationSet VomitingLabel + + NoHIVSymptoms -> + translationSet NoneOfThese + + HIVSymptomReviewQuestion -> + { english = "Which, if any, of these symptoms does the patient have" + , kinyarwanda = Nothing + , kirundi = Nothing + } + HIVTreatmentSign sign -> case sign of HIVTreatmentNoMedicineNotSeenAtPMTCT -> @@ -6909,10 +7280,7 @@ translationSet trans = IllnessSymptom symptom -> case symptom of IllnessSymptomHeadache -> - { english = "Headache" - , kinyarwanda = Just "Kuribwa Umutwe" - , kirundi = Just "Kumeneka umutwe" - } + translationSet HeadacheLabel IllnessSymptomVisionChanges -> { english = "Vision Changes" @@ -6944,10 +7312,7 @@ translationSet trans = translationSet EmptyString NoIllnessSymptoms -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese Immunisation -> { english = "Immunization" @@ -7005,6 +7370,12 @@ translationSet trans = , kirundi = Just "Ukubonana ubwa mbere kw'ikarata y'ikurikiranwa ry'umwana" } + HIVEncounter -> + { english = "First HIV Encounter" + , kinyarwanda = Nothing + , kirundi = Nothing + } + HomeVisitEncounter -> { english = "First Home Visit Encounter" , kinyarwanda = Just "Gusura abarwayi mu rugo bwambere" @@ -7061,6 +7432,12 @@ translationSet trans = , kirundi = Just "Ukubonana kw'ikarata y'ikurikiranwa ry'umwana" } + HIVEncounter -> + { english = "HIV Encounter" + , kinyarwanda = Nothing + , kirundi = Nothing + } + HomeVisitEncounter -> { english = "Home Visit Encounter" , kinyarwanda = Just "Gusura abarwayi mu rugo" @@ -7124,6 +7501,12 @@ translationSet trans = , kirundi = Nothing } + HIVEncounter -> + { english = "Select HIV Visit" + , kinyarwanda = Nothing + , kirundi = Nothing + } + HomeVisitEncounter -> { english = "Select Home Visit" , kinyarwanda = Just "Hitamo Gusura Umurwayi" @@ -7187,6 +7570,12 @@ translationSet trans = , kirundi = Nothing } + HIVEncounter -> + { english = "Subsequent HIV Visit" + , kinyarwanda = Nothing + , kirundi = Nothing + } + HomeVisitEncounter -> { english = "Subsequent Home Visit" , kinyarwanda = Nothing @@ -7234,6 +7623,12 @@ translationSet trans = ChildScoreboardEncounter -> translationSet ChildScorecard + HIVEncounter -> + { english = "HIV Management" + , kinyarwanda = Nothing + , kirundi = Nothing + } + HomeVisitEncounter -> translationSet HomeVisit @@ -9012,6 +9407,12 @@ translationSet trans = NormalLegs -> translationSet Normal + LessCommonAntiRetroviralMedications -> + { english = "Less Common Anti-Retroviral Medications" + , kinyarwanda = Nothing + , kirundi = Nothing + } + LevelOfEducationLabel -> { english = "Level of Education" , kinyarwanda = Just <| "Amashuri wize" @@ -9413,10 +9814,7 @@ translationSet trans = } NoWaterPreparationOption -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese MainWaterSourceQuestion -> { english = "What is the household's main source of water" @@ -10368,6 +10766,12 @@ translationSet trans = , kirundi = Nothing } + MostCommonAntiRetroviralMedications -> + { english = "Most Common Anti-Retroviral Medications" + , kinyarwanda = Nothing + , kirundi = Nothing + } + MotherId -> { english = "Mother ID" , kinyarwanda = Nothing @@ -11288,10 +11692,7 @@ translationSet trans = } WeightLoss -> - { english = "Weight Loss" - , kinyarwanda = Just "Gutakaza ibiro" - , kirundi = Just "Uguta ibiro" - } + translationSet WeightLossLabel Palpitations -> { english = "Palpitations" @@ -11698,6 +12099,12 @@ translationSet trans = -- consistant with other types of Covid steps. translationSet MedicationDistribution + NightSweatsLabel -> + { english = "Night sweats" + , kinyarwanda = Just "Kubira ibyuya nijoro" + , kirundi = Just "Kubira ivyuya mw'ijoro" + } + NightSweatsQuestion -> { english = "Do you have night sweats" , kinyarwanda = Just "Waba ubira ibyuya nijoro" @@ -12019,6 +12426,12 @@ translationSet trans = , kirundi = Just "Nta bana biyandikishije muri ubu buryo bugezweho (muri sisiteme)" } + NoneOfThese -> + { english = "None of these" + , kinyarwanda = Just "Nta na kimwe" + , kirundi = Just "Nta nimwe muri izi" + } + NotAvailable -> { english = "not available" , kinyarwanda = Just "Ntibiboneste" @@ -12806,6 +13219,9 @@ translationSet trans = , kirundi = Just "Kuvyara k'urugero" } + FilterGroupEducation -> + translationSet GroupEducation + PauseEncounter -> { english = "Pause Encounter" , kinyarwanda = Just "Igikorwa cyahagaritswe" @@ -13134,10 +13550,7 @@ translationSet trans = } NoPostpartumChildDangerSigns -> - { english = "None of these" - , kinyarwanda = Just "Nta kimenyetso na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese PostpartumMotherDangerSign sign -> case sign of @@ -13178,10 +13591,7 @@ translationSet trans = } NoPostpartumMotherDangerSigns -> - { english = "None of these" - , kinyarwanda = Just "Nta kimenyetso na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese Predecessor predecessor -> case predecessor of @@ -13900,22 +14310,13 @@ translationSet trans = } DiagnosisPostpartumHeadache -> - { english = "Headache" - , kinyarwanda = Just "Kuribwa Umutwe" - , kirundi = Just "Kumeneka umutwe" - } + translationSet HeadacheLabel DiagnosisPostpartumFatigue -> - { english = "Fatigue" - , kinyarwanda = Just "Umunaniro" - , kirundi = Just "Uburuhe" - } + translationSet Fatigue DiagnosisPostpartumFever -> - { english = "Fever" - , kinyarwanda = Just "Guhinda Umuriro" - , kirundi = Just "Ubushuhe" - } + translationSet Fever DiagnosisPostpartumPerinealPainOrDischarge -> { english = "Perineal Pain or Discharge" @@ -14400,22 +14801,13 @@ translationSet trans = } DiagnosisPostpartumHeadache -> - { english = "Headache" - , kinyarwanda = Just "Kuribwa Umutwe" - , kirundi = Just "Kumeneka umutwe" - } + translationSet HeadacheLabel DiagnosisPostpartumFatigue -> - { english = "Fatigue" - , kinyarwanda = Just "Umunaniro" - , kirundi = Just "Uburuhe" - } + translationSet Fatigue DiagnosisPostpartumFever -> - { english = "Fever" - , kinyarwanda = Just "Guhinda Umuriro" - , kirundi = Just "Ubushuhe" - } + translationSet Fever DiagnosisPostpartumPerinealPainOrDischarge -> { english = "Perineal Pain or Discharge" @@ -14803,22 +15195,13 @@ translationSet trans = } DiagnosisPostpartumHeadache -> - { english = "Headache" - , kinyarwanda = Just "Kuribwa Umutwe" - , kirundi = Just "Kumeneka umutwe" - } + translationSet HeadacheLabel DiagnosisPostpartumFatigue -> - { english = "Fatigue" - , kinyarwanda = Just "Umunaniro" - , kirundi = Just "Uburuhe" - } + translationSet Fatigue DiagnosisPostpartumFever -> - { english = "Fever" - , kinyarwanda = Just "Guhinda Umuriro" - , kirundi = Just "Ubushuhe" - } + translationSet Fever DiagnosisPostpartumPerinealPainOrDischarge -> { english = "Perineal Pain or Discharge" @@ -15332,6 +15715,12 @@ translationSet trans = , kirundi = Just "Rindira" } + PrescribedMedication -> + { english = "Prescribed Medication" + , kinyarwanda = Just "Imiti yatanzwe" + , kirundi = Nothing + } + PrenatalRecurrentNextStepsTask task -> case task of Pages.Prenatal.RecurrentActivity.Types.NextStepsSendToHC -> @@ -15929,10 +16318,7 @@ translationSet trans = } NoOutsideCareMedicationForMalaria -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese OutsideCareMedicationPenecilin1 -> { english = "Penicillin (2.4 million units)" @@ -15965,10 +16351,7 @@ translationSet trans = } NoOutsideCareMedicationForSyphilis -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese OutsideCareMedicationMethyldopa2 -> { english = "Methyldopa (250mg)" @@ -16001,10 +16384,7 @@ translationSet trans = } NoOutsideCareMedicationForHypertension -> - { english = "None of these" - , kinyarwanda = Just "Nta ns kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese OutsideCareMedicationTDF3TC -> { english = "TDF+3TC" @@ -16019,10 +16399,7 @@ translationSet trans = } NoOutsideCareMedicationForHIV -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese OutsideCareMedicationIron1 -> { english = "Iron (60mg)" @@ -16043,10 +16420,7 @@ translationSet trans = } NoOutsideCareMedicationForAnemia -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese _ -> translationSet EmptyString @@ -16138,22 +16512,13 @@ translationSet trans = } PostpartumHeadache -> - { english = "Headache" - , kinyarwanda = Just "Kuribwa Umutwe" - , kirundi = Just "Kumeneka umutwe" - } + translationSet HeadacheLabel PostpartumFatigue -> - { english = "Fatigue" - , kinyarwanda = Just "Umunaniro" - , kirundi = Just "Uburuhe" - } + translationSet Fatigue PostpartumFever -> - { english = "Fever" - , kinyarwanda = Just "Guhinda Umuriro" - , kirundi = Just "Ubushuhe" - } + translationSet Fever PostpartumPerinealPainOrDischarge -> { english = "Perineal pain or Discharge" @@ -16162,10 +16527,7 @@ translationSet trans = } NoPrenatalSymptoms -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese PrenatalSymptomQuestion value -> case value of @@ -16484,6 +16846,12 @@ translationSet trans = , kirundi = Just "Amayira y'iterambere" } + ProphylaxisMedications -> + { english = "Prophylaxis Medications" + , kinyarwanda = Nothing + , kirundi = Nothing + } + ProvideHealthEducationAndInstructToIsolate -> { english = "Provide health education and instruct them to self isolate at home" , kinyarwanda = Nothing @@ -19660,6 +20028,12 @@ translationSet trans = , kirundi = Just "Rungika kw'ivuriro" } + SevereAbdominalPainLabel -> + { english = "Severe abdominal pain" + , kinyarwanda = Just "Kuribwa mu nda bikabije" + , kirundi = Just "Kurimba cane mu bwena" + } + SevereFatigueQuestion -> { english = "Do you have severe fatigue" , kinyarwanda = Just "Waba ugira umunaniro ukabije" @@ -19931,6 +20305,12 @@ translationSet trans = , kirundi = Nothing } + SoreThroatLabel -> + { english = "Sore Throat" + , kinyarwanda = Just "Kubabara mu muhogo" + , kirundi = Just "" + } + SpecialityCareHeaderPrefix -> { english = "You were diagnosed with" , kinyarwanda = Just "Wasuzumwe uburwayi bwa" @@ -20299,22 +20679,13 @@ translationSet trans = } SymptomGeneralFever -> - { english = "Fever" - , kinyarwanda = Just "Umuriro" - , kirundi = Just "Ubushuhe" - } + translationSet Fever Headache -> - { english = "Headache" - , kinyarwanda = Just "Kubabara umutwe" - , kirundi = Just "Kumeneka umutwe" - } + translationSet HeadacheLabel NightSweats -> - { english = "Night Sweats" - , kinyarwanda = Just "Kubira ibyuya nijoro" - , kirundi = Just "Kubira ivyuya mw'ijoro" - } + translationSet NightSweatsLabel Lethargy -> { english = "Lethargy" @@ -20415,10 +20786,7 @@ translationSet trans = } Vomiting -> - { english = "Vomiting" - , kinyarwanda = Just "Araruka" - , kirundi = Just "Ukudahwa" - } + translationSet VomitingLabel NoSymptomsGI -> { english = "None of the above" @@ -20464,10 +20832,7 @@ translationSet trans = } SoreThroat -> - { english = "Sore Throat" - , kinyarwanda = Just "Kubabara mu muhogo" - , kirundi = Just "" - } + translationSet SoreThroatLabel LossOfSmell -> { english = "Loss of Smell" @@ -20755,6 +21120,12 @@ translationSet trans = , kirundi = Just "kuri" } + Topics -> + { english = "Topics" + , kinyarwanda = Nothing + , kirundi = Nothing + } + TotalHighRiskPregnancies -> { english = "Total Number of High Risk Pregnancies" , kinyarwanda = Just "Umubare w'abagore batwite bafite ibimenyetso mpuruza" @@ -21041,10 +21412,7 @@ translationSet trans = TuberculosisActivityTitle activity -> case activity of Backend.TuberculosisActivity.Model.Diagnostics -> - { english = "Diagnostics" - , kinyarwanda = Just "Gusuzuma uburwayi" - , kirundi = Nothing - } + translationSet Diagnostics Backend.TuberculosisActivity.Model.Medication -> translationSet Medication @@ -21210,10 +21578,7 @@ translationSet trans = TuberculosisMedicationTask task -> case task of Pages.Tuberculosis.Activity.Model.TaskPrescribedMedication -> - { english = "Prescribed Medication" - , kinyarwanda = Just "Imiti yatanzwe" - , kirundi = Nothing - } + translationSet PrescribedMedication Pages.Tuberculosis.Activity.Model.TaskDOT -> { english = "DOT" @@ -21323,16 +21688,16 @@ translationSet trans = TuberculosisSymptomQuestion symptom -> case symptom of - SymptomNightSweats -> + TuberculosisSymptomNightSweats -> translationSet NightSweatsQuestion - SymptomBloodInSputum -> + TuberculosisSymptomBloodInSputum -> translationSet BloodInSputumQuestion - SymptomWeightLoss -> + TuberculosisSymptomWeightLoss -> translationSet WeightLossQuestion - SymptomSevereFatigue -> + TuberculosisSymptomSevereFatigue -> translationSet SevereFatigueQuestion NoTuberculosisSymptoms -> @@ -21713,6 +22078,12 @@ translationSet trans = , kirundi = Just "Umugwayi ntiyaronse Vitamine A" } + VomitingLabel -> + { english = "Vomiting" + , kinyarwanda = Just "Araruka" + , kirundi = Just "Ukudahwa" + } + WaitForVitalsRecheckHelper -> { english = "Patient needs to return in 2 hours to confirm blood pressure. Instruct the patient to wait until called for further testing." , kinyarwanda = Just "Umurwayi agomba kugaruka mu masaha 2 kugira ngo twemeze neza umuvuduko w'amaraso. Saba umurwayi kwihangana kugeza umuhamagaye kugira ngo yongere asuzumwe." @@ -21770,6 +22141,12 @@ translationSet trans = , kirundi = Just "Uburemere" } + WeightLossLabel -> + { english = "Weight loss" + , kinyarwanda = Just "Gutakaza ibiro" + , kirundi = Just "Uguta ibiro" + } + WeightLossQuestion -> { english = "Do you have weight loss" , kinyarwanda = Just "Waba waratakaje ibiro" @@ -22347,16 +22724,10 @@ translationSet trans = } SymptomDiarrhea -> - { english = "Diarrhea" - , kinyarwanda = Just "Impiswi" - , kirundi = Just "Uguhitwa" - } + translationSet Diarrhea SymptomVomiting -> - { english = "Vomiting" - , kinyarwanda = Just "Kuruka" - , kirundi = Just "Ukudahwa" - } + translationSet VomitingLabel SymptomUmbilicalCordRedness -> { english = "Umbilical Cord Redness" @@ -22413,10 +22784,7 @@ translationSet trans = } NoWellChildSymptoms -> - { english = "None of these" - , kinyarwanda = Just "Nta na kimwe" - , kirundi = Just "Nta nimwe muri izi" - } + translationSet NoneOfThese WellChildVaccineLabel site vaccineType -> case vaccineType of @@ -22757,6 +23125,12 @@ translateActivePage page = , kirundi = Nothing } + HIVEncounter -> + { english = "HIV Participants" + , kinyarwanda = Nothing + , kirundi = Nothing + } + HomeVisitEncounter -> { english = "Home Visit Participants" , kinyarwanda = Nothing @@ -23084,7 +23458,22 @@ translateActivePage page = } EducationSessionPage _ -> - { english = "Group Education" + translationSet GroupEducation + + HIVParticipantPage _ -> + { english = "HIV Encounter" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVEncounterPage _ -> + { english = "HIV Encounter" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + HIVActivityPage _ _ -> + { english = "HIV Activity" , kinyarwanda = Nothing , kirundi = Nothing } @@ -23657,6 +24046,12 @@ translateDashboard trans = , kirundi = Nothing } + NumberOfGroupSessions -> + { english = "Number of Group Sessions" + , kinyarwanda = Nothing + , kirundi = Nothing + } + NumberOfStunting -> { english = "# of Stunting" , kinyarwanda = Just "Umubare w'abana bagaragaweho igwingira" @@ -23819,6 +24214,12 @@ translateDashboard trans = , kirundi = Just "igitigiri cy'Ivyasuzumwe vyose hamwe" } + TotalAttendees -> + { english = "Total Attendees" + , kinyarwanda = Nothing + , kirundi = Nothing + } + TotalCases -> { english = "Total Cases" , kinyarwanda = Just "Umubare w'abakiriwe bose" @@ -23849,6 +24250,12 @@ translateDashboard trans = , kirundi = Just "Ingwara zo mu nda zoroshe zirashobora gucungegwa n'abaremeshakiyago" } + UniquePatients -> + { english = "Unique Patients" + , kinyarwanda = Nothing + , kirundi = Nothing + } + UseFamilyPlanning -> { english = "use family planning" , kinyarwanda = Nothing diff --git a/client/src/elm/Utils/WebData.elm b/client/src/elm/Utils/WebData.elm index e7afa3704e..66023fc1ca 100644 --- a/client/src/elm/Utils/WebData.elm +++ b/client/src/elm/Utils/WebData.elm @@ -1,5 +1,6 @@ module Utils.WebData exposing - ( isNetworkError + ( decodeDrupalError + , isNetworkError , resetError , resetSuccess , sendWithHandler diff --git a/client/src/js/app.js b/client/src/js/app.js index 2ec6d28c2b..d3758018fb 100644 --- a/client/src/js/app.js +++ b/client/src/js/app.js @@ -293,6 +293,13 @@ dbSync.version(24).stores({ whatsAppUploads: '++localId,screenshot,language,report_type,person,phone_number,fileId,syncStage', }); +dbSync.version(25).stores({ + shards: '&uuid,type,vid,status,person,[shard+vid],prenatal_encounter,nutrition_encounter,acute_illness_encounter,home_visit_encounter,well_child_encounter,ncd_encounter,child_scoreboard_encounter,tuberculosis_encounter,*name_search,[type+clinic],[type+person],[type+related_to],[type+person+related_to],[type+individual_participant],[type+adult],newborn,*participating_patients', +}); + +dbSync.version(26).stores({ + shards: '&uuid,type,vid,status,person,[shard+vid],prenatal_encounter,nutrition_encounter,acute_illness_encounter,home_visit_encounter,well_child_encounter,ncd_encounter,child_scoreboard_encounter,tuberculosis_encounter,hiv_encounter,*name_search,[type+clinic],[type+person],[type+related_to],[type+person+related_to],[type+individual_participant],[type+adult],[type+province+district+sector+cell+village],newborn,*participating_patients', +}); /** * --- !!! IMPORTANT !!! --- @@ -352,7 +359,7 @@ function gatherWords (text) { * * @type {number} */ -const dbVersion = 24; +const dbVersion = 26; /** * Return saved info for General sync. @@ -1023,6 +1030,22 @@ elmApp.ports.askFromIndexDb.subscribe(function(info) { })(); break; + case 'IndexDbQueryGetShardsEntityByUuid': + (async () => { + + let result = await dbSync + .shards + .where('uuid') + .equals(data) + .limit(1) + .toArray(); + + if (result[0]) { + return sendIndexedDbFetchResult(queryType, JSON.stringify(result[0])); + } + })(); + break; + default: throw queryType + ' is not a known Query type for `askFromIndexDb`'; } diff --git a/client/src/js/nodes.js b/client/src/js/nodes.js index 701716f2a2..50e94bb208 100644 --- a/client/src/js/nodes.js +++ b/client/src/js/nodes.js @@ -133,6 +133,9 @@ else if (type === 'tuberculosis-measurements') { return viewMeasurements('tuberculosis_encounter', uuid); } + else if (type === 'hiv-measurements') { + return viewMeasurements('hiv_encounter', uuid); + } else if (type === 'follow-up-measurements') { return viewFollowUpMeasurements(uuid); } @@ -522,6 +525,9 @@ else if (key === 'tuberculosis_encounter') { target = node.tuberculosis_encounter; } + else if (key === 'hiv_encounter') { + target = node.hiv_encounter; + } else if (key === 'newborn') { target = node.newborn; } @@ -574,52 +580,71 @@ 'prenatal_follow_up', 'well_child_follow_up', 'tuberculosis_follow_up', + 'hiv_follow_up', 'acute_illness_trace_contact', 'prenatal_labs_results', 'ncd_labs_results', 'well_child_next_visit' ]; - // These are types of follow ups that need to be loaded, even if they + // These are types of follow-ups that need to be loaded, even if they // were resolved during period of past 6 months. // This is required to present data at Dashboard statistics. - var resolvedFollowUpMeasurementsTypes = [ - 'acute_illness_trace_contact', - 'prenatal_labs_results', - 'ncd_labs_results' + var followUpMeasurementsTypesUsedByDashboard = [ + 'acute_illness_follow_up', + 'follow_up', + 'nutrition_follow_up', + 'prenatal_follow_up', + 'well_child_follow_up', ]; + // These are HIV tests, where HIV positive patient can be diagnosed. + // We need them since HIV followup at case management should appear + // when patient was diagniosed with HIV when taking a test, and did not + // have HIV encounter after. + var hivTestTypes = [ + 'ncd_hiv_test', + 'prenatal_hiv_test', + ] + function viewFollowUpMeasurements (shard) { - // Load all types of follow up measurements that belong to provided healh center. - var query = dbSync.shards.where('type').anyOf(followUpMeasurementsTypes).and(function (item) { + // Load all types of follow up measurements, and HIV test results + // that belong to provided healh center. + var typesToLoad = followUpMeasurementsTypes.concat(hivTestTypes); + var query = dbSync.shards.where('type').anyOf(typesToLoad).and(function (item) { return item.shard === shard; }); // Build an empty list of measurements, so we return some value, even // if no measurements were ever taken. var data = {}; - data = {}; // Decoder is expecting to have the health center UUID. data.uuid = shard; return query.toArray().catch(databaseError).then(function (nodes) { if (nodes) { var today = new Date(); - var sixMonthsFromToday = new Date(); - sixMonthsFromToday.setMonth(today.getMonth() + 6); - + var patientsWithHIVFollowUps = []; nodes.forEach(function (node) { - if (node.date_concluded != undefined && typeof node.date_concluded != 'undefined') { - var targetDate = sixMonthsFromToday; + // Do not process nodes that are not follow ups. + if (hivTestTypes.includes(node.type)) { + return; + } - if (resolvedFollowUpMeasurementsTypes.includes(node.type)) { - var targetDate = today; - } + // Record IDs of patients that have any HIV follow up. + if (node.type == 'hiv_follow_up') { + if (patientsWithHIVFollowUps.indexOf(node.person) === -1) { + patientsWithHIVFollowUps.push(node.person); + } + } - // Do not load resolved items. + if (node.date_concluded != undefined && typeof node.date_concluded != 'undefined') { var resolutionDate = new Date(node.date_concluded); + if (followUpMeasurementsTypesUsedByDashboard.includes(node.type)) { + resolutionDate.setMonth(today.getMonth() + 6); + } - if (resolutionDate < targetDate) { + if (resolutionDate < today) { return; } } @@ -631,6 +656,77 @@ } }); + // Recording all patients that had posiitve HIV test result. + // In case of multiple posiitve results for a patient, we + // record most recent test date. + var positiveHIVMap = {}; + nodes.forEach(function (node) { + // Do not process follow ups nodes. + if (!hivTestTypes.includes(node.type)) { + return; + } + + // Do not process, if test result is not positive. + if (node.test_result !== 'positive') { + return; + } + + // First time positive result for patient is found - recorded. + if (!positiveHIVMap[node.person]) { + positiveHIVMap[node.person] = {id: node.person, date: node.date_measured, uuid: node.uuid}; + return; + } + + // Another positive result for patient is found - record the + // most recent one. + var current = new Date(positiveHIVMap[node.person].date); + var candidate = new Date(node.date_measured); + if (current < candidate) { + positiveHIVMap[node.person] = {id: node.person, date: node.date_measured, uuid: node.uuid}; + } + }); + + // Creating 'dummy' HIV follow ups for patients that have positive HIV + // result, and never had HIV follow up (which means that they were) + // never diagnosed HIV posiitve during HIV encounter. + Object.values(positiveHIVMap).forEach((item) => { + if (patientsWithHIVFollowUps.indexOf(item.id) !== -1) { + // Patinet has HIV follow up - skip to next one. + return; + } + + // Create 'dummy' HIV follow up. + var hivFollowUp = { + date_concluded: null, + // Positive HIV test result date. + date_measured: item.date, + deleted: false, + // Per requirements, positive HIV test result follow up is + // to be scheduled to 1 week. + follow_up_options: ['1-w'], + health_center: null, + // This will be uesd as an indicator for front-end, to understand + // that this follow up represents positive HIV test. + hiv_encounter: 'dummy', + nurse: 'dummy', + person: item.id, + shard: 'dummy', + type: 'hiv_follow_up', + // We only need to have the UUID unique, so we use + // the UUID pf positive HIV test node. + // We don't perform any editing on fornt-end, so it's + // sufficient. + uuid: item.uuid + }; + + // Add 'dummy' HIV follow up to the data. + if (data['hiv_follow_up']) { + data['hiv_follow_up'].push(hivFollowUp); + } else { + data['hiv_follow_up'] = [hivFollowUp]; + } + }); + var body = JSON.stringify({ // Decoder is expecting a list. data: [data] @@ -882,6 +978,7 @@ var encounterTypes = [ 'acute_illness_encounter', 'child_scoreboard_encounter', + 'hiv_encounter', 'home_visit_encounter', 'ncd_encounter', 'nutrition_encounter', @@ -954,6 +1051,22 @@ } } + // For education_session endpoint, check participant param and + // only return those sessions were participant has participated. + if (type === 'education_session') { + var personId = params.get('participant'); + if (personId) { + modifyQuery = modifyQuery.then(function () { + criteria.participating_patients = personId; + query = table.where(criteria); + + countQuery = query.clone(); + + return Promise.resolve(); + }); + } + } + return modifyQuery.then(function () { return countQuery.count().catch(databaseError).then(function (count) { diff --git a/client/src/js/sw.js b/client/src/js/sw.js index 5fa7832ab8..7e102d5e0c 100644 --- a/client/src/js/sw.js +++ b/client/src/js/sw.js @@ -31,7 +31,7 @@ var screenshotsUploadUrlRegex = /\/cache-upload\/screenshots/; * * @type {number} */ -var dbVerno = 24; +var dbVerno = 26; // All those entities are the entities we're going to get from the backend. // They should also be mapped in SyncManager.Model.BackendGeneralEntity (for @@ -73,7 +73,7 @@ var tableForType = { core_physical_exam: 'shards', covid_testing: 'shards', danger_signs: 'shards', - education_session: 'shards', + education_session: 'shards', exposure: 'shards', family_planning: 'shards', follow_up: 'shards', @@ -84,6 +84,15 @@ var tableForType = { health_center: 'nodes', health_education: 'shards', height: 'shards', + hiv_diagnostics: 'shards', + hiv_dot: 'shards', + hiv_encounter: 'shards', + hiv_follow_up: 'shards', + hiv_health_education: 'shards', + hiv_medication: 'shards', + hiv_referral: 'shards', + hiv_symptom_review: 'shards', + hiv_treatment_review: 'shards', home_visit_encounter: 'shards', individual_participant: 'shards', isolation: 'shards', diff --git a/server/hedley/HedleyWebTestBase.inc b/server/hedley/HedleyWebTestBase.inc index 0012ce15a8..13b5b52f12 100644 --- a/server/hedley/HedleyWebTestBase.inc +++ b/server/hedley/HedleyWebTestBase.inc @@ -144,6 +144,7 @@ class HedleyWebTestBase extends DrupalWebTestCase { $wrapper->field_clinic->set($clinic_id); $wrapper->field_ubudehe->set(1); $wrapper->field_education_level->set(2); + $wrapper->field_gender->set('female'); $wrapper->save(); return $node->nid; diff --git a/server/hedley/hedley.info b/server/hedley/hedley.info index 01c495ec40..22a45bc143 100644 --- a/server/hedley/hedley.info +++ b/server/hedley/hedley.info @@ -48,6 +48,7 @@ dependencies[] = hedley_chw dependencies[] = hedley_case_management dependencies[] = hedley_device dependencies[] = hedley_health_center +dependencies[] = hedley_hiv dependencies[] = hedley_general dependencies[] = hedley_group_education dependencies[] = hedley_ncd diff --git a/server/hedley/hedley.install b/server/hedley/hedley.install index 523956d043..fdee4cf08b 100644 --- a/server/hedley/hedley.install +++ b/server/hedley/hedley.install @@ -705,4 +705,11 @@ function hedley_update_7041() { */ function hedley_update_7042() { module_enable(['hedley_group_education']); +} + +/** + * Enable the Hedley HIV module. + */ +function hedley_update_7043() { + module_enable(['hedley_hiv']); } \ No newline at end of file diff --git a/server/hedley/modules/custom/hedley_activity/hedley_activity.module b/server/hedley/modules/custom/hedley_activity/hedley_activity.module index 898ba3f514..2a1deb68cd 100644 --- a/server/hedley/modules/custom/hedley_activity/hedley_activity.module +++ b/server/hedley/modules/custom/hedley_activity/hedley_activity.module @@ -73,6 +73,7 @@ define('HEDLEY_ACTIVITY_NCD_OUTSIDE_CARE_CONTENT_TYPE', 'ncd_outside_care'); define('HEDLEY_ACTIVITY_NCD_CO_MORBIDITIES_CONTENT_TYPE', 'ncd_co_morbidities'); define('HEDLEY_ACTIVITY_GROUP_PARTICIPANT_CONTENT_TYPE', 'pmtct_participant'); define('HEDLEY_ACTIVITY_GROUP_ENCOUNTER_CONTENT_TYPE', 'session'); +define('HEDLEY_ACTIVITY_GROUP_EDUCATION_CONTENT_TYPE', 'education_session'); define('HEDLEY_ACTIVITY_CHILD_SCOREBOARD_ENCOUNTER_CONTENT_TYPE', 'child_scoreboard_encounter'); const HEDLEY_ACTIVITY_HEIGHT_BUNDLES = [ diff --git a/server/hedley/modules/custom/hedley_case_management/hedley_case_management.module b/server/hedley/modules/custom/hedley_case_management/hedley_case_management.module index ea22a70a91..daf38bd3e0 100644 --- a/server/hedley/modules/custom/hedley_case_management/hedley_case_management.module +++ b/server/hedley/modules/custom/hedley_case_management/hedley_case_management.module @@ -61,6 +61,15 @@ function hedley_case_management_node_insert($node) { ]; if (in_array($node->type, $tuberculosis_triggers)) { hedley_case_management_handle_tuberculosis_insert_trigger($node); + return; + } + + $hiv_triggers = [ + 'hiv_follow_up', + 'hiv_encounter', + ]; + if (in_array($node->type, $hiv_triggers)) { + hedley_case_management_handle_hiv_insert_trigger($node); } } @@ -421,6 +430,68 @@ function hedley_case_management_resolve_tuberculosis_follow_ups($person_id, $to_ } } +/** + * Processes create events that trigger hiv follow-ups resolution. + * + * @param object $node + * Created node. + * + * @throws EntityMetadataWrapperException + */ +function hedley_case_management_handle_hiv_insert_trigger($node) { + $wrapper = entity_metadata_wrapper('node', $node); + if ($node->type === 'hiv_encounter') { + // At encounter, person is resolved from the participant. + $person_id = $wrapper->field_individual_participant->field_person->getIdentifier(); + } + else { + // At follow-ups, person is on the node itself. + $person_id = $wrapper->field_person->getIdentifier(); + } + + if (empty($person_id)) { + // Failed to load required data. + return; + } + + // Trigger follow-ups resolution. + hedley_case_management_resolve_hiv_follow_ups($person_id, $node->nid); +} + +/** + * Marks hiv follow-ups belonging to person as resolved. + * + * @param int $person_id + * Person ID. + * @param int $to_nid + * Optional; IDs of loaded follow-ups should be below this node ID. + * @param int $limit + * Maximal number of follow-ups to load. Defaults to 200. + */ +function hedley_case_management_resolve_hiv_follow_ups($person_id, $to_nid = NULL, $limit = 200) { + $query = new EntityFieldQuery(); + $query + ->entityCondition('entity_type', 'node') + ->entityCondition('bundle', 'hiv_follow_up') + ->propertyCondition('status', NODE_PUBLISHED) + ->fieldCondition('field_person', 'target_id', $person_id) + ->addTag('exclude_resolved') + ->range(0, $limit); + + if (!empty($to_nid)) { + $query->propertyCondition('nid', $to_nid, '<'); + } + + $result = $query->execute(); + if (empty($result['node'])) { + return; + } + + foreach (array_keys($result['node']) as $follow_up) { + hedley_case_management_resolve_follow_up($follow_up); + } +} + /** * Processes update that trigger acute illness / prenatal follow-ups resolution. * @@ -433,7 +504,7 @@ function hedley_case_management_handle_update_trigger($node) { $wrapper = entity_metadata_wrapper('node', $node); $type = $wrapper->field_encounter_type->value(); - if (!in_array($type, ['acute-illness', 'antenatal', 'tuberculosis'])) { + if (!in_array($type, ['acute-illness', 'antenatal', 'tuberculosis', 'hiv'])) { // We only track resolution of illnesses and pregnancies. return; } @@ -462,11 +533,17 @@ function hedley_case_management_handle_update_trigger($node) { } if ($type === 'tuberculosis') { - // Dealing with tuberculosis illness. Trigger follow ups resolution. + // Dealing with tuberculosis illness. Trigger follow-ups resolution. hedley_case_management_resolve_tuberculosis_follow_ups($person_id); return; } + if ($type === 'hiv') { + // Dealing with HIV illness. Trigger follow-ups resolution. + hedley_case_management_resolve_hiv_follow_ups($person_id); + return; + } + // If we got so far, we're dealing with pregnancy. // Trigger follow ups resolution. hedley_case_management_resolve_prenatal_follow_ups($person_id); diff --git a/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.field_base.inc b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.field_base.inc new file mode 100644 index 0000000000..3a0a7037d0 --- /dev/null +++ b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.field_base.inc @@ -0,0 +1,230 @@ + 1, + 'cardinality' => -1, + 'deleted' => 0, + 'entity_id_type' => NULL, + 'entity_types' => array(), + 'field_name' => 'field_hiv_diagnosis_signs', + 'indexes' => array( + 'value' => array( + 0 => 'value', + ), + ), + 'locked' => 0, + 'module' => 'list', + 'settings' => array( + 'allowed_values' => array( + 'result-positive-reported' => 'Positive result reported', + 'result-positive-known' => 'Positive result known', + 'result-date-estimated' => 'Positive result date estimated', + 'none' => 'None', + ), + 'allowed_values_function' => '', + ), + 'translatable' => 0, + 'type' => 'list_text', + ); + + // Exported field_base: 'field_hiv_encounter'. + $field_bases['field_hiv_encounter'] = array( + 'active' => 1, + 'cardinality' => 1, + 'deleted' => 0, + 'entity_id_type' => NULL, + 'entity_types' => array(), + 'field_name' => 'field_hiv_encounter', + 'indexes' => array( + 'target_id' => array( + 0 => 'target_id', + ), + ), + 'locked' => 0, + 'module' => 'entityreference', + 'settings' => array( + 'handler' => 'base', + 'handler_settings' => array( + 'behaviors' => array( + 'views-select-list' => array( + 'status' => 0, + ), + ), + 'sort' => array( + 'type' => 'none', + ), + 'target_bundles' => array( + 'hiv_encounter' => 'hiv_encounter', + ), + ), + 'target_type' => 'node', + ), + 'translatable' => 0, + 'type' => 'entityreference', + ); + + // Exported field_base: 'field_hiv_health_education_signs'. + $field_bases['field_hiv_health_education_signs'] = array( + 'active' => 1, + 'cardinality' => -1, + 'deleted' => 0, + 'entity_id_type' => NULL, + 'entity_types' => array(), + 'field_name' => 'field_hiv_health_education_signs', + 'indexes' => array( + 'value' => array( + 0 => 'value', + ), + ), + 'locked' => 0, + 'module' => 'list', + 'settings' => array( + 'allowed_values' => array( + 'positive-result' => 'Positive Result', + 'safer-sex-practices' => 'Safer Sex Practices', + 'encouraged-partner-testing' => 'Encouraged Partner Testing', + 'family-planning-options' => 'Family Planning Options', + 'none' => 'None', + ), + 'allowed_values_function' => '', + ), + 'translatable' => 0, + 'type' => 'list_text', + ); + + // Exported field_base: 'field_hiv_symptoms'. + $field_bases['field_hiv_symptoms'] = array( + 'active' => 1, + 'cardinality' => -1, + 'deleted' => 0, + 'entity_id_type' => NULL, + 'entity_types' => array(), + 'field_name' => 'field_hiv_symptoms', + 'indexes' => array( + 'value' => array( + 0 => 'value', + ), + ), + 'locked' => 0, + 'module' => 'list', + 'settings' => array( + 'allowed_values' => array( + 'fever' => 'Fever', + 'fatigue' => 'Fatigue', + 'swollen-lymph-nodes' => 'Swollen lymph nodes', + 'sore-throat' => 'Sore throat', + 'rash' => 'Rash', + 'muscle-joint-pain' => 'Muscle and joint pain', + 'headache' => 'Headache', + 'severe-abdominal-pain' => 'Severe abdominal pain', + 'night-sweats' => 'Night sweats', + 'diarrhea' => 'Diarrhea', + 'wight-loss' => 'Weight loss', + 'coughing-up-blood' => 'Coughing up blood', + 'hair-loss' => 'Hair loss', + 'mouth-ulcers' => 'Mouth ulcers', + 'difficulty-breathing' => 'Difficulty breathing', + 'vomiting' => 'Vomiting', + 'none' => 'None', + ), + 'allowed_values_function' => '', + ), + 'translatable' => 0, + 'type' => 'list_text', + ); + + // Exported field_base: 'field_positive_result_date'. + $field_bases['field_positive_result_date'] = array( + 'active' => 1, + 'cardinality' => 1, + 'deleted' => 0, + 'entity_id_type' => NULL, + 'entity_types' => array(), + 'field_name' => 'field_positive_result_date', + 'indexes' => array( + 'value' => array( + 0 => 'value', + ), + ), + 'locked' => 0, + 'module' => 'date', + 'settings' => array( + 'granularity' => array( + 'day' => 'day', + 'hour' => 0, + 'minute' => 0, + 'month' => 'month', + 'second' => 0, + 'year' => 'year', + ), + 'timezone_db' => '', + 'todate' => '', + 'tz_handling' => 'none', + ), + 'translatable' => 0, + 'type' => 'datetime', + ); + + // Exported field_base: 'field_prescribed_hiv_medications'. + $field_bases['field_prescribed_hiv_medications'] = array( + 'active' => 1, + 'cardinality' => -1, + 'deleted' => 0, + 'entity_id_type' => NULL, + 'entity_types' => array(), + 'field_name' => 'field_prescribed_hiv_medications', + 'indexes' => array( + 'value' => array( + 0 => 'value', + ), + ), + 'locked' => 0, + 'module' => 'list', + 'settings' => array( + 'allowed_values' => array( + 'dtg-3tc-tdf' => 'Dolutegravir Lamivudine Tenofovir', + 'atz-r' => 'Atazanavir Ritonavir', + 'dtg' => 'Dolutegravir', + 'abc-3tc' => 'Abacavir Lamivudine', + '3tc-tdf' => 'Lamivudine Tenofovir', + 'azt' => 'Zidovudine', + '3tc-azt-nvp' => 'Lamivudine Zidovudine Nevirapine', + 'efv-3tc-tdf' => 'Efavirenz Lamivudine Tenofovir', + '3tc-azt' => 'Lamivudine Zidovudine', + 'lvp-r' => 'Lopinavir Ritonavir', + 'drv-r' => 'Darunavir Ritonavir', + 'drv-c' => 'Darunavir Cobicistat', + 'ral' => 'Raltegravir', + 'efv' => 'Efavirenz', + 'nvp' => 'Nevirapine', + 'etr' => 'Etravirine', + 'tdf' => 'Tenofovir', + '3tc' => 'Lamivudine', + 'abc' => 'Abacavir', + 'bactrim' => 'Bactrim', + 'dapsone' => 'Dapsone', + 'isoniazid' => 'Isoniazid', + 'fluconazole' => 'Fluconazole', + 'azithromycin' => 'Azithromycin', + 'none' => 'None', + ), + 'allowed_values_function' => '', + ), + 'translatable' => 0, + 'type' => 'list_text', + ); + + return $field_bases; +} diff --git a/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.field_instance.inc b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.field_instance.inc new file mode 100644 index 0000000000..9ce1af8769 --- /dev/null +++ b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.field_instance.inc @@ -0,0 +1,2659 @@ + 'hiv_diagnostics', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_date_measured', + 'label' => 'Date Measured', + 'required' => 1, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => 2, + ), + ); + + // Exported field_instance: 'node-hiv_diagnostics-field_hiv_diagnosis_signs'. + $field_instances['node-hiv_diagnostics-field_hiv_diagnosis_signs'] = array( + 'bundle' => 'hiv_diagnostics', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 8, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_diagnosis_signs', + 'label' => 'HIV Diagnosis Signs', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 8, + ), + ); + + // Exported field_instance: 'node-hiv_diagnostics-field_hiv_encounter'. + $field_instances['node-hiv_diagnostics-field_hiv_encounter'] = array( + 'bundle' => 'hiv_diagnostics', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 3, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_encounter', + 'label' => 'HIV Encounter', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 4, + ), + ); + + // Exported field_instance: 'node-hiv_diagnostics-field_nurse'. + $field_instances['node-hiv_diagnostics-field_nurse'] = array( + 'bundle' => 'hiv_diagnostics', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 2, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_nurse', + 'label' => 'Nurse', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 3, + ), + ); + + // Exported field_instance: 'node-hiv_diagnostics-field_person'. + $field_instances['node-hiv_diagnostics-field_person'] = array( + 'bundle' => 'hiv_diagnostics', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_person', + 'label' => 'Person', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 1, + ), + ); + + // Exported field_instance: 'node-hiv_diagnostics-field_positive_result_date'. + $field_instances['node-hiv_diagnostics-field_positive_result_date'] = array( + 'bundle' => 'hiv_diagnostics', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 6, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_positive_result_date', + 'label' => 'Positive Result Date', + 'required' => 0, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 1, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_text', + 'weight' => 9, + ), + ); + + // Exported field_instance: 'node-hiv_diagnostics-field_shards'. + $field_instances['node-hiv_diagnostics-field_shards'] = array( + 'bundle' => 'hiv_diagnostics', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 5, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_shards', + 'label' => 'Shards', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 6, + ), + ); + + // Exported field_instance: 'node-hiv_diagnostics-field_uuid'. + $field_instances['node-hiv_diagnostics-field_uuid'] = array( + 'bundle' => 'hiv_diagnostics', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 4, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_uuid', + 'label' => 'UUID', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => 60, + ), + 'type' => 'text_textfield', + 'weight' => 5, + ), + ); + + // Exported field_instance: 'node-hiv_encounter-field_individual_participant'. + $field_instances['node-hiv_encounter-field_individual_participant'] = array( + 'bundle' => 'hiv_encounter', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_individual_participant', + 'label' => 'Individual Participant', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => -1, + ), + ); + + // Exported field_instance: 'node-hiv_encounter-field_scheduled_date'. + $field_instances['node-hiv_encounter-field_scheduled_date'] = array( + 'bundle' => 'hiv_encounter', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_scheduled_date', + 'label' => 'Scheduled Date', + 'required' => 0, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => -3, + ), + ); + + // Exported field_instance: 'node-hiv_encounter-field_shards'. + $field_instances['node-hiv_encounter-field_shards'] = array( + 'bundle' => 'hiv_encounter', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 3, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_shards', + 'label' => 'Shards', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 3, + ), + ); + + // Exported field_instance: 'node-hiv_encounter-field_uuid'. + $field_instances['node-hiv_encounter-field_uuid'] = array( + 'bundle' => 'hiv_encounter', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 2, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_uuid', + 'label' => 'UUID', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => 60, + ), + 'type' => 'text_textfield', + 'weight' => 1, + ), + ); + + // Exported field_instance: 'node-hiv_follow_up-field_date_concluded'. + $field_instances['node-hiv_follow_up-field_date_concluded'] = array( + 'bundle' => 'hiv_follow_up', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 7, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_date_concluded', + 'label' => 'Resolution Date', + 'required' => 0, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => 11, + ), + ); + + // Exported field_instance: 'node-hiv_follow_up-field_date_measured'. + $field_instances['node-hiv_follow_up-field_date_measured'] = array( + 'bundle' => 'hiv_follow_up', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_date_measured', + 'label' => 'Date Measured', + 'required' => 1, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => -1, + ), + ); + + // Exported field_instance: 'node-hiv_follow_up-field_follow_up_options'. + $field_instances['node-hiv_follow_up-field_follow_up_options'] = array( + 'bundle' => 'hiv_follow_up', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 6, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_follow_up_options', + 'label' => 'Follow up options', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 9, + ), + ); + + // Exported field_instance: 'node-hiv_follow_up-field_hiv_encounter'. + $field_instances['node-hiv_follow_up-field_hiv_encounter'] = array( + 'bundle' => 'hiv_follow_up', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 3, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_encounter', + 'label' => 'HIV Encounter', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 3, + ), + ); + + // Exported field_instance: 'node-hiv_follow_up-field_nurse'. + $field_instances['node-hiv_follow_up-field_nurse'] = array( + 'bundle' => 'hiv_follow_up', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 2, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_nurse', + 'label' => 'Nurse', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 1, + ), + ); + + // Exported field_instance: 'node-hiv_follow_up-field_person'. + $field_instances['node-hiv_follow_up-field_person'] = array( + 'bundle' => 'hiv_follow_up', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_person', + 'label' => 'Person', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => -3, + ), + ); + + // Exported field_instance: 'node-hiv_follow_up-field_shards'. + $field_instances['node-hiv_follow_up-field_shards'] = array( + 'bundle' => 'hiv_follow_up', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 5, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_shards', + 'label' => 'Shards', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 7, + ), + ); + + // Exported field_instance: 'node-hiv_follow_up-field_uuid'. + $field_instances['node-hiv_follow_up-field_uuid'] = array( + 'bundle' => 'hiv_follow_up', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 4, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_uuid', + 'label' => 'UUID', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => 60, + ), + 'type' => 'text_textfield', + 'weight' => 5, + ), + ); + + // Exported field_instance: 'node-hiv_health_education-field_date_measured'. + $field_instances['node-hiv_health_education-field_date_measured'] = array( + 'bundle' => 'hiv_health_education', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_date_measured', + 'label' => 'Date Measured', + 'required' => 1, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => -1, + ), + ); + + // Exported field_instance: 'node-hiv_health_education-field_hiv_encounter'. + $field_instances['node-hiv_health_education-field_hiv_encounter'] = array( + 'bundle' => 'hiv_health_education', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 3, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_encounter', + 'label' => 'HIV Encounter', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 3, + ), + ); + + // Exported field_instance: + // 'node-hiv_health_education-field_hiv_health_education_signs'. + $field_instances['node-hiv_health_education-field_hiv_health_education_signs'] = array( + 'bundle' => 'hiv_health_education', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 6, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_health_education_signs', + 'label' => 'HIV Health Education Signs', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 8, + ), + ); + + // Exported field_instance: 'node-hiv_health_education-field_nurse'. + $field_instances['node-hiv_health_education-field_nurse'] = array( + 'bundle' => 'hiv_health_education', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 2, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_nurse', + 'label' => 'Nurse', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 1, + ), + ); + + // Exported field_instance: 'node-hiv_health_education-field_person'. + $field_instances['node-hiv_health_education-field_person'] = array( + 'bundle' => 'hiv_health_education', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_person', + 'label' => 'Person', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => -3, + ), + ); + + // Exported field_instance: 'node-hiv_health_education-field_shards'. + $field_instances['node-hiv_health_education-field_shards'] = array( + 'bundle' => 'hiv_health_education', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 5, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_shards', + 'label' => 'Shards', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 7, + ), + ); + + // Exported field_instance: 'node-hiv_health_education-field_uuid'. + $field_instances['node-hiv_health_education-field_uuid'] = array( + 'bundle' => 'hiv_health_education', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 4, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_uuid', + 'label' => 'UUID', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => 60, + ), + 'type' => 'text_textfield', + 'weight' => 5, + ), + ); + + // Exported field_instance: 'node-hiv_medication-field_date_measured'. + $field_instances['node-hiv_medication-field_date_measured'] = array( + 'bundle' => 'hiv_medication', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_date_measured', + 'label' => 'Date Measured', + 'required' => 1, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => -1, + ), + ); + + // Exported field_instance: 'node-hiv_medication-field_hiv_encounter'. + $field_instances['node-hiv_medication-field_hiv_encounter'] = array( + 'bundle' => 'hiv_medication', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 3, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_encounter', + 'label' => 'HIV Encounter', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 3, + ), + ); + + // Exported field_instance: 'node-hiv_medication-field_nurse'. + $field_instances['node-hiv_medication-field_nurse'] = array( + 'bundle' => 'hiv_medication', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 2, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_nurse', + 'label' => 'Nurse', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 1, + ), + ); + + // Exported field_instance: 'node-hiv_medication-field_person'. + $field_instances['node-hiv_medication-field_person'] = array( + 'bundle' => 'hiv_medication', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_person', + 'label' => 'Person', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => -3, + ), + ); + + // Exported field_instance: + // 'node-hiv_medication-field_prescribed_hiv_medications'. + $field_instances['node-hiv_medication-field_prescribed_hiv_medications'] = array( + 'bundle' => 'hiv_medication', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 6, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_prescribed_hiv_medications', + 'label' => 'Prescribed HIV medications', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 8, + ), + ); + + // Exported field_instance: 'node-hiv_medication-field_shards'. + $field_instances['node-hiv_medication-field_shards'] = array( + 'bundle' => 'hiv_medication', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 5, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_shards', + 'label' => 'Shards', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 7, + ), + ); + + // Exported field_instance: 'node-hiv_medication-field_uuid'. + $field_instances['node-hiv_medication-field_uuid'] = array( + 'bundle' => 'hiv_medication', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 4, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_uuid', + 'label' => 'UUID', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => 60, + ), + 'type' => 'text_textfield', + 'weight' => 5, + ), + ); + + // Exported field_instance: 'node-hiv_referral-field_date_measured'. + $field_instances['node-hiv_referral-field_date_measured'] = array( + 'bundle' => 'hiv_referral', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_date_measured', + 'label' => 'Date Measured', + 'required' => 1, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => -1, + ), + ); + + // Exported field_instance: 'node-hiv_referral-field_hiv_encounter'. + $field_instances['node-hiv_referral-field_hiv_encounter'] = array( + 'bundle' => 'hiv_referral', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 3, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_encounter', + 'label' => 'HIV Encounter', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 3, + ), + ); + + // Exported field_instance: 'node-hiv_referral-field_nurse'. + $field_instances['node-hiv_referral-field_nurse'] = array( + 'bundle' => 'hiv_referral', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 2, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_nurse', + 'label' => 'Nurse', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 1, + ), + ); + + // Exported field_instance: 'node-hiv_referral-field_person'. + $field_instances['node-hiv_referral-field_person'] = array( + 'bundle' => 'hiv_referral', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_person', + 'label' => 'Person', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => -3, + ), + ); + + // Exported field_instance: 'node-hiv_referral-field_reason_not_sent_to_hc'. + $field_instances['node-hiv_referral-field_reason_not_sent_to_hc'] = array( + 'bundle' => 'hiv_referral', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 7, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_reason_not_sent_to_hc', + 'label' => 'Reason for Not Sending to HC', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 11, + ), + ); + + // Exported field_instance: 'node-hiv_referral-field_send_to_hc'. + $field_instances['node-hiv_referral-field_send_to_hc'] = array( + 'bundle' => 'hiv_referral', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 6, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_send_to_hc', + 'label' => 'Send to HC', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_buttons', + 'weight' => 9, + ), + ); + + // Exported field_instance: 'node-hiv_referral-field_shards'. + $field_instances['node-hiv_referral-field_shards'] = array( + 'bundle' => 'hiv_referral', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 5, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_shards', + 'label' => 'Shards', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 7, + ), + ); + + // Exported field_instance: 'node-hiv_referral-field_uuid'. + $field_instances['node-hiv_referral-field_uuid'] = array( + 'bundle' => 'hiv_referral', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 4, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_uuid', + 'label' => 'UUID', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => 60, + ), + 'type' => 'text_textfield', + 'weight' => 5, + ), + ); + + // Exported field_instance: 'node-hiv_symptom_review-field_date_measured'. + $field_instances['node-hiv_symptom_review-field_date_measured'] = array( + 'bundle' => 'hiv_symptom_review', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_date_measured', + 'label' => 'Date Measured', + 'required' => 1, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => -1, + ), + ); + + // Exported field_instance: 'node-hiv_symptom_review-field_hiv_encounter'. + $field_instances['node-hiv_symptom_review-field_hiv_encounter'] = array( + 'bundle' => 'hiv_symptom_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 3, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_encounter', + 'label' => 'HIV Encounter', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 3, + ), + ); + + // Exported field_instance: 'node-hiv_symptom_review-field_hiv_symptoms'. + $field_instances['node-hiv_symptom_review-field_hiv_symptoms'] = array( + 'bundle' => 'hiv_symptom_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 6, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_symptoms', + 'label' => 'HIV Symptoms', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 8, + ), + ); + + // Exported field_instance: 'node-hiv_symptom_review-field_nurse'. + $field_instances['node-hiv_symptom_review-field_nurse'] = array( + 'bundle' => 'hiv_symptom_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 2, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_nurse', + 'label' => 'Nurse', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 1, + ), + ); + + // Exported field_instance: 'node-hiv_symptom_review-field_person'. + $field_instances['node-hiv_symptom_review-field_person'] = array( + 'bundle' => 'hiv_symptom_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_person', + 'label' => 'Person', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => -3, + ), + ); + + // Exported field_instance: 'node-hiv_symptom_review-field_shards'. + $field_instances['node-hiv_symptom_review-field_shards'] = array( + 'bundle' => 'hiv_symptom_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 5, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_shards', + 'label' => 'Shards', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 7, + ), + ); + + // Exported field_instance: 'node-hiv_symptom_review-field_uuid'. + $field_instances['node-hiv_symptom_review-field_uuid'] = array( + 'bundle' => 'hiv_symptom_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 4, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_uuid', + 'label' => 'UUID', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => 60, + ), + 'type' => 'text_textfield', + 'weight' => 5, + ), + ); + + // Exported field_instance: 'node-hiv_treatment_review-field_adverse_events'. + $field_instances['node-hiv_treatment_review-field_adverse_events'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 9, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_adverse_events', + 'label' => 'Adverse Events', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 15, + ), + ); + + // Exported field_instance: 'node-hiv_treatment_review-field_date_measured'. + $field_instances['node-hiv_treatment_review-field_date_measured'] = array( + 'bundle' => 'hiv_treatment_review', + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'date', + 'settings' => array( + 'custom_date_format' => '', + 'format_type' => 'long', + 'fromto' => 'both', + 'multiple_from' => '', + 'multiple_number' => '', + 'multiple_to' => '', + 'show_remaining_days' => FALSE, + ), + 'type' => 'date_default', + 'weight' => 1, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_date_measured', + 'label' => 'Date Measured', + 'required' => 1, + 'settings' => array( + 'default_value' => 'now', + 'default_value2' => 'same', + 'default_value_code' => '', + 'default_value_code2' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'date', + 'settings' => array( + 'increment' => 15, + 'input_format' => 'm/d/Y - H:i:s', + 'input_format_custom' => '', + 'label_position' => 'above', + 'no_fieldset' => 0, + 'text_parts' => array(), + 'year_range' => '-3:+3', + ), + 'type' => 'date_select', + 'weight' => -1, + ), + ); + + // Exported field_instance: 'node-hiv_treatment_review-field_hiv_encounter'. + $field_instances['node-hiv_treatment_review-field_hiv_encounter'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 3, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_hiv_encounter', + 'label' => 'HIV Encounter', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 3, + ), + ); + + // Exported field_instance: 'node-hiv_treatment_review-field_missed_doses'. + $field_instances['node-hiv_treatment_review-field_missed_doses'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'number', + 'settings' => array( + 'decimal_separator' => '.', + 'prefix_suffix' => TRUE, + 'scale' => 0, + 'thousand_separator' => '', + ), + 'type' => 'number_integer', + 'weight' => 8, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_missed_doses', + 'label' => 'Missed doses', + 'required' => 0, + 'settings' => array( + 'max' => '', + 'min' => '', + 'prefix' => '', + 'suffix' => '', + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 0, + 'module' => 'number', + 'settings' => array(), + 'type' => 'number', + 'weight' => 13, + ), + ); + + // Exported field_instance: 'node-hiv_treatment_review-field_nurse'. + $field_instances['node-hiv_treatment_review-field_nurse'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 2, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_nurse', + 'label' => 'Nurse', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 1, + ), + ); + + // Exported field_instance: 'node-hiv_treatment_review-field_person'. + $field_instances['node-hiv_treatment_review-field_person'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 0, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_person', + 'label' => 'Person', + 'required' => 1, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => -3, + ), + ); + + // Exported field_instance: + // 'node-hiv_treatment_review-field_reason_for_not_taking'. + $field_instances['node-hiv_treatment_review-field_reason_for_not_taking'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 7, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_reason_for_not_taking', + 'label' => 'Reason for not taking', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 11, + ), + ); + + // Exported field_instance: 'node-hiv_treatment_review-field_shards'. + $field_instances['node-hiv_treatment_review-field_shards'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'entityreference', + 'settings' => array( + 'bypass_access' => FALSE, + 'link' => FALSE, + ), + 'type' => 'entityreference_label', + 'weight' => 5, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_shards', + 'label' => 'Shards', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'entityreference', + 'settings' => array( + 'match_operator' => 'CONTAINS', + 'path' => '', + 'size' => 60, + ), + 'type' => 'entityreference_autocomplete', + 'weight' => 7, + ), + ); + + // Exported field_instance: + // 'node-hiv_treatment_review-field_treatment_ongoing'. + $field_instances['node-hiv_treatment_review-field_treatment_ongoing'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'list', + 'settings' => array(), + 'type' => 'list_default', + 'weight' => 6, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_treatment_ongoing', + 'label' => 'Treatment Ongoing', + 'required' => 0, + 'settings' => array( + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'options', + 'settings' => array(), + 'type' => 'options_select', + 'weight' => 9, + ), + ); + + // Exported field_instance: 'node-hiv_treatment_review-field_uuid'. + $field_instances['node-hiv_treatment_review-field_uuid'] = array( + 'bundle' => 'hiv_treatment_review', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 4, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_uuid', + 'label' => 'UUID', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => FALSE, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'size' => 60, + ), + 'type' => 'text_textfield', + 'weight' => 5, + ), + ); + + // Translatables + // Included for use with string extractors like potx. + t('Adverse Events'); + t('Date Measured'); + t('Follow up options'); + t('HIV Diagnosis Signs'); + t('HIV Encounter'); + t('HIV Health Education Signs'); + t('HIV Symptoms'); + t('Individual Participant'); + t('Missed doses'); + t('Nurse'); + t('Person'); + t('Positive Result Date'); + t('Prescribed HIV medications'); + t('Reason for Not Sending to HC'); + t('Reason for not taking'); + t('Resolution Date'); + t('Scheduled Date'); + t('Send to HC'); + t('Shards'); + t('Treatment Ongoing'); + t('UUID'); + + return $field_instances; +} diff --git a/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.inc b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.inc new file mode 100644 index 0000000000..fb0ac4f4a0 --- /dev/null +++ b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.inc @@ -0,0 +1,89 @@ + "1"); + } +} + +/** + * Implements hook_node_info(). + */ +function hedley_hiv_node_info() { + $items = array( + 'hiv_diagnostics' => array( + 'name' => t('HIV Diagnostics'), + 'base' => 'node_content', + 'description' => '', + 'has_title' => '1', + 'title_label' => t('Title'), + 'help' => '', + ), + 'hiv_encounter' => array( + 'name' => t('HIV Encounter'), + 'base' => 'node_content', + 'description' => '', + 'has_title' => '1', + 'title_label' => t('Title'), + 'help' => '', + ), + 'hiv_follow_up' => array( + 'name' => t('HIV Follow Up'), + 'base' => 'node_content', + 'description' => '', + 'has_title' => '1', + 'title_label' => t('Title'), + 'help' => '', + ), + 'hiv_health_education' => array( + 'name' => t('HIV Health Education'), + 'base' => 'node_content', + 'description' => '', + 'has_title' => '1', + 'title_label' => t('Title'), + 'help' => '', + ), + 'hiv_medication' => array( + 'name' => t('HIV Medication'), + 'base' => 'node_content', + 'description' => '', + 'has_title' => '1', + 'title_label' => t('Title'), + 'help' => '', + ), + 'hiv_referral' => array( + 'name' => t('HIV Referral'), + 'base' => 'node_content', + 'description' => '', + 'has_title' => '1', + 'title_label' => t('Title'), + 'help' => '', + ), + 'hiv_symptom_review' => array( + 'name' => t('HIV Symptom Review'), + 'base' => 'node_content', + 'description' => '', + 'has_title' => '1', + 'title_label' => t('Title'), + 'help' => '', + ), + 'hiv_treatment_review' => array( + 'name' => t('HIV Treatment Review'), + 'base' => 'node_content', + 'description' => '', + 'has_title' => '1', + 'title_label' => t('Title'), + 'help' => '', + ), + ); + drupal_alter('node_info', $items); + return $items; +} diff --git a/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.user_permission.inc b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.user_permission.inc new file mode 100644 index 0000000000..7ca9fe043e --- /dev/null +++ b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.features.user_permission.inc @@ -0,0 +1,399 @@ + 'create hiv_diagnostics content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'create hiv_encounter content'. + $permissions['create hiv_encounter content'] = array( + 'name' => 'create hiv_encounter content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'create hiv_follow_up content'. + $permissions['create hiv_follow_up content'] = array( + 'name' => 'create hiv_follow_up content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'create hiv_health_education content'. + $permissions['create hiv_health_education content'] = array( + 'name' => 'create hiv_health_education content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'create hiv_medication content'. + $permissions['create hiv_medication content'] = array( + 'name' => 'create hiv_medication content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'create hiv_referral content'. + $permissions['create hiv_referral content'] = array( + 'name' => 'create hiv_referral content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'create hiv_symptom_review content'. + $permissions['create hiv_symptom_review content'] = array( + 'name' => 'create hiv_symptom_review content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'create hiv_treatment_review content'. + $permissions['create hiv_treatment_review content'] = array( + 'name' => 'create hiv_treatment_review content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete any hiv_diagnostics content'. + $permissions['delete any hiv_diagnostics content'] = array( + 'name' => 'delete any hiv_diagnostics content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete any hiv_encounter content'. + $permissions['delete any hiv_encounter content'] = array( + 'name' => 'delete any hiv_encounter content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete any hiv_follow_up content'. + $permissions['delete any hiv_follow_up content'] = array( + 'name' => 'delete any hiv_follow_up content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete any hiv_health_education content'. + $permissions['delete any hiv_health_education content'] = array( + 'name' => 'delete any hiv_health_education content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete any hiv_medication content'. + $permissions['delete any hiv_medication content'] = array( + 'name' => 'delete any hiv_medication content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete any hiv_referral content'. + $permissions['delete any hiv_referral content'] = array( + 'name' => 'delete any hiv_referral content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete any hiv_symptom_review content'. + $permissions['delete any hiv_symptom_review content'] = array( + 'name' => 'delete any hiv_symptom_review content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete any hiv_treatment_review content'. + $permissions['delete any hiv_treatment_review content'] = array( + 'name' => 'delete any hiv_treatment_review content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete own hiv_diagnostics content'. + $permissions['delete own hiv_diagnostics content'] = array( + 'name' => 'delete own hiv_diagnostics content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete own hiv_encounter content'. + $permissions['delete own hiv_encounter content'] = array( + 'name' => 'delete own hiv_encounter content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete own hiv_follow_up content'. + $permissions['delete own hiv_follow_up content'] = array( + 'name' => 'delete own hiv_follow_up content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete own hiv_health_education content'. + $permissions['delete own hiv_health_education content'] = array( + 'name' => 'delete own hiv_health_education content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete own hiv_medication content'. + $permissions['delete own hiv_medication content'] = array( + 'name' => 'delete own hiv_medication content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete own hiv_referral content'. + $permissions['delete own hiv_referral content'] = array( + 'name' => 'delete own hiv_referral content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete own hiv_symptom_review content'. + $permissions['delete own hiv_symptom_review content'] = array( + 'name' => 'delete own hiv_symptom_review content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'delete own hiv_treatment_review content'. + $permissions['delete own hiv_treatment_review content'] = array( + 'name' => 'delete own hiv_treatment_review content', + 'roles' => array( + 'administrator' => 'administrator', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit any hiv_diagnostics content'. + $permissions['edit any hiv_diagnostics content'] = array( + 'name' => 'edit any hiv_diagnostics content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit any hiv_encounter content'. + $permissions['edit any hiv_encounter content'] = array( + 'name' => 'edit any hiv_encounter content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit any hiv_follow_up content'. + $permissions['edit any hiv_follow_up content'] = array( + 'name' => 'edit any hiv_follow_up content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit any hiv_health_education content'. + $permissions['edit any hiv_health_education content'] = array( + 'name' => 'edit any hiv_health_education content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit any hiv_medication content'. + $permissions['edit any hiv_medication content'] = array( + 'name' => 'edit any hiv_medication content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit any hiv_referral content'. + $permissions['edit any hiv_referral content'] = array( + 'name' => 'edit any hiv_referral content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit any hiv_symptom_review content'. + $permissions['edit any hiv_symptom_review content'] = array( + 'name' => 'edit any hiv_symptom_review content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit any hiv_treatment_review content'. + $permissions['edit any hiv_treatment_review content'] = array( + 'name' => 'edit any hiv_treatment_review content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit own hiv_diagnostics content'. + $permissions['edit own hiv_diagnostics content'] = array( + 'name' => 'edit own hiv_diagnostics content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit own hiv_encounter content'. + $permissions['edit own hiv_encounter content'] = array( + 'name' => 'edit own hiv_encounter content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit own hiv_follow_up content'. + $permissions['edit own hiv_follow_up content'] = array( + 'name' => 'edit own hiv_follow_up content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit own hiv_health_education content'. + $permissions['edit own hiv_health_education content'] = array( + 'name' => 'edit own hiv_health_education content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit own hiv_medication content'. + $permissions['edit own hiv_medication content'] = array( + 'name' => 'edit own hiv_medication content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit own hiv_referral content'. + $permissions['edit own hiv_referral content'] = array( + 'name' => 'edit own hiv_referral content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit own hiv_symptom_review content'. + $permissions['edit own hiv_symptom_review content'] = array( + 'name' => 'edit own hiv_symptom_review content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + // Exported permission: 'edit own hiv_treatment_review content'. + $permissions['edit own hiv_treatment_review content'] = array( + 'name' => 'edit own hiv_treatment_review content', + 'roles' => array( + 'administrator' => 'administrator', + 'sync' => 'sync', + ), + 'module' => 'node', + ); + + return $permissions; +} diff --git a/server/hedley/modules/custom/hedley_hiv/hedley_hiv.info b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.info new file mode 100644 index 0000000000..29606d9fa5 --- /dev/null +++ b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.info @@ -0,0 +1,203 @@ +name = Hedley HIV +description = HIV related code +core = 7.x +package = Hedley +dependencies[] = ctools +dependencies[] = date +dependencies[] = entityreference +dependencies[] = features +dependencies[] = hedley_device +dependencies[] = hedley_schedule +dependencies[] = node +dependencies[] = strongarm +dependencies[] = text +features[ctools][] = strongarm:strongarm:1 +features[features_api][] = api:2 +features[field_base][] = field_hiv_diagnosis_signs +features[field_base][] = field_hiv_encounter +features[field_base][] = field_hiv_health_education_signs +features[field_base][] = field_hiv_symptoms +features[field_base][] = field_positive_result_date +features[field_base][] = field_prescribed_hiv_medications +features[field_instance][] = node-hiv_diagnostics-field_date_measured +features[field_instance][] = node-hiv_diagnostics-field_hiv_diagnosis_signs +features[field_instance][] = node-hiv_diagnostics-field_hiv_encounter +features[field_instance][] = node-hiv_diagnostics-field_nurse +features[field_instance][] = node-hiv_diagnostics-field_person +features[field_instance][] = node-hiv_diagnostics-field_positive_result_date +features[field_instance][] = node-hiv_diagnostics-field_shards +features[field_instance][] = node-hiv_diagnostics-field_uuid +features[field_instance][] = node-hiv_encounter-field_individual_participant +features[field_instance][] = node-hiv_encounter-field_scheduled_date +features[field_instance][] = node-hiv_encounter-field_shards +features[field_instance][] = node-hiv_encounter-field_uuid +features[field_instance][] = node-hiv_follow_up-field_date_concluded +features[field_instance][] = node-hiv_follow_up-field_date_measured +features[field_instance][] = node-hiv_follow_up-field_follow_up_options +features[field_instance][] = node-hiv_follow_up-field_hiv_encounter +features[field_instance][] = node-hiv_follow_up-field_nurse +features[field_instance][] = node-hiv_follow_up-field_person +features[field_instance][] = node-hiv_follow_up-field_shards +features[field_instance][] = node-hiv_follow_up-field_uuid +features[field_instance][] = node-hiv_health_education-field_date_measured +features[field_instance][] = node-hiv_health_education-field_hiv_encounter +features[field_instance][] = node-hiv_health_education-field_hiv_health_education_signs +features[field_instance][] = node-hiv_health_education-field_nurse +features[field_instance][] = node-hiv_health_education-field_person +features[field_instance][] = node-hiv_health_education-field_shards +features[field_instance][] = node-hiv_health_education-field_uuid +features[field_instance][] = node-hiv_medication-field_date_measured +features[field_instance][] = node-hiv_medication-field_hiv_encounter +features[field_instance][] = node-hiv_medication-field_nurse +features[field_instance][] = node-hiv_medication-field_person +features[field_instance][] = node-hiv_medication-field_prescribed_hiv_medications +features[field_instance][] = node-hiv_medication-field_shards +features[field_instance][] = node-hiv_medication-field_uuid +features[field_instance][] = node-hiv_referral-field_date_measured +features[field_instance][] = node-hiv_referral-field_hiv_encounter +features[field_instance][] = node-hiv_referral-field_nurse +features[field_instance][] = node-hiv_referral-field_person +features[field_instance][] = node-hiv_referral-field_reason_not_sent_to_hc +features[field_instance][] = node-hiv_referral-field_send_to_hc +features[field_instance][] = node-hiv_referral-field_shards +features[field_instance][] = node-hiv_referral-field_uuid +features[field_instance][] = node-hiv_symptom_review-field_date_measured +features[field_instance][] = node-hiv_symptom_review-field_hiv_encounter +features[field_instance][] = node-hiv_symptom_review-field_hiv_symptoms +features[field_instance][] = node-hiv_symptom_review-field_nurse +features[field_instance][] = node-hiv_symptom_review-field_person +features[field_instance][] = node-hiv_symptom_review-field_shards +features[field_instance][] = node-hiv_symptom_review-field_uuid +features[field_instance][] = node-hiv_treatment_review-field_adverse_events +features[field_instance][] = node-hiv_treatment_review-field_date_measured +features[field_instance][] = node-hiv_treatment_review-field_hiv_encounter +features[field_instance][] = node-hiv_treatment_review-field_missed_doses +features[field_instance][] = node-hiv_treatment_review-field_nurse +features[field_instance][] = node-hiv_treatment_review-field_person +features[field_instance][] = node-hiv_treatment_review-field_reason_for_not_taking +features[field_instance][] = node-hiv_treatment_review-field_shards +features[field_instance][] = node-hiv_treatment_review-field_treatment_ongoing +features[field_instance][] = node-hiv_treatment_review-field_uuid +features[node][] = hiv_diagnostics +features[node][] = hiv_encounter +features[node][] = hiv_follow_up +features[node][] = hiv_health_education +features[node][] = hiv_medication +features[node][] = hiv_referral +features[node][] = hiv_symptom_review +features[node][] = hiv_treatment_review +features[user_permission][] = create hiv_diagnostics content +features[user_permission][] = create hiv_encounter content +features[user_permission][] = create hiv_follow_up content +features[user_permission][] = create hiv_health_education content +features[user_permission][] = create hiv_medication content +features[user_permission][] = create hiv_referral content +features[user_permission][] = create hiv_symptom_review content +features[user_permission][] = create hiv_treatment_review content +features[user_permission][] = delete any hiv_diagnostics content +features[user_permission][] = delete any hiv_encounter content +features[user_permission][] = delete any hiv_follow_up content +features[user_permission][] = delete any hiv_health_education content +features[user_permission][] = delete any hiv_medication content +features[user_permission][] = delete any hiv_referral content +features[user_permission][] = delete any hiv_symptom_review content +features[user_permission][] = delete any hiv_treatment_review content +features[user_permission][] = delete own hiv_diagnostics content +features[user_permission][] = delete own hiv_encounter content +features[user_permission][] = delete own hiv_follow_up content +features[user_permission][] = delete own hiv_health_education content +features[user_permission][] = delete own hiv_medication content +features[user_permission][] = delete own hiv_referral content +features[user_permission][] = delete own hiv_symptom_review content +features[user_permission][] = delete own hiv_treatment_review content +features[user_permission][] = edit any hiv_diagnostics content +features[user_permission][] = edit any hiv_encounter content +features[user_permission][] = edit any hiv_follow_up content +features[user_permission][] = edit any hiv_health_education content +features[user_permission][] = edit any hiv_medication content +features[user_permission][] = edit any hiv_referral content +features[user_permission][] = edit any hiv_symptom_review content +features[user_permission][] = edit any hiv_treatment_review content +features[user_permission][] = edit own hiv_diagnostics content +features[user_permission][] = edit own hiv_encounter content +features[user_permission][] = edit own hiv_follow_up content +features[user_permission][] = edit own hiv_health_education content +features[user_permission][] = edit own hiv_medication content +features[user_permission][] = edit own hiv_referral content +features[user_permission][] = edit own hiv_symptom_review content +features[user_permission][] = edit own hiv_treatment_review content +features[variable][] = auto_entitylabel_node_hiv_diagnostics +features[variable][] = auto_entitylabel_node_hiv_encounter +features[variable][] = auto_entitylabel_node_hiv_follow_up +features[variable][] = auto_entitylabel_node_hiv_health_education +features[variable][] = auto_entitylabel_node_hiv_medication +features[variable][] = auto_entitylabel_node_hiv_referral +features[variable][] = auto_entitylabel_node_hiv_symptom_review +features[variable][] = auto_entitylabel_node_hiv_treatment_review +features[variable][] = auto_entitylabel_pattern_node_hiv_diagnostics +features[variable][] = auto_entitylabel_pattern_node_hiv_encounter +features[variable][] = auto_entitylabel_pattern_node_hiv_follow_up +features[variable][] = auto_entitylabel_pattern_node_hiv_health_education +features[variable][] = auto_entitylabel_pattern_node_hiv_medication +features[variable][] = auto_entitylabel_pattern_node_hiv_referral +features[variable][] = auto_entitylabel_pattern_node_hiv_symptom_review +features[variable][] = auto_entitylabel_pattern_node_hiv_treatment_review +features[variable][] = auto_entitylabel_php_node_hiv_diagnostics +features[variable][] = auto_entitylabel_php_node_hiv_encounter +features[variable][] = auto_entitylabel_php_node_hiv_follow_up +features[variable][] = auto_entitylabel_php_node_hiv_health_education +features[variable][] = auto_entitylabel_php_node_hiv_medication +features[variable][] = auto_entitylabel_php_node_hiv_referral +features[variable][] = auto_entitylabel_php_node_hiv_symptom_review +features[variable][] = auto_entitylabel_php_node_hiv_treatment_review +features[variable][] = field_bundle_settings_node__hiv_diagnostics +features[variable][] = field_bundle_settings_node__hiv_encounter +features[variable][] = field_bundle_settings_node__hiv_follow_up +features[variable][] = field_bundle_settings_node__hiv_health_education +features[variable][] = field_bundle_settings_node__hiv_medication +features[variable][] = field_bundle_settings_node__hiv_referral +features[variable][] = field_bundle_settings_node__hiv_symptom_review +features[variable][] = field_bundle_settings_node__hiv_treatment_review +features[variable][] = menu_options_hiv_diagnostics +features[variable][] = menu_options_hiv_encounter +features[variable][] = menu_options_hiv_follow_up +features[variable][] = menu_options_hiv_health_education +features[variable][] = menu_options_hiv_medication +features[variable][] = menu_options_hiv_referral +features[variable][] = menu_options_hiv_symptom_review +features[variable][] = menu_options_hiv_treatment_review +features[variable][] = menu_parent_hiv_diagnostics +features[variable][] = menu_parent_hiv_encounter +features[variable][] = menu_parent_hiv_follow_up +features[variable][] = menu_parent_hiv_health_education +features[variable][] = menu_parent_hiv_medication +features[variable][] = menu_parent_hiv_referral +features[variable][] = menu_parent_hiv_symptom_review +features[variable][] = menu_parent_hiv_treatment_review +features[variable][] = node_options_hiv_diagnostics +features[variable][] = node_options_hiv_encounter +features[variable][] = node_options_hiv_follow_up +features[variable][] = node_options_hiv_health_education +features[variable][] = node_options_hiv_medication +features[variable][] = node_options_hiv_referral +features[variable][] = node_options_hiv_symptom_review +features[variable][] = node_options_hiv_treatment_review +features[variable][] = node_preview_hiv_diagnostics +features[variable][] = node_preview_hiv_encounter +features[variable][] = node_preview_hiv_follow_up +features[variable][] = node_preview_hiv_health_education +features[variable][] = node_preview_hiv_medication +features[variable][] = node_preview_hiv_referral +features[variable][] = node_preview_hiv_symptom_review +features[variable][] = node_preview_hiv_treatment_review +features[variable][] = node_submitted_hiv_diagnostics +features[variable][] = node_submitted_hiv_encounter +features[variable][] = node_submitted_hiv_follow_up +features[variable][] = node_submitted_hiv_health_education +features[variable][] = node_submitted_hiv_medication +features[variable][] = node_submitted_hiv_referral +features[variable][] = node_submitted_hiv_symptom_review +features[variable][] = node_submitted_hiv_treatment_review +features_exclude[dependencies][list] = list +features_exclude[dependencies][number] = number +features_exclude[dependencies][options] = options diff --git a/server/hedley/modules/custom/hedley_hiv/hedley_hiv.module b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.module new file mode 100644 index 0000000000..8813539822 --- /dev/null +++ b/server/hedley/modules/custom/hedley_hiv/hedley_hiv.module @@ -0,0 +1,8 @@ +disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_node_hiv_diagnostics'; + $strongarm->value = '1'; + $export['auto_entitylabel_node_hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_node_hiv_encounter'; + $strongarm->value = '1'; + $export['auto_entitylabel_node_hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_node_hiv_follow_up'; + $strongarm->value = '1'; + $export['auto_entitylabel_node_hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_node_hiv_health_education'; + $strongarm->value = '1'; + $export['auto_entitylabel_node_hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_node_hiv_medication'; + $strongarm->value = '1'; + $export['auto_entitylabel_node_hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_node_hiv_referral'; + $strongarm->value = '1'; + $export['auto_entitylabel_node_hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_node_hiv_symptom_review'; + $strongarm->value = '1'; + $export['auto_entitylabel_node_hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_node_hiv_treatment_review'; + $strongarm->value = '1'; + $export['auto_entitylabel_node_hiv_treatment_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_pattern_node_hiv_diagnostics'; + $strongarm->value = '[node:content-type] - [node:field-person:title] - [node:field-date-measured:custom:Y-m-d] '; + $export['auto_entitylabel_pattern_node_hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_pattern_node_hiv_encounter'; + $strongarm->value = '[node:content-type] - [node:field-individual-participant:title] - [node:field-scheduled-date:value:custom:Y-m-d]'; + $export['auto_entitylabel_pattern_node_hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_pattern_node_hiv_follow_up'; + $strongarm->value = '[node:content-type] - [node:field-person:title] - [node:field-date-measured:custom:Y-m-d] '; + $export['auto_entitylabel_pattern_node_hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_pattern_node_hiv_health_education'; + $strongarm->value = '[node:content-type] - [node:field-person:title] - [node:field-date-measured:custom:Y-m-d] '; + $export['auto_entitylabel_pattern_node_hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_pattern_node_hiv_medication'; + $strongarm->value = '[node:content-type] - [node:field-person:title] - [node:field-date-measured:custom:Y-m-d] '; + $export['auto_entitylabel_pattern_node_hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_pattern_node_hiv_referral'; + $strongarm->value = '[node:content-type] - [node:field-person:title] - [node:field-date-measured:custom:Y-m-d] '; + $export['auto_entitylabel_pattern_node_hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_pattern_node_hiv_symptom_review'; + $strongarm->value = '[node:content-type] - [node:field-person:title] - [node:field-date-measured:custom:Y-m-d] '; + $export['auto_entitylabel_pattern_node_hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_pattern_node_hiv_treatment_review'; + $strongarm->value = '[node:content-type] - [node:field-person:title] - [node:field-date-measured:custom:Y-m-d] '; + $export['auto_entitylabel_pattern_node_hiv_treatment_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_php_node_hiv_diagnostics'; + $strongarm->value = 0; + $export['auto_entitylabel_php_node_hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_php_node_hiv_encounter'; + $strongarm->value = 0; + $export['auto_entitylabel_php_node_hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_php_node_hiv_follow_up'; + $strongarm->value = 0; + $export['auto_entitylabel_php_node_hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_php_node_hiv_health_education'; + $strongarm->value = 0; + $export['auto_entitylabel_php_node_hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_php_node_hiv_medication'; + $strongarm->value = 0; + $export['auto_entitylabel_php_node_hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_php_node_hiv_referral'; + $strongarm->value = 0; + $export['auto_entitylabel_php_node_hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_php_node_hiv_symptom_review'; + $strongarm->value = 0; + $export['auto_entitylabel_php_node_hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'auto_entitylabel_php_node_hiv_treatment_review'; + $strongarm->value = 0; + $export['auto_entitylabel_php_node_hiv_treatment_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_node__hiv_diagnostics'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array( + 'title' => array( + 'weight' => '0', + ), + ), + 'display' => array(), + ), + ); + $export['field_bundle_settings_node__hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_node__hiv_encounter'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array( + 'title' => array( + 'weight' => '-5', + ), + ), + 'display' => array(), + ), + ); + $export['field_bundle_settings_node__hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_node__hiv_follow_up'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array( + 'title' => array( + 'weight' => '-5', + ), + ), + 'display' => array(), + ), + ); + $export['field_bundle_settings_node__hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_node__hiv_health_education'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array( + 'title' => array( + 'weight' => '-5', + ), + ), + 'display' => array(), + ), + ); + $export['field_bundle_settings_node__hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_node__hiv_medication'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array( + 'title' => array( + 'weight' => '-5', + ), + ), + 'display' => array(), + ), + ); + $export['field_bundle_settings_node__hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_node__hiv_referral'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array( + 'title' => array( + 'weight' => '-5', + ), + ), + 'display' => array(), + ), + ); + $export['field_bundle_settings_node__hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_node__hiv_symptom_review'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array( + 'title' => array( + 'weight' => '-5', + ), + ), + 'display' => array(), + ), + ); + $export['field_bundle_settings_node__hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'field_bundle_settings_node__hiv_treatment_review'; + $strongarm->value = array( + 'view_modes' => array(), + 'extra_fields' => array( + 'form' => array( + 'title' => array( + 'weight' => '-5', + ), + ), + 'display' => array(), + ), + ); + $export['field_bundle_settings_node__hiv_treatment_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_options_hiv_diagnostics'; + $strongarm->value = array( + 0 => 'main-menu', + ); + $export['menu_options_hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_options_hiv_encounter'; + $strongarm->value = array( + 0 => 'main-menu', + ); + $export['menu_options_hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_options_hiv_follow_up'; + $strongarm->value = array( + 0 => 'main-menu', + ); + $export['menu_options_hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_options_hiv_health_education'; + $strongarm->value = array( + 0 => 'main-menu', + ); + $export['menu_options_hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_options_hiv_medication'; + $strongarm->value = array( + 0 => 'main-menu', + ); + $export['menu_options_hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_options_hiv_referral'; + $strongarm->value = array( + 0 => 'main-menu', + ); + $export['menu_options_hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_options_hiv_symptom_review'; + $strongarm->value = array( + 0 => 'main-menu', + ); + $export['menu_options_hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_options_hiv_treatment_review'; + $strongarm->value = array( + 0 => 'main-menu', + ); + $export['menu_options_hiv_treatment_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_parent_hiv_diagnostics'; + $strongarm->value = 'main-menu:0'; + $export['menu_parent_hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_parent_hiv_encounter'; + $strongarm->value = 'main-menu:0'; + $export['menu_parent_hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_parent_hiv_follow_up'; + $strongarm->value = 'main-menu:0'; + $export['menu_parent_hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_parent_hiv_health_education'; + $strongarm->value = 'main-menu:0'; + $export['menu_parent_hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_parent_hiv_medication'; + $strongarm->value = 'main-menu:0'; + $export['menu_parent_hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_parent_hiv_referral'; + $strongarm->value = 'main-menu:0'; + $export['menu_parent_hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_parent_hiv_symptom_review'; + $strongarm->value = 'main-menu:0'; + $export['menu_parent_hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'menu_parent_hiv_treatment_review'; + $strongarm->value = 'main-menu:0'; + $export['menu_parent_hiv_treatment_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_options_hiv_diagnostics'; + $strongarm->value = array( + 0 => 'status', + 1 => 'promote', + ); + $export['node_options_hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_options_hiv_encounter'; + $strongarm->value = array( + 0 => 'status', + 1 => 'promote', + ); + $export['node_options_hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_options_hiv_follow_up'; + $strongarm->value = array( + 0 => 'status', + 1 => 'promote', + ); + $export['node_options_hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_options_hiv_health_education'; + $strongarm->value = array( + 0 => 'status', + 1 => 'promote', + ); + $export['node_options_hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_options_hiv_medication'; + $strongarm->value = array( + 0 => 'status', + 1 => 'promote', + ); + $export['node_options_hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_options_hiv_referral'; + $strongarm->value = array( + 0 => 'status', + 1 => 'promote', + ); + $export['node_options_hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_options_hiv_symptom_review'; + $strongarm->value = array( + 0 => 'status', + 1 => 'promote', + ); + $export['node_options_hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_options_hiv_treatment_review'; + $strongarm->value = array( + 0 => 'status', + 1 => 'promote', + ); + $export['node_options_hiv_treatment_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_preview_hiv_diagnostics'; + $strongarm->value = '1'; + $export['node_preview_hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_preview_hiv_encounter'; + $strongarm->value = '1'; + $export['node_preview_hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_preview_hiv_follow_up'; + $strongarm->value = '1'; + $export['node_preview_hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_preview_hiv_health_education'; + $strongarm->value = '1'; + $export['node_preview_hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_preview_hiv_medication'; + $strongarm->value = '1'; + $export['node_preview_hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_preview_hiv_referral'; + $strongarm->value = '1'; + $export['node_preview_hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_preview_hiv_symptom_review'; + $strongarm->value = '1'; + $export['node_preview_hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_preview_hiv_treatment_review'; + $strongarm->value = '1'; + $export['node_preview_hiv_treatment_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_submitted_hiv_diagnostics'; + $strongarm->value = 1; + $export['node_submitted_hiv_diagnostics'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_submitted_hiv_encounter'; + $strongarm->value = 1; + $export['node_submitted_hiv_encounter'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_submitted_hiv_follow_up'; + $strongarm->value = 1; + $export['node_submitted_hiv_follow_up'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_submitted_hiv_health_education'; + $strongarm->value = 1; + $export['node_submitted_hiv_health_education'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_submitted_hiv_medication'; + $strongarm->value = 1; + $export['node_submitted_hiv_medication'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_submitted_hiv_referral'; + $strongarm->value = 1; + $export['node_submitted_hiv_referral'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_submitted_hiv_symptom_review'; + $strongarm->value = 1; + $export['node_submitted_hiv_symptom_review'] = $strongarm; + + $strongarm = new stdClass(); + $strongarm->disabled = FALSE; /* Edit this to true to make a default strongarm disabled initially */ + $strongarm->api_version = 1; + $strongarm->name = 'node_submitted_hiv_treatment_review'; + $strongarm->value = 1; + $export['node_submitted_hiv_treatment_review'] = $strongarm; + + return $export; +} diff --git a/server/hedley/modules/custom/hedley_restful/hedley_restful.info b/server/hedley/modules/custom/hedley_restful/hedley_restful.info index 2c394d8093..7e2c6c8989 100644 --- a/server/hedley/modules/custom/hedley_restful/hedley_restful.info +++ b/server/hedley/modules/custom/hedley_restful/hedley_restful.info @@ -15,6 +15,7 @@ files[] = plugins/restful/node/activity/HedleyRestfulHomeVisitActivityBase.class files[] = plugins/restful/node/activity/HedleyRestfulWellChildActivityBase.class.php files[] = plugins/restful/node/activity/HedleyRestfulChildScoreboardActivityBase.class.php files[] = plugins/restful/node/activity/HedleyRestfulTuberculosisActivityBase.class.php +files[] = plugins/restful/node/activity/HedleyRestfulHIVActivityBase.class.php files[] = plugins/restful/node/HedleyRestfulEntityBaseNode.php files[] = plugins/restful/node/HedleyRestfulSyncBase.class.php diff --git a/server/hedley/modules/custom/hedley_restful/hedley_restful.module b/server/hedley/modules/custom/hedley_restful/hedley_restful.module index d55f4c96bb..cb35952c09 100644 --- a/server/hedley/modules/custom/hedley_restful/hedley_restful.module +++ b/server/hedley/modules/custom/hedley_restful/hedley_restful.module @@ -5,7 +5,7 @@ * Code for the RESTful integration. */ -define('HEDLEY_RESTFUL_CLIENT_SIDE_INDEXEDDB_SCHEMA_VERSION', 24); +define('HEDLEY_RESTFUL_CLIENT_SIDE_INDEXEDDB_SCHEMA_VERSION', 26); define('HEDLEY_RESTFUL_INCIDENT_TYPE_CONTENT_UPLOAD', 'content-upload'); /** @@ -44,6 +44,7 @@ const HEDLEY_RESTFUL_SHARDED = [ 'child_scoreboard_encounter' => 'child-scoreboard-encounter', 'clinic' => 'clinics', 'education_session' => 'education-session', + 'hiv_encounter' => 'hiv-encounter', 'home_visit_encounter' => 'home-visit-encounter', 'individual_participant' => 'individual-participants', 'ncd_encounter' => 'ncd-encounter', @@ -94,6 +95,13 @@ const HEDLEY_RESTFUL_SHARDED = [ 'health_education' => 'health-education', 'hc_contact' => 'hc-contacts', 'height' => 'heights', + 'hiv_diagnostics' => 'hiv-diagnostics', + 'hiv_follow_up' => 'hiv-follow-up', + 'hiv_health_education' => 'hiv-health-education', + 'hiv_medication' => 'hiv-medication', + 'hiv_referral' => 'hiv-referral', + 'hiv_symptom_review' => 'hiv-symptom-review', + 'hiv_treatment_review' => 'hiv-treatment-review', 'isolation' => 'isolations', 'lactation' => 'lactations', 'last_menstrual_period' => 'last-menstrual-periods', diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulReportIncidentDetails.class.php b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulReportIncidentDetails.class.php new file mode 100644 index 0000000000..8121ee0736 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulReportIncidentDetails.class.php @@ -0,0 +1,63 @@ + [ + \RestfulInterface::POST => 'processReport', + ], + '^.*$' => [ + // We do not allow any calls here. + ], + ]; + } + + /** + * Implements \RestfulInterface::publicFieldsInfo(). + */ + public function publicFieldsInfo() { + return []; + } + + /** + * Records device state data reported by clients. + * + * @return array + * We don't need to return anything, so we return an empty array. + * + * @throws \EntityMetadataWrapperException + * @throws \RestfulBadRequestException + */ + public function processReport() { + $request = $this->getRequest(); + $account = $this->getAccount(); + + $details = $request['incident_details']; + if (empty($details)) { + throw new RestfulBadRequestException('Must provide incident details.'); + } + + $wrapper = entity_metadata_wrapper('user', $account->uid); + $current_details = $wrapper->field_incident_details->value(); + + if ($current_details !== $details) { + $wrapper->field_incident_details->set($details); + $wrapper->save(); + } + + return []; + } + +} diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulSync.class.php b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulSync.class.php index f4b477663c..422d907711 100644 --- a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulSync.class.php +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulSync.class.php @@ -179,6 +179,7 @@ public function getForAllDevices() { 'stock_management', 'tuberculosis_management', 'group_education', + 'hiv_management', ]; $enabled_features = array_filter( $available_features, @@ -390,6 +391,7 @@ public function handleChanges() { 'execution_date', 'resilience_start_date', 'expiration_date', + 'positive_result_date', ]; $multiDateFields = [ 'administration_dates', diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/HedleyRestfulHIVActivityBase.class.php b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/HedleyRestfulHIVActivityBase.class.php new file mode 100644 index 0000000000..73462d2f58 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/HedleyRestfulHIVActivityBase.class.php @@ -0,0 +1,54 @@ + 'field_hiv_encounter', + 'sub_property' => 'field_uuid', + ]; + + return $public_fields; + } + + /** + * {@inheritdoc} + */ + protected function alterQueryForViewWithDbSelect(SelectQuery $query) { + $query = parent::alterQueryForViewWithDbSelect($query); + + hedley_general_join_field_to_query($query, 'node', 'field_hiv_encounter', FALSE); + // Get the UUID of the HIV encounter. + hedley_general_join_field_to_query($query, 'node', 'field_uuid', FALSE, "field_hiv_encounter.field_hiv_encounter_target_id", 'uuid_hiv_encounter'); + + return $query; + } + + /** + * {@inheritdoc} + */ + protected function postExecuteQueryForViewWithDbSelect(array $items = []) { + $items = parent::postExecuteQueryForViewWithDbSelect($items); + + foreach ($items as &$item) { + $item->hiv_encounter = $item->uuid_hiv_encounter; + unset($item->uuid_hiv_encounter); + } + + return $items; + } + +} diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/HedleyRestfulHIVDiagnostics.class.php b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/HedleyRestfulHIVDiagnostics.class.php new file mode 100644 index 0000000000..57ad940636 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/HedleyRestfulHIVDiagnostics.class.php @@ -0,0 +1,34 @@ + t('HIV Diagnostics'), + 'resource' => 'hiv-diagnostics', + 'name' => 'hiv-diagnostics', + 'entity_type' => 'node', + 'bundle' => 'hiv_diagnostics', + 'description' => t('Exports the HIV Diagnostics bundle.'), + 'class' => 'HedleyRestfulHIVDiagnostics', + 'authentication_types' => TRUE, +); diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-follow-up.inc b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-follow-up.inc new file mode 100644 index 0000000000..e035697226 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-follow-up.inc @@ -0,0 +1,17 @@ + t('HIV Follow Up'), + 'resource' => 'hiv-follow-up', + 'name' => 'hiv-follow-up', + 'entity_type' => 'node', + 'bundle' => 'hiv_follow_up', + 'description' => t('Exports the HIV Follow Up bundle.'), + 'class' => 'HedleyRestfulHIVFollowUp', + 'authentication_types' => TRUE, +); diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-health-education.inc b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-health-education.inc new file mode 100644 index 0000000000..98264c8a99 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-health-education.inc @@ -0,0 +1,17 @@ + t('HIV Health Education'), + 'resource' => 'hiv-health-education', + 'name' => 'hiv-health-education', + 'entity_type' => 'node', + 'bundle' => 'hiv_health_education', + 'description' => t('Exports the HIV Health Education bundle.'), + 'class' => 'HedleyRestfulHIVHealthEducation', + 'authentication_types' => TRUE, +); diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-medication.inc b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-medication.inc new file mode 100644 index 0000000000..814d1b1fa0 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-medication.inc @@ -0,0 +1,17 @@ + t('HIV Medication'), + 'resource' => 'hiv-medication', + 'name' => 'hiv-medication', + 'entity_type' => 'node', + 'bundle' => 'hiv_medication', + 'description' => t('Exports the HIV Medication bundle.'), + 'class' => 'HedleyRestfulHIVMedication', + 'authentication_types' => TRUE, +); diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-referral.inc b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-referral.inc new file mode 100644 index 0000000000..756520e699 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-referral.inc @@ -0,0 +1,17 @@ + t('HIV Referral'), + 'resource' => 'hiv-referral', + 'name' => 'hiv-referral', + 'entity_type' => 'node', + 'bundle' => 'hiv_referral', + 'description' => t('Exports the HIV Referral bundle.'), + 'class' => 'HedleyRestfulHIVReferral', + 'authentication_types' => TRUE, +); diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-symptom-review.inc b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-symptom-review.inc new file mode 100644 index 0000000000..23c3aa3d3d --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-symptom-review.inc @@ -0,0 +1,17 @@ + t('HIV Symptom Review'), + 'resource' => 'hiv-symptom-review', + 'name' => 'hiv-symptom-review', + 'entity_type' => 'node', + 'bundle' => 'hiv_symptom_review', + 'description' => t('Exports the HIV Symptom Review bundle.'), + 'class' => 'HedleyRestfulHIVSymptomReview', + 'authentication_types' => TRUE, +); diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-treatment-review.inc b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-treatment-review.inc new file mode 100644 index 0000000000..f2140f32b1 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/activity/hiv-treatment-review.inc @@ -0,0 +1,17 @@ + t('HIV Treatment Review'), + 'resource' => 'hiv-treatment-review', + 'name' => 'hiv-treatment-review', + 'entity_type' => 'node', + 'bundle' => 'hiv_treatment_review', + 'description' => t('Exports the HIV Treatment Review bundle.'), + 'class' => 'HedleyRestfulHIVTreatmentReview', + 'authentication_types' => TRUE, +); diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/hiv-encounter.inc b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/hiv-encounter.inc new file mode 100644 index 0000000000..7c5f30135a --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/hiv-encounter.inc @@ -0,0 +1,17 @@ + t('HIV encounter'), + 'resource' => 'hiv-encounter', + 'name' => 'hiv-encounter', + 'entity_type' => 'node', + 'bundle' => 'hiv_encounter', + 'description' => t('Exports the HIV Encounter bundle.'), + 'class' => 'HedleyRestfulIndividualEncounter', + 'authentication_types' => TRUE, +); diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/report-incident-details.inc b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/report-incident-details.inc new file mode 100644 index 0000000000..1206242fe0 --- /dev/null +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/report-incident-details.inc @@ -0,0 +1,15 @@ + t('Device State Report'), + 'resource' => 'report-incident-details', + 'name' => 'report-incident-details', + 'description' => t('Processes and records incident details sent by device'), + 'class' => 'HedleyRestfulReportIncidentDetails', + 'authentication_types' => ['token'], +); diff --git a/server/hedley/modules/custom/hedley_schedule/hedley_schedule.features.field_base.inc b/server/hedley/modules/custom/hedley_schedule/hedley_schedule.features.field_base.inc index bd4a81733a..43235ef586 100644 --- a/server/hedley/modules/custom/hedley_schedule/hedley_schedule.features.field_base.inc +++ b/server/hedley/modules/custom/hedley_schedule/hedley_schedule.features.field_base.inc @@ -238,12 +238,13 @@ function hedley_schedule_field_default_field_bases() { 'acute-illness' => 'Acute Illness', 'antenatal' => 'Antenatal', 'child-scoreboard' => 'Child Scoreboard', + 'hiv' => 'HIV', 'home-visit' => 'Home visit', - 'inmmunization' => 'Inmmunization', 'ncd' => 'NCD', 'nutrition' => 'Nutrition', 'tuberculosis' => 'Tuberculosis', 'well-child' => 'Well Child', + 'inmmunization' => 'Inmmunization', ), 'allowed_values_function' => '', ), @@ -496,7 +497,8 @@ function hedley_schedule_field_default_field_bases() { 'patient-died' => 'Patient Died', 'referred-to-hc' => 'Referred to Health Center', 'other' => 'Other', - 'not-diagnosed' => 'Not Diagnosed', + 'not-dignosed' => 'Tuberculosis Not Diagnosed', + 'hiv-not-dignosed' => 'HIV Not Diagnosed', ), 'allowed_values_function' => '', ), diff --git a/server/hedley/modules/custom/hedley_stats/hedley_stats.module b/server/hedley/modules/custom/hedley_stats/hedley_stats.module index f578598321..77b4542cd4 100644 --- a/server/hedley/modules/custom/hedley_stats/hedley_stats.module +++ b/server/hedley/modules/custom/hedley_stats/hedley_stats.module @@ -40,6 +40,7 @@ define('HEDLEY_STATS_SPV', 'sync_stats_spv'); define('HEDLEY_STATS_CHILD_SCOREBOARD', 'sync_stats_child_scoreboard'); define('HEDLEY_STATS_NUTRITION_INDIVIDUAL', 'sync_stats_nutrition_individual'); define('HEDLEY_STATS_NUTRITION_GROUP', 'sync_stats_nutrition_group'); +define('HEDLEY_STATS_GROUP_EDUCATION', 'sync_stats_group_education'); // Cache IDs. define('HEDLEY_STATS_SYNC_STATS_CACHE', 'sync_stats_general'); @@ -56,7 +57,9 @@ define('HEDLEY_STATS_SYNC_SPV_DATA', 'sync_spv_data'); define('HEDLEY_STATS_SYNC_CHILD_SCOREBOARD_DATA', 'sync_child_scoreboard_data'); define('HEDLEY_STATS_SYNC_NUTRITION_INDIVIDUAL_DATA', 'sync_nutrition_individual_data'); define('HEDLEY_STATS_SYNC_NUTRITION_GROUP_DATA', 'sync_nutrition_group_data'); +define('HEDLEY_STATS_SYNC_GROUP_EDUCATION_DATA', 'sync_group_education_data'); define('HEDLEY_STATS_SYNC_VILLAGES_WITH_RESIDENTS', 'villages_with_residents'); +define('HEDLEY_STATS_SYNC_PATIENTS_DETAILS', 'patients_details'); // Cache methods. define('HEDLEY_STATS_CACHE_GET', 'get'); @@ -174,6 +177,10 @@ function hedley_stats_requires_statistics_recalculation($node) { return HEDLEY_STATS_CHILD_SCOREBOARD; } + if (hedley_stats_requires_group_education_statistics_recalculation($wrapper)) { + return HEDLEY_STATS_GROUP_EDUCATION; + } + if (hedley_stats_requires_nutrition_individual_statistics_recalculation($wrapper)) { return HEDLEY_STATS_NUTRITION_INDIVIDUAL; } @@ -397,6 +404,25 @@ function hedley_stats_requires_child_scoreboard_statistics_recalculation($wrappe return FALSE; } +/** + * Checks if entity requires Group Education statistics recalculation. + * + * @param object $wrapper + * Entity metadata wrapper. + * + * @return bool + * True, if statistics recalculation is required. + */ +function hedley_stats_requires_group_education_statistics_recalculation($wrapper) { + $triggering_types = [ + HEDLEY_ACTIVITY_GROUP_EDUCATION_CONTENT_TYPE, + ]; + + $bundle = $wrapper->getBundle(); + + return in_array($bundle, $triggering_types); +} + /** * Checks if entity requires Individual Nutrition statistics recalculation. * @@ -509,6 +535,10 @@ function hedley_stats_clear_caches_for_health_center($nid, $cache_type_for_recal case HEDLEY_STATS_CHILD_SCOREBOARD: hedley_stats_handle_cache(HEDLEY_STATS_CACHE_CLEAR, HEDLEY_STATS_SYNC_CHILD_SCOREBOARD_DATA, $nid); return; + + case HEDLEY_STATS_GROUP_EDUCATION: + hedley_stats_handle_cache(HEDLEY_STATS_CACHE_CLEAR, HEDLEY_STATS_SYNC_GROUP_EDUCATION_DATA, $nid); + return; } if ($cache_type_for_recalculation == HEDLEY_STATS_NUTRITION_INDIVIDUAL) { @@ -615,13 +645,19 @@ function hedley_stats_calculate_stats_for_health_center($health_center_id) { // recalculation is completed). hedley_stats_handle_cache(HEDLEY_STATS_CACHE_CLEAR, HEDLEY_STATS_SYNC_STATS_CACHE, $health_center_id); + // Mapping of patient ID to name and optionally phone number. + $patients_details = []; + if ($cache_data = hedley_stats_handle_cache(HEDLEY_STATS_CACHE_GET, HEDLEY_STATS_SYNC_PATIENTS_DETAILS, $health_center_id)) { + $patients_details = $cache_data; + } + // Get all clinics of type 'FBF' for the HC. $clinics = hedley_health_center_get_clinics_of_health_center($health_center_id); // Calculate statistics that are provided for FBF clinics only. $fbf_clinics = !empty($clinics['fbf']) ? $clinics['fbf'] : []; - hedley_stats_get_session_attendance_stats_by_health_center($health_center_id, $fbf_clinics); - hedley_stats_get_case_management($health_center_id); - hedley_stats_get_children_beneficiaries_stats_by_period($health_center_id); + hedley_stats_get_session_attendance_stats_by_health_center($health_center_id, $fbf_clinics, $patients_details); + hedley_stats_get_case_management($health_center_id, $patients_details); + hedley_stats_get_children_beneficiaries_stats_by_period($health_center_id, $patients_details); hedley_stats_get_family_planning_stats_by_period($health_center_id, HEDLEY_STATS_PERIOD_PAST_THREE_MONTHS); $villages_with_residents = hedley_stats_get_villages_with_residents($health_center_id); hedley_stats_get_total_encounters($health_center_id, $villages_with_residents); @@ -634,6 +670,10 @@ function hedley_stats_calculate_stats_for_health_center($health_center_id) { hedley_stats_get_child_scorecard_data($health_center_id); hedley_stats_get_nutrition_individual_data($health_center_id); hedley_stats_get_nutrition_group_data($health_center_id); + hedley_stats_get_group_education_data($health_center_id, $patients_details); + + // Set (possibly altered) patients details in cache. + hedley_stats_handle_cache(HEDLEY_STATS_CACHE_SET, HEDLEY_STATS_SYNC_PATIENTS_DETAILS, $health_center_id, NULL, $patients_details); $stats_cache_hash = md5(time()); // Store in cache only the hash. All statistics have their own cache. @@ -748,6 +788,15 @@ function hedley_stats_pull_stats_for_health_center($health_center_id, $health_ce } $nutrition_group_data = $cache_data; + $cache_data = hedley_stats_handle_cache(HEDLEY_STATS_CACHE_GET, HEDLEY_STATS_SYNC_GROUP_EDUCATION_DATA, $health_center_id); + if ($cache_data === NULL) { + return []; + } + $group_education_data = $cache_data; + + $cache_data = hedley_stats_handle_cache(HEDLEY_STATS_CACHE_GET, HEDLEY_STATS_SYNC_PATIENTS_DETAILS, $health_center_id); + $patients_details = $cache_data === NULL ? [] : $cache_data; + $wrapper = entity_metadata_wrapper('node', $health_center_id); $health_center_uuid = $wrapper->field_uuid->value(); @@ -770,7 +819,9 @@ function hedley_stats_pull_stats_for_health_center($health_center_id, $health_ce 'child_scoreboard_data' => $child_scoreboard_data, 'nutrition_individual_data' => $nutrition_individual_data, 'nutrition_group_data' => $nutrition_group_data, + 'group_education_data' => $group_education_data, 'villages_with_residents' => $villages_with_residents, + 'patients_details' => $patients_details, ]; $now = time(); @@ -2116,6 +2167,96 @@ function hedley_stats_get_nutrition_group_data($health_center_id) { return $values; } +/** + * Return Group Education data which is used to generate statistics. + * + * We get data of all education sessions that were ran during past 6 months. + * + * @param int $health_center_id + * The health center node ID. + * @param array $patients_details + * Patients Details data structure that will be edited. + * + * @return array + * List of Education Sessions with topics and participants, by village. + * + * @throws Exception + */ +function hedley_stats_get_group_education_data($health_center_id, array &$patients_details) { + // Return the cache if exists. + if ($cache_data = hedley_stats_handle_cache(HEDLEY_STATS_CACHE_GET, HEDLEY_STATS_SYNC_GROUP_EDUCATION_DATA, $health_center_id)) { + return $cache_data; + } + + // Pull all Education Sessions over past 6 months, as dashboard presents + // data for past 6 months only. + $query = hedley_stats_get_base_query($health_center_id, 'education_session', HEDLEY_STATS_PERIOD_PAST_SIX_MONTHS); + // Resolve village UUID of the session. + $query->leftJoin('field_data_field_village_ref', 'vr', 'vr.entity_id = node.nid'); + $query->leftJoin('field_data_field_uuid', 'uuid', 'uuid.entity_id = vr.field_village_ref_target_id'); + $query->addField('uuid', 'field_uuid_value', 'village_uuid'); + // Resolve education topics. + $query->leftJoin('field_data_field_education_topics', 'et', 'et.entity_id = node.nid'); + $query->addField('et', 'field_education_topics_value'); + $query->addExpression("GROUP_CONCAT(DISTINCT et.field_education_topics_value)", 'education_topics'); + // Resolve participants. + $query->leftJoin('field_data_field_participating_patients', 'pp', 'pp.entity_id = node.nid'); + $query->addField('pp', 'field_participating_patients_target_id'); + $query->addExpression("GROUP_CONCAT(DISTINCT pp.field_participating_patients_target_id)", 'participating_patients'); + $query->groupBy('node.nid'); + + $result = $query + ->execute() + ->fetchAll(); + if (empty($result)) { + $result = []; + hedley_stats_handle_cache(HEDLEY_STATS_CACHE_SET, HEDLEY_STATS_SYNC_GROUP_EDUCATION_DATA, $health_center_id, NULL, $result); + return $result; + } + + $data = $patients_for_loading_details = []; + foreach ($result as $row) { + if (empty($row->education_topics)) { + // Session got no topics - skipping it. + continue; + } + + if (empty($row->participating_patients)) { + // Session got no participants - skipping it. + continue; + } + $participating_patients = explode(',', $row->participating_patients); + + $data[$row->village_uuid][] = [ + 'start_date' => date_format(date_create($row->field_scheduled_date), 'Y-m-d'), + 'education_topics' => explode(',', $row->education_topics), + 'participating_patients' => $participating_patients, + ]; + + // Resolve all patients we don't yet have details for. + foreach ($participating_patients as $patient_id) { + if (empty($patients_details[$patient_id])) { + $patients_for_loading_details[] = $patient_id; + } + } + } + + // Load details for patients. + foreach (array_chunk($patients_for_loading_details, 500) as $ids) { + $nodes = node_load_multiple($ids); + foreach ($nodes as $node) { + hedley_stats_add_patient_details($node, $patients_details); + } + // Free up memory. + drupal_static_reset(); + } + + // Store in cache. + hedley_stats_handle_cache(HEDLEY_STATS_CACHE_SET, HEDLEY_STATS_SYNC_GROUP_EDUCATION_DATA, $health_center_id, NULL, $data); + + return $data; +} + /** * Generates base query for Nutrition group data from single measurement type. * @@ -2157,6 +2298,8 @@ function hedley_stats_get_nutrition_group_query_for_bundle($health_center_id, ar * * @param int $health_center_id * The Health center node ID. + * @param array $patients_details + * Patients Details data structure that will be edited. * @param string $period * The period to calculate. By default, it is for one year. * @@ -2165,14 +2308,14 @@ function hedley_stats_get_nutrition_group_query_for_bundle($health_center_id, ar * * @throws \Exception */ -function hedley_stats_get_children_beneficiaries_stats_by_period($health_center_id, $period = HEDLEY_STATS_PERIOD_ONE_YEAR) { +function hedley_stats_get_children_beneficiaries_stats_by_period($health_center_id, array &$patients_details, $period = HEDLEY_STATS_PERIOD_ONE_YEAR) { // Return the cache if exists. if ($cache_data = hedley_stats_handle_cache(HEDLEY_STATS_CACHE_GET, HEDLEY_STATS_SYNC_CHILDREN_BENEFICIARIES, $health_center_id, $period)) { return $cache_data; } - $items = hedley_stats_get_children_beneficiaries_group_stats($health_center_id, $period); - $items['individual'] = hedley_stats_get_children_beneficiaries_individual_stats($health_center_id); + $items = hedley_stats_get_children_beneficiaries_group_stats($health_center_id, $patients_details, $period); + $items['individual'] = hedley_stats_get_children_beneficiaries_individual_stats($health_center_id, $patients_details); // Store in cache. hedley_stats_handle_cache(HEDLEY_STATS_CACHE_SET, HEDLEY_STATS_SYNC_CHILDREN_BENEFICIARIES, $health_center_id, $period, $items); @@ -2185,6 +2328,8 @@ function hedley_stats_get_children_beneficiaries_stats_by_period($health_center_ * * @param int $health_center_id * The Health center node ID. + * @param array $patients_details + * Patients Details data structure that will be edited. * @param string $period * The period to calculate. By default it is for one year. * @@ -2193,7 +2338,7 @@ function hedley_stats_get_children_beneficiaries_stats_by_period($health_center_ * * @throws \Exception */ -function hedley_stats_get_children_beneficiaries_group_stats($health_center_id, $period = HEDLEY_STATS_PERIOD_ONE_YEAR) { +function hedley_stats_get_children_beneficiaries_group_stats($health_center_id, array &$patients_details, $period = HEDLEY_STATS_PERIOD_ONE_YEAR) { $query = hedley_stats_get_base_query($health_center_id, 'pmtct_participant'); $field_names = [ @@ -2223,14 +2368,11 @@ function hedley_stats_get_children_beneficiaries_group_stats($health_center_id, $adults = array_unique($adults); $children = array_unique($children); - $adults_info = $children_info = []; + $children_info = []; foreach (array_chunk($adults, 500) as $ids) { $nodes = node_load_multiple($ids); foreach ($nodes as $node) { - $adults_info[$node->nid] = [ - 'name' => $node->title, - 'phone_number' => empty($node->field_phone_number) ? '' : $node->field_phone_number[LANGUAGE_NONE][0]['value'], - ]; + hedley_stats_add_patient_details($node, $patients_details, TRUE); } // Free up memory. drupal_static_reset(); @@ -2238,9 +2380,9 @@ function hedley_stats_get_children_beneficiaries_group_stats($health_center_id, foreach (array_chunk($children, 500) as $ids) { $nodes = node_load_multiple($ids); foreach ($nodes as $node) { + hedley_stats_add_patient_details($node, $patients_details); $children_info[$node->nid] = [ 'id' => $node->nid, - 'name' => $node->title, 'birth_date' => $node->field_birth_date[LANGUAGE_NONE][0]['value'], 'gender' => $node->field_gender[LANGUAGE_NONE][0]['value'], ]; @@ -2268,11 +2410,9 @@ function hedley_stats_get_children_beneficiaries_group_stats($health_center_id, $items[$clinic_type][] = [ 'created' => hedley_stats_convert_timestamp_to_nominal($row->created), 'id' => $children_info[$child_id]['id'], - 'name' => $children_info[$child_id]['name'], 'birth_date' => date("Y-m-d", strtotime($birth_date)), 'gender' => $children_info[$child_id]['gender'], - 'mother_name' => $adults_info[$adult_id]['name'], - 'phone_number' => $adults_info[$adult_id]['phone_number'], + 'mother_id' => $adult_id, 'graduation_date' => date_format(date_create($row->field_expected_field_expected_value2), 'Y-m-d'), ]; } @@ -2285,13 +2425,15 @@ function hedley_stats_get_children_beneficiaries_group_stats($health_center_id, * * @param int $health_center_id * The Health center node ID. + * @param array $patients_details + * Patients Details data structure that will be edited. * * @return array * Array with the participants details. * * @throws \Exception */ -function hedley_stats_get_children_beneficiaries_individual_stats($health_center_id) { +function hedley_stats_get_children_beneficiaries_individual_stats($health_center_id, array &$patients_details) { $query = hedley_stats_get_base_query($health_center_id, 'individual_participant'); $field_names = [ @@ -2317,9 +2459,9 @@ function hedley_stats_get_children_beneficiaries_individual_stats($health_center foreach (array_chunk($children, 500) as $ids) { $nodes = node_load_multiple($ids); foreach ($nodes as $node) { + hedley_stats_add_patient_details($node, $patients_details); $children_info[$node->nid] = [ 'id' => $node->nid, - 'name' => $node->title, 'birth_date' => $node->field_birth_date[LANGUAGE_NONE][0]['value'], 'gender' => $node->field_gender[LANGUAGE_NONE][0]['value'], ]; @@ -2346,14 +2488,12 @@ function hedley_stats_get_children_beneficiaries_individual_stats($health_center $items[] = [ 'created' => hedley_stats_convert_timestamp_to_nominal($row->created), 'id' => $children_info[$child_id]['id'], - 'name' => $children_info[$child_id]['name'], 'birth_date' => date("Y-m-d", $birth_date), 'gender' => $children_info[$child_id]['gender'], - 'graduation_date' => hedley_stats_convert_timestamp_to_nominal($graduation_date), // No need to provide mother details, because we do not present // it anywhere, when it comes to individual participant data. - 'mother_name' => '', - 'phone_number' => '', + 'mother_id' => NULL, + 'graduation_date' => hedley_stats_convert_timestamp_to_nominal($graduation_date), ]; } @@ -2445,11 +2585,13 @@ function hedley_stats_get_family_planning_stats_by_period($health_center_id, $pe * The Health center node ID. * @param array $fbf_clinics * A list of FBF clinics IDs that belong to health center. + * @param array $patients_details + * Patients Details data structure that will be edited. * * @return array * Array with the results. */ -function hedley_stats_get_session_attendance_stats_by_health_center($health_center_id, array $fbf_clinics) { +function hedley_stats_get_session_attendance_stats_by_health_center($health_center_id, array $fbf_clinics, array &$patients_details) { // Return the cache if exists. if ($cache_data = hedley_stats_handle_cache(HEDLEY_STATS_CACHE_GET, HEDLEY_STATS_SYNC_SESSION_ATTENDANCE, $health_center_id)) { return $cache_data; @@ -2504,14 +2646,11 @@ function hedley_stats_get_session_attendance_stats_by_health_center($health_cent $children = array_unique($children); $mothers = array_unique($mothers); - $children_info = $mothers_info = []; + $children_info = []; foreach (array_chunk($mothers, 500) as $ids) { $nodes = node_load_multiple($ids); foreach ($nodes as $node) { - $mothers_info[$node->nid] = [ - 'name' => $node->title, - 'phone_number' => empty($node->field_phone_number) ? '' : $node->field_phone_number[LANGUAGE_NONE][0]['value'], - ]; + hedley_stats_add_patient_details($node, $patients_details, TRUE); } // Free up memory. drupal_static_reset(); @@ -2519,8 +2658,8 @@ function hedley_stats_get_session_attendance_stats_by_health_center($health_cent foreach (array_chunk($children, 500) as $ids) { $nodes = node_load_multiple($ids); foreach ($nodes as $node) { + hedley_stats_add_patient_details($node, $patients_details); $children_info[$node->nid] = [ - 'name' => $node->title, 'birth_date' => $node->field_birth_date[LANGUAGE_NONE][0]['value'], 'gender' => $node->field_gender[LANGUAGE_NONE][0]['value'], ]; @@ -2547,16 +2686,14 @@ function hedley_stats_get_session_attendance_stats_by_health_center($health_cent continue; } - $mother_info = $mothers_info[$mother_id]; $participant_join_date = $participant_info['join_date']; $participant_graduate_date = $participant_info['graduate_date']; $expected_person = [ - 'name' => $child_info['name'], + 'id' => $child_id, 'gender' => $child_info['gender'], 'birth_date' => hedley_restful_timestamp_only_date($birth_date), - 'mother_name' => $mother_info['name'], - 'phone_number' => $mother_info['phone_number'], + 'mother_id' => $mother_id, 'expected_date' => NULL, ]; @@ -2860,16 +2997,18 @@ function hedley_stats_get_total_nutrition_encounters_by_patient($health_center_i * * @param int $health_center_id * The health center node ID. + * @param array $patients_details + * Patients Details data structure that will be edited. * * @return array * List of nutrition data for person, for current and previous years. * * @throws \Exception */ -function hedley_stats_get_case_management($health_center_id) { +function hedley_stats_get_case_management($health_center_id, array &$patients_details) { return [ - 'this_year' => hedley_stats_get_case_management_for_period($health_center_id), - 'last_year' => hedley_stats_get_case_management_for_period($health_center_id, HEDLEY_STATS_PERIOD_LAST_YEAR), + 'this_year' => hedley_stats_get_case_management_for_period($health_center_id, $patients_details), + 'last_year' => hedley_stats_get_case_management_for_period($health_center_id, $patients_details, HEDLEY_STATS_PERIOD_LAST_YEAR), ]; } @@ -2881,6 +3020,8 @@ function hedley_stats_get_case_management($health_center_id) { * * @param int $health_center_id * The health center node ID. + * @param array $patients_details + * Patients Details data structure that will be edited. * @param string $period * Optional; The period for the data, defaults to one year. * @@ -2889,7 +3030,7 @@ function hedley_stats_get_case_management($health_center_id) { * * @throws \Exception */ -function hedley_stats_get_case_management_for_period($health_center_id, $period = HEDLEY_STATS_PERIOD_ONE_YEAR) { +function hedley_stats_get_case_management_for_period($health_center_id, array &$patients_details, $period = HEDLEY_STATS_PERIOD_ONE_YEAR) { // Return the cache if exists. if ($cache_data = hedley_stats_handle_cache(HEDLEY_STATS_CACHE_GET, HEDLEY_STATS_SYNC_CASE_MANAGEMENT, $health_center_id, $period)) { return $cache_data; @@ -2926,9 +3067,9 @@ function hedley_stats_get_case_management_for_period($health_center_id, $period foreach (array_chunk($people, 500) as $ids) { $nodes = node_load_multiple($ids); foreach ($nodes as $node) { + hedley_stats_add_patient_details($node, $patients_details); $people_info[$node->nid] = [ 'id' => $node->nid, - 'name' => $node->title, 'birth_date' => hedley_restful_timestamp_only_date($node->field_birth_date[LANGUAGE_NONE][0]['value']), 'gender' => $node->field_gender[LANGUAGE_NONE][0]['value'], ]; @@ -3276,9 +3417,9 @@ function hedley_stats_get_base_query($health_center_id, $node_type, $period = FA 'pmtct_participant', ]; - // If we're dealing with group session or individual encounter, - // creation date is resolved using 'field_scheduled_date'. - if (in_array($node_type, $encounter_types) || $node_type == 'session') { + // If we're dealing with group session, education session, or individual + // encounter, creation date is resolved using 'field_scheduled_date'. + if (in_array($node_type, $encounter_types) || in_array($node_type, ['session', 'education_session'])) { $date_field = 'field_scheduled_date'; hedley_general_join_field_to_query($query, 'node', $date_field, FALSE, NULL, NULL, TRUE); } @@ -3584,3 +3725,25 @@ function hedley_stats_handle_cache($method, $cache_name, $health_center_id, $per function hedley_stats_calculate_days_in_month($year, $month) { return (int) date('t', mktime(0, 0, 0, $month, 1, $year)); } + +/** + * Adds name, gender and optionally phone number mapping for patient. + * + * @param object $node + * Patient node. + * @param array $patients_details + * Patients Details data structure that will be edited. + * @param bool $add_phone + * If True, adds phone number. + */ +function hedley_stats_add_patient_details($node, array &$patients_details, $add_phone = FALSE) { + $patients_details[$node->nid]['name'] = $node->title; + $patients_details[$node->nid]['gender'] = $node->field_gender[LANGUAGE_NONE][0]['value']; + + if ($add_phone) { + $phone_number = empty($node->field_phone_number) ? '' : trim($node->field_phone_number[LANGUAGE_NONE][0]['value']); + if (!empty($phone_number)) { + $patients_details[$node->nid]['phone_number'] = $phone_number; + } + } +} diff --git a/server/hedley/modules/custom/hedley_stats/scripts/recalculate-stats.php b/server/hedley/modules/custom/hedley_stats/scripts/recalculate-stats.php index f0126b747d..df4b9eb981 100644 --- a/server/hedley/modules/custom/hedley_stats/scripts/recalculate-stats.php +++ b/server/hedley/modules/custom/hedley_stats/scripts/recalculate-stats.php @@ -70,6 +70,7 @@ hedley_stats_clear_caches_for_health_center($id, HEDLEY_STATS_CHILD_SCOREBOARD); hedley_stats_clear_caches_for_health_center($id, HEDLEY_STATS_NUTRITION_INDIVIDUAL); hedley_stats_clear_caches_for_health_center($id, HEDLEY_STATS_NUTRITION_GROUP); + hedley_stats_clear_caches_for_health_center($id, HEDLEY_STATS_GROUP_EDUCATION); // Add AQ item to re-calculate all the stats offline. hedley_general_add_task_to_advanced_queue_by_id(HEDLEY_STATS_CALCULATE_STATS, $id, [ diff --git a/server/hedley/modules/custom/hedley_stats/tests/HedleyStatsCalculation.test b/server/hedley/modules/custom/hedley_stats/tests/HedleyStatsCalculation.test index 4b7648b248..b1013d41e0 100644 --- a/server/hedley/modules/custom/hedley_stats/tests/HedleyStatsCalculation.test +++ b/server/hedley/modules/custom/hedley_stats/tests/HedleyStatsCalculation.test @@ -115,7 +115,8 @@ class HedleyStatsCalculation extends HedleyWebTestBase { $this->createMuac($session_nid, $child_nid, $measurements[$measurements_state]['muac'], $session['date']);; } - $case_management = hedley_stats_get_case_management($this->healthCenterId); + $patients_details = []; + $case_management = hedley_stats_get_case_management($this->healthCenterId, $patients_details); // Assert the amount of case management. $this->assertEqual(20, count($case_management['this_year']['fbf'])); @@ -134,7 +135,8 @@ class HedleyStatsCalculation extends HedleyWebTestBase { 'end' => time(), ]; $fbf_clinics = hedley_health_center_get_clinics_of_health_center($this->healthCenterId, 'fbf'); - list($completed_programs, $missed_sessions) = hedley_stats_get_session_attendance_stats_by_health_center($this->healthCenterId, $fbf_clinics); + $patients_details = []; + list($completed_programs, $missed_sessions) = hedley_stats_get_session_attendance_stats_by_health_center($this->healthCenterId, $fbf_clinics, $patients_details); // Filter missed sessions. $count_missed_sessions = 0; diff --git a/server/hedley/modules/custom/hedley_user/hedley_user.features.field_instance.inc b/server/hedley/modules/custom/hedley_user/hedley_user.features.field_instance.inc index 07c76735e9..f9edfa3f5b 100644 --- a/server/hedley/modules/custom/hedley_user/hedley_user.features.field_instance.inc +++ b/server/hedley/modules/custom/hedley_user/hedley_user.features.field_instance.inc @@ -507,6 +507,40 @@ function hedley_user_field_default_field_instances() { ), ); + // Exported field_instance: 'user-user-field_incident_details'. + $field_instances['user-user-field_incident_details'] = array( + 'bundle' => 'user', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 9, + ), + ), + 'entity_type' => 'user', + 'field_name' => 'field_incident_details', + 'label' => 'Incident details', + 'required' => 0, + 'settings' => array( + 'text_processing' => 0, + 'user_register_form' => 0, + ), + 'widget' => array( + 'active' => 1, + 'module' => 'text', + 'settings' => array( + 'rows' => 5, + ), + 'type' => 'text_textarea', + 'weight' => 17, + ), + ); + // Exported field_instance: 'user-user-field_phone'. $field_instances['user-user-field_phone'] = array( 'bundle' => 'user', @@ -686,6 +720,7 @@ function hedley_user_field_default_field_instances() { t('Email'); t('Groups'); t('Health centers'); + t('Incident details'); t('PIN code'); t('Phone'); t('Profile photo'); diff --git a/server/hedley/modules/custom/hedley_user/hedley_user.info b/server/hedley/modules/custom/hedley_user/hedley_user.info index 2a023e9a71..6f282d5107 100644 --- a/server/hedley/modules/custom/hedley_user/hedley_user.info +++ b/server/hedley/modules/custom/hedley_user/hedley_user.info @@ -42,6 +42,7 @@ features[field_instance][] = node-nurse-field_villages features[field_instance][] = user-user-field_avatar features[field_instance][] = user-user-field_clinics features[field_instance][] = user-user-field_health_centers +features[field_instance][] = user-user-field_incident_details features[field_instance][] = user-user-field_phone features[field_instance][] = user-user-field_pin_code features[field_instance][] = user-user-field_sync_phase