(() => { const qrInput = document.getElementById("qr-input"); const statusCard = document.getElementById("status-card"); const statusCenterCard = document.getElementById("status-center-card"); const statusVisual = document.getElementById("status-visual"); const statusMiniIcon = document.getElementById("status-mini-icon"); const statusHeadline = document.getElementById("status-headline"); const statusMiniHeadline = document.getElementById("status-mini-headline"); const statusText = document.getElementById("status-text"); const statusMiniMessage = document.getElementById("status-mini-message"); const lastUpdatedTime = document.getElementById("last-updated-time"); const historyBody = document.querySelector("#history-table tbody"); const historyEmpty = document.getElementById("history-empty"); const details = { model: document.getElementById("detail-model"), unique: document.getElementById("detail-unique"), exists: document.getElementById("detail-exists"), marked: document.getElementById("detail-marked"), time: document.getElementById("detail-time") }; const antiForgeryToken = document.querySelector('input[name="__RequestVerificationToken"]')?.value; qrInput.addEventListener("keydown", async event => { if (event.key !== "Enter") { return; } event.preventDefault(); const qrValue = qrInput.value.trim(); if (!qrValue) { return; } await submitScan(qrValue); qrInput.value = ""; qrInput.focus(); }); async function submitScan(qrValue) { try { const response = await fetch("/api/verification/scan", { method: "POST", headers: { "Content-Type": "application/json", "RequestVerificationToken": antiForgeryToken ?? "" }, body: JSON.stringify({ qrValue }) }); const payload = await response.json(); if (!response.ok) { const fallbackMessage = "Verification service is unavailable."; setFailedState(payload.message ?? fallbackMessage); triggerFailureAlarm(); resetDetails(); return; } const result = payload.result; renderDetails(result); renderStatus(result); renderHistory(payload.recentScans ?? []); } catch { setFailedState("Unexpected communication error."); triggerFailureAlarm(); resetDetails(); } } function renderStatus(result) { if (result.isSuccessful) { setStatusClasses("status-success"); statusVisual.textContent = "\u2713"; statusMiniIcon.textContent = "\u2713"; statusHeadline.textContent = "VERIFIED"; statusMiniHeadline.textContent = "VERIFIED"; statusText.textContent = result.message; statusMiniMessage.textContent = result.message; lastUpdatedTime.textContent = formatDisplayTime(result.processedAtUtc); return; } setFailedState(result.message); triggerFailureAlarm(); } function setFailedState(message) { setStatusClasses("status-failed"); statusVisual.textContent = "!"; statusMiniIcon.textContent = "!"; statusHeadline.textContent = "FAILED"; statusMiniHeadline.textContent = "FAILED"; statusText.textContent = message; statusMiniMessage.textContent = message; lastUpdatedTime.textContent = "-"; } function setStatusClasses(statusClass) { statusCard.className = `panel panel-status ${statusClass}`; statusCenterCard.className = `panel panel-center-status ${statusClass}`; } function renderDetails(result) { details.model.textContent = result.modelNumber || "-"; details.unique.textContent = result.uniqueNumber || "-"; details.exists.textContent = result.existsInSystem ? "YES" : "NO"; details.marked.textContent = result.shipmentMarked ? "TRUE" : "FALSE"; details.time.textContent = formatDisplayTime(result.processedAtUtc); } function resetDetails() { details.model.textContent = "-"; details.unique.textContent = "-"; details.exists.textContent = "-"; details.marked.textContent = "-"; details.time.textContent = "-"; } function renderHistory(records) { historyBody.innerHTML = ""; if (records.length === 0) { historyEmpty.classList.remove("is-hidden"); return; } historyEmpty.classList.add("is-hidden"); records.forEach((record, index) => { const row = document.createElement("tr"); row.innerHTML = ` ${index + 1} ${sanitize(record.modelNumber)} ${sanitize(record.uniqueNumber)} ${record.shipmentMarked ? "TRUE" : "FALSE"} ${formatDisplayTime(record.processedAtUtc)} System`; historyBody.appendChild(row); }); } function sanitize(value) { return (value ?? "").replace(/[&<>\"']/g, char => ({ "&": "&", "<": "<", ">": ">", "\"": """, "'": "'" }[char])); } function formatDisplayTime(utcValue) { if (!utcValue) { return "-"; } const date = new Date(utcValue); if (Number.isNaN(date.getTime())) { return "-"; } return date.toLocaleString("en-US", { day: "2-digit", month: "short", year: "numeric", hour: "numeric", minute: "2-digit", second: "2-digit", hour12: true }); } function triggerFailureAlarm() { const context = new AudioContext(); const oscillator = context.createOscillator(); const gainNode = context.createGain(); oscillator.type = "sawtooth"; oscillator.frequency.setValueAtTime(740, context.currentTime); oscillator.frequency.exponentialRampToValueAtTime(320, context.currentTime + 0.4); oscillator.connect(gainNode); gainNode.connect(context.destination); gainNode.gain.setValueAtTime(0.0001, context.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.5, context.currentTime + 0.05); gainNode.gain.exponentialRampToValueAtTime(0.0001, context.currentTime + 0.45); oscillator.start(context.currentTime); oscillator.stop(context.currentTime + 0.45); oscillator.onended = () => context.close(); } })();