shoc-frontend-new/src/data/areas.ts
Alexandre Brandizzi ebc401dcb7
Some checks are pending
Frontend checks / Build and test (push) Waiting to run
Frontend checks / governance (push) Waiting to run
Frontend checks / Visual regression (push) Waiting to run
Deploy dev content / Deploy shoc-frontend-new-dev through Terraform (push) Waiting to run
SH-273: derive Site Area from State (#190)
* feat(locations): derive site areas from state

* chore(locations): keep ticket keys out of source comments

---------

Co-authored-by: Codex Review Integration <codex-review@local.invalid>
2026-09-15 16:38:18 -03:00

170 lines
4.1 KiB
TypeScript

/**
* Canonical source of truth for US states and their Seahaven area zone
* mapping. Exactly the 50 states — no DC and no territories.
* Area is always derived from the state code and never persisted.
*/
export const AREA_ZONES = ["East", "Central", "West", "California"] as const;
export type AreaZone = (typeof AREA_ZONES)[number];
export const AREA_ZONE_STATE_CODES = {
East: [
"CT",
"DE",
"GA",
"MA",
"MD",
"ME",
"NC",
"NH",
"NJ",
"NY",
"PA",
"RI",
"SC",
"VA",
"VT",
"WV",
],
Central: [
"AL",
"AR",
"FL",
"IA",
"IL",
"IN",
"KS",
"KY",
"LA",
"MI",
"MN",
"MO",
"MS",
"ND",
"NE",
"OH",
"OK",
"SD",
"TN",
"WI",
],
West: ["AK", "AZ", "CO", "HI", "ID", "MT", "NM", "NV", "OR", "TX", "UT", "WA", "WY"],
California: ["CA"],
} as const satisfies Record<AreaZone, readonly string[]>;
export type StateCode = (typeof AREA_ZONE_STATE_CODES)[AreaZone][number];
/** All 50 state codes in canonical order: East, Central, West, California. */
export const US_STATE_CODES = [
...AREA_ZONE_STATE_CODES.East,
...AREA_ZONE_STATE_CODES.Central,
...AREA_ZONE_STATE_CODES.West,
...AREA_ZONE_STATE_CODES.California,
] as [StateCode, ...StateCode[]];
const STATE_NAMES = {
AL: "Alabama",
AK: "Alaska",
AZ: "Arizona",
AR: "Arkansas",
CA: "California",
CO: "Colorado",
CT: "Connecticut",
DE: "Delaware",
FL: "Florida",
GA: "Georgia",
HI: "Hawaii",
ID: "Idaho",
IL: "Illinois",
IN: "Indiana",
IA: "Iowa",
KS: "Kansas",
KY: "Kentucky",
LA: "Louisiana",
ME: "Maine",
MD: "Maryland",
MA: "Massachusetts",
MI: "Michigan",
MN: "Minnesota",
MS: "Mississippi",
MO: "Missouri",
MT: "Montana",
NE: "Nebraska",
NV: "Nevada",
NH: "New Hampshire",
NJ: "New Jersey",
NM: "New Mexico",
NY: "New York",
NC: "North Carolina",
ND: "North Dakota",
OH: "Ohio",
OK: "Oklahoma",
OR: "Oregon",
PA: "Pennsylvania",
RI: "Rhode Island",
SC: "South Carolina",
SD: "South Dakota",
TN: "Tennessee",
TX: "Texas",
UT: "Utah",
VT: "Vermont",
VA: "Virginia",
WA: "Washington",
WV: "West Virginia",
WI: "Wisconsin",
WY: "Wyoming",
} as const satisfies Record<StateCode, string>;
export interface StateAreaEntry {
code: StateCode;
name: string;
zone: AreaZone;
}
/** All 50 states with postal code, full name, and their single area zone. */
export const STATE_AREA_ENTRIES: readonly StateAreaEntry[] = AREA_ZONES.flatMap((zone) =>
AREA_ZONE_STATE_CODES[zone].map((code) => ({ code, name: STATE_NAMES[code], zone })),
);
const STATE_CODE_SET = new Set<string>(US_STATE_CODES);
const STATE_NAME_TO_CODE = new Map<string, StateCode>(
STATE_AREA_ENTRIES.map((entry) => [entry.name.toLowerCase(), entry.code]),
);
const STATE_ZONE_BY_CODE = Object.fromEntries(
STATE_AREA_ENTRIES.map((entry) => [entry.code, entry.zone]),
) as Record<StateCode, AreaZone>;
/** Autocomplete option label: `Texas (TX)`. */
export function formatStateOptionLabel(code: StateCode): string {
return `${STATE_NAMES[code]} (${code})`;
}
/**
* Normalizes legacy API state values to the canonical two-letter code.
* Accepts codes in any case and full state names (any case); otherwise null.
*/
export function normalizeStateCode(value: string | null | undefined): StateCode | null {
const trimmed = value?.trim() ?? "";
if (trimmed === "") {
return null;
}
const upper = trimmed.toUpperCase();
if (STATE_CODE_SET.has(upper)) {
return upper as StateCode;
}
return STATE_NAME_TO_CODE.get(trimmed.toLowerCase()) ?? null;
}
/** Derives the area zone for a state code or legacy full-name value. */
export function getAreaForState(value: string | null | undefined): AreaZone | null {
const code = normalizeStateCode(value);
return code === null ? null : STATE_ZONE_BY_CODE[code];
}
/** Expands selected area zones to their state codes in canonical order. */
export function expandAreasToStateCodes(areas: readonly AreaZone[]): StateCode[] {
const selected = new Set<AreaZone>(areas);
return US_STATE_CODES.filter((code) => selected.has(STATE_ZONE_BY_CODE[code]));
}