Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"retired": false,
"pages": [
{
"label": "PHQ-2",
"label": "PHQ-2 Screening",
"sections": [
{
"label": "Introduction",
Expand All @@ -16,9 +16,13 @@
"questionOptions": {
"rendering": "markdown"
},
"id": "fooMarkdown",
"id": "phq9Intro",
"value": [
"**This form is used :** for screening, diagnosing, monitoring and measuring the severity of depression."
"**PHQ-9 Depression Screening**",
"",
"This form is used for screening, diagnosing, monitoring and measuring the severity of depression.",
"",
"**Instructions:** Over the last 2 weeks, how often have you been bothered by any of the following problems?"
]
}
]
Expand All @@ -38,14 +42,6 @@
"type": "CIEL",
"value": "160753"
},
{
"type": "CIEL",
"value": "160753"
},
{
"type": "SNOMED-CT",
"value": "439771001"
},
{
"type": "SNOMED-CT",
"value": "439771001"
Expand Down Expand Up @@ -80,6 +76,16 @@
"questionOptions": {
"rendering": "radio",
"concept": "167006AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"conceptMappings": [
{
"type": "CIEL",
"value": "167006"
},
{
"type": "LOINC",
"value": "44250-9"
}
],
"answers": [
{
"concept": "160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
Expand Down Expand Up @@ -121,6 +127,16 @@
"questionOptions": {
"rendering": "radio",
"concept": "167007AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"conceptMappings": [
{
"type": "CIEL",
"value": "167007"
},
{
"type": "LOINC",
"value": "44255-8"
}
],
"answers": [
{
"concept": "160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
Expand All @@ -142,16 +158,6 @@
"label": "Nearly every day",
"conceptMappings": []
}
],
"conceptMappings": [
{
"type": "CIEL",
"value": "167007"
},
{
"type": "LOINC",
"value": "44255-8"
}
]
},
"behaviours": [
Expand All @@ -171,7 +177,7 @@
]
},
{
"label": "PHQ-9",
"label": "PHQ-9 Additional Questions",
"sections": [
{
"label": "Further evaluation",
Expand Down Expand Up @@ -331,7 +337,7 @@
"id": "phq9_5"
},
{
"label": "6. Feeling bad about yourself - or that youre a failure or have let yourself or your family down",
"label": "6. Feeling bad about yourself - or that you're a failure or have let yourself or your family down",
"type": "obs",
"questionOptions": {
"rendering": "radio",
Expand Down Expand Up @@ -547,21 +553,42 @@
]
},
{
"label": "PHQ-9 score",
"label": "Scoring and Results",
"sections": [
{
"label": "Total scores",
"label": "PHQ-9 Scoring",
"isExpanded": "true",
"questions": [
{
"label": "PHQ-9 score obtained by adding score for each question",
"label": "PHQ-2 Score (Questions 1-2)",
"type": "display",
"questionOptions": {
"rendering": "number",
"max": "6",
"min": "0",
"calculate": {
"calculateExpression": "calcPHQ9Score(phq2_1, phq2_2)"
}
},
"behaviours": [
{
"intent": "*",
"readonly": "true"
}
],
"id": "phq2Score"
},
{
"label": "PHQ-9 Total Score (Questions 1-9)",
"type": "obs",
"questionOptions": {
"rendering": "number",
"concept": "165137AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"max": "27",
"min": "0",
"showDate": "",
"calculate": {
Copy link
Member

@denniskigen denniskigen Oct 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The inline calculateExpression here is quite long (~1000 chars) and repeats the UUID-to-score mapping 9 times. Could we consider factoring it out into a reusable custom expression helper function in the form engine instead?

We could add a calcPHQ9Score() helper to common-expression-helpers.ts (similar to calcBMI(), calcEDD(), etc) that looks like this:

/**
 * Calculates PHQ-9 (Patient Health Questionnaire-9) depression screening score
 * Supports both PHQ-2 (questions 1-2) and full PHQ-9 (questions 1-9)
 * Handles hidden/conditional questions by treating undefined/null values as 0
 * 
 * @param responses - Variable number of PHQ question responses (concept UUIDs)
 * @returns Total score (0-27 for full PHQ-9, 0-6 for PHQ-2 only)
 * 
 * @example
 * // PHQ-2 negative screen (questions 3-9 hidden)
 * calcPHQ9Score(phq2_1, phq2_2, phq9_3, phq9_4, phq9_5, phq9_6, phq9_7, phq9_8, phq9_9)
 * // Returns: 0 if both answered "Not at all"
 * 
 * @example
 * // Full PHQ-9
 * calcPHQ9Score(phq2_1, phq2_2, phq9_3, phq9_4, phq9_5, phq9_6, phq9_7, phq9_8, phq9_9)
 * // Returns: Sum of all 9 responses (0-27)
 */
calcPHQ9Score = (...responses: (string | null | undefined)[]): number => {
  const scoreMap: Record<string, number> = {
    '160215AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': 0, // Not at all
    '167000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': 1, // Several days
    '167001AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': 2, // More than half the days
    '167002AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': 3, // Nearly every day
  };

  return responses.reduce((sum, answer) => {
    return sum + (answer ? (scoreMap[answer] ?? 0) : 0);
  }, 0);
};

And then we could simplify the calculateExpression in this form by leveraging the new expression helper as follows:

  "calculate": {
    "calculateExpression": "calcPHQ9Score(phq2_1, phq2_2, phq9_3, phq9_4, phq9_5, phq9_6, phq9_7, phq9_8, phq9_9)"
  }

Benefits of this approach:

  • Easier to read, test, and maintain
  • Centralizes the UUID mapping logic
  • Follows DRY principle
  • Matches the architectural pattern used elsewhere in the codebase

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@denniskigen thanks for your feedback, are you suggesting that the change (custom expression helper function) should be implemented in the form engine’s codebase, not directly in the form JSON? @samuelmale is this something you can assist us?

Copy link
Member

@denniskigen denniskigen Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: PR merged. Should be available soon.

"calculateExpression": "calcPHQ9Score(phq2_1, phq2_2, phq9_3, phq9_4, phq9_5, phq9_6, phq9_7, phq9_8, phq9_9)"
},
"conceptMappings": [
{
"type": "SNOMED-CT",
Expand All @@ -573,7 +600,13 @@
}
]
},
"id": "phq9Score"
"behaviours": [
{
"intent": "*",
"readonly": "true"
}
],
"id": "phq9TotalScore"
}
]
}
Expand All @@ -583,21 +616,17 @@
"label": "Notes",
"sections": [
{
"label": "Notes",
"label": "Additional Notes",
"isExpanded": "true",
"questions": [
{
"label": "Mental Health Assessment Notes",
"label": "Clinician Notes",
"type": "obs",
"questionOptions": {
"rendering": "textarea",
"concept": "165095AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
"rows": "",
"conceptMappings": [
{
"type": "AMPATH",
"value": "1915"
},
{
"type": "AMPATH",
"value": "1915"
Expand All @@ -612,7 +641,7 @@
}
]
},
"id": "phq9Notes"
"id": "clinicianNotes"
}
]
}
Expand All @@ -629,5 +658,6 @@
"uuid": "2069bd57-d534-3de9-ae24-f1d4e4b2de83",
"referencedForms": [],
"encounterType": "36db5123-0ad5-41c0-9037-625b46e0ceef",
"encounter": "Mental Health Assessment"
}
"encounter": "Mental Health Assessment",
"description": "A form used for screening, diagnosing, monitoring and measuring the severity of depression"
}