// ==========================================
// 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');
}
});