Update location accuracy

This commit is contained in:
2025-08-28 20:47:11 -04:00
parent 6a3c5430fc
commit 299187672d
2 changed files with 321 additions and 225 deletions
+68 -32
View File
@@ -96,7 +96,7 @@ function initializeStaffIdPersistence() {
function loadLastStaffId() { function loadLastStaffId() {
try { try {
const saved = localStorage.getItem('qr_last_staff_id'); const saved = localStorage.getItem("qr_last_staff_id");
if (saved && saved.trim().length >= 2) { if (saved && saved.trim().length >= 2) {
return saved.trim().toUpperCase(); return saved.trim().toUpperCase();
} }
@@ -110,7 +110,7 @@ function loadLastStaffId() {
function saveLastStaffId(staffId) { function saveLastStaffId(staffId) {
try { 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"); console.log("⚠️ Invalid staff ID, not saving");
return false; return false;
} }
@@ -119,7 +119,7 @@ function saveLastStaffId(staffId) {
lastStaffId = cleanId; lastStaffId = cleanId;
// Save to localStorage // Save to localStorage
localStorage.setItem('qr_last_staff_id', cleanId); localStorage.setItem("qr_last_staff_id", cleanId);
console.log(`💾 Last staff ID saved: ${cleanId}`); console.log(`💾 Last staff ID saved: ${cleanId}`);
return true; return true;
@@ -535,9 +535,24 @@ function requestLocationData() {
maximumAge: 300000, maximumAge: 300000,
}; };
navigator.geolocation.getCurrentPosition(
handleLocationSuccess,
(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( navigator.geolocation.getCurrentPosition(
handleLocationSuccess, handleLocationSuccess,
handleLocationError, handleLocationError,
lowAccuracyOptions
);
},
options options
); );
} }
@@ -574,7 +589,7 @@ function reverseGeocode(lat, lng) {
// The server will use Google Maps API first, then fall back to OpenStreetMap // The server will use Google Maps API first, then fall back to OpenStreetMap
// This provides better accuracy and address formatting // 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 // For now, using direct OpenStreetMap as fallback
// In production, this should go through your server API // In production, this should go through your server API
@@ -636,7 +651,9 @@ function toggleLanguage() {
// Apply translations immediately // Apply translations immediately
applyTranslations(); applyTranslations();
console.log(`🌐 Language switched to: ${currentLanguage} (saved to localStorage)`); console.log(
`🌐 Language switched to: ${currentLanguage} (saved to localStorage)`
);
// Optional: Show brief confirmation message // Optional: Show brief confirmation message
showLanguageChangeConfirmation(); showLanguageChangeConfirmation();
@@ -645,23 +662,28 @@ function toggleLanguage() {
function loadLanguagePreference() { function loadLanguagePreference() {
try { try {
// Retrieve language preference from localStorage // Retrieve language preference from localStorage
const savedLanguage = localStorage.getItem('qr_staff_language'); const savedLanguage = localStorage.getItem("qr_staff_language");
// Validate saved language is supported // Validate saved language is supported
if (savedLanguage && translations.hasOwnProperty(savedLanguage)) { if (savedLanguage && translations.hasOwnProperty(savedLanguage)) {
console.log(`📱 Found saved language preference: ${savedLanguage}`); console.log(`📱 Found saved language preference: ${savedLanguage}`);
return savedLanguage; return savedLanguage;
} else if (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 // Clean up invalid preference
localStorage.removeItem('qr_staff_language'); localStorage.removeItem("qr_staff_language");
} else { } else {
console.log("📱 No saved language preference found, using default"); console.log("📱 No saved language preference found, using default");
} }
return null; return null;
} catch (error) { } catch (error) {
console.error("❌ Error loading language preference from localStorage:", error); console.error(
"❌ Error loading language preference from localStorage:",
error
);
return null; return null;
} }
} }
@@ -675,11 +697,14 @@ function saveLanguagePreference(language) {
} }
// Save to localStorage // Save to localStorage
localStorage.setItem('qr_staff_language', language); localStorage.setItem("qr_staff_language", language);
console.log(`💾 Language preference saved: ${language}`); console.log(`💾 Language preference saved: ${language}`);
return true; return true;
} catch (error) { } catch (error) {
console.error("❌ Error saving language preference to localStorage:", error); console.error(
"❌ Error saving language preference to localStorage:",
error
);
return false; return false;
} }
} }
@@ -718,7 +743,7 @@ function applyTranslations() {
function updateDynamicTranslations() { function updateDynamicTranslations() {
// Update submit button text if it exists and has been modified // Update submit button text if it exists and has been modified
const submitButton = document.getElementById("submitCheckin"); const submitButton = document.getElementById("submitCheckin");
if (submitButton && submitButton.innerHTML.includes('data-')) { if (submitButton && submitButton.innerHTML.includes("data-")) {
// Re-apply translations to submit button content // Re-apply translations to submit button content
const spans = submitButton.querySelectorAll(`[data-${currentLanguage}]`); const spans = submitButton.querySelectorAll(`[data-${currentLanguage}]`);
spans.forEach((span) => { spans.forEach((span) => {
@@ -786,7 +811,7 @@ function checkLocationServicesStatus() {
{ {
enableHighAccuracy: false, enableHighAccuracy: false,
timeout: 2500, timeout: 2500,
maximumAge: 60000 maximumAge: 60000,
} }
); );
} }
@@ -800,28 +825,39 @@ function showLocationServicesWarning(errorType) {
const warningMessages = { const warningMessages = {
en: { en: {
not_supported: "Location services are not supported by your browser.<br>Los servicios de ubicación no son compatibles con su navegador.", not_supported:
permission_denied: "Location access has been denied. Please enable location services for accurate check-in.<br>Se ha denegado el acceso a la ubicación. Habilite los servicios de ubicación para un registro preciso.", "Location services are not supported by your browser.<br>Los servicios de ubicación no son compatibles con su navegador.",
position_unavailable: "Location services appear to be disabled. Please turn on location services for accurate check-in.<br>Los servicios de ubicación parecen estar deshabilitados. Active los servicios de ubicación para un registro preciso.", permission_denied:
timeout: "Location services may be disabled. Please check your location settings for accurate check-in.<br>Los servicios de ubicación pueden estar deshabilitados. Verifique su configuración de ubicación para un registro preciso.", "Location access has been denied. Please enable location services for accurate check-in.<br>Se ha denegado el acceso a la ubicación. Habilite los servicios de ubicación para un registro preciso.",
unknown_error: "Unable to access location services. Please check your location settings.<br>No se puede acceder a los servicios de ubicación. Verifique su configuración de ubicación." position_unavailable:
"Location services appear to be disabled. Please turn on location services for accurate check-in.<br>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.<br>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.<br>No se puede acceder a los servicios de ubicación. Verifique su configuración de ubicación.",
}, },
es: { es: {
not_supported: "Los servicios de ubicación no son compatibles con su navegador.", not_supported:
permission_denied: "Se ha denegado el acceso a la ubicación. Habilite los servicios de ubicación para un registro preciso.", "Los servicios de ubicación no son compatibles con su navegador.",
position_unavailable: "Los servicios de ubicación parecen estar deshabilitados. Active los servicios de ubicación para un registro preciso.", permission_denied:
timeout: "Los servicios de ubicación pueden estar deshabilitados. Verifique su configuración de ubicación para un registro preciso.", "Se ha denegado el acceso a la ubicación. Habilite los servicios 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." 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 currentLang = currentLanguage || "en";
const message = warningMessages[currentLang][errorType] || warningMessages['en'][errorType]; const message =
warningMessages[currentLang][errorType] || warningMessages["en"][errorType];
// Create warning banner // Create warning banner
const warningBanner = document.createElement('div'); const warningBanner = document.createElement("div");
warningBanner.id = 'locationServicesWarning'; warningBanner.id = "locationServicesWarning";
warningBanner.className = 'location-warning-banner'; warningBanner.className = "location-warning-banner";
warningBanner.innerHTML = ` warningBanner.innerHTML = `
<div class="warning-content"> <div class="warning-content">
<i class="fas fa-exclamation-triangle warning-icon"></i> <i class="fas fa-exclamation-triangle warning-icon"></i>
@@ -846,7 +882,7 @@ function showLocationServicesWarning(errorType) {
`; `;
// Insert warning at the top of the page // Insert warning at the top of the page
const container = document.querySelector('.destination-container'); const container = document.querySelector(".destination-container");
if (container) { if (container) {
container.insertBefore(warningBanner, container.firstChild); container.insertBefore(warningBanner, container.firstChild);
} }
@@ -859,7 +895,7 @@ function showLocationServicesWarning(errorType) {
* Hide location services warning banner * Hide location services warning banner
*/ */
function hideLocationServicesWarning() { function hideLocationServicesWarning() {
const existingWarning = document.getElementById('locationServicesWarning'); const existingWarning = document.getElementById("locationServicesWarning");
if (existingWarning) { if (existingWarning) {
existingWarning.remove(); existingWarning.remove();
console.log("✅ Location services warning hidden"); console.log("✅ Location services warning hidden");
@@ -878,7 +914,7 @@ function initializeLocationServicesCheck() {
// Also check before form submission // Also check before form submission
const originalHandleFormSubmit = handleFormSubmit; const originalHandleFormSubmit = handleFormSubmit;
window.handleFormSubmit = function(event) { window.handleFormSubmit = function (event) {
// Quick location check before submission // Quick location check before submission
checkLocationServicesStatus(); checkLocationServicesStatus();
+169 -109
View File
@@ -173,12 +173,20 @@
/* Check In - Blue Icon */ /* Check In - Blue Icon */
.check-in .header-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 - Orange Icon */
.check-out .header-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 { .header-icon i {
@@ -516,8 +524,12 @@
} }
@keyframes spin { @keyframes spin {
0% { transform: rotate(0deg); } 0% {
100% { transform: rotate(360deg); } transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
} }
.fade-transition { .fade-transition {
@@ -724,7 +736,9 @@
} }
</style> </style>
</head> </head>
<body class="{% if qr_code.location_event == 'Check Out' %}check-out{% else %}check-in{% endif %}"> <body
class="{% if qr_code.location_event == 'Check Out' %}check-out{% else %}check-in{% endif %}"
>
<div class="destination-container"> <div class="destination-container">
<!-- Header Section with Dynamic Styling and Color-Coded Languages --> <!-- Header Section with Dynamic Styling and Color-Coded Languages -->
<div class="destination-header fade-transition active"> <div class="destination-header fade-transition active">
@@ -737,7 +751,7 @@
onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';"
/> />
<!-- Fallback QR Icon (hidden by default, shown if logo fails to load) --> <!-- Fallback QR Icon (hidden by default, shown if logo fails to load) -->
<i class="fas fa-qrcode fallback-icon" style="display: none;"></i> <i class="fas fa-qrcode fallback-icon" style="display: none"></i>
</div> </div>
{% if qr_code.location_event == 'Check In' %} {% if qr_code.location_event == 'Check In' %}
<h1> <h1>
@@ -773,7 +787,9 @@
<p> <p>
<span class="english-text">Please enter your Employee ID.</span> <span class="english-text">Please enter your Employee ID.</span>
<span class="language-separator">/</span> <span class="language-separator">/</span>
<span class="spanish-text">Por favor ingrese su ID de empleado.</span> <span class="spanish-text"
>Por favor ingrese su ID de empleado.</span
>
</p> </p>
</div> </div>
</div> </div>
@@ -825,9 +841,13 @@
</h2> </h2>
<div class="bilingual-container"> <div class="bilingual-container">
<p> <p>
<span class="english-text">Your submission has been recorded successfully.</span> <span class="english-text"
>Your submission has been recorded successfully.</span
>
<span class="language-separator">/</span> <span class="language-separator">/</span>
<span class="spanish-text">Su registro ha sido guardado exitosamente.</span> <span class="spanish-text"
>Su registro ha sido guardado exitosamente.</span
>
</p> </p>
</div> </div>
<div class="success-details" id="successDetails"> <div class="success-details" id="successDetails">
@@ -852,9 +872,9 @@
let locationCaptureActive = false; let locationCaptureActive = false;
// Initialize the page when DOM is loaded // Initialize the page when DOM is loaded
document.addEventListener('DOMContentLoaded', function() { document.addEventListener("DOMContentLoaded", function () {
console.log('🚀 QR Destination page loaded successfully'); console.log("🚀 QR Destination page loaded successfully");
console.log('📱 Enhanced with color-coded bilingual support'); console.log("📱 Enhanced with color-coded bilingual support");
// Initialize Employee ID auto-fill FIRST (before other functionality) // Initialize Employee ID auto-fill FIRST (before other functionality)
initializeEmployeeIdAutoFill(); initializeEmployeeIdAutoFill();
@@ -865,8 +885,8 @@
// Add fade-in animations // Add fade-in animations
setTimeout(() => { setTimeout(() => {
document.querySelectorAll('.fade-transition').forEach(el => { document.querySelectorAll(".fade-transition").forEach((el) => {
el.classList.add('active'); el.classList.add("active");
}); });
}, 100); }, 100);
}); });
@@ -875,7 +895,7 @@
function initializeEmployeeIdAutoFill() { function initializeEmployeeIdAutoFill() {
console.log("👤 Initializing Employee ID auto-fill functionality"); console.log("👤 Initializing Employee ID auto-fill functionality");
const employeeIdInput = document.getElementById('employee_id'); const employeeIdInput = document.getElementById("employee_id");
if (!employeeIdInput) { if (!employeeIdInput) {
console.log("❌ Employee ID input not found"); console.log("❌ Employee ID input not found");
return; return;
@@ -883,17 +903,19 @@
// Load and auto-fill last used Employee ID immediately // Load and auto-fill last used Employee ID immediately
try { try {
const lastEmployeeId = localStorage.getItem('qr_last_employee_id'); const lastEmployeeId = localStorage.getItem("qr_last_employee_id");
console.log(`📱 Checking localStorage for last employee ID: ${lastEmployeeId}`); console.log(
`📱 Checking localStorage for last employee ID: ${lastEmployeeId}`
);
if (lastEmployeeId && lastEmployeeId.trim() !== '') { if (lastEmployeeId && lastEmployeeId.trim() !== "") {
employeeIdInput.value = lastEmployeeId.trim(); employeeIdInput.value = lastEmployeeId.trim();
console.log(`✅ Auto-filled employee ID: ${lastEmployeeId}`); console.log(`✅ Auto-filled employee ID: ${lastEmployeeId}`);
// Visual feedback that it's auto-filled // Visual feedback that it's auto-filled
employeeIdInput.style.backgroundColor = '#f0f9ff'; employeeIdInput.style.backgroundColor = "#f0f9ff";
setTimeout(() => { setTimeout(() => {
employeeIdInput.style.backgroundColor = ''; employeeIdInput.style.backgroundColor = "";
}, 2000); }, 2000);
} else { } else {
console.log(`📱 No previous employee ID found`); console.log(`📱 No previous employee ID found`);
@@ -903,11 +925,12 @@
} }
// Save Employee ID when it's entered successfully // Save Employee ID when it's entered successfully
employeeIdInput.addEventListener('input', function() { employeeIdInput.addEventListener("input", function () {
const currentId = this.value.trim(); 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 { try {
localStorage.setItem('qr_last_employee_id', currentId); localStorage.setItem("qr_last_employee_id", currentId);
console.log(`💾 Saved employee ID: ${currentId}`); console.log(`💾 Saved employee ID: ${currentId}`);
} catch (error) { } catch (error) {
console.log(`❌ Error saving employee ID: ${error.message}`); console.log(`❌ Error saving employee ID: ${error.message}`);
@@ -938,34 +961,33 @@
} }
locationCaptureActive = true; locationCaptureActive = true;
console.log("📍 Requesting enhanced location data (high accuracy)..."); console.log("📍 Requesting enhanced location data...");
const highAccuracyOptions = { const options = {
enableHighAccuracy: true, enableHighAccuracy: true,
timeout: 15000, // 15 sec for GPS attempt timeout: 10000,
maximumAge: 300000 maximumAge: 300000,
}; };
navigator.geolocation.getCurrentPosition( navigator.geolocation.getCurrentPosition(
handleEnhancedLocationSuccess, handleEnhancedLocationSuccess,
function(error) { (error) => {
console.warn("⚠️ High accuracy failed:", error.message); console.log(" High accuracy failed, trying low accuracy...");
// Fallback to low accuracy // Simple fallback with low accuracy
const lowAccuracyOptions = { const lowAccuracyOptions = {
enableHighAccuracy: false, enableHighAccuracy: false,
timeout: 10000, timeout: 15000,
maximumAge: 600000 maximumAge: 600000,
}; };
console.log("📍 Retrying with low accuracy...");
navigator.geolocation.getCurrentPosition( navigator.geolocation.getCurrentPosition(
handleEnhancedLocationSuccess, handleEnhancedLocationSuccess,
handleEnhancedLocationError, handleEnhancedLocationError,
lowAccuracyOptions lowAccuracyOptions
); );
}, },
highAccuracyOptions options
); );
} }
@@ -986,7 +1008,10 @@
console.log("📍 Enhanced location data:", currentUserLocation); console.log("📍 Enhanced location data:", currentUserLocation);
// Reverse geocode to get address // Reverse geocode to get address
reverseGeocodeEnhanced(currentUserLocation.latitude, currentUserLocation.longitude); reverseGeocodeEnhanced(
currentUserLocation.latitude,
currentUserLocation.longitude
);
locationCaptureActive = false; locationCaptureActive = false;
} }
@@ -1000,7 +1025,9 @@
// Reverse geocode coordinates to address (renamed to avoid conflicts) // Reverse geocode coordinates to address (renamed to avoid conflicts)
function reverseGeocodeEnhanced(lat, lng) { 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 // Using Nominatim (OpenStreetMap) reverse geocoding service
const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&addressdetails=1&zoom=18`; const url = `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&addressdetails=1&zoom=18`;
@@ -1015,74 +1042,88 @@
.then((data) => { .then((data) => {
if (data && data.display_name) { if (data && data.display_name) {
currentUserLocation.address = 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 { } else {
console.log(`⚠️ No address found, using coordinates as fallback`); 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) => { .catch((error) => {
console.error(`❌ Enhanced reverse geocoding error:`, error); console.error(`❌ Enhanced reverse geocoding error:`, error);
// Fallback to coordinates if reverse geocoding fails // 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 // Enhanced form handling with bilingual status messages
function initializeFormHandling() { function initializeFormHandling() {
const form = document.getElementById('checkinForm'); const form = document.getElementById("checkinForm");
const submitButton = document.getElementById('submitButton'); const submitButton = document.getElementById("submitButton");
console.log('🔧 Initializing enhanced form handling...'); console.log("🔧 Initializing enhanced form handling...");
console.log('Form element:', form); console.log("Form element:", form);
console.log('Submit button:', submitButton); console.log("Submit button:", submitButton);
if (form && submitButton) { if (form && submitButton) {
// Remove any existing event listeners // Remove any existing event listeners
form.removeEventListener('submit', handleEnhancedFormSubmission); form.removeEventListener("submit", handleEnhancedFormSubmission);
submitButton.removeEventListener('click', handleEnhancedFormSubmission); submitButton.removeEventListener(
"click",
handleEnhancedFormSubmission
);
// Add form submit event listener // Add form submit event listener
form.addEventListener('submit', function(e) { form.addEventListener("submit", function (e) {
console.log('📝 Enhanced form submit event triggered'); console.log("📝 Enhanced form submit event triggered");
e.preventDefault(); e.preventDefault();
handleEnhancedFormSubmission(); handleEnhancedFormSubmission();
}); });
// Also add click event listener to button as backup // Also add click event listener to button as backup
submitButton.addEventListener('click', function(e) { submitButton.addEventListener("click", function (e) {
console.log('🖱️ Enhanced button click event triggered'); console.log("🖱️ Enhanced button click event triggered");
e.preventDefault(); e.preventDefault();
handleEnhancedFormSubmission(); handleEnhancedFormSubmission();
}); });
console.log('✅ Enhanced form handling initialized successfully'); console.log("✅ Enhanced form handling initialized successfully");
} else { } 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) // Handle form submission with location data (renamed to avoid conflicts)
function handleEnhancedFormSubmission() { function handleEnhancedFormSubmission() {
console.log('🚀 handleEnhancedFormSubmission called'); console.log("🚀 handleEnhancedFormSubmission called");
const employeeId = document.getElementById('employee_id').value.trim(); const employeeId = document.getElementById("employee_id").value.trim();
const submitButton = document.getElementById('submitButton'); const submitButton = document.getElementById("submitButton");
console.log('Employee ID:', employeeId); console.log("Employee ID:", employeeId);
console.log('Submit button:', submitButton); console.log("Submit button:", submitButton);
if (!employeeId) { if (!employeeId) {
console.log('❌ No employee ID provided'); console.log("❌ No employee ID provided");
showStatusMessage('Please enter your Employee ID / Por favor ingrese su ID de empleado', 'error'); showStatusMessage(
"Please enter your Employee ID / Por favor ingrese su ID de empleado",
"error"
);
return; 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 // Save Employee ID to localStorage for next time
try { try {
localStorage.setItem('qr_last_employee_id', employeeId); localStorage.setItem("qr_last_employee_id", employeeId);
console.log(`💾 Saved employee ID for next time: ${employeeId}`); console.log(`💾 Saved employee ID for next time: ${employeeId}`);
} catch (error) { } catch (error) {
console.log(`❌ Error saving employee ID: ${error.message}`); console.log(`❌ Error saving employee ID: ${error.message}`);
@@ -1099,80 +1140,92 @@
`; `;
} }
showStatusMessage('Processing check-in... / Procesando registro...', 'processing'); showStatusMessage(
"Processing check-in... / Procesando registro...",
"processing"
);
// Get current URL to determine QR URL // 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]; const qrUrl = pathParts[pathParts.length - 1];
console.log('QR URL:', qrUrl); console.log("QR URL:", qrUrl);
console.log('Current enhanced location data:', currentUserLocation); console.log("Current enhanced location data:", currentUserLocation);
// Prepare form data with location information // Prepare form data with location information
const formData = new FormData(); const formData = new FormData();
formData.append('employee_id', employeeId); formData.append("employee_id", employeeId);
// Add location data to form submission // Add location data to form submission
if (currentUserLocation.latitude !== null) { if (currentUserLocation.latitude !== null) {
formData.append('latitude', currentUserLocation.latitude.toString()); formData.append("latitude", currentUserLocation.latitude.toString());
} }
if (currentUserLocation.longitude !== null) { if (currentUserLocation.longitude !== null) {
formData.append('longitude', currentUserLocation.longitude.toString()); formData.append(
"longitude",
currentUserLocation.longitude.toString()
);
} }
if (currentUserLocation.accuracy !== null) { if (currentUserLocation.accuracy !== null) {
formData.append('accuracy', currentUserLocation.accuracy.toString()); formData.append("accuracy", currentUserLocation.accuracy.toString());
} }
if (currentUserLocation.altitude !== null) { if (currentUserLocation.altitude !== null) {
formData.append('altitude', currentUserLocation.altitude.toString()); formData.append("altitude", currentUserLocation.altitude.toString());
} }
if (currentUserLocation.address) { 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, employee_id: employeeId,
latitude: currentUserLocation.latitude, latitude: currentUserLocation.latitude,
longitude: currentUserLocation.longitude, longitude: currentUserLocation.longitude,
accuracy: currentUserLocation.accuracy, accuracy: currentUserLocation.accuracy,
altitude: currentUserLocation.altitude, altitude: currentUserLocation.altitude,
address: currentUserLocation.address, address: currentUserLocation.address,
location_source: currentUserLocation.source location_source: currentUserLocation.source,
}); });
// Submit to backend // Submit to backend
fetch(`/qr/${qrUrl}/checkin`, { fetch(`/qr/${qrUrl}/checkin`, {
method: 'POST', method: "POST",
body: formData body: formData,
}) })
.then(response => { .then((response) => {
console.log('📨 Received enhanced response:', response); console.log("📨 Received enhanced response:", response);
return response.json(); return response.json();
}) })
.then(data => { .then((data) => {
console.log('📨 Enhanced response data:', data); console.log("📨 Enhanced response data:", data);
if (data.success) { if (data.success) {
showStatusMessage('Submission successful! / Envío exitoso', 'success'); showStatusMessage(
"Submission successful! / Envío exitoso",
"success"
);
showEnhancedSuccessCard(data); showEnhancedSuccessCard(data);
} else { } else {
showStatusMessage(data.message || 'Submission failed / Envío fallido', 'error'); showStatusMessage(
data.message || "Submission failed / Envío fallido",
"error"
);
resetEnhancedSubmitButton(); resetEnhancedSubmitButton();
} }
}) })
.catch(error => { .catch((error) => {
console.error('❌ Enhanced fetch error:', error); console.error("❌ Enhanced fetch error:", error);
showStatusMessage('Network error / Error de red', 'error'); showStatusMessage("Network error / Error de red", "error");
resetEnhancedSubmitButton(); resetEnhancedSubmitButton();
}); });
} }
// Reset submit button (renamed to avoid conflicts) // Reset submit button (renamed to avoid conflicts)
function resetEnhancedSubmitButton() { function resetEnhancedSubmitButton() {
const submitButton = document.getElementById('submitButton'); const submitButton = document.getElementById("submitButton");
submitButton.disabled = false; submitButton.disabled = false;
// Get the current location event from the page // 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) { if (isCheckOut) {
submitButton.innerHTML = ` submitButton.innerHTML = `
@@ -1193,50 +1246,55 @@
// Enhanced status message display with color coding // Enhanced status message display with color coding
function showStatusMessage(message, type) { function showStatusMessage(message, type) {
const statusMessage = document.getElementById('statusMessage'); const statusMessage = document.getElementById("statusMessage");
const statusSpan = statusMessage.querySelector('span'); const statusSpan = statusMessage.querySelector("span");
statusSpan.innerHTML = message; statusSpan.innerHTML = message;
statusMessage.className = `status-message ${type} show`; statusMessage.className = `status-message ${type} show`;
setTimeout(() => { setTimeout(() => {
statusMessage.classList.remove('show'); statusMessage.classList.remove("show");
}, 5000); }, 5000);
} }
// Enhanced success display with bilingual details (renamed to avoid conflicts) // Enhanced success display with bilingual details (renamed to avoid conflicts)
function showEnhancedSuccessCard(data) { function showEnhancedSuccessCard(data) {
const successCard = document.getElementById('successCard'); const successCard = document.getElementById("successCard");
const checkinCard = document.querySelector('.checkin-card'); const checkinCard = document.querySelector(".checkin-card");
const successDetails = document.getElementById('successDetails'); const successDetails = document.getElementById("successDetails");
// Hide check-in form // 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) // Get employee ID from form input (since data.employee_id might be undefined)
const employeeIdInput = document.getElementById('employee_id'); const employeeIdInput = document.getElementById("employee_id");
const employeeId = data.employee_id || (employeeIdInput ? employeeIdInput.value.trim() : 'N/A'); const employeeId =
data.employee_id ||
(employeeIdInput ? employeeIdInput.value.trim() : "N/A");
// Use QR code location instead of GPS address for main location display // Use QR code location instead of GPS address for main location display
const qrLocationElement = document.querySelector('.location-info'); const qrLocationElement = document.querySelector(".location-info");
let qrLocationName = 'Unknown Location'; let qrLocationName = "Unknown Location";
if (qrLocationElement) { if (qrLocationElement) {
// Extract text content, removing the icon // Extract text content, removing the icon
const locationText = qrLocationElement.textContent || qrLocationElement.innerText; const locationText =
qrLocationElement.textContent || qrLocationElement.innerText;
qrLocationName = locationText.trim(); qrLocationName = locationText.trim();
} }
// Get location event (Check In or Check Out) // Get location event (Check In or Check Out)
const isCheckOut = document.body.classList.contains('check-out'); const isCheckOut = document.body.classList.contains("check-out");
const locationEvent = isCheckOut ? 'Check Out' : 'Check In'; const locationEvent = isCheckOut ? "Check Out" : "Check In";
const locationEventSpanish = isCheckOut ? 'Salida' : 'Entrada'; const locationEventSpanish = isCheckOut ? "Salida" : "Entrada";
// Alternative: try to get from page title or header // Alternative: try to get from page title or header
if (qrLocationName === 'Unknown Location') { if (qrLocationName === "Unknown Location") {
const headerElement = document.querySelector('.destination-header h1'); const headerElement = document.querySelector(
".destination-header h1"
);
if (headerElement) { if (headerElement) {
// Extract just the location event part (Check In/Check Out) // 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 @@
<span class="language-separator">/</span> <span class="language-separator">/</span>
<span class="spanish-text">Hora</span> <span class="spanish-text">Hora</span>
</span> </span>
<span class="detail-value">${data.timestamp || new Date().toLocaleString()}</span> <span class="detail-value">${
data.timestamp || new Date().toLocaleString()
}</span>
</div> </div>
<div class="detail-row"> <div class="detail-row">
<span class="detail-label"> <span class="detail-label">
@@ -1280,13 +1340,13 @@
`; `;
// Show success card // Show success card
successCard.classList.add('show'); successCard.classList.add("show");
console.log('✅ Enhanced success card displayed with:', { console.log("✅ Enhanced success card displayed with:", {
employeeId: employeeId, employeeId: employeeId,
locationEvent: locationEvent, locationEvent: locationEvent,
qrLocation: qrLocationName, qrLocation: qrLocationName,
timestamp: data.timestamp || new Date().toLocaleString() timestamp: data.timestamp || new Date().toLocaleString(),
}); });
} }
</script> </script>