import type { Address, Location, Organization } from "fhir/r4"; import { normalizeFhirAddress } from "./fhirAddress"; import { withTimezoneExtension } from "./practiceTimezone"; import { LOCATION_PHYSICAL_TYPE_SYSTEM, SITE_PHYSICAL_TYPE_CODE } from "./roomLocation"; import { isUsStateCode } from "./usStates"; export type SiteLocationDraft = { name: string; street: string; city: string; state: string; postalCode: string; timezone: string; }; export type SiteLocationField = keyof SiteLocationDraft; export const EMPTY_SITE_LOCATION: SiteLocationDraft = { name: "", street: "", city: "", state: "", postalCode: "", timezone: "", }; const US_CORE_LOCATION_PROFILE = "http://hl7.org/fhir/us/core/StructureDefinition/us-core-location"; export const siteLocationAddress = (draft: SiteLocationDraft): Address => ({ use: "work", type: "physical", line: [draft.street.trim()], city: draft.city.trim(), state: draft.state, postalCode: draft.postalCode.trim(), country: "US", }); // An existing site at the draft's address, which a primary-location step resumes instead of // creating a second one. export const findSameAddress = (draft: SiteLocationDraft, existing: Location[]): Location | undefined => { const address = normalizeFhirAddress(siteLocationAddress(draft)); return existing.find((l) => normalizeFhirAddress(l.address) === address); }; // Field-specific messages, in form order, so the first one is the field to focus. export const validateSiteLocation = ( draft: SiteLocationDraft, existing: Location[], ): Partial> => { const errors: Partial> = {}; if (!draft.name.trim()) errors.name = "Name this location."; if (!draft.street.trim()) errors.street = "Enter the street address."; if (!draft.city.trim()) errors.city = "Enter the city."; if (!isUsStateCode(draft.state)) errors.state = "Choose the state."; if (!/^\d{5}(-\d{4})?$/.test(draft.postalCode.trim())) errors.postalCode = "Enter a 5-digit ZIP code."; if (!draft.timezone.trim()) errors.timezone = "Choose the time zone."; if (!errors.street && !errors.city && !errors.state && !errors.postalCode) { const duplicate = findSameAddress(draft, existing); if (duplicate) errors.street = `This address already exists for ${duplicate.name || "another location"}.`; } return errors; }; export const buildSiteLocation = (draft: SiteLocationDraft, org: Organization): Location => ({ resourceType: "Location", meta: { profile: [US_CORE_LOCATION_PROFILE] }, status: "active", mode: "instance", name: draft.name.trim(), physicalType: { coding: [{ system: LOCATION_PHYSICAL_TYPE_SYSTEM, code: SITE_PHYSICAL_TYPE_CODE, display: "Site" }], }, address: siteLocationAddress(draft), managingOrganization: { reference: `Organization/${org.id}`, display: org.name }, extension: withTimezoneExtension(undefined, draft.timezone), });