From 299187672d9461f7ff10db9a2a08974eb187de21 Mon Sep 17 00:00:00 2001 From: Nguyen Ngo Date: Thu, 28 Aug 2025 20:47:11 -0400 Subject: [PATCH] Update location accuracy --- static/js/qr_destination.js | 146 ++++++++----- templates/qr_destination.html | 400 +++++++++++++++++++--------------- 2 files changed, 321 insertions(+), 225 deletions(-) diff --git a/static/js/qr_destination.js b/static/js/qr_destination.js index 36c7019..3522119 100644 --- a/static/js/qr_destination.js +++ b/static/js/qr_destination.js @@ -76,12 +76,12 @@ document.addEventListener("DOMContentLoaded", function () { // ENHANCED STAFF ID PERSISTENCE FUNCTIONALITY function initializeStaffIdPersistence() { console.log("👤 Initializing staff ID persistence functionality"); - + // Load last staff ID from localStorage lastStaffId = loadLastStaffId(); if (lastStaffId) { console.log(`📱 Found last staff ID: ${lastStaffId}`); - + // Automatically fill the last staff ID const employeeIdInput = document.getElementById("employee_id"); if (employeeIdInput) { @@ -96,7 +96,7 @@ function initializeStaffIdPersistence() { function loadLastStaffId() { try { - const saved = localStorage.getItem('qr_last_staff_id'); + const saved = localStorage.getItem("qr_last_staff_id"); if (saved && saved.trim().length >= 2) { return saved.trim().toUpperCase(); } @@ -110,18 +110,18 @@ function loadLastStaffId() { function saveLastStaffId(staffId) { try { - if (!staffId || typeof staffId !== 'string' || staffId.trim().length < 2) { + if (!staffId || typeof staffId !== "string" || staffId.trim().length < 2) { console.log("⚠️ Invalid staff ID, not saving"); return false; } - + const cleanId = staffId.trim().toUpperCase(); lastStaffId = cleanId; - + // Save to localStorage - localStorage.setItem('qr_last_staff_id', cleanId); + localStorage.setItem("qr_last_staff_id", cleanId); console.log(`💾 Last staff ID saved: ${cleanId}`); - + return true; } catch (error) { console.error("❌ Error saving last staff ID to localStorage:", error); @@ -537,7 +537,22 @@ function requestLocationData() { navigator.geolocation.getCurrentPosition( handleLocationSuccess, - handleLocationError, + (error) => { + console.log("❌ High accuracy failed, trying low accuracy..."); + + // Simple fallback with low accuracy + const lowAccuracyOptions = { + enableHighAccuracy: false, + timeout: 15000, + maximumAge: 600000, + }; + + navigator.geolocation.getCurrentPosition( + handleLocationSuccess, + handleLocationError, + lowAccuracyOptions + ); + }, options ); } @@ -574,8 +589,8 @@ function reverseGeocode(lat, lng) { // The server will use Google Maps API first, then fall back to OpenStreetMap // This provides better accuracy and address formatting - const url = '/api/reverse-geocode'; // You may want to create this endpoint - + const url = "/api/reverse-geocode"; // You may want to create this endpoint + // For now, using direct OpenStreetMap as fallback // In production, this should go through your server API const osmUrl = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&addressdetails=1&zoom=18`; @@ -606,7 +621,7 @@ function reverseGeocode(lat, lng) { // ENHANCED LANGUAGE FUNCTIONALITY WITH PERSISTENCE function initializeLanguage() { console.log("🌐 Initializing language functionality with persistence"); - + // Load saved language preference from localStorage const savedLanguage = loadLanguagePreference(); if (savedLanguage && savedLanguage !== currentLanguage) { @@ -629,15 +644,17 @@ function toggleLanguage() { // Switch between languages const newLanguage = currentLanguage === "en" ? "es" : "en"; currentLanguage = newLanguage; - + // Save new language preference to localStorage saveLanguagePreference(currentLanguage); - + // Apply translations immediately applyTranslations(); - - console.log(`🌐 Language switched to: ${currentLanguage} (saved to localStorage)`); - + + console.log( + `🌐 Language switched to: ${currentLanguage} (saved to localStorage)` + ); + // Optional: Show brief confirmation message showLanguageChangeConfirmation(); } @@ -645,23 +662,28 @@ function toggleLanguage() { function loadLanguagePreference() { try { // Retrieve language preference from localStorage - const savedLanguage = localStorage.getItem('qr_staff_language'); - + const savedLanguage = localStorage.getItem("qr_staff_language"); + // Validate saved language is supported if (savedLanguage && translations.hasOwnProperty(savedLanguage)) { console.log(`📱 Found saved language preference: ${savedLanguage}`); return savedLanguage; } else if (savedLanguage) { - console.log(`⚠️ Invalid saved language preference: ${savedLanguage}, using default`); + console.log( + `⚠️ Invalid saved language preference: ${savedLanguage}, using default` + ); // Clean up invalid preference - localStorage.removeItem('qr_staff_language'); + localStorage.removeItem("qr_staff_language"); } else { console.log("📱 No saved language preference found, using default"); } - + return null; } catch (error) { - console.error("❌ Error loading language preference from localStorage:", error); + console.error( + "❌ Error loading language preference from localStorage:", + error + ); return null; } } @@ -673,13 +695,16 @@ function saveLanguagePreference(language) { console.error(`❌ Invalid language code: ${language}`); return false; } - + // Save to localStorage - localStorage.setItem('qr_staff_language', language); + localStorage.setItem("qr_staff_language", language); console.log(`💾 Language preference saved: ${language}`); return true; } catch (error) { - console.error("❌ Error saving language preference to localStorage:", error); + console.error( + "❌ Error saving language preference to localStorage:", + error + ); return false; } } @@ -691,7 +716,7 @@ function showLanguageChangeConfirmation() { // Add temporary visual feedback languageToggle.style.transform = "scale(1.05)"; languageToggle.style.background = "rgba(255, 255, 255, 0.4)"; - + setTimeout(() => { languageToggle.style.transform = ""; languageToggle.style.background = ""; @@ -710,7 +735,7 @@ function applyTranslations() { document.querySelectorAll(`[data-${currentLanguage}]`).forEach((element) => { element.textContent = element.getAttribute(`data-${currentLanguage}`); }); - + // Update any dynamic content that might have been generated after initial load updateDynamicTranslations(); } @@ -718,7 +743,7 @@ function applyTranslations() { function updateDynamicTranslations() { // Update submit button text if it exists and has been modified const submitButton = document.getElementById("submitCheckin"); - if (submitButton && submitButton.innerHTML.includes('data-')) { + if (submitButton && submitButton.innerHTML.includes("data-")) { // Re-apply translations to submit button content const spans = submitButton.querySelectorAll(`[data-${currentLanguage}]`); spans.forEach((span) => { @@ -742,7 +767,7 @@ function startClock() { function checkLocationServicesStatus() { console.log("📱 Checking location services status..."); - + // Check if geolocation is supported if (!navigator.geolocation) { console.log("❌ Geolocation not supported by this browser"); @@ -767,7 +792,7 @@ function checkLocationServicesStatus() { // Error - location services may be disabled clearTimeout(timeoutId); console.log("❌ Location services error:", error.message); - + switch (error.code) { case error.PERMISSION_DENIED: showLocationServicesWarning("permission_denied"); @@ -786,7 +811,7 @@ function checkLocationServicesStatus() { { enableHighAccuracy: false, timeout: 2500, - maximumAge: 60000 + maximumAge: 60000, } ); } @@ -797,31 +822,42 @@ function checkLocationServicesStatus() { function showLocationServicesWarning(errorType) { // Remove existing warning if present hideLocationServicesWarning(); - + const warningMessages = { en: { - not_supported: "Location services are not supported by your browser.
Los servicios de ubicación no son compatibles con su navegador.", - permission_denied: "Location access has been denied. Please enable location services for accurate check-in.
Se ha denegado el acceso a la ubicación. Habilite los servicios de ubicación para un registro preciso.", - position_unavailable: "Location services appear to be disabled. Please turn on location services for accurate check-in.
Los servicios de ubicación parecen estar deshabilitados. Active los servicios de ubicación para un registro preciso.", - timeout: "Location services may be disabled. Please check your location settings for accurate check-in.
Los servicios de ubicación pueden estar deshabilitados. Verifique su configuración de ubicación para un registro preciso.", - unknown_error: "Unable to access location services. Please check your location settings.
No se puede acceder a los servicios de ubicación. Verifique su configuración de ubicación." + not_supported: + "Location services are not supported by your browser.
Los servicios de ubicación no son compatibles con su navegador.", + permission_denied: + "Location access has been denied. Please enable location services for accurate check-in.
Se ha denegado el acceso a la ubicación. Habilite los servicios de ubicación para un registro preciso.", + position_unavailable: + "Location services appear to be disabled. Please turn on location services for accurate check-in.
Los servicios de ubicación parecen estar deshabilitados. Active los servicios de ubicación para un registro preciso.", + timeout: + "Location services may be disabled. Please check your location settings for accurate check-in.
Los servicios de ubicación pueden estar deshabilitados. Verifique su configuración de ubicación para un registro preciso.", + unknown_error: + "Unable to access location services. Please check your location settings.
No se puede acceder a los servicios de ubicación. Verifique su configuración de ubicación.", }, es: { - not_supported: "Los servicios de ubicación no son compatibles con su navegador.", - permission_denied: "Se ha denegado el acceso a la ubicación. Habilite los servicios de ubicación para un registro preciso.", - position_unavailable: "Los servicios de ubicación parecen estar deshabilitados. Active los servicios de ubicación para un registro preciso.", - timeout: "Los servicios de ubicación pueden estar deshabilitados. Verifique su configuración de ubicación para un registro preciso.", - unknown_error: "No se puede acceder a los servicios de ubicación. Verifique su configuración de ubicación." - } + not_supported: + "Los servicios de ubicación no son compatibles con su navegador.", + permission_denied: + "Se ha denegado el acceso a la ubicación. Habilite los servicios de ubicación para un registro preciso.", + position_unavailable: + "Los servicios de ubicación parecen estar deshabilitados. Active los servicios de ubicación para un registro preciso.", + timeout: + "Los servicios de ubicación pueden estar deshabilitados. Verifique su configuración de ubicación para un registro preciso.", + unknown_error: + "No se puede acceder a los servicios de ubicación. Verifique su configuración de ubicación.", + }, }; - const currentLang = currentLanguage || 'en'; - const message = warningMessages[currentLang][errorType] || warningMessages['en'][errorType]; - + const currentLang = currentLanguage || "en"; + const message = + warningMessages[currentLang][errorType] || warningMessages["en"][errorType]; + // Create warning banner - const warningBanner = document.createElement('div'); - warningBanner.id = 'locationServicesWarning'; - warningBanner.className = 'location-warning-banner'; + const warningBanner = document.createElement("div"); + warningBanner.id = "locationServicesWarning"; + warningBanner.className = "location-warning-banner"; warningBanner.innerHTML = `
@@ -846,7 +882,7 @@ function showLocationServicesWarning(errorType) { `; // Insert warning at the top of the page - const container = document.querySelector('.destination-container'); + const container = document.querySelector(".destination-container"); if (container) { container.insertBefore(warningBanner, container.firstChild); } @@ -859,7 +895,7 @@ function showLocationServicesWarning(errorType) { * Hide location services warning banner */ function hideLocationServicesWarning() { - const existingWarning = document.getElementById('locationServicesWarning'); + const existingWarning = document.getElementById("locationServicesWarning"); if (existingWarning) { existingWarning.remove(); console.log("✅ Location services warning hidden"); @@ -875,13 +911,13 @@ function initializeLocationServicesCheck() { setTimeout(() => { checkLocationServicesStatus(); }, 1000); // Small delay to ensure page is fully loaded - + // Also check before form submission const originalHandleFormSubmit = handleFormSubmit; - window.handleFormSubmit = function(event) { + window.handleFormSubmit = function (event) { // Quick location check before submission checkLocationServicesStatus(); - + // Continue with original form submission after brief delay setTimeout(() => { originalHandleFormSubmit.call(this, event); diff --git a/templates/qr_destination.html b/templates/qr_destination.html index 9318bf4..9f4e38a 100644 --- a/templates/qr_destination.html +++ b/templates/qr_destination.html @@ -26,7 +26,7 @@ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1); --border-radius: 0.5rem; --transition: all 0.2s ease-in-out; - + /* Language Color Coding - High Contrast Theme */ --english-color: #1e40af; --english-bg: rgba(59, 130, 246, 0.1); @@ -173,12 +173,20 @@ /* Check In - Blue Icon */ .check-in .header-icon { - background: linear-gradient(135deg, var(--primary-color), var(--primary-hover)); + background: linear-gradient( + 135deg, + var(--primary-color), + var(--primary-hover) + ); } /* Check Out - Orange Icon */ .check-out .header-icon { - background: linear-gradient(135deg, var(--orange-color), var(--orange-hover)); + background: linear-gradient( + 135deg, + var(--orange-color), + var(--orange-hover) + ); } .header-icon i { @@ -516,8 +524,12 @@ } @keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } .fade-transition { @@ -710,11 +722,11 @@ flex-direction: column; gap: 0.5rem; } - + .warning-actions { justify-content: center; } - + .warning-retry-btn, .warning-dismiss-btn { flex: 1; @@ -724,34 +736,36 @@ } - +
- - +
{% if qr_code.location_event == 'Check In' %} -

- {{ qr_code.location_event }} - / - Entrada -

+

+ {{ qr_code.location_event }} + / + Entrada +

{% else %} -

- {{ qr_code.location_event }} - / - Salida -

- {% endif %} +

+ {{ qr_code.location_event }} + / + Salida +

+ {% endif %}

{{ qr_code.location }} @@ -773,7 +787,9 @@

Please enter your Employee ID. / - Por favor ingrese su ID de empleado. + Por favor ingrese su ID de empleado.

@@ -799,15 +815,15 @@ @@ -825,9 +841,13 @@

- Your submission has been recorded successfully. + Your submission has been recorded successfully. / - Su registro ha sido guardado exitosamente. + Su registro ha sido guardado exitosamente.

@@ -852,21 +872,21 @@ let locationCaptureActive = false; // Initialize the page when DOM is loaded - document.addEventListener('DOMContentLoaded', function() { - console.log('🚀 QR Destination page loaded successfully'); - console.log('📱 Enhanced with color-coded bilingual support'); - + document.addEventListener("DOMContentLoaded", function () { + console.log("🚀 QR Destination page loaded successfully"); + console.log("📱 Enhanced with color-coded bilingual support"); + // Initialize Employee ID auto-fill FIRST (before other functionality) initializeEmployeeIdAutoFill(); - + // Then initialize other functionality initializeFormHandling(); initializeLocationCapture(); - + // Add fade-in animations setTimeout(() => { - document.querySelectorAll('.fade-transition').forEach(el => { - el.classList.add('active'); + document.querySelectorAll(".fade-transition").forEach((el) => { + el.classList.add("active"); }); }, 100); }); @@ -874,8 +894,8 @@ // FIXED Employee ID auto-fill functionality function initializeEmployeeIdAutoFill() { console.log("👤 Initializing Employee ID auto-fill functionality"); - - const employeeIdInput = document.getElementById('employee_id'); + + const employeeIdInput = document.getElementById("employee_id"); if (!employeeIdInput) { console.log("❌ Employee ID input not found"); return; @@ -883,17 +903,19 @@ // Load and auto-fill last used Employee ID immediately try { - const lastEmployeeId = localStorage.getItem('qr_last_employee_id'); - console.log(`📱 Checking localStorage for last employee ID: ${lastEmployeeId}`); - - if (lastEmployeeId && lastEmployeeId.trim() !== '') { + const lastEmployeeId = localStorage.getItem("qr_last_employee_id"); + console.log( + `📱 Checking localStorage for last employee ID: ${lastEmployeeId}` + ); + + if (lastEmployeeId && lastEmployeeId.trim() !== "") { employeeIdInput.value = lastEmployeeId.trim(); console.log(`✅ Auto-filled employee ID: ${lastEmployeeId}`); - + // Visual feedback that it's auto-filled - employeeIdInput.style.backgroundColor = '#f0f9ff'; + employeeIdInput.style.backgroundColor = "#f0f9ff"; setTimeout(() => { - employeeIdInput.style.backgroundColor = ''; + employeeIdInput.style.backgroundColor = ""; }, 2000); } else { console.log(`📱 No previous employee ID found`); @@ -903,11 +925,12 @@ } // Save Employee ID when it's entered successfully - employeeIdInput.addEventListener('input', function() { + employeeIdInput.addEventListener("input", function () { const currentId = this.value.trim(); - if (currentId.length >= 2) { // Save if at least 2 characters + if (currentId.length >= 2) { + // Save if at least 2 characters try { - localStorage.setItem('qr_last_employee_id', currentId); + localStorage.setItem("qr_last_employee_id", currentId); console.log(`💾 Saved employee ID: ${currentId}`); } catch (error) { console.log(`❌ Error saving employee ID: ${error.message}`); @@ -938,34 +961,33 @@ } locationCaptureActive = true; - console.log("📍 Requesting enhanced location data (high accuracy)..."); + console.log("📍 Requesting enhanced location data..."); - const highAccuracyOptions = { + const options = { enableHighAccuracy: true, - timeout: 15000, // 15 sec for GPS attempt - maximumAge: 300000 + timeout: 10000, + maximumAge: 300000, }; navigator.geolocation.getCurrentPosition( handleEnhancedLocationSuccess, - function(error) { - console.warn("⚠️ High accuracy failed:", error.message); + (error) => { + console.log("❌ High accuracy failed, trying low accuracy..."); - // Fallback to low accuracy + // Simple fallback with low accuracy const lowAccuracyOptions = { enableHighAccuracy: false, - timeout: 10000, - maximumAge: 600000 + timeout: 15000, + maximumAge: 600000, }; - console.log("📍 Retrying with low accuracy..."); navigator.geolocation.getCurrentPosition( handleEnhancedLocationSuccess, handleEnhancedLocationError, lowAccuracyOptions ); }, - highAccuracyOptions + options ); } @@ -986,7 +1008,10 @@ console.log("📍 Enhanced location data:", currentUserLocation); // Reverse geocode to get address - reverseGeocodeEnhanced(currentUserLocation.latitude, currentUserLocation.longitude); + reverseGeocodeEnhanced( + currentUserLocation.latitude, + currentUserLocation.longitude + ); locationCaptureActive = false; } @@ -1000,7 +1025,9 @@ // Reverse geocode coordinates to address (renamed to avoid conflicts) function reverseGeocodeEnhanced(lat, lng) { - console.log(`🌍 Starting enhanced reverse geocoding for: ${lat}, ${lng}`); + console.log( + `🌍 Starting enhanced reverse geocoding for: ${lat}, ${lng}` + ); // Using Nominatim (OpenStreetMap) reverse geocoding service const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&addressdetails=1&zoom=18`; @@ -1015,74 +1042,88 @@ .then((data) => { if (data && data.display_name) { currentUserLocation.address = data.display_name; - console.log(`✅ Enhanced reverse geocoded address: ${currentUserLocation.address}`); + console.log( + `✅ Enhanced reverse geocoded address: ${currentUserLocation.address}` + ); } else { console.log(`⚠️ No address found, using coordinates as fallback`); - currentUserLocation.address = `${lat.toFixed(10)}, ${lng.toFixed(10)}`; + currentUserLocation.address = `${lat.toFixed(10)}, ${lng.toFixed( + 10 + )}`; } }) .catch((error) => { console.error(`❌ Enhanced reverse geocoding error:`, error); // Fallback to coordinates if reverse geocoding fails - currentUserLocation.address = `${lat.toFixed(10)}, ${lng.toFixed(10)}`; + currentUserLocation.address = `${lat.toFixed(10)}, ${lng.toFixed( + 10 + )}`; }); } // Enhanced form handling with bilingual status messages function initializeFormHandling() { - const form = document.getElementById('checkinForm'); - const submitButton = document.getElementById('submitButton'); - - console.log('🔧 Initializing enhanced form handling...'); - console.log('Form element:', form); - console.log('Submit button:', submitButton); - + const form = document.getElementById("checkinForm"); + const submitButton = document.getElementById("submitButton"); + + console.log("🔧 Initializing enhanced form handling..."); + console.log("Form element:", form); + console.log("Submit button:", submitButton); + if (form && submitButton) { // Remove any existing event listeners - form.removeEventListener('submit', handleEnhancedFormSubmission); - submitButton.removeEventListener('click', handleEnhancedFormSubmission); - + form.removeEventListener("submit", handleEnhancedFormSubmission); + submitButton.removeEventListener( + "click", + handleEnhancedFormSubmission + ); + // Add form submit event listener - form.addEventListener('submit', function(e) { - console.log('📝 Enhanced form submit event triggered'); + form.addEventListener("submit", function (e) { + console.log("📝 Enhanced form submit event triggered"); e.preventDefault(); handleEnhancedFormSubmission(); }); - + // Also add click event listener to button as backup - submitButton.addEventListener('click', function(e) { - console.log('🖱️ Enhanced button click event triggered'); + submitButton.addEventListener("click", function (e) { + console.log("🖱️ Enhanced button click event triggered"); e.preventDefault(); handleEnhancedFormSubmission(); }); - - console.log('✅ Enhanced form handling initialized successfully'); + + console.log("✅ Enhanced form handling initialized successfully"); } else { - console.error('❌ Form or submit button not found!'); + console.error("❌ Form or submit button not found!"); } } // Handle form submission with location data (renamed to avoid conflicts) function handleEnhancedFormSubmission() { - console.log('🚀 handleEnhancedFormSubmission called'); - - const employeeId = document.getElementById('employee_id').value.trim(); - const submitButton = document.getElementById('submitButton'); - - console.log('Employee ID:', employeeId); - console.log('Submit button:', submitButton); - + console.log("🚀 handleEnhancedFormSubmission called"); + + const employeeId = document.getElementById("employee_id").value.trim(); + const submitButton = document.getElementById("submitButton"); + + console.log("Employee ID:", employeeId); + console.log("Submit button:", submitButton); + if (!employeeId) { - console.log('❌ No employee ID provided'); - showStatusMessage('Please enter your Employee ID / Por favor ingrese su ID de empleado', 'error'); + console.log("❌ No employee ID provided"); + showStatusMessage( + "Please enter your Employee ID / Por favor ingrese su ID de empleado", + "error" + ); return; } - console.log('✅ Employee ID valid, proceeding with enhanced submission'); + console.log( + "✅ Employee ID valid, proceeding with enhanced submission" + ); // Save Employee ID to localStorage for next time try { - localStorage.setItem('qr_last_employee_id', employeeId); + localStorage.setItem("qr_last_employee_id", employeeId); console.log(`💾 Saved employee ID for next time: ${employeeId}`); } catch (error) { console.log(`❌ Error saving employee ID: ${error.message}`); @@ -1099,81 +1140,93 @@ `; } - showStatusMessage('Processing check-in... / Procesando registro...', 'processing'); + showStatusMessage( + "Processing check-in... / Procesando registro...", + "processing" + ); // Get current URL to determine QR URL - const pathParts = window.location.pathname.split('/'); + const pathParts = window.location.pathname.split("/"); const qrUrl = pathParts[pathParts.length - 1]; - - console.log('QR URL:', qrUrl); - console.log('Current enhanced location data:', currentUserLocation); + + console.log("QR URL:", qrUrl); + console.log("Current enhanced location data:", currentUserLocation); // Prepare form data with location information const formData = new FormData(); - formData.append('employee_id', employeeId); - + formData.append("employee_id", employeeId); + // Add location data to form submission if (currentUserLocation.latitude !== null) { - formData.append('latitude', currentUserLocation.latitude.toString()); + formData.append("latitude", currentUserLocation.latitude.toString()); } if (currentUserLocation.longitude !== null) { - formData.append('longitude', currentUserLocation.longitude.toString()); + formData.append( + "longitude", + currentUserLocation.longitude.toString() + ); } if (currentUserLocation.accuracy !== null) { - formData.append('accuracy', currentUserLocation.accuracy.toString()); + formData.append("accuracy", currentUserLocation.accuracy.toString()); } if (currentUserLocation.altitude !== null) { - formData.append('altitude', currentUserLocation.altitude.toString()); + formData.append("altitude", currentUserLocation.altitude.toString()); } if (currentUserLocation.address) { - formData.append('address', currentUserLocation.address); + formData.append("address", currentUserLocation.address); } - formData.append('location_source', currentUserLocation.source); + formData.append("location_source", currentUserLocation.source); - console.log('📤 Submitting enhanced form with location data:', { + console.log("📤 Submitting enhanced form with location data:", { employee_id: employeeId, latitude: currentUserLocation.latitude, longitude: currentUserLocation.longitude, accuracy: currentUserLocation.accuracy, altitude: currentUserLocation.altitude, address: currentUserLocation.address, - location_source: currentUserLocation.source + location_source: currentUserLocation.source, }); // Submit to backend fetch(`/qr/${qrUrl}/checkin`, { - method: 'POST', - body: formData + method: "POST", + body: formData, }) - .then(response => { - console.log('📨 Received enhanced response:', response); - return response.json(); - }) - .then(data => { - console.log('📨 Enhanced response data:', data); - if (data.success) { - showStatusMessage('Submission successful! / Envío exitoso', 'success'); - showEnhancedSuccessCard(data); - } else { - showStatusMessage(data.message || 'Submission failed / Envío fallido', 'error'); + .then((response) => { + console.log("📨 Received enhanced response:", response); + return response.json(); + }) + .then((data) => { + console.log("📨 Enhanced response data:", data); + if (data.success) { + showStatusMessage( + "Submission successful! / Envío exitoso", + "success" + ); + showEnhancedSuccessCard(data); + } else { + showStatusMessage( + data.message || "Submission failed / Envío fallido", + "error" + ); + resetEnhancedSubmitButton(); + } + }) + .catch((error) => { + console.error("❌ Enhanced fetch error:", error); + showStatusMessage("Network error / Error de red", "error"); resetEnhancedSubmitButton(); - } - }) - .catch(error => { - console.error('❌ Enhanced fetch error:', error); - showStatusMessage('Network error / Error de red', 'error'); - resetEnhancedSubmitButton(); - }); + }); } // Reset submit button (renamed to avoid conflicts) function resetEnhancedSubmitButton() { - const submitButton = document.getElementById('submitButton'); + const submitButton = document.getElementById("submitButton"); submitButton.disabled = false; - + // Get the current location event from the page - const isCheckOut = document.body.classList.contains('check-out'); - + const isCheckOut = document.body.classList.contains("check-out"); + if (isCheckOut) { submitButton.innerHTML = ` @@ -1193,50 +1246,55 @@ // Enhanced status message display with color coding function showStatusMessage(message, type) { - const statusMessage = document.getElementById('statusMessage'); - const statusSpan = statusMessage.querySelector('span'); - + const statusMessage = document.getElementById("statusMessage"); + const statusSpan = statusMessage.querySelector("span"); + statusSpan.innerHTML = message; statusMessage.className = `status-message ${type} show`; - + setTimeout(() => { - statusMessage.classList.remove('show'); + statusMessage.classList.remove("show"); }, 5000); } // Enhanced success display with bilingual details (renamed to avoid conflicts) function showEnhancedSuccessCard(data) { - const successCard = document.getElementById('successCard'); - const checkinCard = document.querySelector('.checkin-card'); - const successDetails = document.getElementById('successDetails'); - + const successCard = document.getElementById("successCard"); + const checkinCard = document.querySelector(".checkin-card"); + const successDetails = document.getElementById("successDetails"); + // Hide check-in form - checkinCard.style.display = 'none'; - + checkinCard.style.display = "none"; + // Get employee ID from form input (since data.employee_id might be undefined) - const employeeIdInput = document.getElementById('employee_id'); - const employeeId = data.employee_id || (employeeIdInput ? employeeIdInput.value.trim() : 'N/A'); - + const employeeIdInput = document.getElementById("employee_id"); + const employeeId = + data.employee_id || + (employeeIdInput ? employeeIdInput.value.trim() : "N/A"); + // Use QR code location instead of GPS address for main location display - const qrLocationElement = document.querySelector('.location-info'); - let qrLocationName = 'Unknown Location'; + const qrLocationElement = document.querySelector(".location-info"); + let qrLocationName = "Unknown Location"; if (qrLocationElement) { // Extract text content, removing the icon - const locationText = qrLocationElement.textContent || qrLocationElement.innerText; + const locationText = + qrLocationElement.textContent || qrLocationElement.innerText; qrLocationName = locationText.trim(); } - + // Get location event (Check In or Check Out) - const isCheckOut = document.body.classList.contains('check-out'); - const locationEvent = isCheckOut ? 'Check Out' : 'Check In'; - const locationEventSpanish = isCheckOut ? 'Salida' : 'Entrada'; - + const isCheckOut = document.body.classList.contains("check-out"); + const locationEvent = isCheckOut ? "Check Out" : "Check In"; + const locationEventSpanish = isCheckOut ? "Salida" : "Entrada"; + // Alternative: try to get from page title or header - if (qrLocationName === 'Unknown Location') { - const headerElement = document.querySelector('.destination-header h1'); + if (qrLocationName === "Unknown Location") { + const headerElement = document.querySelector( + ".destination-header h1" + ); if (headerElement) { // Extract just the location event part (Check In/Check Out) - qrLocationName = data.location || 'Check-in Location'; + qrLocationName = data.location || "Check-in Location"; } } @@ -1267,7 +1325,9 @@ / Hora - ${data.timestamp || new Date().toLocaleString()} + ${ + data.timestamp || new Date().toLocaleString() + }
@@ -1278,17 +1338,17 @@ ${qrLocationName}
`; - + // Show success card - successCard.classList.add('show'); - - console.log('✅ Enhanced success card displayed with:', { + successCard.classList.add("show"); + + console.log("✅ Enhanced success card displayed with:", { employeeId: employeeId, locationEvent: locationEvent, qrLocation: qrLocationName, - timestamp: data.timestamp || new Date().toLocaleString() + timestamp: data.timestamp || new Date().toLocaleString(), }); } - \ No newline at end of file +