Profile & Settings
Profile​
Route: /profile
File: memberportal/src/pages/ProfilePage.tsx
FHIR Resource: Patient
The Profile page shows the patient's personal information pulled from their Patient FHIR resource:
- Full name
- Date of birth
- Gender
- Contact information (phone, email)
- Address
Settings​
Route: /settings
File: memberportal/src/pages/SettingsPage.tsx
The Settings page is the most complex page in the portal. It is organized into sections:
1. Hospital Connections​
Patients can connect to hospitals registered in the system via SMART on FHIR. The Hospital Connections section lists all currently connected hospitals and provides a Connect Hospitals button that opens the HospitalPickerModal.
Connected hospital actions:
- Sync — triggers a background data refresh for that hospital (
POST fhir/referesh/single/{connectionId}). The app polls sync status viauseSyncPolleruntil the job completes. - Disconnect — opens a confirmation modal, then calls
POST fhir/ehr-import/disconnect/{connectionId}. The hospital is removed from the list; existing synced records remain visible.
HospitalPickerModal​
The picker fetches hospitals from GET fhir/hospitals/search and displays them in a searchable, filterable list.
Search & filters:
| Control | Behaviour |
|---|---|
| Name search | Debounced 400 ms; sends name query param |
| State | Dropdown (country-state-city); sends state param and primes the state cache |
| City | Autocomplete populated from the selected state; filtered client-side from cache |
| Zip Code | Free-text; filtered client-side from cache |
State endpoint cache: When the patient selects a state with no city/postal/name filter, the full results are stored in stateEndpointCache. Subsequent city, postal, or name changes are applied client-side without a new API call. The cache is cleared when the modal opens or when the state is changed.
Pagination: Results without address filters include _count=50. If hasMore is true the modal uses an IntersectionObserver on a sentinel <div> to automatically call GET {nextUrl} (load-more) as the patient scrolls.
Hospital result card: Each result shows the hospital name, address (city / state / zip from _org), and a Connect button. Already-connected hospitals show a "Connected" badge instead.
Connect flow:
- Patient clicks Connect on a hospital.
- If the hospital's
EHR_VENDOR_EXT_URLextension identifies the vendor ashealow, a country check runs first (see Healow geo-restriction below). POST fhir/ehr-import/hospital-startis called with{ hospitalId }.- The server returns
{ authorizeUrl }and the browser is redirected there to complete OAuth2. - After the patient authenticates, the EHR redirects back and the hospital appears in the connected list.
Healow geo-restriction:
Healow only supports OAuth connections from within the United States. Before redirecting a patient to a Healow hospital's authorization endpoint, the app checks their country:
getCountryCode()is called — it resolves in this priority order:- In-memory cache (
countryCodeCacheref, lives for the tab session) localStoragekey_cc_geo(persists across sessions)- HTTP call to
https://api.country.is/with a 3-second timeout
- In-memory cache (
- If the resolved country is not
US, an error notification is shown and the redirect is cancelled. - On any API error the check fails open (returns
'US') so an outage never blocks a legitimate US patient.
2. Privacy & Security​
Password reset:
- Patient can request a password reset email.
- Protected by invisible reCAPTCHA to prevent abuse.
- Calls
POST auth/resetpasswordwith the patient's email, project ID, and reCAPTCHA token.
Two-Factor Authentication (2FA):
- Patient can enable or disable TOTP-based 2FA.
- Enable flow:
GET auth/mfa/status— server returns a TOTP secret and QR code URI.- Patient scans the QR code with their authenticator app (or enters the manual secret).
- Patient enters a 6-digit code;
POST auth/mfa/enrollverifies it. - 2FA is now active on the account.
- Disable flow:
- Patient enters their current 6-digit code.
POST auth/mfa/disableremoves 2FA from the account.
Session Timeout: Patient can choose how long before they are automatically logged out due to inactivity:
- 15 minutes (default)
- 30 minutes
- 60 minutes
- 4 hours
The setting is saved to localStorage and read by useIdleTimeout.