New page lets a rep see their own rep_visits on a Leaflet map.
Defaults to last 7 days; toggleable to 14 / 30 / 90.
/rep/visits ── server-side fetch + re-export to client
/rep/visits map ── per-customer cluster, count badge, last-visit
label, popup with full per-visit timeline + notes
+ 'manual' badge, side-list of customers in window
+ search filter + heatmap toggle
Service + route (no pb-helpers):
visits-service.getVisitsForRep(repId, {from?, to?, limit?})
- admin PB (session-scoped at the route layer)
- expands customer relation, filters position_source != 'tracker'
server-side, PB date format gotcha (T → space), 5000-row cap
/api/v1/rep-visits/list GET, browser-session auth, scopes repId
from user.id (never a query param — same
hardening as POST /api/v1/visits)
Heatmap:
leaflet.heat wrapper at src/components/leaflet-heatmap-layer.tsx
- useMap() + useEffect lifecycle
- brand gradient (deep blue → green → amber → yellow → crimson)
- reads on both light OSM and dark CARTO tile sets
- maxZoom default 10 — leaflet.heat scales intensity by
1/2^(maxZoom-currentZoom); without this the OSM default maxZoom
of 18 makes points render at ~5% opacity at our default zoom 10
Other fixes landed mid-feature:
- KPI cards collapsed from 3 into 1 (clusters count is a
zoom-dependent implementation detail, not a glanceable stat)
- added 'View my visits on a map' nav link under /rep header
Dep: +leaflet.heat@^0.2.0, +@types/leaflet.heat@^0.2.5
(react-leaflet@5, leaflet@1.9.4 already present)
Tests: 50 + 34 = 84 pass in the touched (rep) area + visits-service
+ rep-visits API. Pre-existing failures on main (sidebar,
pocketbase-admin, quotes-service) confirmed unrelated by
stashing this branch.