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>
|
<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>
|
||||||
<div id="mapContainer"></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>
|
</div>
|
||||||
|
|
||||||
<!-- ═══════════════════════════════════════════════════════════════════════
|
<!-- ═══════════════════════════════════════════════════════════════════════
|
||||||
@@ -1904,9 +1900,6 @@
|
|||||||
}
|
}
|
||||||
setTimeout(() => map.invalidateSize(), 150);
|
setTimeout(() => map.invalidateSize(), 150);
|
||||||
loadAssetPins(); // Refresh pins on every tab visit
|
loadAssetPins(); // Refresh pins on every tab visit
|
||||||
startVisitTracking();
|
|
||||||
} else {
|
|
||||||
stopVisitTracking();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dispatch event so child tab implementations can hook in
|
// 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) {
|
function renderGpsPreview(lat, lng, containerEl) {
|
||||||
if (!containerEl) return;
|
if (!containerEl) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user