Skip to content

fix: include imaging encounters in all outpatient encounter type checks#9503

Open
Copilot wants to merge 2 commits intomainfrom
copilot/fix-ui-behaviour-for-encounter-types
Open

fix: include imaging encounters in all outpatient encounter type checks#9503
Copilot wants to merge 2 commits intomainfrom
copilot/fix-ui-behaviour-for-encounter-types

Conversation

Copy link
Copy Markdown

Copilot AI commented Apr 3, 2026

UI behaviour and logic throughout the codebase was gating on ENCOUNTER_TYPES.CLINIC when the intent was to match the outpatient category — which also includes ENCOUNTER_TYPES.IMAGING. The canonical mapping in getPatientStatus.js already treats both as PATIENT_STATUS.OUTPATIENT, but many callsites bypassed it.

Changes

  • DischargeForm.jsx (×2) — dischargeDiagnosisMandatory now uses getPatientStatus(encounterType) !== PATIENT_STATUS.OUTPATIENT instead of !== ENCOUNTER_TYPES.CLINIC
  • PharmacyOrderModal.jsx — Default prescription type uses getPatientStatus() === PATIENT_STATUS.OUTPATIENT (supersedes fix(web): use patient status instead of specific encounter type for pharmacy prescription default #9502)
  • EncounterActions.jsx — "Admit to hospital" condition uses getPatientStatus() === PATIENT_STATUS.OUTPATIENT instead of === ENCOUNTER_TYPES.CLINIC
  • TopBar.jsx — Added [ENCOUNTER_TYPES.IMAGING]: '#F9BA5B' to dotColors (same as CLINIC)
  • RecentlyViewedPatientsList.jsx — Added imaging: '#E9AC50' to colorFromEncounterType
  • EditEncounterModal.jsx — Added IMAGING fallthrough to CLINIC in both FormFields switch and getFormInitialValues (was rendering error string)
  • PatientListingView.jsx — Outpatient recently-viewed now passes [CLINIC, IMAGING] instead of "clinic"
  • user.js (facility-server)recently-viewed-patients filter changed from = :encounterType to IN (:encounterTypes), accepting a single value or array (backward compatible)
// Before — misses imaging encounters
encounterType !== ENCOUNTER_TYPES.CLINIC

// After — covers all outpatient types via canonical mapping
getPatientStatus(encounterType) !== PATIENT_STATUS.OUTPATIENT

Auto-Deploy

  • Deploy
Options
  • Synthetic test

Tests

  • Run E2E Tests

Review Hero

  • Run Review Hero
  • Auto-fix review suggestions Wait for Review Hero to finish, resolve any comments you disagree with or want to fix manually, then check this to auto-fix the rest.
  • Auto-fix CI failures Check this to auto-fix lint errors, test failures, and other CI issues.
  • Auto-merge upstream Check this to merge the base branch into this PR, with AI conflict resolution if needed.

Remember to...

  • ...write or update tests
  • ...add UI screenshots and testing notes to the Linear issue
  • ...add any manual upgrade steps to the Linear issue
  • ...update the config reference, settings reference, or any relevant runbook(s)
  • ...call out additions or changes to config files for the deployment team to take note of
Original prompt

Problem

Throughout the codebase, UI behaviour and logic switches on specific hardcoded encounter type values (usually ENCOUNTER_TYPES.CLINIC) when the actual intent is to check an encounter category (e.g. "outpatient"). This causes imaging encounters — which are also outpatient — to be missed, resulting in incorrect UI behaviour.

The codebase already has a canonical source of truth for mapping encounter types to patient statuses in packages/web/app/utils/getPatientStatus.js:

const ENCOUNTER_TYPE_TO_STATUS = {
  [ENCOUNTER_TYPES.ADMISSION]: PATIENT_STATUS.INPATIENT,
  [ENCOUNTER_TYPES.CLINIC]: PATIENT_STATUS.OUTPATIENT,
  [ENCOUNTER_TYPES.IMAGING]: PATIENT_STATUS.OUTPATIENT,
  [ENCOUNTER_TYPES.OBSERVATION]: PATIENT_STATUS.EMERGENCY,
  [ENCOUNTER_TYPES.EMERGENCY]: PATIENT_STATUS.EMERGENCY,
  [ENCOUNTER_TYPES.TRIAGE]: PATIENT_STATUS.EMERGENCY,
};

And existing helpers isInpatient() (in packages/web/app/utils/isInpatient.js) and isEmergencyPatient() (in packages/web/app/utils/isEmergencyPatient.js) already use this mapping correctly. But many places bypass these helpers and compare against a single hardcoded type.

Fixes Required

1. DischargeForm.jsx — Discharge diagnosis mandatory skips only CLINIC (misses IMAGING)

File: packages/web/app/forms/DischargeForm.jsx (two locations: lines ~420-422 and ~527-529)

The current code:

const dischargeDiagnosisMandatory =
  getSetting('features.discharge.dischargeDiagnosisMandatory') &&
  encounterType !== ENCOUNTER_TYPES.CLINIC;

Should be changed to use getPatientStatus and PATIENT_STATUS to check for outpatient status instead:

import { getPatientStatus } from '../utils/getPatientStatus';
import { PATIENT_STATUS } from '../constants';

const dischargeDiagnosisMandatory =
  getSetting('features.discharge.dischargeDiagnosisMandatory') &&
  getPatientStatus(encounterType) !== PATIENT_STATUS.OUTPATIENT;

Both locations need to be fixed. The first is in EncounterOverview component and uses encounterType directly. The second is in DischargeFormScreen and uses encounter.encounterType.

2. PharmacyOrderModal.jsx — Default prescription type only checks CLINIC (misses IMAGING)

File: packages/web/app/components/Medication/PharmacyOrderModal.jsx (line ~242)

The current code:

if (encounter.encounterType === ENCOUNTER_TYPES.CLINIC) {
  setPrescriptionType(PHARMACY_PRESCRIPTION_TYPES.DISCHARGE_OR_OUTPATIENT);
} else {
  setPrescriptionType(PHARMACY_PRESCRIPTION_TYPES.INPATIENT);
}

Should be changed to:

import { getPatientStatus } from '../../utils/getPatientStatus';
import { PATIENT_STATUS } from '../../constants';

if (getPatientStatus(encounter.encounterType) === PATIENT_STATUS.OUTPATIENT) {
  setPrescriptionType(PHARMACY_PRESCRIPTION_TYPES.DISCHARGE_OR_OUTPATIENT);
} else {
  setPrescriptionType(PHARMACY_PRESCRIPTION_TYPES.INPATIENT);
}

Also remove the now-unused ENCOUNTER_TYPES import if it's no longer needed by other code in this file.

3. EncounterActions.jsx — "Admit to hospital" only allows upgrade from CLINIC (misses IMAGING)

File: packages/web/app/views/patients/components/EncounterActions.jsx (lines ~153-156)

The current code:

condition: () =>
  canWriteEncounter &&
  (isProgressionForward(encounter.encounterType, ENCOUNTER_TYPES.ADMISSION) ||
    encounter.encounterType === ENCOUNTER_TYPES.CLINIC),

The ENCOUNTER_TYPE_PROGRESSION map only includes triage→observation→emergency→admission. CLINIC is special-cased as an additional allowed source. But IMAGING encounters (also outpatient) can't be admitted to hospital.

Should be changed to:

import { getPatientStatus } from '../../../utils/getPatientStatus';
import { PATIENT_STATUS } from '../../../constants';

condition: () =>
  canWriteEncounter &&
  (isProgressionForward(encounter.encounterType, ENCOUNTER_TYPES.ADMISSION) ||
    getPatientStatus(encounter.encounterType) === PATIENT_STATUS.OUTPATIENT),

4. TopBar.jsxdotColors map missing IMAGING

File: packages/web/app/components/TopBar.jsx (lines ~47-53)

The current code:

const dotColors = {
  [ENCOUNTER_TYPES.ADMISSION]: Colors.safe,
  [ENCOUNTER_TYPES.CLINIC]: '#F9BA5B',
  [ENCOUNTER_TYPES.TRIAGE]: Colors.orange,
  [ENCOUNTER_TYPES.OBSERVATION]: Colors.orange,
  [ENCOUNTER_TYPES.EMERGENCY]: Colors.orange,
};

Should add IMAGING with the same color as CLINIC:

const dotColors = {
  [ENCOUNTER_TYPES.ADMISSION]: Colors.safe,
  [ENCOUNTER_TYPES.CLINIC]: '#F9BA5B',
  [ENCOUNTER_TYPES.IMAGING]: '#F9BA5B',
  [ENCOUNTER_TYPES.TRIAGE]: Colors.orange,
  [ENCOUNTER_TYPES.OBSERVATION]: Colors.orange,
  [ENCOUNTER_TYPES.EMERGENCY]: Colors.orange,
};

5. RecentlyViewedPatientsList.jsxcolorFromEncounterType missing IMAGING

File: packages/web/app/components/RecentlyViewedPatientsList.jsx (lines ~15-22)

The current code:

const colorFromEncounterType = ...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

- DischargeForm.jsx: use getPatientStatus() !== OUTPATIENT instead of !== CLINIC for discharge diagnosis mandatory check (both locations)
- PharmacyOrderModal.jsx: use getPatientStatus() === OUTPATIENT for default prescription type (supersedes #9502)
- EncounterActions.jsx: use getPatientStatus() === OUTPATIENT for 'Admit to hospital' condition
- TopBar.jsx: add IMAGING to dotColors map with same color as CLINIC
- RecentlyViewedPatientsList.jsx: add imaging to colorFromEncounterType map
- EditEncounterModal.jsx: add IMAGING as fallthrough to CLINIC in FormFields and getFormInitialValues
- PatientListingView.jsx: pass both CLINIC and IMAGING encounter types for outpatient recently-viewed list
- user.js backend: support array of encounter types using IN clause (backward compatible)

Agent-Logs-Url: https://github.com/beyondessential/tamanu/sessions/d109dd8c-a51f-4caa-be6c-14817bff86bc

Co-authored-by: passcod <155787+passcod@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix UI logic for handling encounter categories fix: include imaging encounters in all outpatient encounter type checks Apr 3, 2026
Copilot AI requested a review from passcod April 3, 2026 03:18
Copilot stopped work on behalf of passcod due to an error April 3, 2026 03:35
@passcod
Copy link
Copy Markdown
Member

passcod commented Apr 4, 2026

That all LGTM but I'll get someone from Tamanu UX to review for intent.

@passcod passcod marked this pull request as ready for review April 4, 2026 01:09
@review-hero
Copy link
Copy Markdown

review-hero Bot commented Apr 4, 2026

🦸 Review Hero Summary
9 agents reviewed this PR | 0 critical | 0 suggestions | 0 nitpicks | Filtering: consensus 3 voters, 2 below threshold

No issues found. Looks good!

Below consensus threshold (2 unique issues not confirmed by majority)
Location Agent Severity Comment
packages/web/app/components/RecentlyViewedPatientsList.jsx:18 BES Requirements nitpick Uses the string literal 'imaging' as a key, while the same PR uses ENCOUNTER_TYPES.IMAGING in TopBar.jsx. All other entries in this object also use string literals (existing pattern), but sin...
packages/web/app/utils/getPatientStatus.js:23 BES Requirements suggestion getPatientStatus returns a human-readable label string like 'Outpatient' rather than the raw PATIENT_STATUS enum value. At the call sites (e.g. EncounterActions.jsx, DischargeForm.jsx, `P...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants