feat(logging): measure distance & bearing from the on-air station's grid#248
Merged
Merged
Conversation
The "how far, which way" readout on the logging form always computed distance and bearing from the account's home grid (currentUser.grid_locator), ignoring the grid of the station actually selected for the QSO. A portable/POTA/rover operator working from a different grid than their home account therefore saw a distance and beam heading measured from the wrong place. Resolve the origin from the selected station's grid_locator first, falling back to the account home grid only when the station has none. A new pure helper `resolveOriginGrid(stationGrid, homeGrid)` in @/lib/grid encapsulates the precedence, ignores a blank/malformed locator at either level, and normalizes the winner to trimmed uppercase — unit-tested alongside the rest of the grid math. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
patrickrb
added a commit
that referenced
this pull request
Jul 24, 2026
… API (#249) Commit #246 added canonical 8-character (extended) Maidenhead support to `src/lib/grid.ts` (`isValidGrid`, `gridToLatLon`), and #248 uses the on-air station's grid as the distance/bearing origin. But three input validators kept their own 4/6-only regex and drifted behind: - `new-contact` form's inline `validateGridLocator` - `POST /api/stations` - `PUT /api/stations/[id]` Result: typing an 8-char grid (e.g. `FN31pr55`) into the logging form showed "Invalid grid locator format" and blocked save, and saving an 8-char station grid — the exact locator used as the distance origin — 400'd. VHF/UHF/ microwave and satellite operators log 8-char locators for the extra precision, so this silently rejected valid input. Centralize the check as `gridLocatorError(grid)` in the canonical grid module (null for blank/valid, message otherwise) and route all three call sites through it, so the form and the API can never drift from `isValidGrid` again. Tested: added unit coverage for `gridLocatorError` (blank, 4/6/8-char, malformed); `grid.spec.ts` 30/30 pass; typecheck, lint, and build all clean. Co-authored-by: Optio Agent <optio-agent@noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The "how far, which way" distance-and-bearing readout on the Log a contact form always measured from the operator's account home grid (
currentUser.grid_locator), regardless of which station was selected for the QSO.Nextlog supports multiple stations per user, and each station has its own
grid_locator. A portable / POTA / rover operator working from a station in a different grid than their home account saw a distance and beam heading computed from the wrong location — sometimes hundreds of miles off, pointing the antenna the wrong way.Solution
Resolve the readout origin from the selected station's
grid_locatorfirst, falling back to the account home grid only when the station has none.resolveOriginGrid(stationGrid, homeGrid)insrc/lib/grid.tsencapsulates the precedence: on-air station grid wins → account home grid →null. It ignores a blank or malformed locator at either level (so a half-configured station never yields a bogus origin) and normalizes the winner to trimmed uppercase, so it feedsgridToLatLonlike any other locator.src/app/new-contact/page.tsxnow derives the readout'sfrompoint viaresolveOriginGrid(station?.grid_locator, currentUser?.grid_locator). The station's grid is already returned byGET /api/stations(SELECT *); the page's localStationinterface just needed the field added.No API shape changes, no schema changes, fully backwards compatible — when a station has no grid (or only the home grid is set), behavior is identical to before.
Testing
resolveOriginGridintests/grid.spec.ts(precedence, fallback, normalization, malformed-value skipping, both-null). Written first and confirmed to fail (resolveOriginGrid is not a function) before implementing.npx playwright test tests/grid.spec.ts— 27 passed (22 pre-existing + 5 new).npm run typecheck— clean.npm run lint— clean.npm run build— compiled successfully.Future follow-up
QuickLogCardcomponent doesn't yet show a distance/bearing readout; if one is added it should use the sameresolveOriginGridhelper.latitude/longitude; a future refinement could prefer those over the grid-square center for sub-grid precision.🤖 Generated with Claude Code