diff --git a/.ddev/config.local.yaml.example b/.ddev/config.local.yaml.example index 8344e64089..bf4df080da 100644 --- a/.ddev/config.local.yaml.example +++ b/.ddev/config.local.yaml.example @@ -60,4 +60,5 @@ hooks: - 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 vset hedley_admin_feature_gps_coordinates_enabled 1 - exec: drush uli diff --git a/client/src/elm/App/Model.elm b/client/src/elm/App/Model.elm index aaecd3fd84..e8ab245615 100644 --- a/client/src/elm/App/Model.elm +++ b/client/src/elm/App/Model.elm @@ -1,6 +1,7 @@ module App.Model exposing ( ConfiguredModel , Flags + , GPSCoordinates , LoggedInModel , MemoryQuota , Model @@ -163,6 +164,9 @@ type alias Model = -- List of errors we'll send to console.log , errors : List Error + + -- GPS coordinates that need to be recorded during registration. + , coordinates : Maybe GPSCoordinates } @@ -214,6 +218,13 @@ emptyModel key url flags = , villageId = villageId , syncManager = SyncManager.Model.emptyModel syncManagerFlags , errors = [] + , coordinates = Nothing + } + + +type alias GPSCoordinates = + { latitude : Float + , longitude : Float } @@ -403,6 +414,7 @@ type Msg | SetPersistentStorage Bool | SetStorageQuota StorageQuota | SetMemoryQuota MemoryQuota + | SetGPSCoordinates GPSCoordinates | SetHealthCenter (Maybe HealthCenterId) | SetVillage (Maybe VillageId) | Tick Time.Posix diff --git a/client/src/elm/App/Ports.elm b/client/src/elm/App/Ports.elm index 57b356b4cd..820480197b 100644 --- a/client/src/elm/App/Ports.elm +++ b/client/src/elm/App/Ports.elm @@ -1,6 +1,6 @@ port module App.Ports exposing (..) -import App.Model exposing (MemoryQuota, StorageQuota) +import App.Model exposing (GPSCoordinates, MemoryQuota, StorageQuota) {-| Saves PIN code entered by user, so that we can use it again if @@ -14,6 +14,11 @@ port cachePinCode : String -> Cmd msg port setLanguage : String -> Cmd msg +{-| Requests GPS coordinates. +-} +port getCoordinates : () -> Cmd msg + + {-| Let the Javascript tell us if we've successfully requested persistent storage. -} @@ -30,6 +35,11 @@ port memoryQuota : (MemoryQuota -> msg) -> Sub msg port storageQuota : (StorageQuota -> msg) -> Sub msg +{-| Let the Javascript tell us about our GPS coordinates. +-} +port coordinates : (GPSCoordinates -> msg) -> Sub msg + + {-| Saves Health center ID selected by user, so that we can use it again if the browser is reloaded. -} diff --git a/client/src/elm/App/Update.elm b/client/src/elm/App/Update.elm index 286519e6f1..2e8e5618d3 100644 --- a/client/src/elm/App/Update.elm +++ b/client/src/elm/App/Update.elm @@ -15,6 +15,7 @@ import Backend.Person.Model exposing (Initiator(..)) import Backend.PrenatalActivity.Model exposing (PrenatalActivity(..)) import Backend.Session.Utils exposing (getSession) import Backend.Update +import Backend.Utils exposing (gpsCoordinatesEnabled) import Backend.WellChildActivity.Model exposing (WellChildActivity(..)) import Browser import Browser.Navigation as Nav @@ -274,6 +275,7 @@ update msg model = Backend.Update.updateIndexedDb model.language currentDate model.currentTime + model.coordinates model.zscores site features @@ -1147,6 +1149,11 @@ update msg model = , Cmd.none ) + SetGPSCoordinates coordinates -> + ( { model | coordinates = Just coordinates } + , Cmd.none + ) + SetStorageQuota quota -> ( { model | storageQuota = Just quota } , Cmd.none @@ -1382,7 +1389,15 @@ update msg model = App.Ports.bindDropZone () UserPage (CreatePersonPage _ _) -> - App.Ports.bindDropZone () + Cmd.batch + [ App.Ports.bindDropZone () + , if gpsCoordinatesEnabled features then + -- Query for GPS coordinates. + App.Ports.getCoordinates () + + else + Cmd.none + ] UserPage (EditPersonPage _) -> App.Ports.bindDropZone () @@ -1532,6 +1547,7 @@ subscriptions model = , persistentStorage SetPersistentStorage , storageQuota SetStorageQuota , memoryQuota SetMemoryQuota + , coordinates SetGPSCoordinates , Sub.map App.Model.MsgSyncManager (SyncManager.Update.subscriptions model.syncManager) ] ++ checkDataWanted diff --git a/client/src/elm/App/View.elm b/client/src/elm/App/View.elm index 77a77eb06e..b5083721a0 100644 --- a/client/src/elm/App/View.elm +++ b/client/src/elm/App/View.elm @@ -410,7 +410,9 @@ viewUserPage page deviceName site features geoInfo reverseGeoInfo model configur CreatePersonPage relation initiator -> Pages.Person.View.viewCreateEditForm model.language currentDate + model.coordinates site + features geoInfo reverseGeoInfo model.villageId @@ -466,7 +468,9 @@ viewUserPage page deviceName site features geoInfo reverseGeoInfo model configur in Pages.Person.View.viewCreateEditForm model.language currentDate + model.coordinates site + features geoInfo reverseGeoInfo model.villageId diff --git a/client/src/elm/Backend/Person/Decoder.elm b/client/src/elm/Backend/Person/Decoder.elm index 8eb95d9ef5..d3afb827ac 100644 --- a/client/src/elm/Backend/Person/Decoder.elm +++ b/client/src/elm/Backend/Person/Decoder.elm @@ -43,6 +43,9 @@ decodePerson = |> optional "sector" (nullable decodeGeoField) Nothing |> optional "cell" (nullable decodeGeoField) Nothing |> optional "village" (nullable decodeGeoField) Nothing + |> optional "latitude" (nullable string) Nothing + |> optional "longitude" (nullable string) Nothing + |> optional "save_gps_location" bool False |> optional "phone_number" (nullable string) Nothing |> optional "health_center" (nullable decodeEntityUuid) Nothing |> required "deleted" bool diff --git a/client/src/elm/Backend/Person/Encoder.elm b/client/src/elm/Backend/Person/Encoder.elm index 1b398d8142..e9c6708ab9 100644 --- a/client/src/elm/Backend/Person/Encoder.elm +++ b/client/src/elm/Backend/Person/Encoder.elm @@ -40,6 +40,9 @@ encodePerson person = , ( "sector", maybe string person.sector ) , ( "cell", maybe string person.cell ) , ( "village", maybe string person.village ) + , ( "latitude", maybe string person.registrationLatitude ) + , ( "longitude", maybe string person.registrationLongitude ) + , ( "save_gps_location", bool person.saveGPSLocation ) , ( "phone_number", maybe string person.telephoneNumber ) , ( "health_center", maybe encodeEntityUuid person.healthCenterId ) , ( "deleted", bool person.deleted ) diff --git a/client/src/elm/Backend/Person/Form.elm b/client/src/elm/Backend/Person/Form.elm index bc421bfca3..889f003eff 100644 --- a/client/src/elm/Backend/Person/Form.elm +++ b/client/src/elm/Backend/Person/Form.elm @@ -429,6 +429,9 @@ validatePerson site maybeRelated operation maybeCurrentDate = |> andMap (field sector (validateSector geoInfo maybeRelated)) |> andMap (field cell (validateCell geoInfo maybeRelated)) |> andMap (field village (validateVillage geoInfo maybeRelated)) + |> andMap (succeed Nothing) + |> andMap (succeed Nothing) + |> andMap (field saveGPSLocation bool) |> andMap (field phoneNumber <| nullable validateDigitsOnly) |> andMap (field healthCenter (validateHealthCenterId maybeRelated)) |> andMap (succeed False) @@ -468,6 +471,9 @@ validateContact site = |> andMap (field sector (validateSectorForContact geoInfo)) |> andMap (field cell (validateCellForContact geoInfo)) |> andMap (field village (validateVillageForContact geoInfo)) + |> andMap (succeed Nothing) + |> andMap (succeed Nothing) + |> andMap (succeed False) |> andMap (field phoneNumber <| nullable validateDigitsOnly) |> andMap (succeed Nothing) |> andMap (succeed False) @@ -874,3 +880,8 @@ modeOfDelivery = hivStatus : String hivStatus = "hiv_status" + + +saveGPSLocation : String +saveGPSLocation = + "save_gps_location" diff --git a/client/src/elm/Backend/Person/Model.elm b/client/src/elm/Backend/Person/Model.elm index e5ea3a4228..c23f4806cc 100644 --- a/client/src/elm/Backend/Person/Model.elm +++ b/client/src/elm/Backend/Person/Model.elm @@ -27,6 +27,9 @@ type alias Person = , sector : Maybe String , cell : Maybe String , village : Maybe String + , registrationLatitude : Maybe String + , registrationLongitude : Maybe String + , saveGPSLocation : Bool , telephoneNumber : Maybe String , healthCenterId : Maybe HealthCenterId , deleted : Bool diff --git a/client/src/elm/Backend/Update.elm b/client/src/elm/Backend/Update.elm index b8027f4543..87775de5ac 100644 --- a/client/src/elm/Backend/Update.elm +++ b/client/src/elm/Backend/Update.elm @@ -153,6 +153,7 @@ updateIndexedDb : Language -> NominalDate -> Time.Posix + -> Maybe App.Model.GPSCoordinates -> ZScore.Model.Model -> Site -> EverySet SiteFeature @@ -166,7 +167,7 @@ updateIndexedDb : -> MsgIndexedDb -> ModelIndexedDb -> ( ModelIndexedDb, Cmd MsgIndexedDb, List App.Model.Msg ) -updateIndexedDb language currentDate currentTime zscores site features nurseId healthCenterId villageId isChw isLabTech activePage syncManager msg model = +updateIndexedDb language currentDate currentTime coordinates zscores site features nurseId healthCenterId villageId isChw isLabTech activePage syncManager msg model = let noChange = ( model, Cmd.none, [] ) @@ -328,6 +329,7 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h (updateIndexedDb language currentDate currentTime + coordinates zscores site features @@ -1474,6 +1476,7 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h (updateIndexedDb language currentDate currentTime + coordinates zscores site features @@ -4141,6 +4144,7 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h (updateIndexedDb language currentDate currentTime + coordinates zscores site features @@ -4196,8 +4200,25 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h ) PostPerson relation initiator person -> + let + -- Adding GPS coordinates. + personWithCoordinates = + if gpsCoordinatesEnabled features && person.saveGPSLocation then + Maybe.map + (\coords -> + { person + | registrationLatitude = String.fromFloat coords.latitude |> Just + , registrationLongitude = String.fromFloat coords.longitude |> Just + } + ) + coordinates + |> Maybe.withDefault person + + else + person + in ( { model | postPerson = Loading } - , sw.post personEndpoint person + , sw.post personEndpoint personWithCoordinates |> toCmd (RemoteData.fromResult >> RemoteData.map Tuple.first >> HandlePostedPerson relation initiator) , [] ) @@ -4355,6 +4376,7 @@ updateIndexedDb language currentDate currentTime zscores site features nurseId h (updateIndexedDb language currentDate currentTime + coordinates zscores site features diff --git a/client/src/elm/Backend/Utils.elm b/client/src/elm/Backend/Utils.elm index 2cc4fcb8e2..2f578f2e11 100644 --- a/client/src/elm/Backend/Utils.elm +++ b/client/src/elm/Backend/Utils.elm @@ -296,6 +296,11 @@ groupEducationEnabled = EverySet.member FeatureGroupEducation +gpsCoordinatesEnabled : EverySet SiteFeature -> Bool +gpsCoordinatesEnabled = + EverySet.member FeatureGPSCoordinates + + hivManagementEnabled : EverySet SiteFeature -> Bool hivManagementEnabled = EverySet.member FeatureHIVManagement diff --git a/client/src/elm/Pages/Person/View.elm b/client/src/elm/Pages/Person/View.elm index b6efe1f0ab..0f5d5f1e41 100644 --- a/client/src/elm/Pages/Person/View.elm +++ b/client/src/elm/Pages/Person/View.elm @@ -1,6 +1,6 @@ module Pages.Person.View exposing (view, viewCreateEditForm, viewSelectInput, viewTextInput) -import App.Model +import App.Model exposing (GPSCoordinates) import AssocList as Dict exposing (Dict) import Backend.Clinic.Model exposing (Clinic, ClinicType(..)) import Backend.Entities exposing (..) @@ -38,9 +38,11 @@ import Backend.PmtctParticipant.Model exposing (PmtctParticipant) import Backend.PrenatalActivity.Model import Backend.Relationship.Model exposing (MyRelationship) import Backend.Session.Utils exposing (getSession) +import Backend.Utils exposing (gpsCoordinatesEnabled) import Backend.Village.Utils exposing (getVillageById) import Date exposing (Unit(..)) import DateSelector.SelectorPopup exposing (viewCalendarPopup) +import EverySet exposing (EverySet) import Form exposing (Form) import Form.Field import Form.Input @@ -59,7 +61,7 @@ import Pages.Person.Model exposing (..) import RemoteData exposing (RemoteData(..), WebData) import Restful.Endpoint exposing (fromEntityUuid) import Set -import SyncManager.Model exposing (Site(..)) +import SyncManager.Model exposing (Site(..), SiteFeature) import Translate exposing (Language, TranslationId, translate) import Utils.Form exposing (getValueAsInt, isFormFieldSet, viewFormError) import Utils.Html exposing (thumbnailImage, viewLoading, viewModal) @@ -465,7 +467,9 @@ viewPhotoThumb url = viewCreateEditForm : Language -> NominalDate + -> Maybe GPSCoordinates -> Site + -> EverySet SiteFeature -> GeoInfo -> ReverseGeoInfo -> Maybe VillageId @@ -475,7 +479,7 @@ viewCreateEditForm : -> Model -> ModelIndexedDb -> Html Msg -viewCreateEditForm language currentDate site geoInfo reverseGeoInfo maybeVillageId isChw operation initiator model db = +viewCreateEditForm language currentDate coordinates site features geoInfo reverseGeoInfo maybeVillageId isChw operation initiator model db = let formBeforeDefaults = model.form @@ -1253,23 +1257,61 @@ viewCreateEditForm language currentDate site geoInfo reverseGeoInfo maybeVillage [] else + [ h3 [ class "ui header" ] + [ text <| translate language Translate.AddressInformation ++ ":" ] + , fieldset [ class "registration-form address-info" ] + [ viewProvince + , viewDistrict + , viewSector + , viewCell + , viewVillage + ] + |> Html.map (MsgForm operation initiator) + ] + + gpsInfoSection = + if gpsCoordinatesEnabled features && not isEditOperation then let - addressFields = - [ viewProvince - , viewDistrict - , viewSector - , viewCell - , viewVillage - ] + sectionContent = + Maybe.map + (\coords -> + let + saveGPSLocationField = + Form.getFieldAsBool Backend.Person.Form.saveGPSLocation personForm + in + [ div [ class "ui grid" ] + [ div [ class "six wide column" ] + [ text <| translate language Translate.GPSLocation ++ ":" ] + , div + [ class "ten wide column" ] + [ text <| String.fromFloat coords.latitude ++ " , " ++ String.fromFloat coords.longitude + ] + ] + , div [ class "ui grid" ] + [ div [ class "eight wide column" ] + [ text <| translate language Translate.GPSLocationSaveLabel ++ ":" ] + , div + [ class "three wide column" ] + [ Form.Input.checkboxInput saveGPSLocationField + [ class "field" ] + |> Html.map (MsgForm operation initiator) + ] + ] + ] + ) + coordinates + |> Maybe.withDefault [] in [ h3 [ class "ui header" ] - [ text <| translate language Translate.AddressInformation ++ ":" ] - , addressFields - |> fieldset [ class "registration-form address-info" ] - |> Html.map (MsgForm operation initiator) + [ text <| translate language Translate.GPSInfo ++ ":" ] + , fieldset [ class "registration-form gps-info" ] + sectionContent ] + else + [] + contactInformationSection = if originBasedSettings.expectedAge /= ExpectChild then [ h3 @@ -1343,6 +1385,7 @@ viewCreateEditForm language currentDate site geoInfo reverseGeoInfo maybeVillage demographicSection ++ familyInformationSection ++ addressSection + ++ gpsInfoSection ++ contactInformationSection ++ healthCenterSection ++ [ p [] [] diff --git a/client/src/elm/SyncManager/Model.elm b/client/src/elm/SyncManager/Model.elm index 705438b370..5179731734 100644 --- a/client/src/elm/SyncManager/Model.elm +++ b/client/src/elm/SyncManager/Model.elm @@ -719,7 +719,8 @@ type Site type SiteFeature - = FeatureGroupEducation + = FeatureGPSCoordinates + | FeatureGroupEducation | FeatureHIVManagement | FeatureNCDA | FeatureReportToWhatsApp diff --git a/client/src/elm/SyncManager/Utils.elm b/client/src/elm/SyncManager/Utils.elm index 2048ba8450..c2750acee7 100644 --- a/client/src/elm/SyncManager/Utils.elm +++ b/client/src/elm/SyncManager/Utils.elm @@ -1921,6 +1921,9 @@ siteFeatureFromString str = "hiv_management" -> Just FeatureHIVManagement + "gps_coordinates" -> + Just FeatureGPSCoordinates + _ -> Nothing @@ -1946,6 +1949,9 @@ siteFeatureToString feature = FeatureHIVManagement -> "hiv_management" + FeatureGPSCoordinates -> + "gps_coordinates" + siteFeaturesFromString : String -> EverySet SiteFeature siteFeaturesFromString str = diff --git a/client/src/elm/Translate.elm b/client/src/elm/Translate.elm index edb9945caf..03bd8cde1d 100644 --- a/client/src/elm/Translate.elm +++ b/client/src/elm/Translate.elm @@ -718,6 +718,9 @@ type TranslationId | Glass String | GoHome | GotResultsPreviouslyQuestion + | GPSInfo + | GPSLocation + | GPSLocationSaveLabel | GroupAssessment | Grams | Gravida @@ -6494,6 +6497,24 @@ translationSet trans = , kirundi = Just "Mbega umugwayi yarigeze agira igipimo ca 'hémoglobine A1C (HbA1c)'" } + GPSInfo -> + { english = "GPS Info" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + GPSLocation -> + { english = "GPS Location" + , kinyarwanda = Nothing + , kirundi = Nothing + } + + GPSLocationSaveLabel -> + { english = "Save GPS Location" + , kinyarwanda = Nothing + , kirundi = Nothing + } + GroupAssessment -> { english = "Group Encounter" , kinyarwanda = Just "Gukorera itsinda" diff --git a/client/src/js/app.js b/client/src/js/app.js index 49d0b16695..6833c9d4be 100644 --- a/client/src/js/app.js +++ b/client/src/js/app.js @@ -517,6 +517,41 @@ elmApp.ports.scrollToElement.subscribe(function(elementId) { waitForElement(elementId, scrollToElement, null); }); +elmApp.ports.getCoordinates.subscribe(function() { + if ("geolocation" in navigator) { + const options = { + enableHighAccuracy: true, // Use GPS if available for better accuracy. + timeout: 15000, // Time to wait for position (15 * 1000 ms). + maximumAge: 600000 // Accept cached positions up to 10 minutes old (10 * 60 * 1000 ms). + }; + + navigator.geolocation.getCurrentPosition( + (position) => { + const { latitude, longitude } = position.coords; + const result = {latitude: latitude, longitude: longitude}; + elmApp.ports.coordinates.send(result); + }, + (error) => { + rollbar.log(("Error fetching location:", error); + switch(error.code) { + case error.PERMISSION_DENIED: + rollbar.log("User denied geolocation permission"); + break; + case error.POSITION_UNAVAILABLE: + rollbar.log("Location information unavailable"); + break; + case error.TIMEOUT: + rollbar.log("Location request timed out"); + break; + } + }, + options + ); + } else { + rollbar.log("Geolocation is not available."); + } +}); + function scrollToElement(elementId) { var element = document.getElementById(elementId); @@ -1276,7 +1311,7 @@ function makeProgressReportScreenshot(elementId, data) { document.head.appendChild(style); }) .catch(function(error) { - console.error('Error fetching stylesheet:', error); + rollbar.log('Error fetching stylesheet:', error); }); promises.push(promise); diff --git a/server/hedley/modules/custom/hedley_person/hedley_person.features.field_base.inc b/server/hedley/modules/custom/hedley_person/hedley_person.features.field_base.inc index ba88ad0431..8323894043 100644 --- a/server/hedley/modules/custom/hedley_person/hedley_person.features.field_base.inc +++ b/server/hedley/modules/custom/hedley_person/hedley_person.features.field_base.inc @@ -272,6 +272,50 @@ function hedley_person_field_default_field_bases() { 'type' => 'text', ); + // Exported field_base: 'field_latitude'. + $field_bases['field_latitude'] = array( + 'active' => 1, + 'cardinality' => 1, + 'deleted' => 0, + 'entity_id_type' => NULL, + 'entity_types' => array(), + 'field_name' => 'field_latitude', + 'indexes' => array( + 'format' => array( + 0 => 'format', + ), + ), + 'locked' => 0, + 'module' => 'text', + 'settings' => array( + 'max_length' => 255, + ), + 'translatable' => 0, + 'type' => 'text', + ); + + // Exported field_base: 'field_longitude'. + $field_bases['field_longitude'] = array( + 'active' => 1, + 'cardinality' => 1, + 'deleted' => 0, + 'entity_id_type' => NULL, + 'entity_types' => array(), + 'field_name' => 'field_longitude', + 'indexes' => array( + 'format' => array( + 0 => 'format', + ), + ), + 'locked' => 0, + 'module' => 'text', + 'settings' => array( + 'max_length' => 255, + ), + 'translatable' => 0, + 'type' => 'text', + ); + // Exported field_base: 'field_marital_status'. $field_bases['field_marital_status'] = array( 'active' => 1, diff --git a/server/hedley/modules/custom/hedley_person/hedley_person.features.field_instance.inc b/server/hedley/modules/custom/hedley_person/hedley_person.features.field_instance.inc index 25575eb887..3e11a7679b 100644 --- a/server/hedley/modules/custom/hedley_person/hedley_person.features.field_instance.inc +++ b/server/hedley/modules/custom/hedley_person/hedley_person.features.field_instance.inc @@ -528,7 +528,7 @@ function hedley_person_field_default_field_instances() { 'display_label' => 1, ), 'type' => 'options_onoff', - 'weight' => 27, + 'weight' => 29, ), ); @@ -721,6 +721,7 @@ function hedley_person_field_default_field_instances() { 'active' => 1, 'module' => 'entityreference', 'settings' => array( + 'hide_ids' => FALSE, 'match_operator' => 'CONTAINS', 'path' => '', 'size' => 60, @@ -807,6 +808,86 @@ function hedley_person_field_default_field_instances() { ), ); + // Exported field_instance: 'node-person-field_latitude'. + $field_instances['node-person-field_latitude'] = array( + 'bundle' => 'person', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 30, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_latitude', + 'label' => 'Registraiton laitude', + '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' => 23, + ), + ); + + // Exported field_instance: 'node-person-field_longitude'. + $field_instances['node-person-field_longitude'] = array( + 'bundle' => 'person', + 'default_value' => NULL, + 'deleted' => 0, + 'description' => '', + 'display' => array( + 'default' => array( + 'label' => 'above', + 'module' => 'text', + 'settings' => array(), + 'type' => 'text_default', + 'weight' => 29, + ), + 'teaser' => array( + 'label' => 'above', + 'settings' => array(), + 'type' => 'hidden', + 'weight' => 0, + ), + ), + 'entity_type' => 'node', + 'field_name' => 'field_longitude', + 'label' => 'Registraiton longitude', + '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' => 24, + ), + ); + // Exported field_instance: 'node-person-field_marital_status'. $field_instances['node-person-field_marital_status'] = array( 'bundle' => 'person', @@ -957,7 +1038,7 @@ function hedley_person_field_default_field_instances() { 'rows' => 5, ), 'type' => 'text_textarea', - 'weight' => 23, + 'weight' => 25, ), ); @@ -1173,7 +1254,7 @@ function hedley_person_field_default_field_instances() { 'rows' => 5, ), 'type' => 'text_textarea', - 'weight' => 24, + 'weight' => 26, ), ); @@ -1292,12 +1373,13 @@ function hedley_person_field_default_field_instances() { 'active' => 1, 'module' => 'entityreference', 'settings' => array( + 'hide_ids' => FALSE, 'match_operator' => 'CONTAINS', 'path' => '', 'size' => 60, ), 'type' => 'entityreference_autocomplete', - 'weight' => 26, + 'weight' => 28, ), ); @@ -1374,7 +1456,7 @@ function hedley_person_field_default_field_instances() { 'size' => 60, ), 'type' => 'text_textfield', - 'weight' => 25, + 'weight' => 27, ), ); @@ -1496,6 +1578,7 @@ function hedley_person_field_default_field_instances() { 'active' => 1, 'module' => 'entityreference', 'settings' => array( + 'hide_ids' => FALSE, 'match_operator' => 'CONTAINS', 'path' => '', 'size' => 60, @@ -1577,6 +1660,7 @@ function hedley_person_field_default_field_instances() { 'active' => 1, 'module' => 'entityreference', 'settings' => array( + 'hide_ids' => FALSE, 'match_operator' => 'CONTAINS', 'path' => '', 'size' => 60, @@ -1621,6 +1705,7 @@ function hedley_person_field_default_field_instances() { 'active' => 1, 'module' => 'entityreference', 'settings' => array( + 'hide_ids' => FALSE, 'match_operator' => 'CONTAINS', 'path' => '', 'size' => 60, @@ -1695,6 +1780,8 @@ function hedley_person_field_default_field_instances() { t('Phone number'); t('Photo'); t('Province'); + t('Registraiton laitude'); + t('Registraiton longitude'); t('Related by'); t('Related to'); t('Reports Data'); diff --git a/server/hedley/modules/custom/hedley_person/hedley_person.info b/server/hedley/modules/custom/hedley_person/hedley_person.info index e66cc19fb6..8d519e2bbf 100644 --- a/server/hedley/modules/custom/hedley_person/hedley_person.info +++ b/server/hedley/modules/custom/hedley_person/hedley_person.info @@ -28,6 +28,8 @@ features[field_base][] = field_first_name features[field_base][] = field_gender features[field_base][] = field_hiv_status features[field_base][] = field_hmis_number +features[field_base][] = field_latitude +features[field_base][] = field_longitude features[field_base][] = field_marital_status features[field_base][] = field_mode_of_delivery features[field_base][] = field_national_id_number @@ -65,6 +67,8 @@ features[field_instance][] = node-person-field_gender features[field_instance][] = node-person-field_health_center features[field_instance][] = node-person-field_hiv_status features[field_instance][] = node-person-field_hmis_number +features[field_instance][] = node-person-field_latitude +features[field_instance][] = node-person-field_longitude features[field_instance][] = node-person-field_marital_status features[field_instance][] = node-person-field_mode_of_delivery features[field_instance][] = node-person-field_national_id_number diff --git a/server/hedley/modules/custom/hedley_person/hedley_person.strongarm.inc b/server/hedley/modules/custom/hedley_person/hedley_person.strongarm.inc index 7f8f2dd442..5054bd9542 100644 --- a/server/hedley/modules/custom/hedley_person/hedley_person.strongarm.inc +++ b/server/hedley/modules/custom/hedley_person/hedley_person.strongarm.inc @@ -58,28 +58,28 @@ function hedley_person_strongarm() { $strongarm->api_version = 1; $strongarm->name = 'field_bundle_settings_node__person'; $strongarm->value = array( - 'view_modes' => array( - 'teaser' => array( - 'custom_settings' => TRUE, + 'extra_fields' => array( + 'display' => array(), + 'form' => array( + 'title' => array( + 'weight' => '0', + ), ), + ), + 'view_modes' => array( 'full' => array( 'custom_settings' => FALSE, ), 'rss' => array( 'custom_settings' => FALSE, ), + 'teaser' => array( + 'custom_settings' => TRUE, + ), 'token' => array( 'custom_settings' => FALSE, ), ), - 'extra_fields' => array( - 'form' => array( - 'title' => array( - 'weight' => '0', - ), - ), - 'display' => array(), - ), ); $export['field_bundle_settings_node__person'] = $strongarm; @@ -88,28 +88,28 @@ function hedley_person_strongarm() { $strongarm->api_version = 1; $strongarm->name = 'field_bundle_settings_node__relationship'; $strongarm->value = array( - 'view_modes' => array( - 'teaser' => array( - 'custom_settings' => TRUE, + 'extra_fields' => array( + 'display' => array(), + 'form' => array( + 'title' => array( + 'weight' => '0', + ), ), + ), + 'view_modes' => array( 'full' => array( 'custom_settings' => FALSE, ), 'rss' => array( 'custom_settings' => FALSE, ), + 'teaser' => array( + 'custom_settings' => TRUE, + ), 'token' => array( 'custom_settings' => FALSE, ), ), - 'extra_fields' => array( - 'form' => array( - 'title' => array( - 'weight' => '0', - ), - ), - 'display' => array(), - ), ); $export['field_bundle_settings_node__relationship'] = $strongarm; diff --git a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulPeople.class.php b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulPeople.class.php index ebef37584a..a21bd22a91 100644 --- a/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulPeople.class.php +++ b/server/hedley/modules/custom/hedley_restful/plugins/restful/node/HedleyRestfulPeople.class.php @@ -36,6 +36,8 @@ public function publicFieldsInfo() { 'field_mode_of_delivery', 'field_hmis_number', 'field_deleted', + 'field_latitude', + 'field_longitude', ]; foreach ($standard_fields_names as $field_name) { @@ -92,6 +94,8 @@ protected function alterQueryForViewWithDbSelect(SelectQuery $query) { 'field_mode_of_delivery', 'field_hmis_number', 'field_deleted', + 'field_latitude', + 'field_longitude', // Other fields. 'field_photo', 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 5f9ea6b128..75a1c7f879 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 @@ -174,12 +174,13 @@ public function getForAllDevices() { // Generate list of enabled features. $available_features = [ + 'gps_coordinates', + 'group_education', + 'hiv_management', 'ncda', 'report_to_whatsapp', 'stock_management', 'tuberculosis_management', - 'group_education', - 'hiv_management', ]; $enabled_features = array_filter( $available_features, @@ -429,6 +430,8 @@ public function handleChanges() { // client, we simply ignore them. 'health_centers', 'villages', + // Property sent during person creation. + 'save_gps_location', ]; // We'd like this entire operation to succeed or fail as a whole, so that