Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 55 additions & 11 deletions src/pages/AttendancePage/AttendancePage.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect, useContext } from "react";
import React, { useState, useEffect, useContext, useRef } from "react";
import { EventCard } from "../../components";
import { Button } from "../../components/Core";
import AuthContext from "../../context/AuthContext";
Expand All @@ -24,6 +24,12 @@ const AttendancePage = () => {
const [isSuccess, setIsSuccess] = useState(false);
const authCtx = useContext(AuthContext);

// Refs to prevent duplicate execution & stale closures
const isProcessingRef = useRef(false);
const alertShownRef = useRef(false);
const scannerRef = useRef(null);
const selectedEventIdRef = useRef(null);

useEffect(() => {
const fetchEvents = async () => {
try {
Expand Down Expand Up @@ -79,32 +85,48 @@ const AttendancePage = () => {
);

qrScanner.render(onScanSuccess, onScanFailure);
scannerRef.current = qrScanner;
setScanner(qrScanner);
} catch (error) {
console.error("Error initializing scanner:", error);
if (!hasShownAlert) {
if (!alertShownRef.current) {
Alert({
type: "error",
message: "Failed to initialize QR scanner",
position: "top-right",
});
alertShownRef.current = true;
setHasShownAlert(true);
}
setShowScanner(false);
}
};

const onScanSuccess = async (decodedText) => {
if (isProcessingRef.current) {
return;
}
isProcessingRef.current = true;
setIsScanning(true);

// Pause scanner immediately to stop further video frames from triggering onScanSuccess
if (scannerRef.current) {
try {
scannerRef.current.pause(true);
} catch (err) {
console.warn("Could not pause scanner:", err);
}
}

console.log("QR Code scanned successfully:", decodedText);
console.log("Selected Event ID:", selectedEventId);
console.log("Selected Event ID:", selectedEventIdRef.current);

try {
// jwt token from qr code
const response = await api.post(
`/api/form/markAttendance`,
{
formId: selectedEventId,
formId: selectedEventIdRef.current,
token: decodedText,
},
{
Expand All @@ -118,8 +140,12 @@ const AttendancePage = () => {
// store user details
setAttendedUser(response.data.user || response.data);
setIsSuccess(true);
if (scanner) {
scanner.clear();
if (scannerRef.current) {
try {
scannerRef.current.clear();
} catch (err) {
console.error("Error clearing scanner on success:", err);
}
}
setShowSuccessModal(true);
setIsScanning(false);
Expand Down Expand Up @@ -150,14 +176,26 @@ const AttendancePage = () => {
}

// show error alert
if (!hasShownAlert) {
if (!alertShownRef.current) {
Alert({
type: "error",
message: errorMessage,
position: "top-right",
});
alertShownRef.current = true;
setHasShownAlert(true);
}

// Resume scanning on error since the scan session failed
if (scannerRef.current) {
try {
scannerRef.current.resume();
} catch (err) {
console.warn("Could not resume scanner:", err);
}
}
isProcessingRef.current = false;
alertShownRef.current = false;
} finally {
setIsScanning(false);
}
Expand All @@ -168,7 +206,10 @@ const AttendancePage = () => {
};

const handleScanQR = (eventId) => {
selectedEventIdRef.current = eventId;
setSelectedEventId(eventId);
isProcessingRef.current = false;
alertShownRef.current = false;
setShowScanner(true);
setHasShownAlert(false); // reset alert state
setIsSuccess(false); // reset success state
Expand All @@ -177,6 +218,8 @@ const AttendancePage = () => {
const handleCloseSuccessModal = () => {
setShowSuccessModal(false);
setAttendedUser(null);
isProcessingRef.current = false;
alertShownRef.current = false;
// auto open scanner for next scan
setTimeout(() => {
setShowScanner(true);
Expand Down Expand Up @@ -273,9 +316,9 @@ const AttendancePage = () => {
initializeScanner();
}
return () => {
if (scanner) {
if (scannerRef.current) {
try {
scanner.clear();
scannerRef.current.clear();
} catch (error) {
console.error("Error clearing scanner in cleanup:", error);
}
Expand Down Expand Up @@ -313,14 +356,15 @@ const AttendancePage = () => {
<button
className={styles.closeButton}
onClick={() => {
if (scanner) {
if (scannerRef.current) {
try {
scanner.clear();
scannerRef.current.clear();
} catch (error) {
console.error("Error clearing scanner:", error);
}
}
setShowScanner(false);
scannerRef.current = null;
setScanner(null);
}}
>
Expand Down