Show the GPS-measured distance under the declared one, with a button to measure #1
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/gps-mileage"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The backend now measures each reservation against the car's tracker and stores
the result beside the declared figure, but none of it was visible: the Dashboard
showed only the editable declared value, so the whole point — seeing that a
reservation declared at 100 km actually covered 156 — was invisible.
The Distance cell now stacks the editable declared value over a read-only line
carrying a satellite icon and the measured kilometres. Hovering it explains where
the number comes from, including the window actually measured, which is not the
declared start/end: it is widened to whole days and split with the neighbouring
reservation, so an early pickup and a late return count. That is the answer to
"pourquoi ma réservation de midi affiche 200 km ?", and it needs saying next to
the number rather than in a commit message.
Nothing renders before a pass has run — gpsComputedAt is the marker — so the 22
reservations that predate the cut-off stay as they were. Once a pass has run, a
missing distance means the tracker stayed dark for the window, which shows as
"GPS muet" rather than being passed off as "not measured".
A discreet outline button next to "Nouveau trajet" runs a pass on demand instead
of waiting for the twelve-hourly timer.
forceis deliberately not exposed: thebutton only measures what is missing, so nobody can rewrite every measurement by
accident.
Design notes:
DateTime). The latter empties the ENTIRE reservation list: it pipes its
transform onto Sc.NullOr(schema) and then targets Sc.UndefinedOr(schema), so it
hands the target the decoded value where the encoded one is expected. That is
fine for every existing use — plain primitives and structs, where both sides
coincide — and fails with "Expected string | undefined" the moment the inner
schema is itself a transformation, whereupon getAllTrips' decode fallback
swallows it into []. The string ↔ Date conversion therefore happens inside one
transform, the way NotANumberToOptionalLocalDate does it.
Traccar is unreachable, and catchUnauthorized maps 400 to NotAuthenticated,
which Remix turns into a redirect to /login — logging the user out because a
homelab box was down.
disturbs actionData or the pending state that the trip form and the distance
calculator both read. The POST still revalidates the loader, so the table picks
up the new values without a manual refresh.
the PUT body and updateData spreads the whole row. That is safe: the backend's
update statement lists its columns and cannot touch them.
its three branches. Two stacked lines inside 32 px wrap character by character.
argument into state through useEffect(..., [loaderTrips]), so the fresh [] the
route built on every render sent it into an unbounded update loop whenever the
loader failed — after a mutation revalidated against a backend that had gone
away, for instance — taking the page down rather than showing the error. The
existing edit-and-blur path reaches it too; the new button is one more way in.
Verified in a browser against both halves running locally: 156 km and 0 km appear
under a declared 100 and a blank, seed rows show no GPS line, the button reports
"2 réservation(s) mesurée(s)" and then "Rien à mesurer", editing a declared value
leaves the measurement intact, the line does not wrap at 390 px, and with Traccar
unreachable the red banner appears while the session survives.
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com