Photo ID upload: add QR code for phone + scanner device support
Three upload methods: - Upload File: standard file picker - Camera / Scanner: uses capture attribute for camera on mobile or TWAIN/WIA scanner devices on desktop - QR Code: generates QR with current page URL so user can scan with phone and take a photo of their ID on mobile QR generated via api.qrserver.com (no library dependency). Remove button restores all upload options. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b8a52303b3
commit
e8769e4d5d
1 changed files with 84 additions and 10 deletions
|
|
@ -214,10 +214,34 @@
|
|||
<img id="dot-id-img" style="max-width:200px;max-height:150px;border-radius:6px;border:1px solid #d1d5db" />
|
||||
<button type="button" id="dot-id-remove" style="background:#fee2e2;color:#991b1b;border:none;padding:4px 12px;border-radius:4px;font-size:12px;cursor:pointer">Remove</button>
|
||||
</div>
|
||||
<button type="button" id="dot-id-btn" style="display:flex;flex-direction:column;align-items:center;gap:6px;margin:0 auto;padding:12px 24px;background:none;border:none;cursor:pointer;color:#374151;font-size:13px">
|
||||
<svg style="width:24px;height:24px;color:#64748b" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M6.827 6.175A2.31 2.31 0 015.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 00-1.134-.175 2.31 2.31 0 01-1.64-1.055l-.822-1.316a2.192 2.192 0 00-1.736-1.039 48.774 48.774 0 00-5.232 0 2.192 2.192 0 00-1.736 1.039l-.821 1.316z"/><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 12.75a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zM18.75 10.5h.008v.008h-.008V10.5z"/></svg>
|
||||
<span>Take Photo or Upload ID</span>
|
||||
</button>
|
||||
<div id="dot-id-upload-options">
|
||||
<div style="display:flex;flex-wrap:wrap;gap:8px;justify-content:center">
|
||||
<button type="button" id="dot-id-btn" style="display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border:1px solid #d1d5db;border-radius:8px;cursor:pointer;color:#374151;font-size:13px;font-weight:500">
|
||||
<svg style="width:20px;height:20px;color:#64748b" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5"/></svg>
|
||||
Upload File
|
||||
</button>
|
||||
<button type="button" id="dot-id-scan-btn" style="display:flex;align-items:center;gap:8px;padding:10px 20px;background:#fff;border:1px solid #d1d5db;border-radius:8px;cursor:pointer;color:#374151;font-size:13px;font-weight:500">
|
||||
<svg style="width:20px;height:20px;color:#64748b" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M6.827 6.175A2.31 2.31 0 015.186 7.23c-.38.054-.757.112-1.134.175C2.999 7.58 2.25 8.507 2.25 9.574V18a2.25 2.25 0 002.25 2.25h15A2.25 2.25 0 0021.75 18V9.574c0-1.067-.75-1.994-1.802-2.169a47.865 47.865 0 00-1.134-.175 2.31 2.31 0 01-1.64-1.055l-.822-1.316a2.192 2.192 0 00-1.736-1.039 48.774 48.774 0 00-5.232 0 2.192 2.192 0 00-1.736 1.039l-.821 1.316z"/><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 12.75a4.5 4.5 0 11-9 0 4.5 4.5 0 019 0zM18.75 10.5h.008v.008h-.008V10.5z"/></svg>
|
||||
Camera / Scanner
|
||||
</button>
|
||||
</div>
|
||||
<input type="file" id="dot-photo-id-scan" accept="image/*" capture="environment" style="display:none" />
|
||||
<div style="text-align:center;margin:12px 0 0">
|
||||
<div style="display:flex;align-items:center;gap:12px;justify-content:center;margin-bottom:8px">
|
||||
<div style="flex:1;height:1px;background:#d1d5db"></div>
|
||||
<span style="font-size:11px;color:#94a3b8;white-space:nowrap">or use your phone</span>
|
||||
<div style="flex:1;height:1px;background:#d1d5db"></div>
|
||||
</div>
|
||||
<button type="button" id="dot-id-qr-btn" style="display:inline-flex;align-items:center;gap:8px;padding:8px 16px;background:#f8fafc;border:1px solid #d1d5db;border-radius:6px;cursor:pointer;font-size:12px;color:#374151">
|
||||
<svg style="width:16px;height:16px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M3.75 4.875c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5A1.125 1.125 0 013.75 9.375v-4.5zM3.75 14.625c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5a1.125 1.125 0 01-1.125-1.125v-4.5zM13.5 4.875c0-.621.504-1.125 1.125-1.125h4.5c.621 0 1.125.504 1.125 1.125v4.5c0 .621-.504 1.125-1.125 1.125h-4.5A1.125 1.125 0 0113.5 9.375v-4.5z"/><path stroke-linecap="round" stroke-linejoin="round" d="M6.75 6.75h.75v.75h-.75v-.75zM6.75 16.5h.75v.75h-.75v-.75zM16.5 6.75h.75v.75h-.75v-.75zM13.5 13.5h.75v.75h-.75v-.75zM13.5 19.5h.75v.75h-.75v-.75zM19.5 13.5h.75v.75h-.75v-.75zM19.5 19.5h.75v.75h-.75v-.75zM16.5 16.5h.75v.75h-.75v-.75z"/></svg>
|
||||
Scan QR code to upload from phone
|
||||
</button>
|
||||
</div>
|
||||
<div id="dot-id-qr-container" hidden style="text-align:center;margin:16px 0 0;padding:16px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px">
|
||||
<canvas id="dot-id-qr-canvas" style="margin:0 auto;display:block"></canvas>
|
||||
<p style="font-size:12px;color:#64748b;margin:10px 0 0">Scan this QR code with your phone's camera to open this form on your mobile device and take a photo of your ID.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pw-security-notice" style="margin-top:8px">
|
||||
<svg style="width:14px;height:14px;flex-shrink:0;margin-top:2px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z"/></svg>
|
||||
|
|
@ -402,24 +426,74 @@
|
|||
const idPreview = document.getElementById("dot-id-preview");
|
||||
const idImg = document.getElementById("dot-id-img");
|
||||
const idRemove = document.getElementById("dot-id-remove");
|
||||
idBtn?.addEventListener("click", () => idInput?.click());
|
||||
idInput?.addEventListener("change", () => {
|
||||
const file = idInput.files?.[0];
|
||||
const idQrBtn = document.getElementById("dot-id-qr-btn");
|
||||
const idQrContainer = document.getElementById("dot-id-qr-container");
|
||||
const idUploadOpts = document.getElementById("dot-id-upload-options");
|
||||
|
||||
// Upload button — opens file picker
|
||||
idBtn?.addEventListener("click", function() { if (idInput) idInput.click(); });
|
||||
|
||||
// Scanner/camera button — uses capture attribute to trigger camera or scanner
|
||||
var idScanBtn = document.getElementById("dot-id-scan-btn");
|
||||
var idScanInput = document.getElementById("dot-photo-id-scan");
|
||||
idScanBtn?.addEventListener("click", function() { if (idScanInput) idScanInput.click(); });
|
||||
idScanInput?.addEventListener("change", function() {
|
||||
var file = idScanInput.files?.[0];
|
||||
if (!file) return;
|
||||
(window).__dotPhotoId = file;
|
||||
// Copy to main input handler
|
||||
window.__dotPhotoId = file;
|
||||
if (file.type.startsWith("image/") && idImg) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) { idImg.src = e.target?.result; };
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
if (idPreview) idPreview.hidden = false;
|
||||
if (idUploadOpts) idUploadOpts.style.display = "none";
|
||||
});
|
||||
|
||||
// QR code button — show QR with current page URL for phone upload
|
||||
idQrBtn?.addEventListener("click", function() {
|
||||
if (!idQrContainer) return;
|
||||
var showing = !idQrContainer.hidden;
|
||||
idQrContainer.hidden = showing;
|
||||
if (!showing) {
|
||||
// Generate QR code using canvas
|
||||
var canvas = document.getElementById("dot-id-qr-canvas");
|
||||
if (canvas && !canvas.dataset.rendered) {
|
||||
var url = window.location.href;
|
||||
// Use a simple QR code API (Google Charts - no library needed)
|
||||
var img = new Image();
|
||||
img.crossOrigin = "anonymous";
|
||||
img.onload = function() {
|
||||
canvas.width = 200;
|
||||
canvas.height = 200;
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0, 200, 200);
|
||||
canvas.dataset.rendered = "1";
|
||||
};
|
||||
img.src = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" + encodeURIComponent(url);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
idInput?.addEventListener("change", function() {
|
||||
var file = idInput.files?.[0];
|
||||
if (!file) return;
|
||||
window.__dotPhotoId = file;
|
||||
if (file.type.startsWith("image/")) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => { idImg.src = e.target?.result; };
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
if (idPreview) idPreview.hidden = false;
|
||||
if (idBtn) idBtn.style.display = "none";
|
||||
if (idUploadOpts) idUploadOpts.style.display = "none";
|
||||
});
|
||||
idRemove?.addEventListener("click", () => {
|
||||
(window).__dotPhotoId = null;
|
||||
if (idInput) idInput.value = "";
|
||||
if (idScanInput) idScanInput.value = "";
|
||||
if (idPreview) idPreview.hidden = true;
|
||||
if (idBtn) idBtn.style.display = "flex";
|
||||
if (idUploadOpts) idUploadOpts.style.display = "";
|
||||
});
|
||||
|
||||
} // end guard
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue