Fix check-in page issue, display check-in information

This commit is contained in:
2025-09-16 20:58:59 -04:00
parent 7933fcc24f
commit 6603a1cd06
3 changed files with 219 additions and 142 deletions
+11 -4
View File
@@ -3736,8 +3736,9 @@ def qr_checkin(qr_url):
'employee_id': attendance.employee_id, 'employee_id': attendance.employee_id,
'location': attendance.location_name, 'location': attendance.location_name,
'location_event': qr_code.location_event, 'location_event': qr_code.location_event,
'check_in_time': attendance.check_in_time.strftime('%H:%M:%S'), 'event': qr_code.location_event, # Add both for compatibility
'check_in_date': attendance.check_in_date.strftime('%m/%d/%Y'), 'check_in_time': attendance.check_in_time.strftime('%I:%M %p'), # 12-hour format
'check_in_date': attendance.check_in_date.strftime('%B %d, %Y'), # Full date format
'device_info': attendance.device_info, 'device_info': attendance.device_info,
'ip_address': attendance.ip_address, 'ip_address': attendance.ip_address,
'location_accuracy': location_accuracy, 'location_accuracy': location_accuracy,
@@ -3752,13 +3753,19 @@ def qr_checkin(qr_url):
if location_data['latitude'] and location_data['longitude']: if location_data['latitude'] and location_data['longitude']:
response_data['data']['coordinates'] = f"{location_data['latitude']:.10f}, {location_data['longitude']:.10f}" response_data['data']['coordinates'] = f"{location_data['latitude']:.10f}, {location_data['longitude']:.10f}"
# Enhanced logging for successful check-in with all details
print(f"✅ Check-in completed successfully") print(f"✅ Check-in completed successfully")
print(f" Employee: {attendance.employee_id}") print(f" Employee ID: {attendance.employee_id}")
print(f" Time: {attendance.check_in_time}") print(f" Time: {attendance.check_in_time.strftime('%I:%M %p')}")
print(f" Date: {attendance.check_in_date.strftime('%B %d, %Y')}")
print(f" Location: {attendance.location_name}") print(f" Location: {attendance.location_name}")
print(f" Action: {qr_code.location_event}")
print(f" Address: {attendance.address}") print(f" Address: {attendance.address}")
print(f" Today's count: {today_checkin_count}") print(f" Today's count: {today_checkin_count}")
# Log to database for audit trail
logger_handler.logger.info(f"Check-in success - Employee: {attendance.employee_id}, Location: {attendance.location_name}, Time: {attendance.check_in_time}, Action: {qr_code.location_event}")
return jsonify(response_data), 200 return jsonify(response_data), 200
except Exception as e: except Exception as e:
+72 -60
View File
@@ -142,10 +142,11 @@ function initializeForm() {
function disableFormImmediately() { function disableFormImmediately() {
// Find and disable submit button immediately // Find and disable submit button immediately
const submitButton = document.getElementById("submitCheckin") || const submitButton =
document.getElementById("submitCheckin") ||
document.getElementById("submitButton") || document.getElementById("submitButton") ||
document.querySelector('button[type="submit"]') || document.querySelector('button[type="submit"]') ||
document.querySelector('.btn-primary'); document.querySelector(".btn-primary");
const employeeIdInput = document.getElementById("employee_id"); const employeeIdInput = document.getElementById("employee_id");
const form = document.getElementById("checkinForm"); const form = document.getElementById("checkinForm");
@@ -155,11 +156,14 @@ function disableFormImmediately() {
submitButton.style.opacity = "0.5"; submitButton.style.opacity = "0.5";
submitButton.style.cursor = "not-allowed"; submitButton.style.cursor = "not-allowed";
submitButton.style.pointerEvents = "none"; submitButton.style.pointerEvents = "none";
submitButton.setAttribute('data-location-blocked', 'true'); submitButton.setAttribute("data-location-blocked", "true");
// Store original content // Store original content
if (!submitButton.getAttribute('data-original-content')) { if (!submitButton.getAttribute("data-original-content")) {
submitButton.setAttribute('data-original-content', submitButton.innerHTML); submitButton.setAttribute(
"data-original-content",
submitButton.innerHTML
);
} }
// Show loading/checking state // Show loading/checking state
@@ -172,7 +176,7 @@ function disableFormImmediately() {
if (employeeIdInput) { if (employeeIdInput) {
employeeIdInput.disabled = true; employeeIdInput.disabled = true;
employeeIdInput.style.opacity = "0.7"; employeeIdInput.style.opacity = "0.7";
employeeIdInput.setAttribute('data-location-blocked', 'true'); employeeIdInput.setAttribute("data-location-blocked", "true");
employeeIdInput.placeholder = "Checking location services..."; employeeIdInput.placeholder = "Checking location services...";
} }
@@ -257,7 +261,7 @@ function proceedWithCheckin() {
function showLocationServicesBlockedMessage() { function showLocationServicesBlockedMessage() {
const messages = { const messages = {
en: "Check-in blocked: Location Services must be enabled to continue.", en: "Check-in blocked: Location Services must be enabled to continue.",
es: "Registro bloqueado: Los Servicios de Ubicación deben estar habilitados para continuar." es: "Registro bloqueado: Los Servicios de Ubicación deben estar habilitados para continuar.",
}; };
const currentLang = currentLanguage || "en"; const currentLang = currentLanguage || "en";
@@ -349,6 +353,8 @@ function handleCheckinResponse(data) {
// ENHANCED SUCCESS HANDLING WITH MULTIPLE CHECK-IN INFO // ENHANCED SUCCESS HANDLING WITH MULTIPLE CHECK-IN INFO
function handleCheckinSuccess(data) { function handleCheckinSuccess(data) {
console.log("✅ Success data received:", data);
const responseData = data.data || data || {}; const responseData = data.data || data || {};
const checkinCount = responseData.checkin_count_today || 1; const checkinCount = responseData.checkin_count_today || 1;
const checkinSequence = responseData.checkin_sequence || "Check-in"; const checkinSequence = responseData.checkin_sequence || "Check-in";
@@ -379,15 +385,36 @@ function handleCheckinSuccess(data) {
} }
}; };
const employeeId = responseData.employee_id || "Unknown"; // Get employee ID from form input if not in response data
const employeeIdInput = document.getElementById("employee_id");
const employeeId =
responseData.employee_id ||
(employeeIdInput
? employeeIdInput.value.trim().toUpperCase()
: "Unknown");
const location = responseData.location || "Unknown Location"; const location = responseData.location || "Unknown Location";
const event = const event =
responseData.event || responseData.location_event || "Check-in"; responseData.event || responseData.location_event || "Check-in";
const checkInTime =
responseData.check_in_time || new Date().toLocaleTimeString();
const checkInDate =
responseData.check_in_date || new Date().toLocaleDateString();
// Format current date and time if not provided in response
const now = new Date();
const checkInTime =
responseData.check_in_time ||
now.toLocaleTimeString("en-US", {
hour: "2-digit",
minute: "2-digit",
hour12: true,
});
const checkInDate =
responseData.check_in_date ||
now.toLocaleDateString("en-US", {
year: "numeric",
month: "short",
day: "numeric",
});
// Update success card elements
updateElement("successEmployeeId", employeeId); updateElement("successEmployeeId", employeeId);
updateElement("successLocation", location); updateElement("successLocation", location);
updateElement("successEvent", event); updateElement("successEvent", event);
@@ -416,36 +443,11 @@ function handleCheckinSuccess(data) {
`${responseData.location_accuracy} miles` `${responseData.location_accuracy} miles`
); );
} }
}
// NEW: Add option to check in again after success // Log successful check-in with details
//setTimeout(() => { console.log(
// addCheckInAgainOption(); `✅ Check-in successful for Employee ID: ${employeeId}, Location: ${location}, Time: ${checkInTime}, Date: ${checkInDate}, Action: ${event}`
//}, 3000); );
}
// NEW: Add option to check in again
function addCheckInAgainOption() {
const successCard = document.getElementById("successCard");
if (successCard && !document.getElementById("checkInAgainButton")) {
const checkInAgainHtml = `
<div class="check-in-again-section" style="margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid #e0e4e7;">
<p class="check-in-again-text" style="margin-bottom: 1rem; color: #64748b; font-size: 0.9rem;">
<span data-en="Need to check in again? You can do so after 30 minutes."
data-es="¿Necesita registrarse nuevamente? Puede hacerlo después de 30 minutos.">
Need to check in again? You can do so after 30 minutes.
</span>
</p>
<button id="checkInAgainButton" class="btn btn-outline" style="width: 100%;" onclick="resetForNewCheckin()">
<i class="fas fa-redo"></i>
<span data-en="Check In Again" data-es="Registrarse Nuevamente">Check In Again</span>
</button>
</div>
`;
successCard.insertAdjacentHTML("beforeend", checkInAgainHtml);
// Apply current language translations
applyTranslations();
} }
} }
@@ -874,10 +876,11 @@ function checkLocationServicesStatus() {
function blockCheckInProcess(shouldBlock) { function blockCheckInProcess(shouldBlock) {
// Try multiple possible submit button IDs from your codebase // Try multiple possible submit button IDs from your codebase
const submitButton = document.getElementById("submitCheckin") || const submitButton =
document.getElementById("submitCheckin") ||
document.getElementById("submitButton") || document.getElementById("submitButton") ||
document.querySelector('button[type="submit"]') || document.querySelector('button[type="submit"]') ||
document.querySelector('.btn-primary'); document.querySelector(".btn-primary");
const employeeIdInput = document.getElementById("employee_id"); const employeeIdInput = document.getElementById("employee_id");
const form = document.getElementById("checkinForm"); const form = document.getElementById("checkinForm");
@@ -894,11 +897,14 @@ function blockCheckInProcess(shouldBlock) {
submitButton.style.pointerEvents = "none"; submitButton.style.pointerEvents = "none";
// Add data attribute to track blocking state // Add data attribute to track blocking state
submitButton.setAttribute('data-location-blocked', 'true'); submitButton.setAttribute("data-location-blocked", "true");
// Store original button content // Store original button content
if (!submitButton.getAttribute('data-original-content')) { if (!submitButton.getAttribute("data-original-content")) {
submitButton.setAttribute('data-original-content', submitButton.innerHTML); submitButton.setAttribute(
"data-original-content",
submitButton.innerHTML
);
} }
// Update button text to show it's blocked // Update button text to show it's blocked
@@ -912,7 +918,7 @@ function blockCheckInProcess(shouldBlock) {
submitButton.parentNode.replaceChild(newButton, submitButton); submitButton.parentNode.replaceChild(newButton, submitButton);
// Add blocking event listener // Add blocking event listener
newButton.addEventListener('click', function(e) { newButton.addEventListener("click", function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
showLocationServicesBlockedMessage(); showLocationServicesBlockedMessage();
@@ -923,7 +929,7 @@ function blockCheckInProcess(shouldBlock) {
if (employeeIdInput) { if (employeeIdInput) {
employeeIdInput.disabled = true; employeeIdInput.disabled = true;
employeeIdInput.style.opacity = "0.7"; employeeIdInput.style.opacity = "0.7";
employeeIdInput.setAttribute('data-location-blocked', 'true'); employeeIdInput.setAttribute("data-location-blocked", "true");
} }
if (form) { if (form) {
@@ -931,7 +937,7 @@ function blockCheckInProcess(shouldBlock) {
form.style.pointerEvents = "none"; form.style.pointerEvents = "none";
// Override form submission completely // Override form submission completely
form.onsubmit = function(e) { form.onsubmit = function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
showLocationServicesBlockedMessage(); showLocationServicesBlockedMessage();
@@ -952,16 +958,18 @@ function blockCheckInProcess(shouldBlock) {
submitButton.style.pointerEvents = "auto"; submitButton.style.pointerEvents = "auto";
// Remove blocking data attribute // Remove blocking data attribute
submitButton.removeAttribute('data-location-blocked'); submitButton.removeAttribute("data-location-blocked");
// Restore original button content // Restore original button content
const originalContent = submitButton.getAttribute('data-original-content'); const originalContent = submitButton.getAttribute(
"data-original-content"
);
if (originalContent) { if (originalContent) {
submitButton.innerHTML = originalContent; submitButton.innerHTML = originalContent;
} }
// Re-attach proper event listeners // Re-attach proper event listeners
submitButton.onclick = function(e) { submitButton.onclick = function (e) {
e.preventDefault(); e.preventDefault();
handleFormSubmit(e); handleFormSubmit(e);
return false; return false;
@@ -971,7 +979,7 @@ function blockCheckInProcess(shouldBlock) {
if (employeeIdInput) { if (employeeIdInput) {
employeeIdInput.disabled = false; employeeIdInput.disabled = false;
employeeIdInput.style.opacity = "1"; employeeIdInput.style.opacity = "1";
employeeIdInput.removeAttribute('data-location-blocked'); employeeIdInput.removeAttribute("data-location-blocked");
} }
if (form) { if (form) {
@@ -979,7 +987,7 @@ function blockCheckInProcess(shouldBlock) {
form.style.pointerEvents = "auto"; form.style.pointerEvents = "auto";
// Restore proper form submission handler // Restore proper form submission handler
form.onsubmit = function(e) { form.onsubmit = function (e) {
e.preventDefault(); e.preventDefault();
handleFormSubmit(e); handleFormSubmit(e);
return false; return false;
@@ -1022,7 +1030,7 @@ function showLocationServicesWarning(errorType) {
unknown_error: unknown_error:
"⚠️ Error de Servicios de Ubicación<br><strong>El registro está bloqueado.</strong><br>No se puede acceder a los servicios. Verifique la configuración.", "⚠️ Error de Servicios de Ubicación<br><strong>El registro está bloqueado.</strong><br>No se puede acceder a los servicios. Verifique la configuración.",
}, },
}; };
const currentLang = currentLanguage || "en"; const currentLang = currentLanguage || "en";
const message = const message =
@@ -1084,14 +1092,17 @@ function initializeLocationServicesCheck() {
console.log("✅ Initial Location Services check passed"); console.log("✅ Initial Location Services check passed");
}) })
.catch(() => { .catch(() => {
console.log("❌ Initial Location Services check failed - Check-in blocked"); console.log(
"❌ Initial Location Services check failed - Check-in blocked"
);
}); });
}, 1000); }, 1000);
// Override form initialization to ensure our handlers are used // Override form initialization to ensure our handlers are used
setTimeout(() => { setTimeout(() => {
const form = document.getElementById("checkinForm"); const form = document.getElementById("checkinForm");
const submitButton = document.getElementById("submitCheckin") || const submitButton =
document.getElementById("submitCheckin") ||
document.querySelector('button[type="submit"]'); document.querySelector('button[type="submit"]');
if (form) { if (form) {
@@ -1100,16 +1111,17 @@ function initializeLocationServicesCheck() {
form.parentNode.replaceChild(newForm, form); form.parentNode.replaceChild(newForm, form);
// Add our controlled event listener // Add our controlled event listener
newForm.addEventListener('submit', handleFormSubmit); newForm.addEventListener("submit", handleFormSubmit);
} }
if (submitButton) { if (submitButton) {
// Find the new submit button after form cloning // Find the new submit button after form cloning
const newSubmitButton = document.getElementById("submitCheckin") || const newSubmitButton =
document.getElementById("submitCheckin") ||
document.querySelector('button[type="submit"]'); document.querySelector('button[type="submit"]');
if (newSubmitButton) { if (newSubmitButton) {
newSubmitButton.addEventListener('click', function(e) { newSubmitButton.addEventListener("click", function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
handleFormSubmit(e); handleFormSubmit(e);
+66 -8
View File
@@ -829,7 +829,6 @@
</form> </form>
</div> </div>
<!-- Success Card -->
<div class="success-card" id="successCard"> <div class="success-card" id="successCard">
<div class="success-icon"> <div class="success-icon">
<i class="fas fa-check"></i> <i class="fas fa-check"></i>
@@ -841,17 +840,76 @@
</h2> </h2>
<div class="bilingual-container"> <div class="bilingual-container">
<p> <p>
<span class="english-text" <span class="english-text">Your submission has been recorded successfully.</span>
>Your submission has been recorded successfully.</span
>
<span class="language-separator">/</span> <span class="language-separator">/</span>
<span class="spanish-text" <span class="spanish-text">Su registro ha sido guardado exitosamente.</span>
>Su registro ha sido guardado exitosamente.</span
>
</p> </p>
</div> </div>
<!-- Enhanced Success Details with Employee Information -->
<div class="success-details" id="successDetails"> <div class="success-details" id="successDetails">
<!-- Success details will be populated here --> <div class="detail-row">
<span class="detail-label">
<span class="english-text">Employee ID</span>
<span class="language-separator">/</span>
<span class="spanish-text">ID del Empleado</span>
</span>
<span class="detail-value" id="successEmployeeId">-</span>
</div>
<div class="detail-row">
<span class="detail-label">
<span class="english-text">Date</span>
<span class="language-separator">/</span>
<span class="spanish-text">Fecha</span>
</span>
<span class="detail-value" id="successCheckInDate">-</span>
</div>
<div class="detail-row">
<span class="detail-label">
<span class="english-text">Time</span>
<span class="language-separator">/</span>
<span class="spanish-text">Hora</span>
</span>
<span class="detail-value" id="successCheckInTime">-</span>
</div>
<div class="detail-row">
<span class="detail-label">
<span class="english-text">Action</span>
<span class="language-separator">/</span>
<span class="spanish-text">Acción</span>
</span>
<span class="detail-value" id="successEvent">-</span>
</div>
<div class="detail-row">
<span class="detail-label">
<span class="english-text">Location</span>
<span class="language-separator">/</span>
<span class="spanish-text">Ubicación</span>
</span>
<span class="detail-value" id="successLocation">-</span>
</div>
<!-- Optional Additional Details (hidden by default) -->
<div class="detail-row" style="display: none;" id="successAddressRow">
<span class="detail-label">
<span class="english-text">Address</span>
<span class="language-separator">/</span>
<span class="spanish-text">Dirección</span>
</span>
<span class="detail-value" id="successAddress">-</span>
</div>
<div class="detail-row" style="display: none;" id="successAccuracyRow">
<span class="detail-label">
<span class="english-text">Accuracy</span>
<span class="language-separator">/</span>
<span class="spanish-text">Precisión</span>
</span>
<span class="detail-value" id="successLocationAccuracy">-</span>
</div> </div>
</div> </div>
</div> </div>