// ========================================== // SEEMYDRIVER - COMPLETE UI CONTROLLER & FLEET ENGINE // ========================================== window.activeSessionId = SafeStorage.getItem('smd_session_id') || ('session_' + Math.random().toString(36).substring(2, 11)); SafeStorage.setItem('smd_session_id', window.activeSessionId); // Smart Cloud Base Origin Helper (Points to your live custom domain) function getAppBaseUrl() { const origin = window.location.origin; if (!origin || origin.includes('localhost') || origin.includes('capacitor') || origin.includes('file://')) { return 'https://seemydriver.com'; } return origin; } let map = null; let driverMarker = null; let destMarker = null; let routeLine = null; let driverMap = null; let driverMapMarker = null; let driverDestMarker = null; let driverRouteLine = null; let driverMapLabelMarker = null; let custMapLabelMarker = null; window.fleetMasterMap = null; let driverRouteIndex = 0; let custRouteIndex = 0; window.driverCachedRouteCoords = null; window.custCachedRouteCoords = null; window.activeTrackingUrl = null; let cachedDestLat = null; let cachedDestLng = null; let connectionMonitorInitialized = false; let activeFirebaseListener = null; function initConnectionMonitor() { if (connectionMonitorInitialized) return; connectionMonitorInitialized = true; db.ref('.info/connected').on('value', (snapshot) => { const isConnected = snapshot.val(); const dot = document.getElementById('connection-indicator-dot'); const text = document.getElementById('connection-status-text'); if (dot && text) { if (isConnected) { dot.className = "w-2.5 h-2.5 rounded-full bg-emerald-400 animate-ping"; text.innerText = "LIVE SYNC"; } else { dot.className = "w-2.5 h-2.5 rounded-full bg-amber-400 animate-pulse"; text.innerText = "RECONNECTING..."; try { db.goOnline(); } catch(e){} } } }); } function getLivePosition() { return new Promise((resolve, reject) => { if (!navigator.geolocation) { reject(new Error('Geolocation is not supported by your browser')); return; } navigator.geolocation.getCurrentPosition( position => resolve({ lat: position.coords.latitude, lng: position.coords.longitude, speed: position.coords.speed !== null && !isNaN(position.coords.speed) && position.coords.speed >= 0 ? position.coords.speed * 2.23694 : 0 }), err => reject(err), { enableHighAccuracy: true, timeout: 10000, maximumAge: 0 } ); }); } window.getLivePosition = getLivePosition; window.fleetMarkers = {}; // Tracks active Leaflet markers on the master map window.initFleetMasterMap = function() { setTimeout(() => { const container = document.getElementById('fleet-master-map-container'); if (!container) return; if (window.fleetMasterMap) { window.fleetMasterMap.invalidateSize(); window.loadFleetTelemetryData(); return; } container.style.width = '100%'; container.style.height = '100%'; try { window.fleetMasterMap = L.map('fleet-master-map-container', { zoomControl: false }).setView([29.9902, -95.2636], 13); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(window.fleetMasterMap); window.loadFleetTelemetryData(); } catch (e) { console.error('Fleet Map init error:', e); } }, 200); }; // Global Fleet Master Map Navigation Controls window.fitAllFleetUnits = function() { if (!window.fleetMasterMap) return; const markers = []; Object.keys(window.fleetMarkers).forEach(sessionId => { const markerObj = window.fleetMarkers[sessionId]; if (markerObj && markerObj.truck) { markers.push(markerObj.truck); } }); if (markers.length > 0) { const group = new L.featureGroup(markers); window.fleetMasterMap.fitBounds(group.getBounds().pad(0.3)); } else { alert('No active units on the radar to fit.'); } }; window.centerDispatcherLocation = function() { if (!window.fleetMasterMap) return; if (navigator.geolocation) { navigator.geolocation.getCurrentPosition( pos => { window.fleetMasterMap.setView([pos.coords.latitude, pos.coords.longitude], 15); }, err => { alert('Unable to retrieve your GPS location. Please check browser permissions.'); window.fitAllFleetUnits(); }, { enableHighAccuracy: true, timeout: 8000, maximumAge: 0 } ); } else { alert('Geolocation is not supported by your browser.'); } }; let activeDriverIndex = 0; window.cycleNextDriver = function() { if (!window.fleetMasterMap) return; const sessionIds = Object.keys(window.fleetMarkers); if (sessionIds.length === 0) { alert('No active drivers broadcasting right now.'); return; } activeDriverIndex = (activeDriverIndex + 1) % sessionIds.length; const targetSessionId = sessionIds[activeDriverIndex]; const markerObj = window.fleetMarkers[targetSessionId]; if (markerObj && markerObj.truck) { window.fleetMasterMap.setView(markerObj.truck.getLatLng(), 17); } }; // Real-World Driver Job Dispatch via SMS window.dispatchDriverSMS = function() { const driverName = document.getElementById('fleet-driver-name').value.trim(); const driverPhone = document.getElementById('fleet-driver-phone').value.trim(); const destAddress = document.getElementById('fleet-dest-address').value.trim(); if (!driverName || !driverPhone || !destAddress) { alert('Please fill out the Driver Name, Mobile Number, and Destination Address.'); return; } const driverSessionId = 'driver_' + Math.random().toString(36).substring(2, 11); const baseUrl = getAppBaseUrl(); const driverUrl = `${baseUrl}/?view=job-setup&driver=${encodeURIComponent(driverName)}&session=${driverSessionId}`; db.ref('broadcasts/' + driverSessionId).set({ driverName: driverName, driverPhone: driverPhone, custName: 'Client', custAddress: destAddress, lat: 29.9902, lng: -95.2636, speed: 0, status: 'Dispatched', timestamp: Date.now() }); const smsBody = `Hi ${driverName}, you have a new job dispatch!\n\nDestination: ${destAddress}\n\nTap to launch your navigation broadcast: ${driverUrl}`; window.location.href = `sms:${driverPhone}?body=${encodeURIComponent(smsBody)}`; document.getElementById('fleet-driver-name').value = ''; document.getElementById('fleet-driver-phone').value = ''; document.getElementById('fleet-dest-address').value = ''; }; // Clear all active/stale fleet broadcasts from Firebase safely in chunked batches window.clearAllFleetBroadcasts = function() { if (confirm('Are you sure you want to clear all active and stale fleet units from the network?')) { db.ref('broadcasts').once('value', (snapshot) => { const data = snapshot.val() || {}; const keys = Object.keys(data); if (keys.length === 0) { alert('No units to clear.'); return; } let index = 0; function deleteNextChunk() { const chunk = keys.slice(index, index + 15); if (chunk.length === 0) { if (window.fleetMarkers) { Object.keys(window.fleetMarkers).forEach(sessionId => { const markerObj = window.fleetMarkers[sessionId]; if (markerObj) { if (markerObj.truck && window.fleetMasterMap) window.fleetMasterMap.removeLayer(markerObj.truck); if (markerObj.label && window.fleetMasterMap) window.fleetMasterMap.removeLayer(markerObj.label); } }); window.fleetMarkers = {}; } const rosterList = document.getElementById('fleet-roster-list'); if (rosterList) rosterList.innerHTML = `
No active units broadcasting.
`; const activeCountEl = document.getElementById('fleet-active-count'); if (activeCountEl) activeCountEl.innerText = '0'; alert('All fleet telemetry data wiped clean.'); return; } const promises = chunk.map(sessionId => db.ref('broadcasts/' + sessionId).remove()); Promise.all(promises).then(() => { index += 15; setTimeout(deleteNextChunk, 50); }).catch(err => { alert('Error clearing chunk: ' + err.message); }); } deleteNextChunk(); }); } }; // Listen to all active broadcasts in Firebase and update the Fleet Roster & Master Map window.loadFleetTelemetryData = function() { db.ref('broadcasts').on('value', (snapshot) => { const data = snapshot.val() || {}; const rosterList = document.getElementById('fleet-roster-list'); const activeCountEl = document.getElementById('fleet-active-count'); if (!rosterList) return; rosterList.innerHTML = ''; let activeCount = 0; const keys = Object.keys(data); Object.keys(window.fleetMarkers).forEach(sessionId => { if (!data[sessionId]) { const markerObj = window.fleetMarkers[sessionId]; if (markerObj) { if (markerObj.truck && window.fleetMasterMap) window.fleetMasterMap.removeLayer(markerObj.truck); if (markerObj.label && window.fleetMasterMap) window.fleetMasterMap.removeLayer(markerObj.label); } delete window.fleetMarkers[sessionId]; } }); keys.forEach(sessionId => { const unit = data[sessionId]; if (!unit || !unit.lat || !unit.lng) return; activeCount++; const driverName = unit.driverName || 'Unnamed Driver'; const speed = unit.speed || 0; const custAddress = unit.custAddress || 'No destination set'; let statusText = 'Waiting'; let statusBadgeClass = 'text-amber-400 bg-amber-950/60 border-amber-500/30'; if (speed > 3) { statusText = 'Arriving / En Route'; statusBadgeClass = 'text-emerald-400 bg-emerald-950/60 border-emerald-500/30'; } else if (unit.custAddress && unit.custAddress !== 'Waiting for Job...') { statusText = 'Active / Dispatched'; statusBadgeClass = 'text-sky-400 bg-sky-950/60 border-sky-500/30'; } const rosterItem = document.createElement('div'); rosterItem.className = "bg-neutral-950/60 border border-neutral-800/80 p-3.5 rounded-2xl flex items-center justify-between transition hover:border-amber-400/40"; rosterItem.innerHTML = `
🚚
${driverName}
Dest: ${custAddress} • ${speed} mph
${statusText}
`; rosterList.appendChild(rosterItem); if (window.fleetMasterMap) { const truckIcon = getTruckIcon(0); const labelIcon = getDriverLabelIcon(driverName); if (window.fleetMarkers[sessionId]) { const markerObj = window.fleetMarkers[sessionId]; markerObj.truck.setLatLng([unit.lat, unit.lng]); markerObj.label.setLatLng([unit.lat, unit.lng]); } else { const truckMarker = L.marker([unit.lat, unit.lng], { icon: truckIcon }).addTo(window.fleetMasterMap); const labelMarker = L.marker([unit.lat, unit.lng], { icon: labelIcon }).addTo(window.fleetMasterMap); window.fleetMarkers[sessionId] = { truck: truckMarker, label: labelMarker }; } } }); if (activeCountEl) { activeCountEl.innerText = activeCount; } if (activeCount === 0) { rosterList.innerHTML = `
No active units broadcasting. Dispatch a driver above to start tracking.
`; } }); }; function switchView(viewId, cleanUrl = false) { const views = ['landing-view', 'plans-view', 'job-setup-view', 'active-broadcast-view', 'customer-view-view', 'signin-view', 'register-view', 'fleet-dashboard-view']; views.forEach(v => { const el = document.getElementById(v); if (el) { el.classList.add('hidden'); el.style.setProperty('display', 'none', 'important'); } }); if (cleanUrl && window.history.replaceState) { window.history.replaceState({}, document.title, window.location.pathname); } const targetId = (viewId === 'customer') ? 'customer-view-view' : (viewId.endsWith('-view') ? viewId : (viewId + '-view')); let target = document.getElementById(targetId); if (!target) { target = document.getElementById('landing-view'); } if (target) { target.classList.remove('hidden'); target.style.setProperty('display', 'flex', 'important'); target.style.setProperty('flex-direction', 'column', 'important'); } updateHeaderNav(); try { if (typeof checkActiveBroadcastBanner === 'function') { checkActiveBroadcastBanner(); } } catch (e) {} let banner = document.getElementById('live-broadcast-banner'); const activeView = document.getElementById('active-broadcast-view'); if (viewId === 'active-broadcast' && activeView) { if (!banner) { banner = document.createElement('div'); banner.id = 'live-broadcast-banner'; banner.className = 'w-xl py-3 px-4 text-center flex items-center justify-center gap-3 z-50 mx-auto'; banner.innerHTML = ` Broadcasting Live — Dispatch Active `; activeView.insertBefore(banner, activeView.firstChild); } banner.style.display = 'flex'; } else { if (banner) banner.style.display = 'none'; } if (viewId === 'customer') { const custViewEl = document.getElementById('customer-view-view'); if (custViewEl) { const appreciationP = custViewEl.querySelector('p'); if (appreciationP) { appreciationP.className = "text-sm text-amber-400 font-semibold tracking-wider uppercase"; } } } if (viewId === 'job-setup') { const driverNameEl = document.getElementById('job-driver-name'); const driverPhoneEl = document.getElementById('job-driver-phone'); if (driverNameEl) driverNameEl.value = SafeStorage.getItem('smd_driver_name') || ''; if (driverPhoneEl) driverPhoneEl.value = SafeStorage.getItem('smd_driver_phone') || ''; } if (viewId === 'active-broadcast') { setTimeout(() => { initDriverActiveMap(); if (driverMap) { driverMap.invalidateSize(); setTimeout(() => driverMap.invalidateSize(), 250); } }, 150); } if (viewId === 'customer') { setTimeout(() => { initCustomerMapLive(); if (map) { map.invalidateSize(); setTimeout(() => map.invalidateSize(), 250); } }, 150); } if (viewId === 'fleet-dashboard' || targetId === 'fleet-dashboard-view') { setTimeout(() => { if (typeof window.initFleetMasterMap === 'function') { window.initFleetMasterMap(); } }, 150); } } window.switchView = switchView; function updateHeaderNav() { const nav = document.getElementById('header-nav-actions'); if (!nav) return; const urlParams = new URLSearchParams(window.location.search); const signinView = document.getElementById('signin-view'); const registerView = document.getElementById('register-view'); const isSigninHidden = signinView ? signinView.classList.contains('hidden') : true; const isRegisterHidden = registerView ? registerView.classList.contains('hidden') : true; if (urlParams.get('view') === 'customer' || urlParams.has('s') || urlParams.has('session') || !isSigninHidden || !isRegisterHidden) { nav.innerHTML = ''; return; } if (SafeStorage.getItem('smd_is_logged_in') === 'true') { const fleetView = document.getElementById('fleet-dashboard-view'); const isFleetActive = fleetView && !fleetView.classList.contains('hidden') && fleetView.style.display === 'flex'; nav.innerHTML = ` `; } else { nav.innerHTML = ` `; } } window.toggleAppMode = function() { const fleetView = document.getElementById('fleet-dashboard-view'); const isFleetVisible = fleetView && !fleetView.classList.contains('hidden') && fleetView.style.display === 'flex'; if (isFleetVisible) { switchView('job-setup'); } else { switchView('fleet-dashboard'); if (typeof window.initFleetMasterMap === 'function') { window.initFleetMasterMap(); } } updateHeaderNav(); }; window.upgradeToFleet = function() { SafeStorage.setItem('smd_user_tier', 'fleet'); alert('Enterprise subscription active! Welcome to Fleet Command Center.'); switchView('fleet-dashboard'); if (typeof window.initFleetMasterMap === 'function') { window.initFleetMasterMap(); } }; function handleRegister() { const email = document.getElementById('reg-email').value.trim(); const password = document.getElementById('password-input').value.trim(); if (!email || !password) { alert('Email and password required.'); return; } SafeStorage.setItem('smd_is_logged_in', 'true'); SafeStorage.setItem('smd_user_email', email); switchView('job-setup'); } window.handleRegister = handleRegister; function handleSignIn() { const email = document.getElementById('signin-email').value.trim().toLowerCase(); const password = document.getElementById('signin-password').value.trim(); if (!email || !password) { alert('Email and password required.'); return; } SafeStorage.setItem('smd_is_logged_in', 'true'); SafeStorage.setItem('smd_user_email', email); switchView('job-setup'); } window.handleSignIn = handleSignIn; function handleSignOut() { SafeStorage.removeItem('smd_is_logged_in'); SafeStorage.removeItem('smd_user_tier'); if (typeof stopRealTimeTracking === 'function') { stopRealTimeTracking(); } switchView('landing'); } window.handleSignOut = handleSignOut; function endBroadcastAndHome() { try { if (typeof stopRealTimeTracking === 'function') { stopRealTimeTracking(); } } catch(e) {} if (window.activeSessionId) { try { db.ref('broadcasts/' + window.activeSessionId).off(); } catch(e) {} } driverRouteIndex = 0; custRouteIndex = 0; window.driverCachedRouteCoords = null; window.custCachedRouteCoords = null; window.activeTrackingUrl = null; cachedDestLat = null; cachedDestLng = null; let banner = document.getElementById('live-broadcast-banner'); if (banner) banner.style.display = 'none'; try { if (driverMap) { if (driverRouteLine) { driverMap.removeLayer(driverRouteLine); driverRouteLine = null; } if (driverDestMarker) { driverMap.removeLayer(driverDestMarker); driverDestMarker = null; } if (driverMapMarker) { driverMap.removeLayer(driverMapMarker); driverMapMarker = null; } if (driverMapLabelMarker) { driverMap.removeLayer(driverMapLabelMarker); driverMapLabelMarker = null; } } if (map) { if (routeLine) { map.removeLayer(routeLine); routeLine = null; } if (destMarker) { map.removeLayer(destMarker); destMarker = null; } if (driverMarker) { map.removeLayer(driverMarker); driverMarker = null; } if (custMapLabelMarker) { map.removeLayer(custMapLabelMarker); custMapLabelMarker = null; } } } catch(e) {} driverMapMarker = null; driverMapLabelMarker = null; driverMarker = null; custMapLabelMarker = null; SafeStorage.removeItem('smd_active_broadcast'); SafeStorage.removeItem('smd_cust_address'); SafeStorage.removeItem('smd_session_id'); window.activeSessionId = null; switchView('landing', true); } window.endBroadcastAndHome = endBroadcastAndHome; async function launchLiveBroadcast() { const custName = document.getElementById('job-cust-name').value.trim() || 'Client'; const custPhone = document.getElementById('job-cust-phone').value.trim(); const custAddress = document.getElementById('job-cust-address').value.trim(); const driverName = document.getElementById('job-driver-name').value.trim() || 'Driver'; const driverPhone = document.getElementById('job-driver-phone').value.trim(); if (!custAddress) { alert('Enter client address.'); return; } SafeStorage.setItem('smd_driver_name', driverName); SafeStorage.setItem('smd_driver_phone', driverPhone); SafeStorage.setItem('smd_cust_name', custName); SafeStorage.setItem('smd_cust_phone', custPhone); SafeStorage.setItem('smd_cust_address', custAddress); SafeStorage.setItem('smd_active_broadcast', 'true'); let livePos; try { livePos = await getLivePosition(); } catch (err) { alert('GPS Hardware Error: ' + err.message); SafeStorage.removeItem('smd_active_broadcast'); return; } window.activeSessionId = 'session_' + Math.random().toString(36).substring(2, 11); SafeStorage.setItem('smd_session_id', window.activeSessionId); driverRouteIndex = 0; window.driverCachedRouteCoords = null; cachedDestLat = null; cachedDestLng = null; if (driverMap) { if (driverRouteLine) { driverMap.removeLayer(driverRouteLine); driverRouteLine = null; } if (driverDestMarker) { driverMap.removeLayer(driverDestMarker); driverDestMarker = null; } if (driverMapMarker) { driverMap.removeLayer(driverMapMarker); driverMapMarker = null; } if (driverMapLabelMarker) { driverMap.removeLayer(driverMapLabelMarker); driverMapLabelMarker = null; } } driverMapMarker = null; driverMapLabelMarker = null; await db.ref('broadcasts/' + window.activeSessionId).set({ driverName: driverName, driverPhone: driverPhone, custName: custName, custPhone: custPhone, custAddress: custAddress, lat: livePos.lat, lng: livePos.lng, speed: Math.round(livePos.speed), timestamp: Date.now() }); if (typeof startRealTimeTracking === 'function') { startRealTimeTracking(); } const baseUrl = getAppBaseUrl(); window.activeTrackingUrl = `${baseUrl}/?view=customer&session=${window.activeSessionId}`; switchView('active-broadcast'); } window.launchLiveBroadcast = launchLiveBroadcast; function copyTrackingLink() { const baseUrl = getAppBaseUrl(); const urlToCopy = window.activeTrackingUrl || `${baseUrl}/?view=customer&session=${window.activeSessionId}`; navigator.clipboard.writeText(urlToCopy); alert('Client tracking link copied to clipboard!'); } window.copyTrackingLink = copyTrackingLink; function textTrackingLink() { const custPhone = SafeStorage.getItem('smd_cust_phone') || ''; const baseUrl = getAppBaseUrl(); const urlToText = window.activeTrackingUrl || `${baseUrl}/?view=customer&session=${window.activeSessionId}`; const smsBody = `Track my live arrival in real time here: ${urlToText}`; if (custPhone) { window.location.href = `sms:${custPhone}?body=${encodeURIComponent(smsBody)}`; } else { window.location.href = `sms:?body=${encodeURIComponent(smsBody)}`; } } window.textTrackingLink = textTrackingLink; function calculateDistance(lat1, lon1, lat2, lon2) { const R = 3958.8, dLat = (lat2 - lat1) * Math.PI / 180, dLon = (lon2 - lon1) * Math.PI / 180; const a = Math.sin(dLat/2)**2 + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon/2)**2; return R * (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))); } function getClosestPointOnPolyline(lat, lng, coords) { if (!coords || !coords.length) return [lat, lng]; let minDist = Infinity, bestPoint = [lat, lng]; for (let i = 0; i < coords.length - 1; i++) { const proj = getClosestPointOnSegment([lat, lng], coords[i], coords[i+1]); const dist = calculateDistance(lat, lng, proj[0], proj[1]); if (dist < minDist) { minDist = dist; bestPoint = proj; } } return bestPoint; } function getClosestPointOnSegment(p, a, b) { const AB = { x: b[1] - a[1], y: b[0] - a[0] }, AP = { x: p[1] - a[1], y: p[0] - a[0] }; const abLenSq = AB.x**2 + AB.y**2; if (abLenSq === 0) return a; let t = Math.max(0, Math.min(1, (AP.x * AB.x + AP.y * AB.y) / abLenSq)); return [a[0] + t * (b[0] - a[0]), a[1] + t * (b[1] - a[1])]; } const markerAnimIds = new WeakMap(); function smoothMoveMarker(marker, targetLat, targetLng, speedMph = 15) { if (!marker) return; const prev = markerAnimIds.get(marker); if (prev) cancelAnimationFrame(prev); const start = marker.getLatLng(), startTime = performance.now(), duration = 1500; function animate(now) { const p = Math.min((now - startTime) / duration, 1); marker.setLatLng([start.lat + (targetLat - start.lat) * p, start.lng + (targetLng - start.lng) * p]); if (p < 1) markerAnimIds.set(marker, requestAnimationFrame(animate)); } markerAnimIds.set(marker, requestAnimationFrame(animate)); } // Enterprise-Grade Fleet Box Truck SVG Icon function getTruckIcon(bearing = 0) { return L.divIcon({ className: 'custom-truck-svg-marker', html: `
`, iconSize: [0, 0], iconAnchor: [0, 0] }); } // Strictly Horizontal Floating Black Driver Label function getDriverLabelIcon(driverName = 'Driver') { return L.divIcon({ className: 'custom-driver-label-marker', html: `
${driverName}
`, iconSize: [0, 0], iconAnchor: [0, -25] }); } window.fitDriverMap = function() { if (driverMapMarker && driverDestMarker && driverMap) { const group = new L.featureGroup([driverMapMarker, driverDestMarker]); driverMap.fitBounds(group.getBounds().pad(0.2)); } else if (driverMapMarker && driverMap) { driverMap.setView(driverMapMarker.getLatLng(), 16); } }; window.recenterDriverMap = function() { if (driverMapMarker && driverMap) { driverMap.setView(driverMapMarker.getLatLng(), 16); } }; window.openDriverDirections = function() { const destAddr = SafeStorage.getItem('smd_cust_address'); if (destAddr) { window.open(`https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent(destAddr)}`, '_blank'); } else { alert('No destination address found for directions.'); } }; window.fitCustomerMap = function() { if (driverMarker && destMarker && map) { const group = new L.featureGroup([driverMarker, destMarker]); map.fitBounds(group.getBounds().pad(0.2)); } else if (driverMarker && map) { map.setView(driverMarker.getLatLng(), 16); } }; window.recenterCustomerMap = function() { if (driverMarker && map) { map.setView(driverMarker.getLatLng(), 16); } }; async function handleAddressInput(value) { const suggestions = document.getElementById('address-suggestions'); if (!suggestions) return; if (value.trim().length < 3) { suggestions.classList.add('hidden'); suggestions.style.display = 'none'; return; } try { const res = await fetch(`https://photon.komoot.io/api/?q=${encodeURIComponent(value)}&limit=5`); const data = await res.json(); suggestions.innerHTML = ''; data.features.forEach(f => { const name = `${f.properties.name || ''}, ${f.properties.city || ''}, ${f.properties.state || ''}`.replace(/^, /, ''); const div = document.createElement('div'); div.className = "px-3.5 py-2.5 text-xs text-neutral-200 hover:bg-neutral-800 cursor-pointer border-b border-neutral-800 backdrop-blur-md"; div.innerText = name; div.onclick = () => { document.getElementById('job-cust-address').value = name; suggestions.classList.add('hidden'); suggestions.style.display = 'none'; }; suggestions.appendChild(div); }); suggestions.classList.remove('hidden'); suggestions.style.display = 'block'; } catch(e){} } window.handleAddressInput = handleAddressInput; async function initDriverActiveMap() { const container = document.getElementById('driver-map-container'); if (container) { container.style.height = '240px'; if (container.parentElement) container.parentElement.style.height = '240px'; } let startLat = 29.9902, startLng = -95.2636; try { const pos = await getLivePosition(); startLat = pos.lat; startLng = pos.lng; } catch(e) {} if (!driverMap && container) { driverMap = L.map('driver-map-container', {zoomControl: false}).setView([startLat, startLng], 16); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(driverMap); } else if (driverMap) { driverMap.invalidateSize(); } const destName = SafeStorage.getItem('smd_cust_address') || 'Destination'; const driverName = SafeStorage.getItem('smd_driver_name') || 'Driver'; let destLat = null, destLng = null, addressFound = false; try { let res = await fetch(`https://photon.komoot.io/api/?q=${encodeURIComponent(destName)}&limit=1`); let data = await res.json(); if (data.features?.length) { destLng = data.features[0].geometry.coordinates[0]; destLat = data.features[0].geometry.coordinates[1]; addressFound = true; } else { res = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(destName)}&limit=1`); data = await res.json(); if (data && data.length > 0) { destLng = parseFloat(data[0].lon); destLat = parseFloat(data[0].lat); addressFound = true; } } } catch(e) {} if (activeFirebaseListener && window.activeSessionId) { db.ref('broadcasts/' + window.activeSessionId).off('value', activeFirebaseListener); } activeFirebaseListener = db.ref('broadcasts/' + window.activeSessionId).on('value', async (snap) => { const data = snap.val() || { lat: startLat, lng: startLng, speed: 0, driverName: driverName }; let lat = data.lat || startLat, lng = data.lng || startLng; const speed = data.speed || 0; const currentDriverName = data.driverName || driverName; const speedEl = document.getElementById('driver-map-speed'); if (speedEl) speedEl.innerText = speed + ' mph'; let fullRoute = [[lat, lng]]; if (addressFound && destLat && destLng) { if (window.driverCachedRouteCoords && window.driverCachedRouteCoords.length > 0) { const currentRoutePt = window.driverCachedRouteCoords[driverRouteIndex] || [lat, lng]; const deviationDist = calculateDistance(lat, lng, currentRoutePt[0], currentRoutePt[1]); if (deviationDist > 0.03) { window.driverCachedRouteCoords = null; driverRouteIndex = 0; } } if (!window.driverCachedRouteCoords) { try { const r = await fetch(`https://router.project-osrm.org/route/v1/driving/${lng},${lat};${destLng},${destLat}?overview=full&geometries=geojson`); const j = await r.json(); if (j.routes && j.routes.length > 0) { window.driverCachedRouteCoords = j.routes[0].geometry.coordinates.map(c => [c[1], c[0]]); driverRouteIndex = 0; } } catch(e) {} if (!window.driverCachedRouteCoords || window.driverCachedRouteCoords.length === 0) { window.driverCachedRouteCoords = [[lat, lng], [destLat, destLng]]; } } fullRoute = window.driverCachedRouteCoords; const snapped = getClosestPointOnPolyline(lat, lng, fullRoute); lat = snapped[0]; lng = snapped[1]; } let bearing = window.lastValidHeading || 0; if (fullRoute.length > 1) { let minDist = Infinity; let bestIdx = driverRouteIndex; let searchLimit = Math.min(fullRoute.length, driverRouteIndex + 40); for (let i = driverRouteIndex; i < searchLimit; i++) { let pt = fullRoute[i]; let d = Math.hypot(pt[0] - lat, pt[1] - lng); if (d < minDist) { minDist = d; bestIdx = i; } } driverRouteIndex = Math.max(driverRouteIndex, bestIdx); let idx1 = driverRouteIndex; let idx2 = Math.min(driverRouteIndex + 1, fullRoute.length - 1); if (idx1 === idx2 && idx1 > 0) { idx1 = idx1 - 1; } const p1 = fullRoute[idx1]; const p2 = fullRoute[idx2]; const dLat = -(p2[0] - p1[0]); const dLng = (p2[1] - p1[1]) * Math.cos(p1[0] * Math.PI / 180); if (dLat !== 0 || dLng !== 0) { bearing = Math.atan2(dLng, dLat) * (180 / Math.PI); window.lastValidHeading = bearing; } } let activeForwardPath = fullRoute.length > 1 ? fullRoute.slice(driverRouteIndex) : fullRoute; const truckIcon = getTruckIcon(bearing); const labelIcon = getDriverLabelIcon(currentDriverName); const pinIcon = L.divIcon({ className: 'custom-pin-marker', html: `
📍
`, iconSize: [0, 0], iconAnchor: [0, 0] }); if (driverMap) { driverMap.setView([lat, lng], 16); driverMap.invalidateSize(); } if (!driverMapMarker) { driverMapMarker = L.marker([lat, lng], {icon: truckIcon}).addTo(driverMap); } else { smoothMoveMarker(driverMapMarker, lat, lng, speed); driverMapMarker.setIcon(truckIcon); } if (!driverMapLabelMarker) { driverMapLabelMarker = L.marker([lat, lng], {icon: labelIcon}).addTo(driverMap); } else { smoothMoveMarker(driverMapLabelMarker, lat, lng, speed); driverMapLabelMarker.setIcon(labelIcon); } if (addressFound && destLat && destLng) { if (!driverDestMarker) { driverDestMarker = L.marker([destLat, destLng], {icon: pinIcon}).addTo(driverMap); } if (!driverRouteLine) { driverRouteLine = L.polyline(activeForwardPath, {color: '#3b82f6', weight: 5, className: 'drop-shadow-md'}).addTo(driverMap); driverMap.fitBounds(L.featureGroup([driverMapMarker, driverDestMarker]).getBounds().pad(0.2)); } else { driverRouteLine.setLatLngs(activeForwardPath); } } else { if (driverDestMarker) { driverMap.removeLayer(driverDestMarker); driverDestMarker = null; } if (driverRouteLine) { driverMap.removeLayer(driverRouteLine); driverRouteLine = null; } } }); } async function initCustomerMapLive() { initConnectionMonitor(); const urlParams = new URLSearchParams(window.location.search); const sessionId = urlParams.get('session') || urlParams.get('s') || window.activeSessionId; const container = document.getElementById('customer-map-container'); if (container) { container.style.height = '288px'; if (container.parentElement) container.parentElement.style.height = '288px'; } let startLat = 29.9902, startLng = -95.2636; if (!map && container) { map = L.map('customer-map-container', {zoomControl: false}).setView([startLat, startLng], 16); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map); } else if (map) { map.invalidateSize(); } db.ref('broadcasts/' + sessionId).on('value', async (snap) => { const data = snap.val() || { lat: startLat, lng: startLng, speed: 0, driverName: 'Driver' }; const driverNameEl = document.getElementById('cust-driver-name'); const custDestEl = document.getElementById('cust-destination'); const custSpeedEl = document.getElementById('cust-speed'); const custDistEl = document.getElementById('cust-distance'); const custEtaEl = document.getElementById('cust-eta'); const currentDriverName = data.driverName || 'Driver'; if (driverNameEl) driverNameEl.innerText = currentDriverName; if (custDestEl) custDestEl.innerText = data.custAddress || 'Destination'; const speed = data.speed || 0; if (custSpeedEl) custSpeedEl.innerText = speed + ' mph'; if (data.driverPhone) { const callBtn = document.getElementById('cust-call-btn'); const msgBtn = document.getElementById('cust-msg-btn'); if (callBtn) callBtn.href = `tel:${data.driverPhone}`; if (msgBtn) msgBtn.href = `sms:${data.driverPhone}?body=Hi%20${encodeURIComponent(currentDriverName)},%20tracking%20your%20arrival!`; } let lat = data.lat || startLat, lng = data.lng || startLng; let destLat = cachedDestLat, destLng = cachedDestLng, addressFound = !!cachedDestLat; if (!addressFound && data.custAddress) { try { const res = await fetch(`https://photon.komoot.io/api/?q=${encodeURIComponent(data.custAddress)}&limit=1`); const resData = await res.json(); if (resData.features?.length) { destLng = resData.features[0].geometry.coordinates[0]; destLat = resData.features[0].geometry.coordinates[1]; cachedDestLat = destLat; cachedDestLng = destLng; addressFound = true; } } catch(e){} } let fullRoute = [[lat, lng]]; if (addressFound) { const dist = calculateDistance(lat, lng, destLat, destLng); if (custDistEl) custDistEl.innerText = dist.toFixed(1) + ' mi'; if (custEtaEl) custEtaEl.innerText = Math.round((dist / (speed > 10 ? speed : 30)) * 60) + ' mins'; if (!window.custCachedRouteCoords) { const r = await fetch(`https://router.project-osrm.org/route/v1/driving/${lng},${lat};${destLng},${destLat}?overview=full&geometries=geojson`); const j = await r.json(); window.custCachedRouteCoords = j.routes?.[0]?.geometry?.coordinates.map(c => [c[1], c[0]]) || [[lat, lng], [destLat, destLng]]; } fullRoute = window.custCachedRouteCoords; const snapped = getClosestPointOnPolyline(lat, lng, fullRoute); lat = snapped[0]; lng = snapped[1]; } let bearing = window.lastValidHeading || 0; if (fullRoute.length > 1) { let minDist = Infinity; let bestIdx = custRouteIndex; let searchLimit = Math.min(fullRoute.length, custRouteIndex + 40); for (let i = custRouteIndex; i < searchLimit; i++) { let pt = fullRoute[i]; let d = Math.hypot(pt[0] - lat, pt[1] - lng); if (d < minDist) { minDist = d; bestIdx = i; } } custRouteIndex = Math.max(custRouteIndex, bestIdx); let idx1 = custRouteIndex; let idx2 = Math.min(custRouteIndex + 1, fullRoute.length - 1); if (idx1 === idx2 && idx1 > 0) { idx1 = idx1 - 1; } const p1 = fullRoute[idx1]; const p2 = fullRoute[idx2]; const dLat = -(p2[0] - p1[0]); const dLng = (p2[1] - p1[1]) * Math.cos(p1[0] * Math.PI / 180); if (dLat !== 0 || dLng !== 0) { bearing = Math.atan2(dLng, dLat) * (180 / Math.PI); window.lastValidHeading = bearing; } } let activeForwardPath = fullRoute.length > 1 ? fullRoute.slice(custRouteIndex) : fullRoute; const truckIcon = getTruckIcon(bearing); const labelIcon = getDriverLabelIcon(currentDriverName); const pinIcon = L.divIcon({ className: 'custom-pin-marker', html: `
📍
`, iconSize: [0, 0], iconAnchor: [0, 0] }); if (map) { map.panTo([lat, lng]); map.invalidateSize(); } if (!driverMarker) { driverMarker = L.marker([lat, lng], {icon: truckIcon}).addTo(map); } else { smoothMoveMarker(driverMarker, lat, lng, speed); driverMarker.setIcon(truckIcon); } if (!custMapLabelMarker) { custMapLabelMarker = L.marker([lat, lng], {icon: labelIcon}).addTo(map); } else { smoothMoveMarker(custMapLabelMarker, lat, lng, speed); custMapLabelMarker.setIcon(labelIcon); } if (addressFound && routeLine) { routeLine.setLatLngs(activeForwardPath); } else if (addressFound && !routeLine) { routeLine = L.polyline(activeForwardPath, {color: '#3b82f6', weight: 5, className: 'drop-shadow-md'}).addTo(map); if (driverMarker && destMarker) { map.fitBounds(L.featureGroup([driverMarker, destMarker]).getBounds().pad(0.2)); } } }); } // FORCE LANDING VIEW ON STARTUP UNLESS CUSTOMER LINK PARAMS ARE PRESENT window.addEventListener('DOMContentLoaded', () => { try { const urlParams = new URLSearchParams(window.location.search); if (urlParams.get('view') === 'customer' || urlParams.has('s') || urlParams.has('session')) { switchView('customer'); } else { // Stripped out all auto-login checks so the public landing page loads first by default! switchView('landing'); } } catch (e) { switchView('landing'); } });