From c4f67230425636b59817d9027b48b022cd4723ec Mon Sep 17 00:00:00 2001 From: BOHA Date: Fri, 24 Apr 2026 11:40:51 +0200 Subject: [PATCH] fix: attendance clock-in button stuck when geolocation fails or hangs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit handlePunch set submitting=true before calling geolocation, but the error callback never reset it. When geolocation was denied or timed out: - Error alert showed - GPS confirm modal opened - Button stayed disabled showing "Zpracovávám..." - User thought it was stuck; no server request appeared to happen Also added a 12s safety timeout fallback because some browsers silently hang on getCurrentPosition without calling either callback. Fix: call setSubmitting(false) in the error callback and clear the safety timeout in both success and error paths. Co-Authored-By: Claude Opus 4.7 --- src/admin/pages/Attendance.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/admin/pages/Attendance.tsx b/src/admin/pages/Attendance.tsx index 25b1319..55f178c 100644 --- a/src/admin/pages/Attendance.tsx +++ b/src/admin/pages/Attendance.tsx @@ -186,7 +186,18 @@ export default function Attendance() { setSubmitting(true); latestActionRef.current = action; + // Safety timeout: if geolocation hangs silently (some browsers ignore + // the timeout option), reset the button so the user isn't stuck. + const safetyTimeout = setTimeout(() => { + if (mountedRef.current) { + setSubmitting(false); + alert.error("Vypršel časový limit pro získání polohy"); + setGpsConfirm({ isOpen: true, action }); + } + }, 12000); + if (!navigator.geolocation) { + clearTimeout(safetyTimeout); alert.warning("GPS není dostupná"); submitPunch(action, {}); return; @@ -194,6 +205,7 @@ export default function Attendance() { navigator.geolocation.getCurrentPosition( (position) => { + clearTimeout(safetyTimeout); if (!mountedRef.current) return; const { latitude, longitude, accuracy } = position.coords; submitPunch(action, { latitude, longitude, accuracy, address: "" }); @@ -228,6 +240,7 @@ export default function Attendance() { .catch(() => {}); }, (geoError) => { + clearTimeout(safetyTimeout); if (!mountedRef.current) return; let errorMsg = "Nepodařilo se získat polohu"; if (geoError.code === geoError.PERMISSION_DENIED) { @@ -236,6 +249,7 @@ export default function Attendance() { errorMsg = "Vypršel časový limit"; } alert.error(errorMsg); + setSubmitting(false); setGpsConfirm({ isOpen: true, action }); }, { enableHighAccuracy: true, timeout: 10000, maximumAge: 60000 },