diff --git a/static/index.html b/static/index.html
index 574a532..2e3b2fb 100644
--- a/static/index.html
+++ b/static/index.html
@@ -2028,8 +2028,13 @@
opts.headers['Authorization'] = 'Bearer ' + AppState.authToken;
}
}
+ // 15s timeout to prevent hanging lookups on slow/mobile networks
+ const controller = new AbortController();
+ const timeoutId = setTimeout(() => controller.abort(), 15000);
+ opts.signal = controller.signal;
try {
const res = await fetch(url, opts);
+ clearTimeout(timeoutId);
if (res.status === 204) return null;
const text = await res.text();
let data = null;
@@ -2041,9 +2046,13 @@
if (returnMeta) return { data, headers: res.headers };
return data;
} catch (e) {
+ clearTimeout(timeoutId);
if (e.name === 'TypeError' && e.message === 'Failed to fetch') {
throw new Error('Network error — check your connection');
}
+ if (e.name === 'AbortError') {
+ throw new Error('Request timed out — check your connection');
+ }
throw e;
}
}
@@ -3060,6 +3069,10 @@
barcodeDebounce = machineId;
currentScannedMachineId = machineId;
+ // Stop the camera scanner before the API call — on mobile browsers
+ // an active camera stream can throttle concurrent fetch requests.
+ stopScanning();
+
setScanStatus(`Scanned: ${machineId} — looking up...`, 'working');
document.getElementById('scanResult').style.display = 'none';
document.getElementById('checkinCard').style.display = 'none';