Building > Features > Targets
Dashboards to track metrics for an individual CHW or for an entire health facility
This tutorial will take you through how to build target widgets.
Target widgets provide a summary or analysis of the data in submitted reports.
You will be adding target widgets that will allow Community Health Workers (CHWs) to track various metrics based on assessment reports submitted.
Targets is the user dashboard or analytics tab.
Target widgets provide a summary or analysis of the data in submitted reports.
Count widgets show a tally of a particular report that has been submitted or data within a report that matches a set of criteria.
Percent widgets display a ratio, which helps to provide insight into the proportion that matches a defined criteria.
Target schema details a set of properties for targets.
Target instance is an object emitted and counted or aggregated based on target configuration.
You should have a functioning CHT instance with cht-conf
installed locally, completed a project folder setup, and an assessment form.
It is good practice to set up a reference document outlining the specifications of the target widgets similar to the one below. Other formats may also be used.
Source | UI Label | Definition | Type | Reporting Period | Goal |
---|---|---|---|---|---|
Assessment form | Total assessments | Total number of assessment reports submitted | Count | All time | _ |
Assessment form | Total assessments | Total number of assessment reports submitted this month | Count | This month | 2 |
Assessment form | Total population with cough | Total number of household members with cough | Count | This month | _ |
Assessment form | % Population with cough | Total number of contacts with cough/Total number of contacts assessed | Percent | This month | _ |
Assessment form | Total households with assessments | Total number of households with at least one submitted assessment form | Count | This month | 2 |
Assessment form | % Household with >=2 assessments | Total number of households with at least two patients assessed/Total number of households | Percent | All time | 60 |
Create a targets.js
file (this may have already been created by the initialise-project-layout
command).
This widget counts the total number of assessment reports that have been submitted by the user from the time that they started reporting.
Edit the targets.js
file to define the total assessments all-time widget as shown below:
{
id: 'assessments-all-time',
type: 'count',
icon: 'icon-healthcare-assessment',
goal: -1,
translation_key: 'targets.assessments.title',
subtitle_translation_key: 'targets.all_time.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
date: 'now'
}
This widget counts the total number of assessment reports that have been submitted by the user for this month.
Edit the targets.js
file and add another target widget definition object to define the total assessments monthly widget as shown below:
{
id: 'assessments-this-month',
type: 'count',
icon: 'icon-healthcare-assessment',
goal: 2,
translation_key: 'targets.assessments.title',
subtitle_translation_key: 'targets.this_month.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
date: 'reported'
}
date
property set to now
while monthly widgets have the date
property set to reported
.The images show the monthly
and all-time
target widgets respectively, with the resulting figures varying depending on the number of assessment reports submitted within the respective durations.
This widget calculates the total number of patients assessed that have been indicated to have a cough this month, regardless of the number of reports submitted for them. Note that idType
counts the contact IDs.
Edit the targets.js
file and add the target widget as shown below:
{
id: 'total-contacts-with-cough-this-month',
type: 'count',
icon: 'icon-cough',
goal: -1,
translation_key: 'targets.assessments.total.cough.title',
subtitle_translation_key: 'targets.this_month.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
appliesIf: function (contact, report) {
return Utils.getField(report, 'group_assessment.cough') === 'yes';
},
idType: 'contact',
date: 'reported'
}
This widget calculates the percentage patients assessed that have been indicated to have a cough this month, regardless of the number of reports submitted for them.
Edit the targets.js
file and add the target widget as shown below:
{
id: 'percentage-contacts-with-cough-this-month',
type: 'percent',
icon: 'icon-cough',
goal: -1,
translation_key: 'targets.assessments.percentage.cough.title',
percentage_count_translation_key: 'targets.assessments.percentage.with.cough',
subtitle_translation_key: 'targets.this_month.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
appliesIf: function (contact) {
return contact.contact && contact.contact.parent && contact.contact.parent.parent && contact.contact.parent.parent.parent;
},
passesIf: function(contact, report) {
return Utils.getField(report, 'group_assessment.cough') === 'yes';
},
idType: 'contact',
date: 'reported'
}
This widget calculates the number of households that have patients assessed this month. Note that emitCustom
emits a target with custom conditions that may otherwise not be directly configurable through the target schema. Filter based on reports, and use the contact information from the reports to emit targets. The target ID is the household ID.
Edit the targets.js
file and add the target widget as shown below:
{
id: 'households-with-assessments-this-month',
type: 'count',
icon: 'icon-household',
goal: 2,
translation_key: 'targets.households.with.assessments.title',
subtitle_translation_key: 'targets.this_month.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
date: 'reported',
emitCustom: (emit, original, contact) => {
const householdId = contact.contact && contact.contact.parent._id;
emit(Object.assign({}, original, {
_id: householdId,
pass: true
}));
}
},
Note the difference in appearance on the resulting count
target widgets based on whether the goal
is achieved. The figures vary depending on the number of assessment reports submitted for household members.
This widget calculates the percentage of households that have two or more patients assessed all time. Use emitCustom
to emit a custom target instance. The target instance ID is the household ID.
Edit the targets.js
file and add the target widget as shown below:
//Define a function to get the household ID based on the hierarchy configuration
const getHouseholdId = (contact) => contact.contact && contact.contact.type === 'clinic' ? contact.contact._id : contact.contact.parent && contact.contact.parent._id;
//Define a function to determine if contact is patient
const isPatient = (contact) => contact.contact && contact.contact.type === 'person' && contact.contact.parent && contact.contact.parent.parent && contact.contact.parent.parent.parent;
{
id: 'households-with-gt2-assessments-this-month',
type: 'percent',
icon: 'icon-household',
goal: 60,
translation_key: 'targets.households.with.gt2.assessments.title',
subtitle_translation_key: 'targets.all_time.subtitle',
appliesTo: 'contacts',
appliesToType: ['person', 'clinic'], //Need the total number of households as denominator
date: 'now',
emitCustom: (emit, original, contact) => {
const householdId = getHouseholdId(contact);
if (isPatient(contact)) {
if (contact.reports.some(report => report.form === 'assessment')) {
emit(Object.assign({}, original, const targetInstance = {
_id: householdId, //Emits a passing target instance with the household ID as the target instance ID
pass: true
}));
}
}
if(contact.contact && contact.contact.type === 'clinic') { //This represents the denominator, which is the total number of households
emit(Object.assign({}, original,
_id: householdId,
pass: false, //Set to false so that it is counted in the denominator
}));
}
},
groupBy: contact => getHouseholdId(contact),
passesIfGroupCount: { gte: 2 }
}
See Also: Hierarchies
The images show the resulting percent
target widgets, with the figures varying depending on the number of assessment reports submitted for household members. Note the difference in appearance based on whether the goal
is achieved.
targets.js
fileInclude the functions and replace appropriately in the file. The final content of the targets file should be similar the one below:
//Define a function to get the household ID based on the hierarchy configuration
const getHouseholdId = (contact) => contact.contact && contact.contact.type === 'clinic' ? contact.contact._id : contact.contact.parent && contact.contact.parent._id;
//Define a function to determine if contact is patient
const isPatient = (contact) => contact.contact && contact.contact.type === 'person' && contact.contact.parent && contact.contact.parent.parent && contact.contact.parent.parent.parent;
module.exports = [
{
id: 'assessments-all-time',
type: 'count',
icon: 'icon-healthcare-assessment',
goal: -1,
translation_key: 'targets.assessments.title',
subtitle_translation_key: 'targets.all_time.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
date: 'now'
},
{
id: 'assessments-this-month',
type: 'count',
icon: 'icon-healthcare-assessment',
goal: 2,
translation_key: 'targets.assessments.title',
subtitle_translation_key: 'targets.this_month.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
date: 'reported'
},
{
id: 'total-contacts-with-cough-this-month',
type: 'count',
icon: 'icon-cough',
goal: -1,
translation_key: 'targets.assessments.total.cough.title',
subtitle_translation_key: 'targets.this_month.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
appliesIf: function (contact, report) {
return Utils.getField(report, 'group_assessment.cough') === 'yes';
},
idType: 'contact',
date: 'reported'
},
{
id: 'percentage-contacts-with-cough-this-month',
type: 'percent',
icon: 'icon-cough',
goal: -1,
translation_key: 'targets.assessments.percentage.cough.title',
subtitle_translation_key: 'targets.this_month.subtitle',
percentage_count_translation_key: 'targets.assessments.percentage.with.cough',
appliesTo: 'reports',
appliesToType: ['assessment'],
appliesIf: function (contact) {
return isPatient(contact);
},
passesIf: function(contact, report) {
return Utils.getField(report, 'group_assessment.cough') === 'yes';
},
idType: 'contact',
date: 'reported'
},
{
id: 'households-with-assessments-this-month',
type: 'count',
icon: 'icon-household',
goal: 2,
translation_key: 'targets.households.with.assessments.title',
subtitle_translation_key: 'targets.this_month.subtitle',
appliesTo: 'reports',
appliesToType: ['assessment'],
date: 'reported',
emitCustom: (emit, original, contact) => {
const householdId = getHouseholdId(contact);
emit(Object.assign({}, original, {
_id: householdId,
pass: true
}));
}
},
{
id: 'households-with-gt2-assessments-this-month',
type: 'percent',
icon: 'icon-household',
goal: 60,
translation_key: 'targets.households.with.gt2.assessments.title',
subtitle_translation_key: 'targets.all_time.subtitle',
appliesTo: 'contacts',
appliesToType: ['person', 'clinic'], //Need the total number of households as denominator
date: 'now',
emitCustom: (emit, original, contact) => {
const householdId = getHouseholdId(contact);
if (isPatient(contact)) {
if (contact.reports.some(report => report.form === 'assessment')) {
emit(Object.assign({}, original, const targetInstance = {
_id: householdId, //Emits a passing target instance with the household ID as the target instance ID
pass: true
}));
}
}
if(contact.contact && contact.contact.type === 'clinic') { //This represents the denominator, which is the total number of households
emit(Object.assign({}, original,
_id: householdId,
pass: false, //Set to false so that it is counted in the denominator
}));
}
},
groupBy: contact => getHouseholdId(contact),
passesIfGroupCount: { gte: 2 },
}
];
See Also: Targets overview
To compile and upload app settings to your local instance, run the following command:
cht --url=https://<username>:<password>@localhost --accept-self-signed-certs compile-app-settings upload-app-settings
<username>
and <password>
with the actual username and password of your test instance.The image on the right-hand side shows the expected outcome on the analytics tab
, with figures varying depending on the number of reports submitted on your instance.
To update the titles of the target widgets, ensure that the translation keys
are in the translations file. Add the following translation keys and their values in the messages-en.properties
file. You may word your translation keys and values differently.
targets.assessments.title = Total assessments
targets.assessments.total.cough.title = Total population with cough
targets.assessments.percentage.cough.title = % Population with cough
targets.households.with.assessments.title = Total households with assessments
targets.households.with.gt2.assessments.title = % Household with >=2 assessments
To upload translations to your local instance, run the following command:
cht --url=https://<username>:<password>@localhost --accept-self-signed-certs upload-custom-translations
The image on the right-hand side shows the updated target titles. Your image may be different depending on your wording.
translation_key
property.You may add icons
to your target widgets to enhance their appearance and to help users locate specific widgets more quickly. Use the icons in the targets icon library, or icons of your choice for the target widgets. Add your selected icons to the resources
folder in your project folder. In your resources.json
file, add key/value pairs for your icon resources.
{
"icon-healthcare-assessment": "icon-healthcare-assessment.svg",
"icon-household": "icon-places-household.svg",
"icon-cough": "icon-condition-cough.svg"
}
key
in the resources.json
file is the value of the icon
property in the target widget configuration.See Also: Icon Library
To upload resources to your local instance, run the following command:
cht --url=https://<username>:<password>@localhost --accept-self-signed-certs upload-resources
The image on the right-hand side shows the expected final appearance of the target widgets on adding and uploading resources. The figures on the widgets will depend on the number of reports submitted for contacts and the number of contacts you have created on your instance.
Dashboards to track metrics for an individual CHW or for an entire health facility
Targets: Definition of target widgets calculated and seen in the app
This document covers the configuration best practices of forms, tasks, targets, and contact profiles when building your own community health app.
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.