Skip to content

fix: early exit when userLocation is undefined - #13859

Merged
gkartalis merged 1 commit into
mainfrom
fix/global-map-invalid-user-location
Jul 30, 2026
Merged

fix: early exit when userLocation is undefined#13859
gkartalis merged 1 commit into
mainfrom
fix/global-map-invalid-user-location

Conversation

@gkartalis

@gkartalis gkartalis commented Jul 30, 2026

Copy link
Copy Markdown
Member

This PR resolves PHIRE-3337

Description

No UI changes, this PR just protects the user location button on the maps from being called with undefined lon + lat.

Fixes this sentry issue https://artsynet.sentry.io/issues/7529680301/events/f15319ccfbf4490280c6ad21e606af80/

PR Checklist

  • I have tested my changes on the following platforms:
    • Android.
    • iOS.
  • I hid my changes behind a feature flag, or they don't need one.
  • I have included screenshots or videos at least on Android, or I have not changed the UI.
  • I have added tests, or my changes don't require any.
  • I added an app state migration, or my changes do not require one.
  • I have documented any follow-up work that this PR will require, or it does not require any.
  • I have added a changelog entry below, or my changes do not require one.

To the reviewers 👀

  • I would like at least one of the reviewers to run this PR on the simulator or device.
Changelog updates

Changelog updates

Cross-platform user-facing changes

iOS user-facing changes

Android user-facing changes

Dev changes

  • early exit when userLocation is undefined

Need help with something? Have a look at our docs, or get in touch with us.

@gkartalis gkartalis self-assigned this Jul 30, 2026
@artsyit

artsyit commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

This PR contains the following changes:

  • Dev changes (early exit when userLocation is undefined - gkartalis)

Generated by 🚫 dangerJS against 02b296a

* `city.coordinates` is nullable in the schema and location updates can arrive without coordinates,
* so make sure we actually have numbers before handing them over to the map.
*/
const isValidLatLng = (location: any): location is { lat: number; lng: number } => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

any here throws away the type info the caller already has. userLocation comes from viewer.city?.coordinates, whose schema type is { lat: Float, lng: Float } (both nullable — data/schema.graphql:22546). Naming that shape keeps the guard honest and still narrows correctly:

Suggested change
const isValidLatLng = (location: any): location is { lat: number; lng: number } => {
const isValidLatLng = (
location: { lat?: number | null; lng?: number | null } | null | undefined
): location is { lat: number; lng: number } => {

Not blocking — @typescript-eslint/no-explicit-any is off in this repo — but this PR is deleting a STRICTNESS_MIGRATION escape hatch, so it'd be nice not to add an any in its place.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

no need for this

onPress={onPressCitySwitcherButton}
/>
{!!userLocation && (
{!!isValidLatLng(userLocation) && (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

isValidLatLng already returns a boolean, so the !! is a no-op here (the old !!userLocation needed it to coerce an object).

Suggested change
{!!isValidLatLng(userLocation) && (
{isValidLatLng(userLocation) && (

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

nope

@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Guards the map user-location button against undefined/null coordinates. Adds an isValidLatLng type predicate used both to gate the button render and its setCamera call, and tightens onUserLocationUpdate to require numeric latitude/longitude before storing a location. Also drops a STRICTNESS_MIGRATION escape hatch.

The fix targets the right spot: userLocation is seeded from viewer.city?.coordinates (GlobalMap.tsx:85-86), and LatLng.lat / LatLng.lng are both nullable Float in the schema (data/schema.graphql:22546-22549), so the old !!userLocation check happily passed an object of nulls into centerCoordinate.

Issues Found

No blocking issues.

  • 🟢 isValidLatLng(location: any) (GlobalMap.tsx:604) — see inline. The caller type is known; { lat?: number | null; lng?: number | null } | null | undefined narrows the same way without any.
  • 🟢 Redundant !! (GlobalMap.tsx:151) — isValidLatLng already returns a boolean.
  • 🟢 No test. src/app/Scenes/Map/__tests__/ only has Bucket.tests.ts and exhibitionPeriodParser.tests.ts, so GlobalMap.tsx is untested and nothing pins this behavior. Exporting isValidLatLng and adding a few cases (undefined, { lat: null, lng: null }, { lat: 0, lng: 0 }) is cheap and would catch a regression where someone swaps the guard back for a truthiness check. The lat: 0 case matters — a naive !location.lat rewrite would break the equator and prime meridian.

Areas Reviewed

Bugs and edge cases: the typeof === "number" checks correctly accept 0, which a truthiness check would drop. onUserLocationUpdate now rejects strictly more inputs than before (!location || !location.coords, plus numeric lat/lng), so no path that previously stored a good location is lost. Nothing else in the file reads userLocation coordinates; highlight={userLocation === currentLocation} at line 154 is reference equality and unaffected.

Performance and architecture: nothing notable, the helper is a module-level pure function.

Questions for Author

  1. The description says "No UI changes", but the render condition went from !!userLocation to !!isValidLatLng(userLocation). Those differ when a city has coordinates: { lat: null, lng: null }: the button used to render (and crash on tap) and now hides. That is the right call, just worth stating in the description so QA is not surprised by a missing button in a data-broken city.
  2. The Android box is unchecked, and the new comment at lines 344-346 attributes the empty-coords updates to the native side. Since onUserLocationUpdate is driven by the platform location provider, a quick Android run would confirm the guard does not swallow legitimate first fixes there. Do you have a repro city or device for the Sentry crash to check against?

@gkartalis
gkartalis merged commit 9879901 into main Jul 30, 2026
20 checks passed
@gkartalis
gkartalis deleted the fix/global-map-invalid-user-location branch July 30, 2026 13:43
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.

3 participants