259 lines
11 KiB
HTML
259 lines
11 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="robots" content="noindex">
|
||
<title>Upload Photo ID | Performance West</title>
|
||
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
||
<script>
|
||
window.__PW_API = (function() {
|
||
var h = window.location.hostname;
|
||
if (h === "localhost" || h === "127.0.0.1") return "http://" + h + ":3001";
|
||
if (h === "dev.performancewest.net") return "https://api.dev.performancewest.net";
|
||
return "https://api.performancewest.net";
|
||
})();
|
||
</script>
|
||
<style>
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body { font-family: -apple-system, system-ui, sans-serif; background: #f8fafc; min-height: 100vh; display: flex; flex-direction: column; }
|
||
.header { background: #1a2744; padding: 16px 20px; text-align: center; }
|
||
.header img { height: 36px; }
|
||
.header p { color: #94a3b8; font-size: 12px; margin-top: 4px; }
|
||
.main { flex: 1; padding: 20px; max-width: 480px; margin: 0 auto; width: 100%; }
|
||
h1 { font-size: 20px; color: #1a2744; margin-bottom: 8px; text-align: center; }
|
||
.subtitle { font-size: 14px; color: #64748b; text-align: center; margin-bottom: 20px; }
|
||
.security { display: flex; gap: 8px; align-items: flex-start; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 8px; padding: 10px 14px; margin-bottom: 16px; font-size: 11px; color: #1e40af; }
|
||
.upload-area { border: 3px dashed #d1d5db; border-radius: 12px; padding: 32px 20px; text-align: center; background: #fff; }
|
||
.upload-btn { display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; padding: 18px 24px; background: #f97316; color: #fff; border: none; border-radius: 10px; cursor: pointer; font-size: 17px; font-weight: 600; box-shadow: 0 4px 12px rgba(249,115,22,0.3); }
|
||
.upload-btn:active { transform: scale(0.98); }
|
||
.hint { font-size: 12px; color: #94a3b8; margin-top: 10px; }
|
||
.preview { text-align: center; margin: 16px 0; }
|
||
.preview img { max-width: 100%; max-height: 300px; border-radius: 8px; border: 2px solid #d1d5db; }
|
||
.status { text-align: center; padding: 20px; }
|
||
.status.success { background: #f0fdf4; border: 2px solid #86efac; border-radius: 12px; }
|
||
.status.error { background: #fef2f2; border: 2px solid #fca5a5; border-radius: 12px; }
|
||
.actions { display: flex; gap: 8px; justify-content: center; margin-top: 12px; }
|
||
.btn-green { padding: 12px 28px; background: #059669; color: #fff; border: none; border-radius: 8px; font-size: 15px; font-weight: 600; cursor: pointer; }
|
||
.btn-outline { padding: 12px 28px; background: #fff; color: #374151; border: 1px solid #d1d5db; border-radius: 8px; font-size: 14px; cursor: pointer; }
|
||
.footer { padding: 16px; text-align: center; font-size: 11px; color: #94a3b8; border-top: 1px solid #e2e8f0; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div class="header">
|
||
<img src="/images/logo.png" alt="Performance West">
|
||
<p>Secure ID Upload</p>
|
||
</div>
|
||
|
||
<div class="main">
|
||
<h1>📷 Take a Photo of Your ID</h1>
|
||
<p class="subtitle">Hold your ID flat and take a clear photo of the front. Make sure all text is readable.</p>
|
||
|
||
<div class="security">
|
||
<span>🔒</span>
|
||
<span>Your photo is encrypted and transmitted securely. It is used only to verify your identity for your FMCSA filing and is automatically deleted afterward.</span>
|
||
</div>
|
||
|
||
<div id="upload-section">
|
||
<div class="upload-area">
|
||
<input type="file" id="id-file" accept="image/*" capture="environment" style="display:none">
|
||
<button type="button" id="take-photo-btn" class="upload-btn">
|
||
📷 Take Photo of ID
|
||
</button>
|
||
<p class="hint">Tap the button to open your camera</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="preview-section" style="display:none">
|
||
<div class="preview">
|
||
<img id="preview-img" alt="Your ID">
|
||
</div>
|
||
<div id="quality-info" style="font-size:12px;color:#374151;text-align:center;margin-bottom:12px"></div>
|
||
<div class="actions">
|
||
<button type="button" id="submit-btn" class="btn-green">✓ Submit ID</button>
|
||
<button type="button" id="retake-btn" class="btn-outline">Retake</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="uploading-section" style="display:none">
|
||
<div style="text-align:center;padding:32px">
|
||
<div style="font-size:32px;margin-bottom:12px">⏳</div>
|
||
<p style="font-size:15px;color:#374151;font-weight:500">Uploading securely...</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="success-section" style="display:none">
|
||
<div class="status success">
|
||
<div style="font-size:32px;margin-bottom:8px">✅</div>
|
||
<p style="font-size:16px;font-weight:600;color:#166534">ID Uploaded Successfully</p>
|
||
<p style="font-size:13px;color:#374151;margin-top:8px">You can close this page and return to the form on your computer. Your ID has been attached to your order.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="error-section" style="display:none">
|
||
<div class="status error">
|
||
<div style="font-size:32px;margin-bottom:8px">❌</div>
|
||
<p style="font-size:16px;font-weight:600;color:#991b1b">Upload Failed</p>
|
||
<p id="error-msg" style="font-size:13px;color:#7f1d1d;margin-top:8px"></p>
|
||
<p style="font-size:12px;color:#7f1d1d;margin-top:8px">If the problem continues, you can upload your ID from the intake form on your computer instead.</p>
|
||
<div class="actions">
|
||
<button type="button" id="retry-btn" class="btn-outline">Try Again</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="footer">
|
||
Performance West Inc. · (888) 411-0383 · performancewest.net
|
||
</div>
|
||
|
||
<script>
|
||
var API = window.__PW_API;
|
||
var params = new URLSearchParams(window.location.search);
|
||
var orderNumber = params.get("order") || "";
|
||
var token = params.get("token") || "";
|
||
|
||
var fileInput = document.getElementById("id-file");
|
||
var takeBtn = document.getElementById("take-photo-btn");
|
||
var previewSection = document.getElementById("preview-section");
|
||
var uploadSection = document.getElementById("upload-section");
|
||
var uploadingSection = document.getElementById("uploading-section");
|
||
var successSection = document.getElementById("success-section");
|
||
var errorSection = document.getElementById("error-section");
|
||
var previewImg = document.getElementById("preview-img");
|
||
var qualityInfo = document.getElementById("quality-info");
|
||
var submitBtn = document.getElementById("submit-btn");
|
||
var retakeBtn = document.getElementById("retake-btn");
|
||
var retryBtn = document.getElementById("retry-btn");
|
||
|
||
var selectedFile = null;
|
||
|
||
takeBtn.addEventListener("click", function() { fileInput.click(); });
|
||
|
||
fileInput.addEventListener("change", function() {
|
||
var file = fileInput.files[0];
|
||
if (!file) return;
|
||
selectedFile = file;
|
||
|
||
var reader = new FileReader();
|
||
reader.onload = function(e) {
|
||
previewImg.src = e.target.result;
|
||
previewImg.onload = function() {
|
||
var w = previewImg.naturalWidth;
|
||
var h = previewImg.naturalHeight;
|
||
var sizeMB = (file.size / 1024 / 1024).toFixed(1);
|
||
var ok = w >= 400 && h >= 250 && file.size >= 50000;
|
||
qualityInfo.innerHTML = ok
|
||
? '<span style="color:#059669">✓ ' + w + '×' + h + ' pixels, ' + sizeMB + 'MB — looks good</span>'
|
||
: '<span style="color:#dc2626">⚠ ' + w + '×' + h + ' pixels, ' + sizeMB + 'MB — image may be too small. Try getting closer to the ID.</span>';
|
||
};
|
||
};
|
||
reader.readAsDataURL(file);
|
||
|
||
uploadSection.style.display = "none";
|
||
previewSection.style.display = "block";
|
||
});
|
||
|
||
retakeBtn.addEventListener("click", function() {
|
||
selectedFile = null;
|
||
fileInput.value = "";
|
||
previewSection.style.display = "none";
|
||
uploadSection.style.display = "block";
|
||
});
|
||
|
||
retryBtn.addEventListener("click", function() {
|
||
errorSection.style.display = "none";
|
||
uploadSection.style.display = "block";
|
||
});
|
||
|
||
submitBtn.addEventListener("click", function() {
|
||
if (!selectedFile || !orderNumber) return;
|
||
previewSection.style.display = "none";
|
||
uploadingSection.style.display = "block";
|
||
|
||
var uploadToken = params.get("upload_token") || "";
|
||
if (!uploadToken) {
|
||
document.getElementById("error-msg").textContent = "Missing upload token. Please use the QR code link from the form.";
|
||
uploadingSection.style.display = "none";
|
||
errorSection.style.display = "block";
|
||
return;
|
||
}
|
||
|
||
// Resize image if too large, then send as base64
|
||
function resizeAndUpload(file) {
|
||
var maxWidth = 2000;
|
||
var maxHeight = 1500;
|
||
var maxBytes = 2 * 1024 * 1024; // 2MB target
|
||
|
||
var img = new Image();
|
||
img.onload = function() {
|
||
var w = img.width;
|
||
var h = img.height;
|
||
|
||
// Only resize if image is larger than limits
|
||
if (w > maxWidth || h > maxHeight || file.size > maxBytes) {
|
||
var scale = Math.min(maxWidth / w, maxHeight / h, 1);
|
||
var canvas = document.createElement("canvas");
|
||
canvas.width = Math.round(w * scale);
|
||
canvas.height = Math.round(h * scale);
|
||
var ctx = canvas.getContext("2d");
|
||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||
|
||
// Compress as JPEG
|
||
var quality = file.size > 5 * 1024 * 1024 ? 0.7 : 0.85;
|
||
var dataUrl = canvas.toDataURL("image/jpeg", quality);
|
||
sendUpload(dataUrl);
|
||
} else {
|
||
// Small enough — send as-is
|
||
var reader3 = new FileReader();
|
||
reader3.onload = function(e) { sendUpload(e.target.result); };
|
||
reader3.readAsDataURL(file);
|
||
}
|
||
};
|
||
img.onerror = function() {
|
||
// Not an image (PDF?) — send as-is
|
||
var reader3 = new FileReader();
|
||
reader3.onload = function(e) { sendUpload(e.target.result); };
|
||
reader3.readAsDataURL(file);
|
||
};
|
||
|
||
var reader2 = new FileReader();
|
||
reader2.onload = function(e) { img.src = e.target.result; };
|
||
reader2.readAsDataURL(file);
|
||
}
|
||
|
||
function sendUpload(dataUrl) {
|
||
fetch(API + "/api/v1/id-upload/" + uploadToken, {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({
|
||
image_data: dataUrl,
|
||
filename: selectedFile.name,
|
||
content_type: "image/jpeg",
|
||
}),
|
||
})
|
||
.then(function(r) {
|
||
if (!r.ok) return r.json().then(function(d) { throw new Error(d.error || "Upload failed"); });
|
||
return r.json();
|
||
})
|
||
.then(function() {
|
||
uploadingSection.style.display = "none";
|
||
successSection.style.display = "block";
|
||
})
|
||
.catch(function(err) {
|
||
uploadingSection.style.display = "none";
|
||
errorSection.style.display = "block";
|
||
document.getElementById("error-msg").textContent = err.message;
|
||
});
|
||
}
|
||
resizeAndUpload(selectedFile);
|
||
});
|
||
|
||
// If no order number, show error
|
||
if (!orderNumber) {
|
||
uploadSection.innerHTML = '<div class="status error"><p style="font-size:14px;color:#991b1b">Invalid link — no order number found. Please use the link from your email.</p></div>';
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|