diff --git a/templates/verification_review.html b/templates/verification_review.html index 1e604c3..2bcc304 100644 --- a/templates/verification_review.html +++ b/templates/verification_review.html @@ -177,7 +177,7 @@
{% if record.verification_photo %} - Verification Photo + Verification Photo {% else %}
@@ -185,6 +185,19 @@
{% endif %}
+ {% if record.verification_photo %} +
+ + + + + +
+ {% endif %}
@@ -554,6 +567,56 @@ margin-bottom: 0.5rem; } + .photo-actions { + display: flex; + gap: 0.5rem; + justify-content: center; + margin-top: 0.75rem; + } + + .btn-photo { + width: 36px; + height: 36px; + border: none; + border-radius: 0.5rem; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s; + text-decoration: none; + } + + .btn-photo.download { + background: #3b82f6; + color: white; + } + + .btn-photo.download:hover { + background: #2563eb; + transform: translateY(-2px); + } + + .btn-photo.email { + background: #8b5cf6; + color: white; + } + + .btn-photo.email:hover { + background: #7c3aed; + transform: translateY(-2px); + } + + .btn-photo.view { + background: #10b981; + color: white; + } + + .btn-photo.view:hover { + background: #059669; + transform: translateY(-2px); + } + .details-section { display: flex; flex-direction: column; @@ -661,11 +724,22 @@ return; } - // Optional: Add note - let note = ''; - if (status === 'rejected') { - note = prompt('Optional: Add a note explaining why this was rejected:'); - if (note === null) return; // User cancelled + // Prompt for reason + const reasonPrompt = status === 'approved' + ? 'Optional: Enter a reason for approval:' + : 'Please enter a reason for rejection:'; + + let note = prompt(reasonPrompt); + + // For rejection, reason is required + if (status === 'rejected' && (!note || note.trim() === '')) { + alert('A reason is required when rejecting a verification.'); + return; + } + + // User cancelled the prompt + if (note === null) { + return; } // Disable buttons @@ -708,5 +782,90 @@ }); }); }); + + // Download verification photo + function downloadPhoto(recordId, employeeId, checkInDate) { + const card = document.querySelector(`[data-record-id="${recordId}"]`); + const photoElement = card.querySelector('.verification-photo'); + + if (!photoElement) { + alert('No photo available to download.'); + return; + } + + const photoSrc = photoElement.src; + const fileName = `verification_photo_${employeeId}_${checkInDate}.jpg`; + + // Handle base64 data URL + if (photoSrc.startsWith('data:')) { + const link = document.createElement('a'); + link.href = photoSrc; + link.download = fileName; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + console.log('[LOG] Photo downloaded:', fileName); + } else { + // Handle regular URL - fetch and download + fetch(photoSrc) + .then(response => response.blob()) + .then(blob => { + const url = window.URL.createObjectURL(blob); + const link = document.createElement('a'); + link.href = url; + link.download = fileName; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + window.URL.revokeObjectURL(url); + console.log('[LOG] Photo downloaded:', fileName); + }) + .catch(error => { + console.error('[ERROR] Failed to download photo:', error); + alert('Failed to download photo. Please try again.'); + }); + } + } + + // Send verification details by email + function sendByEmail(recordId, employeeId, employeeName, checkInDate, checkInTime, locationName, locationEvent, verificationStatus, qrAddress, checkInAddress, distance, deviceInfo) { + // Build the verification record URL + const recordUrl = window.location.origin + `/verification-review/${recordId}`; + + // Build email subject + const subject = encodeURIComponent(`Verification Review - Employee ${employeeId} (${employeeName}) - ${checkInDate}`); + + // Build email body with verification details + let body = `VERIFICATION PHOTO REVIEW DETAILS\n`; + body += `================================\n\n`; + body += `VIEW VERIFICATION RECORD ONLINE:\n`; + body += `${recordUrl}\n\n`; + body += `EMPLOYEE INFORMATION\n`; + body += `--------------------\n`; + body += `Employee ID: ${employeeId}\n`; + body += `Employee Name: ${employeeName}\n`; + body += `Check-in Date: ${checkInDate}\n`; + body += `Check-in Time: ${checkInTime}\n`; + body += `Verification Status: ${verificationStatus.toUpperCase()}\n\n`; + body += `LOCATION INFORMATION\n`; + body += `--------------------\n`; + body += `Location Name: ${locationName}\n`; + body += `Event Type: ${locationEvent}\n`; + body += `Distance from QR: ${distance} miles\n`; + body += `QR Code Address: ${qrAddress}\n`; + body += `Check-in Address: ${checkInAddress}\n`; + body += `Device: ${deviceInfo}\n\n`; + body += `--------------------\n`; + body += `Record ID: ${recordId}\n\n`; + body += `Note: Click the link above to view the verification photo and full details.\n`; + + const encodedBody = encodeURIComponent(body); + + // Open default email client + const mailtoLink = `mailto:?subject=${subject}&body=${encodedBody}`; + window.location.href = mailtoLink; + + console.log('[LOG] Email client opened for verification record:', recordId); + } {% endblock %} \ No newline at end of file diff --git a/templates/verification_review_detail.html b/templates/verification_review_detail.html index 756758b..b6b7b57 100644 --- a/templates/verification_review_detail.html +++ b/templates/verification_review_detail.html @@ -210,6 +210,50 @@ QR Code Management{% endblock %} {% block extra_head %} box-shadow: 0 6px 16px rgba(107, 114, 128, 0.3); } + .btn-download { + background: #3b82f6; + color: white; + } + + .btn-download:hover { + background: #2563eb; + transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(59, 130, 246, 0.3); + } + + .btn-email { + background: #8b5cf6; + color: white; + } + + .btn-email:hover { + background: #7c3aed; + transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(139, 92, 246, 0.3); + } + + .photo-actions { + display: flex; + gap: 10px; + justify-content: center; + margin-top: 15px; + flex-wrap: wrap; + } + + .photo-actions .btn { + padding: 10px 20px; + font-size: 0.9rem; + font-weight: 600; + border-radius: 6px; + border: none; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 8px; + transition: all 0.2s; + text-decoration: none; + } + .alert { padding: 15px 20px; border-radius: 8px; @@ -369,7 +413,18 @@ QR Code Management{% endblock %} {% block extra_head %} src="{{ record.verification_photo }}" alt="Verification Photo for {{ record.employee_id }}" class="verification-photo" + id="verificationPhoto" /> +
+ + +
{% else %}
@@ -408,6 +463,7 @@ QR Code Management{% endblock %} {% block extra_head %} {% endblock %}