Skip to content

fix(webhooks): stop GPS ticks overwriting the saved Poracle location#1231

Merged
Mygod merged 3 commits into
WatWowMap:mainfrom
unseenmagik:fix/webhook-location-gps-overwrite
Jul 24, 2026
Merged

fix(webhooks): stop GPS ticks overwriting the saved Poracle location#1231
Mygod merged 3 commits into
WatWowMap:mainfrom
unseenmagik:fix/webhook-location-gps-overwrite

Conversation

@unseenmagik

Copy link
Copy Markdown
Contributor

Problem

A user reported that their Poracle notification location kept changing to wherever they physically were, rather than staying at the location they had deliberately set:

Whenever I go into edit my notifications settings, my location auto updates to my current location rather than where I scan from (I scan from a park that I play at, but adjust settings at home). Is there anyway to turn this off/get it to just keep the location I originally assigned?

They had set alerts for a park they play at, then edited a tracking from home — and started getting pings for spawns near their house instead.

This is real, and it isn't user error. Location.jsx listened for Leaflet's locationfound event and persisted every one of them straight to Poracle via the setLocation mutation, with no confirmation:

const map = useMapEvents({
  locationfound: (newLoc) => {
    const { location } = useWebhookStore.getState()
    const { lat, lng } = newLoc.latlng
    if (lat !== location[0] && lng !== location[1]) {
      handleLocationChange([lat, lng])   // <- writes to Poracle
    }
  },
})

leaflet.locatecontrol runs geolocation in watch mode, so once the locate control is active it keeps emitting position fixes for as long as it runs. That means merely opening the notification panel with locate engaged was enough to silently overwrite a saved location — the user sees their current coordinates in the panel, but by then the write has already happened.

Users tracking by coordinates + distance are hit hardest. Poracle stores a single lat/lng per human (POST /api/humans/:id/setLocation), not one per tracking or per profile, so a single stray GPS tick relocates every distance-based tracking they have at once.

Fix

Gate the handler behind a ref that only the My Location button arms, and clear it on the first event so a continuing watch can't write a second time. Passive GPS ticks are now ignored; the location only changes when the user asks for it via My Location, the map pin, or the Nominatim search.

_onClick toggles the control, so the flag is armed from lc._active after the call — clicking it while already active stops locating, and arming beforehand would leave the flag set with no event coming, letting a later stray tick through.

Also included

Two adjacent issues found while verifying:

  • && should have been || in both coordinate comparisons. They required both latitude and longitude to differ, so moving a pin along a single axis silently didn't save.
  • The init effect could seed the store with [undefined, undefined]. human is empty until the query resolves, and the every(x => x === 0) guard then never re-fires once real coordinates arrive. Harmless under &&, but worth closing now that the save effect is more eager.

useLocation's return typedef gains _active?: boolean. The property is real and already relied on in useStopFollowingOnFly.js, so widening the typedef seemed cleaner than a cast — though it is the same coupling to leaflet.locatecontrol internals that the existing _onClick usage already has.

Testing

⚠️ Not verified beyond code review — my checkout had no node_modules, so I could not run the linter or a build. Worth a manual pass before merging. Suggested check:

  1. Engage the locate control (blue/green), then open the notification panel — the saved location should now stay put.
  2. Click My Location in the panel — it should still update, once.
  3. Drop a pin via Choose on Map and change only longitude — it should save (this was broken before).

Note

This doesn't change the underlying design: location remains one value per user, so distance-based trackings still all share it. This only stops it from moving on its own. Tracking by area is still the robust answer for "alert me about this specific place regardless of where I am."

The notification panel listened for Leaflet `locationfound` events and
persisted every one of them via the `setLocation` mutation. Because
`leaflet.locatecontrol` runs geolocation in watch mode, an active locate
control keeps emitting position fixes for as long as it is running, so
simply opening the panel was enough to silently rewrite a location the
user had deliberately set elsewhere.

Users who track by coordinates + distance are hit hardest: Poracle stores
one lat/lng per human, so a single background tick moves every
distance-based tracking they have. Reported by a user who set alerts for a
park, then had them follow him home the next time he edited a tracking.

Gate the handler behind a ref that only the "My Location" button arms, and
consume it on the first event so a continuing watch cannot write again.
`_onClick` toggles the control, so arm from `_active` after the call --
clicking it while active stops locating and no event is coming.

Also fix two adjacent issues found while verifying:

- The coordinate comparisons required *both* lat and lng to differ, so
  moving a pin along a single axis never saved.
- `human` is empty until the query resolves, so the init effect seeded the
  store with `[undefined, undefined]`, and its `every(x => x === 0)` guard
  then never re-fired once real coordinates arrived.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2818b64969

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/features/webhooks/human/Location.jsx
A GPS fix can take many seconds on mobile. If the user clicked My Location
and then picked a different location via search or Choose on Map while
waiting, the ref stayed armed and the late fix overwrote the newer explicit
pick -- reintroducing the silent overwrite through a race.

Clear the pending request whenever a location is actually persisted, so the
most recent deliberate choice wins.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@unseenmagik

Copy link
Copy Markdown
Contributor Author

resolved with (1f42fc6)

@unseenmagik

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 1f42fc649f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Stops passive Leaflet geolocation “watch” ticks from silently overwriting a user’s saved Poracle webhook location by only accepting a locationfound update immediately after the user explicitly requests “My Location”. Also fixes coordinate-change detection and guards store initialization against undefined human coordinates.

Changes:

  • Gate locationfound writes behind an explicit user-armed ref and disarm after first fix.
  • Correct coordinate comparisons from && to || so one-axis moves persist.
  • Prevent initializing the webhook store location with [undefined, undefined]; widen useLocation’s typedef for _active.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/hooks/useLocation.js Updates the JSDoc return type to include lc._active used by consumers.
src/features/webhooks/human/Location.jsx Adds one-shot “awaiting locate” gating, fixes coordinate comparison logic, and adds guards around initial location seeding.
Comments suppressed due to low confidence (1)

src/features/webhooks/human/Location.jsx:93

  • The webhookLocation sync effect can re-call handleLocationChange right after handleLocationChange itself updates the store, resulting in two POSTs for a single user action. Once a savingLocation ref exists, consider short-circuiting the effect when it would only duplicate an in-flight save for the same coordinates.
  React.useEffect(() => {
    if (webhookLocation[0] !== latitude || webhookLocation[1] !== longitude) {
      handleLocationChange(webhookLocation)
    }
  }, [webhookLocation])

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/features/webhooks/human/Location.jsx
Search and My Location call handleLocationChange directly, which writes the
store and POSTs. That store write re-fires the webhookLocation sync effect
(kept for the drag picker, whose only signal is the store), which then POSTs
the same coordinates a second time. Switching the comparison to || widened
this to single-axis moves as well.

Track the coordinates currently being persisted in a ref and short-circuit
the effect when it would only duplicate that in-flight save, clearing the ref
once the mutation settles (guarded so a newer save isn't wiped by an older
one). The drag picker still routes through the effect and saves exactly once.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Mygod
Mygod merged commit 0f27862 into WatWowMap:main Jul 24, 2026
2 checks passed
github-actions Bot pushed a commit that referenced this pull request Jul 24, 2026
## [1.48.2](v1.48.1...v1.48.2) (2026-07-24)

### Bug Fixes

* **webhooks:** stop GPS ticks overwriting the saved Poracle location ([#1231](#1231)) ([0f27862](0f27862))
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 1.48.2 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants