Remove auto-visit GPS tracking
- Removed startVisitTracking / stopVisitTracking functions - Removed checkProximityToAssets and haversineM - Removed logAutoVisit and all visit timer logic - Removed visitTracker UI div on Map tab - Removed GPS watchPosition call (was polling at ~1-5s intervals) - Kept server-side /api/visits endpoints (used by heatmap) and one-shot GPS for scan check-in Reason: GPS auto-tracker can't distinguish machines above/below each other on different floors.
This commit is contained in:
@@ -1353,10 +1353,6 @@
|
||||
<span class="map-chip" id="chipGeoGPS" onclick="if(navigator.geolocation)navigator.geolocation.getCurrentPosition(p=>{map.setView([p.coords.latitude,p.coords.longitude],15)})">◎ My GPS</span>
|
||||
</div>
|
||||
<div id="mapContainer"></div>
|
||||
<!-- Auto-visit status indicator -->
|
||||
<div id="visitTracker" style="display:none;margin-top:6px;padding:8px 12px;background:var(--green-bg);border-radius:var(--radius-sm);font-size:12px;color:var(--green);">
|
||||
📍 Near <span id="vtAssetName">—</span> · <span id="vtTimer">0 min</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ═══════════════════════════════════════════════════════════════════════
|
||||
@@ -1904,9 +1900,6 @@
|
||||
}
|
||||
setTimeout(() => map.invalidateSize(), 150);
|
||||
loadAssetPins(); // Refresh pins on every tab visit
|
||||
startVisitTracking();
|
||||
} else {
|
||||
stopVisitTracking();
|
||||
}
|
||||
|
||||
// Dispatch event so child tab implementations can hook in
|
||||
@@ -4578,149 +4571,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// AUTO-VISIT LOGGING (Client-side GPS tracking)
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
let geoWatchId = null;
|
||||
let visitTimers = {};
|
||||
|
||||
function startVisitTracking() {
|
||||
if (!navigator.geolocation) return;
|
||||
if (geoWatchId !== null) return; // already tracking
|
||||
|
||||
geoWatchId = navigator.geolocation.watchPosition(
|
||||
pos => {
|
||||
const lat = pos.coords.latitude;
|
||||
const lng = pos.coords.longitude;
|
||||
AppState.gpsLat = lat;
|
||||
AppState.gpsLng = lng;
|
||||
// Show GPS center chip on map
|
||||
const chip = document.getElementById('chipGeoGPS');
|
||||
if (chip) chip.style.display = '';
|
||||
checkProximityToAssets(lat, lng);
|
||||
},
|
||||
err => { /* silently fail — GPS permission may change */ },
|
||||
{ enableHighAccuracy: true, maximumAge: 30000, timeout: 20000 }
|
||||
);
|
||||
}
|
||||
|
||||
function stopVisitTracking() {
|
||||
if (geoWatchId !== null) {
|
||||
navigator.geolocation.clearWatch(geoWatchId);
|
||||
geoWatchId = null;
|
||||
}
|
||||
// Clear all timers
|
||||
Object.keys(visitTimers).forEach(k => clearTimeout(visitTimers[k]?._timer));
|
||||
visitTimers = {};
|
||||
document.getElementById('visitTracker').style.display = 'none';
|
||||
}
|
||||
|
||||
// Haversine distance in meters
|
||||
function haversineM(lat1, lng1, lat2, lng2) {
|
||||
const R = 6371000;
|
||||
const dLat = (lat2 - lat1) * Math.PI / 180;
|
||||
const dLng = (lng2 - lng1) * Math.PI / 180;
|
||||
const a = Math.sin(dLat / 2) ** 2 +
|
||||
Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
|
||||
Math.sin(dLng / 2) ** 2;
|
||||
return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
}
|
||||
|
||||
function checkProximityToAssets(userLat, userLng) {
|
||||
let nearestAsset = null;
|
||||
let nearestDist = Infinity;
|
||||
|
||||
assetMarkers.forEach(({ asset }) => {
|
||||
if (asset.latitude == null || asset.longitude == null) return;
|
||||
const dist = haversineM(userLat, userLng, asset.latitude, asset.longitude);
|
||||
if (dist < nearestDist) {
|
||||
nearestDist = dist;
|
||||
nearestAsset = asset;
|
||||
}
|
||||
|
||||
// Check if within threshold
|
||||
if (dist <= VISIT_THRESHOLD_M) {
|
||||
if (!visitTimers[asset.id]) {
|
||||
visitTimers[asset.id] = {
|
||||
startTime: Date.now(),
|
||||
lastSeen: Date.now(),
|
||||
asset: asset,
|
||||
};
|
||||
} else {
|
||||
visitTimers[asset.id].lastSeen = Date.now();
|
||||
}
|
||||
} else {
|
||||
// Asset no longer in range — clear timer
|
||||
if (visitTimers[asset.id]) {
|
||||
clearTimeout(visitTimers[asset.id]._timer);
|
||||
delete visitTimers[asset.id];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Check if any timer has reached threshold
|
||||
const now = Date.now();
|
||||
const tracker = document.getElementById('visitTracker');
|
||||
|
||||
let trackingAsset = null;
|
||||
for (const [id, timer] of Object.entries(visitTimers)) {
|
||||
const elapsed = Math.floor((now - timer.startTime) / 60000);
|
||||
timer._elapsed = elapsed;
|
||||
|
||||
if (timer.asset === nearestAsset) {
|
||||
trackingAsset = timer;
|
||||
}
|
||||
|
||||
// If 10+ minutes, auto-log a visit via checkin
|
||||
if (elapsed >= VISIT_DURATION_MIN && !timer._logged) {
|
||||
timer._logged = true;
|
||||
logAutoVisit(timer.asset);
|
||||
}
|
||||
|
||||
// Cleanup stale timers (not seen in 2 minutes)
|
||||
if (now - timer.lastSeen > 120000) {
|
||||
clearTimeout(timer._timer);
|
||||
delete visitTimers[id];
|
||||
}
|
||||
}
|
||||
|
||||
// Update visit tracker UI
|
||||
if (trackingAsset && trackingAsset._elapsed >= 0) {
|
||||
tracker.style.display = 'block';
|
||||
document.getElementById('vtAssetName').textContent = trackingAsset.asset.name;
|
||||
document.getElementById('vtTimer').textContent = trackingAsset._elapsed + ' min';
|
||||
if (trackingAsset._elapsed >= VISIT_DURATION_MIN) {
|
||||
tracker.style.background = 'var(--accent-bg)';
|
||||
tracker.style.color = 'var(--accent2)';
|
||||
}
|
||||
} else {
|
||||
tracker.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
async function logAutoVisit(asset) {
|
||||
try {
|
||||
// Log a visit record (auto-detected stay)
|
||||
await api('/api/visits', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
asset_id: asset.id,
|
||||
user_id: AppState.currentUser?.id || null,
|
||||
latitude: AppState.gpsLat,
|
||||
longitude: AppState.gpsLng,
|
||||
duration_minutes: VISIT_DURATION_MIN,
|
||||
}),
|
||||
});
|
||||
showToast('📍 Visit auto-logged for ' + asset.name);
|
||||
// Refresh heatmap if visible
|
||||
if (heatVisible) await loadHeatmapData();
|
||||
} catch (e) {
|
||||
console.error('Auto-visit log failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
function renderGpsPreview(lat, lng, containerEl) {
|
||||
if (!containerEl) return;
|
||||
|
||||
Reference in New Issue
Block a user