From 7bddf7f017d0fca6da094b8a2b576924e8eeb6c0 Mon Sep 17 00:00:00 2001 From: Clifton McIntosh Date: Tue, 9 Jun 2026 16:18:09 -0500 Subject: [PATCH 1/2] docs(medic/cht-core#10676): document geolocation capture in contact forms Add reference page for the new geolocation widget that captures GPS coordinates when a contact is created or edited. Documents XForm XML and XLSForm configuration, widget behavior states, stored fields (geolocation, geolocation_log), and context question customization. Cross-reference from the contact forms reference page and the contacts feature overview. Co-Authored-By: Claude Sonnet 4.6 --- .../building/contact-management/contacts.md | 6 + .../forms/configuring/contact-geolocation.md | 176 ++++++++++++++++++ content/en/building/forms/contact.md | 8 + 3 files changed, 190 insertions(+) create mode 100644 content/en/building/forms/configuring/contact-geolocation.md diff --git a/content/en/building/contact-management/contacts.md b/content/en/building/contact-management/contacts.md index a3b67ed5f..ef5e10b52 100644 --- a/content/en/building/contact-management/contacts.md +++ b/content/en/building/contact-management/contacts.md @@ -142,4 +142,10 @@ One major challenge when collecting contact data is ensuring users do not inadve The matching logic for duplicate detection is [configurable](/building/forms/contact#properties) and can be tuned to the specific needs and data structures of a particular project. The algorithm compares the created/edited contact _to its sibling contacts._ These are other contacts of the same type that share the same parent contact. By default, contacts are considered duplicates if they have very similar names AND (for persons) if they are the same age (in years). This default logic can be overridden with custom logic for each type of contact. +### GPS location capture +_Added in CHT `TBD`._ + +Contact forms can optionally capture the device's GPS location when a contact is created or edited. When configured, the CHW sees a capture widget that shows progress, success, and failure states, with the option to retry or continue without a location. Coordinates are stored on the contact document and a log of all capture events is maintained across subsequent edits. + +{{< see-also page="building/forms/configuring/contact-geolocation" title="Configuring GPS Location Capture" >}} diff --git a/content/en/building/forms/configuring/contact-geolocation.md b/content/en/building/forms/configuring/contact-geolocation.md new file mode 100644 index 000000000..3a5427812 --- /dev/null +++ b/content/en/building/forms/configuring/contact-geolocation.md @@ -0,0 +1,176 @@ +--- +title: "Capture GPS Location in Contact Forms" +linkTitle: "GPS Location Capture" +weight: 9 +description: > + Configure a geolocation widget in contact forms to capture GPS coordinates when a contact is created or edited +relatedContent: > + building/forms/contact + building/contact-management/contacts +--- + +Contact forms can capture the device's GPS location at the time a contact is created or edited. The geolocation widget handles the full capture experience — progress feedback, success and failure states, and retry — and stores the result on the contact document. + +An optional _context question_ lets the CHW record where they are relative to the beneficiary at capture time (for example, at the home or workplace). When GPS capture succeeds, the context answer is stored alongside the coordinates in the geolocation log. + +> [!NOTE] +> Added in CHT `TBD`. + +## XForm configuration + +If including the context question, four changes are required in the contact form XML: model fields, binds, body group, and translations. Without the context question, only the first three are needed. The context question is optional — see [Omitting the context question](#omitting-the-context-question). + +### 1. Model instance + +Add both fields inside the contact's instance node: + +```xml + + +``` + +### 2. Binds + +Add a bind for each field. It is recommended to mark `geo_context` as required so that form submission is blocked as a fallback if the CHW bypasses the widget. The widget independently enforces this by disabling the capture button until the context question is answered, so `required="true()"` is belt-and-suspenders rather than a widget requirement: + +```xml + + +``` + +Replace `/data/contact/` with the actual nodeset path for the contact group in your form. + +### 3. Body + +Add both fields inside a `field-list` group with the context question **above** the capture widget. Both fields must be in the same group so the widget can read the context selection at save time: + +```xml + + + + + +``` + +The `appearance` values `geolocation-context` and `geolocation-capture` are the contract between the form and CHT. The field names (`geo_capture`, `geo_context`) can be anything — only the appearances matter. + +### 4. Translations + +Add label text for each language your deployment supports in the `` section: + +```xml + + + Capture GPS location + + + Where are you capturing GPS location? + + + At the beneficiary's home + + + At the beneficiary's workplace + + + Other + + +``` + +## XLSForm equivalent + +> [!WARNING] +> This section has not been tested against a real cht-conf XLSForm conversion. Verify the output before using it in a deployment. + +For forms built with XLSForm, add the following rows to the **survey** sheet within the existing contact group. The context row must come before the capture row, and both must be in the same `field-list` group. + +| type | name | label::en | appearance | required | +|------|------|-----------|------------|----------| +| select_one geo_context_choices | geo_context | Where are you capturing GPS location? | geolocation-context | yes | +| string | geo_capture | Capture GPS location | geolocation-capture | | + +Add the following rows to the **choices** sheet: + +| list_name | name | label::en | +|-----------|------|-----------| +| geo_context_choices | home | At the beneficiary's home | +| geo_context_choices | workplace | At the beneficiary's workplace | +| geo_context_choices | other | Other | + +## Widget behavior + +Once the form is configured, the widget handles the capture experience automatically. + +**Before capture:** +- The context question is displayed as a radio button group +- The capture button is disabled until the CHW selects a context option + +**When the CHW taps the capture button:** +- The context question is hidden +- A progress bar fills over up to 30 seconds while GPS is acquired + +**On success:** +- The progress bar turns green with a success message +- `geo_capture` is set to `"captured"` +- The CHW can proceed to the next page + +**On failure:** +- The progress bar turns red with a failure message +- **Retry** and **Continue without location tracking** buttons appear +- Tapping **Retry** resets the progress bar and tries again +- Tapping **Continue without location tracking** sets `geo_capture` to `"not_captured"` and skips GPS storage; `geo_context` is still saved to the contact document + +**On Android when location permission is denied:** + +- The capture button is not shown +- Instead, the widget displays the message: "Location access is turned off. Check your device settings to enable it." +- No form configuration is required for this behavior — it is handled automatically + +## What gets stored + +When the form is submitted, the following fields are written to the contact document. The names `geo_capture` and `geo_context` are from the examples above — your form may use different names. + +| Field | Value | Notes | +|-------|-------|-------| +| `geo_capture` (example; field name is arbitrary) | `"captured"` or `"not_captured"` | Normal form field | +| `geo_context` (example; field name is arbitrary) | The selected choice value (for example, `"home"`) | Normal form field; present even when GPS fails | +| `geolocation` | GPS coordinates object, or error object on failure | Written by CHT at save time | +| `geolocation_log` | Array of capture events | Append-only; grows on subsequent edits | + +Each entry in `geolocation_log` has this shape: + +```json +{ + "timestamp": 1234567890000, + "recording": { "latitude": 1.23, "longitude": 4.56, "accuracy": 10 }, + "context": "home" +} +``` + +`context` is only written to a log entry when GPS capture succeeds. If capture fails, `geo_context` is present on the contact document as a form field but `geolocation_log[n].context` is absent. + +## Customizing context choices + +The context choices are defined in the XForm and can be changed per deployment. The defaults (`home`, `workplace`, `other`) are a suggested baseline. To add, remove, or relabel choices, edit the `` elements and their corresponding `` entries in ``. + +The widget identifies the context question by `appearance="geolocation-context"` — not by field name or choice values — so the choices are fully customizable. + +## Omitting the context question + +The context question is optional. If a form includes the capture widget (`appearance="geolocation-capture"`) without a context field (`appearance="geolocation-context"`) in the same group, the capture button is enabled immediately and no context is stored. GPS coordinates are still captured and stored normally. diff --git a/content/en/building/forms/contact.md b/content/en/building/forms/contact.md index 6446cb9e8..cd368ff94 100644 --- a/content/en/building/forms/contact.md +++ b/content/en/building/forms/contact.md @@ -82,6 +82,14 @@ The equivalent XForm XML for the above example is: ``` +## Capturing GPS Location + +_Added in CHT `TBD`._ + +Contact forms can capture the device's GPS location when a contact is created or edited. The widget stores coordinates on the contact document and maintains a geolocation log across edits. An optional context question records where the CHW is relative to the beneficiary at capture time. + +{{< see-also page="building/forms/configuring/contact-geolocation" >}} + ## Properties The meta information in the `{contact_type_id}-{create|edit}.properties.json` file defines additional configuration controlling when the form is available and checks that will be performed when submitting the form. From 88304446780bed9b2e0ce591a4415fcda67ba543 Mon Sep 17 00:00:00 2001 From: Clifton McIntosh Date: Fri, 19 Jun 2026 07:59:26 -0500 Subject: [PATCH 2/2] docs(medic/cht-core#10676): update geolocation docs to match updated implementation Correct factual errors introduced before implementation was finalized: remove geo_context XForm field, fix geolocation_log shape (is_home boolean), fix skip value ("skipped"), scope geolocation field to home captures only. Add edit mode and weak-signal failure path. Replace UI string quotes and button labels with functional descriptions. Co-Authored-By: Claude Sonnet 4.6 --- .../forms/configuring/contact-geolocation.md | 142 ++++++++---------- 1 file changed, 62 insertions(+), 80 deletions(-) diff --git a/content/en/building/forms/configuring/contact-geolocation.md b/content/en/building/forms/configuring/contact-geolocation.md index 3a5427812..064ca351f 100644 --- a/content/en/building/forms/configuring/contact-geolocation.md +++ b/content/en/building/forms/configuring/contact-geolocation.md @@ -9,87 +9,60 @@ relatedContent: > building/contact-management/contacts --- -Contact forms can capture the device's GPS location at the time a contact is created or edited. The geolocation widget handles the full capture experience — progress feedback, success and failure states, and retry — and stores the result on the contact document. +Contact forms can capture the device's GPS location at the time a contact is created or edited. The geolocation widget handles the full capture experience: progress feedback, success and failure states, and retry. It stores the result on the contact document. -An optional _context question_ lets the CHW record where they are relative to the beneficiary at capture time (for example, at the home or workplace). When GPS capture succeeds, the context answer is stored alongside the coordinates in the geolocation log. +The widget includes an embedded context question ("Home" or "Other") that records where the CHW is relative to the beneficiary at capture time. This is part of the widget and requires no additional XForm fields. -> [!NOTE] -> Added in CHT `TBD`. +_Added in CHT `TBD`._ + +> [!CAUTION] +> This widget is designed for contact forms only. Adding it to a report form is unsupported and may produce unexpected behavior. ## XForm configuration -If including the context question, four changes are required in the contact form XML: model fields, binds, body group, and translations. Without the context question, only the first three are needed. The context question is optional — see [Omitting the context question](#omitting-the-context-question). +Three changes are required in the contact form XML: a model field, a bind, and a body element. ### 1. Model instance -Add both fields inside the contact's instance node: +Add the capture field inside the contact's instance node: ```xml - ``` -### 2. Binds +### 2. Bind -Add a bind for each field. It is recommended to mark `geo_context` as required so that form submission is blocked as a fallback if the CHW bypasses the widget. The widget independently enforces this by disabling the capture button until the context question is answered, so `required="true()"` is belt-and-suspenders rather than a widget requirement: +Add a bind for the capture field: ```xml - - + ``` -Replace `/data/contact/` with the actual nodeset path for the contact group in your form. +Replace `/data/contact/` with the actual nodeset path for the contact group in your form. The `required="true()"` attribute is recommended. The widget independently prevents the CHW from proceeding without a result, so this acts as a belt-and-suspenders fallback at submission. ### 3. Body -Add both fields inside a `field-list` group with the context question **above** the capture widget. Both fields must be in the same group so the widget can read the context selection at save time: +Add the field inside a `field-list` group: ```xml - - ``` -The `appearance` values `geolocation-context` and `geolocation-capture` are the contract between the form and CHT. The field names (`geo_capture`, `geo_context`) can be anything — only the appearances matter. +The `appearance="geolocation-capture"` value is the contract between the form and CHT. The field name (`geo_capture` in this example) can be anything; only the appearance matters. -### 4. Translations +### Translations -Add label text for each language your deployment supports in the `` section: +Add a label for the capture field in the `` section for each language your deployment supports: ```xml Capture GPS location - - Where are you capturing GPS location? - - - At the beneficiary's home - - - At the beneficiary's workplace - - - Other - ``` @@ -98,59 +71,76 @@ Add label text for each language your deployment supports in the `` secti > [!WARNING] > This section has not been tested against a real cht-conf XLSForm conversion. Verify the output before using it in a deployment. -For forms built with XLSForm, add the following rows to the **survey** sheet within the existing contact group. The context row must come before the capture row, and both must be in the same `field-list` group. - -| type | name | label::en | appearance | required | -|------|------|-----------|------------|----------| -| select_one geo_context_choices | geo_context | Where are you capturing GPS location? | geolocation-context | yes | -| string | geo_capture | Capture GPS location | geolocation-capture | | +For forms built with XLSForm, add the following row to the **survey** sheet within the existing contact group: -Add the following rows to the **choices** sheet: - -| list_name | name | label::en | -|-----------|------|-----------| -| geo_context_choices | home | At the beneficiary's home | -| geo_context_choices | workplace | At the beneficiary's workplace | -| geo_context_choices | other | Other | +| type | name | label::en | appearance | required | +|--------|-------------|----------------------|---------------------|----------| +| string | geo_capture | Capture GPS location | geolocation-capture | yes | ## Widget behavior Once the form is configured, the widget handles the capture experience automatically. **Before capture:** -- The context question is displayed as a radio button group -- The capture button is disabled until the CHW selects a context option + +- The widget displays a capture button and an embedded context question with two options +- The CHW selects a context option before tapping the capture button **When the CHW taps the capture button:** + - The context question is hidden - A progress bar fills over up to 30 seconds while GPS is acquired **On success:** + - The progress bar turns green with a success message - `geo_capture` is set to `"captured"` - The CHW can proceed to the next page -**On failure:** -- The progress bar turns red with a failure message -- **Retry** and **Continue without location tracking** buttons appear -- Tapping **Retry** resets the progress bar and tries again -- Tapping **Continue without location tracking** sets `geo_capture` to `"not_captured"` and skips GPS storage; `geo_context` is still saved to the contact document +**On failure (GPS signal weak):** + +When GPS acquisition fails due to a weak or unavailable signal: + +- The progress bar turns red +- A warning appears above the buttons prompting the CHW to move to an area with better signal +- A retry button and a button to skip location capture appear +- The skip button is disabled until the CHW checks an acknowledgement confirming the contact will be saved without a location +- Tapping the retry button resets the progress bar and tries again +- Tapping the skip button sets `geo_capture` to `"skipped"`; no coordinates are stored **On Android when location permission is denied:** - The capture button is not shown -- Instead, the widget displays the message: "Location access is turned off. Check your device settings to enable it." -- No form configuration is required for this behavior — it is handled automatically +- The widget displays a message informing the CHW that location access is disabled and directing them to their device settings +- No form configuration is required. This behavior is handled automatically. + +## Edit mode + +When a contact already has at least one successful GPS capture on record, editing that contact activates a different widget state. No additional XForm configuration is required. + +**Edit mode UI:** + +- A green badge is shown indicating the location is already saved, along with the capture context (home or other) and the number of days since the last capture +- Two radio options appear: an option to keep the existing location (pre-selected) and an option to capture a new location + +**Capturing a new location in edit mode:** + +- Selecting the option to capture a new location reveals a confirmation prompt asking the CHW to verify their location, along with an acknowledgement checkbox +- The CHW must check the acknowledgement before capture begins automatically +- If GPS acquisition fails, tapping the skip button returns the CHW to the keep/capture radio choice. The existing location is never discarded. + +**Contacts with only failed captures:** + +- A contact whose prior captures all failed (for example, permission denied) is treated the same as a contact with no location; the standard create-mode UI is shown instead of the badge ## What gets stored -When the form is submitted, the following fields are written to the contact document. The names `geo_capture` and `geo_context` are from the examples above — your form may use different names. +When the form is submitted, the following fields are written to the contact document. The name `geo_capture` is from the example above; your form may use a different name. | Field | Value | Notes | |-------|-------|-------| -| `geo_capture` (example; field name is arbitrary) | `"captured"` or `"not_captured"` | Normal form field | -| `geo_context` (example; field name is arbitrary) | The selected choice value (for example, `"home"`) | Normal form field; present even when GPS fails | -| `geolocation` | GPS coordinates object, or error object on failure | Written by CHT at save time | +| `geo_capture` (example; field name is arbitrary) | `"captured"` or `"skipped"` | Normal form field | +| `geolocation` | GPS coordinates object | Written by CHT at save time; only present when a home capture succeeds | | `geolocation_log` | Array of capture events | Append-only; grows on subsequent edits | Each entry in `geolocation_log` has this shape: @@ -159,18 +149,10 @@ Each entry in `geolocation_log` has this shape: { "timestamp": 1234567890000, "recording": { "latitude": 1.23, "longitude": 4.56, "accuracy": 10 }, - "context": "home" + "is_home": true } ``` -`context` is only written to a log entry when GPS capture succeeds. If capture fails, `geo_context` is present on the contact document as a form field but `geolocation_log[n].context` is absent. - -## Customizing context choices - -The context choices are defined in the XForm and can be changed per deployment. The defaults (`home`, `workplace`, `other`) are a suggested baseline. To add, remove, or relabel choices, edit the `` elements and their corresponding `` entries in ``. - -The widget identifies the context question by `appearance="geolocation-context"` — not by field name or choice values — so the choices are fully customizable. - -## Omitting the context question +`is_home` is `true` for home captures and `false` for other-context captures. On GPS failure, `recording` will be an error object (`{ "code": 2, "message": "..." }`) and `is_home` will not be present. -The context question is optional. If a form includes the capture widget (`appearance="geolocation-capture"`) without a context field (`appearance="geolocation-context"`) in the same group, the capture button is enabled immediately and no context is stored. GPS coordinates are still captured and stored normally. +`geolocation` is only updated when GPS capture succeeds and the CHW selected the home option. When the CHW selects the other option, coordinates are written to `geolocation_log` only.