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
- Entry point: button on Zones list (e.g. Zone from distance…) or zone create flow — opens a dedicated page/modal.
- 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)
- Distance slider (km) — updates results live as the slider moves (debounced if needed).
- 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)
- Selection: default all in-range rows selected; checkboxes to trim.
- 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.ts — filterChannelsByDistance |
| 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
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.
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
OperatorPositionProvider/UseMyLocationButton)geocodeQuery(Mapbox token from Settings or Photon fallback) — same pattern as channel location lookup (#11 debt)filterChannelsByDistance,haversineDistanceM,distanceLabelForChannelfrom channel list)CodeplugMap) showing centre marker + in-range channels (reuse channel list map patterns)channelHasGeolocation,useLocationsemantics aligned with channel list / map)Within 50 km of IO92orNear Derby), thenaddZonewith selectedmemberChannelIdsin distance order (nearest first). Navigate to new zone detail.Existing building blocks
src/lib/channels.ts—filterChannelsByDistancesrc/lib/geoDistance.tssrc/hooks/useChannelListQuery.ts,src/routes/channels/list.tsxsrc/state/operatorPosition.tsxsrc/lib/maidenhead.tssrc/lib/geocode.tsaddZoneinsrc/lib/codeplugMutations.tssrc/components/CodeplugMap/Scope
In scope
/zones/from-distanceOut of scope (follow-ups)
Vendor boundaries
Internal model only — no radio profile member limits in UI or mutations. Filter and zone creation use UUID
memberChannelIds.Acceptance criteria
Relates to
docs/features/map/Workflow note
Likely multi-commit: lib/helper → route/UI → map wiring → tests. Atomic conventional commits; PR
Closes #N.