Skip to content

feat: create zone from distance (coords, locator, my location) #180

Description

@pskillen

Problem / outcome

Operators planning a trip or local activity often want a zone of repeaters within range of a point — home QTH, a campsite locator, or current GPS position. Today they must manually filter the channel list, note which channels qualify, then create a zone and add members one by one.

Add a Create zone from distance workflow: pick a centre point, set a radius, see matching channels in a table + map, then create a zone from the selection in one action.

User flow

  1. Entry point: button on Zones list (e.g. Zone from distance…) or zone create flow — opens a dedicated page/modal.
  2. Centre point (one required):
    • Enter lat/lon (decimal degrees)
    • Enter Maidenhead locator (4- or 6-char)
    • Use my location (reuse OperatorPositionProvider / UseMyLocationButton)
    • Optional: address or UK postcode via existing geocodeQuery (Mapbox token from Settings or Photon fallback) — same pattern as channel location lookup (#11 debt)
  3. Distance slider (km) — updates results live as the slider moves (debounced if needed).
  4. Results panel:
    • Table of in-range channels: name, callsign, band, mode, distance from centre (reuse filterChannelsByDistance, haversineDistanceM, distanceLabelForChannel from channel list)
    • Map (CodeplugMap) showing centre marker + in-range channels (reuse channel list map patterns)
    • Only channels with usable geolocation (channelHasGeolocation, useLocation semantics aligned with channel list / map)
  5. Selection: default all in-range rows selected; checkboxes to trim.
  6. Create zone: prompt for zone name (sensible default e.g. Within 50 km of IO92 or Near Derby), then addZone with selected memberChannelIds in distance order (nearest first). Navigate to new zone detail.

Existing building blocks

Piece Location
Distance filter src/lib/channels.tsfilterChannelsByDistance
Haversine / formatting src/lib/geoDistance.ts
Channel list distance UX src/hooks/useChannelListQuery.ts, src/routes/channels/list.tsx
Operator position src/state/operatorPosition.tsx
Locator ↔ coords src/lib/maidenhead.ts
Geocode src/lib/geocode.ts
Zone create addZone in src/lib/codeplugMutations.ts
Map src/components/CodeplugMap/

Scope

In scope

  • New route under zones, e.g. /zones/from-distance
  • Centre input component (coords / locator / my location / geocode)
  • Live distance slider + table + map
  • Create zone from selected channels

Out of scope (follow-ups)

  • Pulling remote repeaters from ukrepeater.net into this flow (combine with #92 directory search separately)
  • Export-time zone member caps (export boundary only)
  • Auto-naming zones from band/mode splits

Vendor boundaries

Internal model only — no radio profile member limits in UI or mutations. Filter and zone creation use UUID memberChannelIds.

Acceptance criteria

  • User can set centre via coords, locator, or my location.
  • Distance slider filters channels dynamically; table shows distance column.
  • Map reflects the same filtered set + centre point.
  • Create zone adds a zone with selected channel ids; validation passes.
  • Channels without geolocation are excluded (with count hint if useful).
  • Tests for distance filtering integration or zone-create-from-selection helper.

Relates to

  • #12 — zone CRUD
  • #11 — geolocation / address lookup patterns
  • Channel map feature — docs/features/map/

Workflow note

Likely multi-commit: lib/helper → route/UI → map wiring → tests. Atomic conventional commits; PR Closes #N.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions