From 30f7f184723c9fbe9f2faac4051b22e8793ad641 Mon Sep 17 00:00:00 2001 From: gsinghpal Date: Thu, 14 May 2026 01:25:12 -0400 Subject: [PATCH] feat(fusion_clock): camera capture on NFC kiosk Replace camera stub with real getUserMedia + canvas capture. Setup button now starts NFC reader and camera together; camera failure is non-fatal when photo is not required. Co-Authored-By: Claude Sonnet 4.6 --- .../static/src/js/fusion_clock_nfc_kiosk.js | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/fusion_clock/static/src/js/fusion_clock_nfc_kiosk.js b/fusion_clock/static/src/js/fusion_clock_nfc_kiosk.js index 54fd3d0a..8a82aad0 100644 --- a/fusion_clock/static/src/js/fusion_clock_nfc_kiosk.js +++ b/fusion_clock/static/src/js/fusion_clock_nfc_kiosk.js @@ -177,10 +177,33 @@ } // ────────────────────────────────────────────────────────────── - // Camera capture (real implementation in Task 17, stub for now) + // Camera // ────────────────────────────────────────────────────────────── + let cameraStream = null; + const videoEl = document.getElementById("nfc_camera_feed"); + const canvasEl = document.getElementById("nfc_camera_canvas"); + + async function startCamera() { + if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { + throw new Error("Camera not supported on this browser/device."); + } + cameraStream = await navigator.mediaDevices.getUserMedia({ + video: { facingMode: "user", width: { ideal: 640 }, height: { ideal: 480 } }, + audio: false, + }); + videoEl.srcObject = cameraStream; + await videoEl.play(); + } + async function capturePhoto() { - return ""; // overridden in Task 17 + if (!videoEl || !canvasEl || !videoEl.videoWidth) return ""; + const w = videoEl.videoWidth; + const h = videoEl.videoHeight; + canvasEl.width = w; + canvasEl.height = h; + const ctx = canvasEl.getContext("2d"); + ctx.drawImage(videoEl, 0, 0, w, h); + return canvasEl.toDataURL("image/jpeg", 0.7); } // ────────────────────────────────────────────────────────────── @@ -191,6 +214,12 @@ setupBtn.addEventListener("click", async () => { try { await startNfcReader(); + try { + await startCamera(); + } catch (camErr) { + if (photoRequired) throw camErr; + console.warn("[nfc-kiosk] camera unavailable, continuing (photo not required)", camErr); + } setState(STATE.IDLE); } catch (e) { stateContainer.innerHTML = `