feat(fusion_clock): NFC kiosk on-screen debug overlay + clearer settings label

This commit is contained in:
gsinghpal
2026-05-14 08:03:47 -04:00
parent 878d05685c
commit 98cb42d2e5
3 changed files with 59 additions and 11 deletions

View File

@@ -16,6 +16,29 @@
const debugEnabled = root.dataset.debugEnabled === "1";
const locationConfigured = root.dataset.locationConfigured === "1";
// ──────────────────────────────────────────────────────────────
// Debug overlay (visible only when fusion_clock.nfc_kiosk_debug = True)
// ──────────────────────────────────────────────────────────────
let _debugOverlayEl = null;
function debugLog(msg) {
try { console.log("[nfc-kiosk-debug]", msg); } catch (e) {}
if (!debugEnabled) return;
if (!_debugOverlayEl) {
_debugOverlayEl = document.createElement("div");
_debugOverlayEl.style.cssText = "position:fixed;top:0;left:0;right:0;background:rgba(0,0,0,0.9);color:#0f0;font-family:monospace;font-size:11px;padding:0.5rem;max-height:35vh;overflow-y:auto;z-index:9999;line-height:1.3;border-bottom:1px solid #0f0;";
document.body.appendChild(_debugOverlayEl);
}
const line = document.createElement("div");
const ts = new Date().toLocaleTimeString();
line.textContent = "[" + ts + "] " + msg;
_debugOverlayEl.appendChild(line);
while (_debugOverlayEl.childNodes.length > 40) {
_debugOverlayEl.removeChild(_debugOverlayEl.firstChild);
}
_debugOverlayEl.scrollTop = _debugOverlayEl.scrollHeight;
}
debugLog("page loaded; debugEnabled=" + debugEnabled + " photoRequired=" + photoRequired + " NDEFReader=" + ("NDEFReader" in window));
// ──────────────────────────────────────────────────────────────
// State machine
// ──────────────────────────────────────────────────────────────
@@ -281,49 +304,68 @@
let nfcReady = false;
async function startNfcReader() {
debugLog("startNfcReader: NDEFReader in window = " + ("NDEFReader" in window));
if (!("NDEFReader" in window)) {
throw new Error("Web NFC not supported on this browser/device. Use Chrome on Android.");
}
ndefReader = new NDEFReader();
debugLog("startNfcReader: ndefReader created, calling scan()...");
await ndefReader.scan();
debugLog("startNfcReader: scan() resolved ✓");
ndefReader.addEventListener("reading", onNfcReading);
ndefReader.addEventListener("readingerror", () => {
ndefReader.addEventListener("readingerror", (ev) => {
debugLog("readingerror event fired");
console.warn("[nfc-kiosk] reading error; reader still active");
});
nfcReady = true;
debugLog("startNfcReader: listeners attached, nfcReady=true");
}
function onNfcReading(event) {
// event.serialNumber is the card UID — works for raw MIFARE access cards
const uid = (event.serialNumber || "").toUpperCase();
if (!uid) return;
const rawSerial = event.serialNumber || "";
const uid = rawSerial.toUpperCase();
const recCount = (event.message && event.message.records) ? event.message.records.length : 0;
debugLog("reading event: serialNumber=" + JSON.stringify(rawSerial) + " (len=" + rawSerial.length + ") records=" + recCount + " state=" + currentState);
if (!uid) {
debugLog(" → IGNORED: empty serialNumber");
return;
}
if (currentState === STATE.ENROLL) {
// Enroll Mode handles taps differently (wired up in Task 18)
debugLog(" → routing to _onEnrollTap");
window.__nfcKiosk._onEnrollTap && window.__nfcKiosk._onEnrollTap(uid);
return;
}
if (currentState !== STATE.IDLE) return; // ignore taps mid-result
if (currentState !== STATE.IDLE) {
debugLog(" → IGNORED: not in IDLE (state=" + currentState + ")");
return;
}
debugLog(" → calling handleTap(" + uid + ")");
handleTap(uid);
}
async function handleTap(uid) {
debugLog("handleTap: uid=" + uid);
setState(STATE.PROCESSING);
let photoB64 = "";
try {
photoB64 = await capturePhoto();
debugLog("handleTap: photo captured, size=" + photoB64.length);
} catch (e) {
debugLog("handleTap: photo capture failed: " + e.message);
console.warn("[nfc-kiosk] camera capture failed", e);
// Server enforces photo_required if needed
}
try {
debugLog("handleTap: POST /fusion_clock/kiosk/nfc/tap...");
const result = await postJson("/fusion_clock/kiosk/nfc/tap", { card_uid: uid, photo_b64: photoB64 });
debugLog("handleTap: response = " + JSON.stringify(result).slice(0, 200));
if (result.error === "debounce") {
// silent — back to IDLE
setState(STATE.IDLE);
return;
}
setState(STATE.RESULT, result);
} catch (e) {
debugLog("handleTap: POST failed: " + e.message);
setState(STATE.RESULT, { error: "network", message: "No connection. Please try again." });
}
}
@@ -374,11 +416,15 @@
const setupBtn = document.getElementById("nfc_setup_start");
if (setupBtn) {
setupBtn.addEventListener("click", async () => {
debugLog("setup button clicked");
try {
await startNfcReader();
debugLog("setup: NFC ready, starting camera...");
try {
await startCamera();
debugLog("setup: camera ready ✓");
} catch (camErr) {
debugLog("setup: camera failed: " + camErr.message);
if (photoRequired) throw camErr;
console.warn("[nfc-kiosk] camera unavailable, continuing (photo not required)", camErr);
}