Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[INJIVER-613] implementing zing library #155

Merged
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions inji-verify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"@types/react-dom": "^18.2.23",
"@types/react-redux": "^7.1.33",
"@types/redux-thunk": "^2.1.0",
"@zxing/library": "^0.21.3",
"html5-qrcode": "^2.3.8",
"jsqr": "^1.4.0",
"patch-package": "^8.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {raiseAlert} from "../../../../redux/features/alerts/alerts.slice";
import {AlertMessages} from "../../../../utils/config";
import { MdArrowForwardIos } from "react-icons/md";
import { MdArrowBackIos } from "react-icons/md";
import { terminateScanning } from '../../../../utils/qr-utils';

const Tab = ({id, active, label, disabled, onClick}: {id: string, active: boolean, label: string, disabled?: boolean, onClick?: () => void}) => {
const activeTab = "bg-[#FF7F00] border-t-[6px] border-y-[#FF7F00] text-white";
Expand All @@ -31,7 +30,6 @@ function VerificationMethodTabs(props: any) {
const method = useVerificationFlowSelector(state => state.method);

function switchToVerificationMethod(method: VerificationMethod) {
terminateScanning()
dispatch(goHomeScreen({method}))
}

Expand Down
128 changes: 99 additions & 29 deletions inji-verify/src/components/Home/VerificationSection/QrScanner.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import CameraAccessDenied from "./CameraAccessDenied";
import { ScanSessionExpiryTime } from "../../../utils/config";
import { useAppDispatch } from "../../../redux/hooks";
Expand All @@ -8,35 +8,89 @@ import {
} from "../../../redux/features/verification/verification.slice";
import { raiseAlert } from "../../../redux/features/alerts/alerts.slice";
import "./ScanningLine.css";
import { initiateQrScanning, terminateScanning } from "../../../utils/qr-utils";
import { BrowserMultiFormatReader, NotFoundException } from "@zxing/library";

let timer: NodeJS.Timeout;

function QrScanner() {
const dispatch = useAppDispatch();
const [isCameraBlocked, setIsCameraBlocked] = useState(false);

const videoRef = useRef<HTMLVideoElement | null>(null);
const [isScanning, setIsScanning] = useState<boolean>(false);
const codeReader = useRef<BrowserMultiFormatReader | null>(null);
const scannerRef = useRef<HTMLDivElement>(null);

const onSuccess = useCallback(
(decodedText: any) => {
dispatch(
verificationInit({
qrReadResult: { qrData: decodedText, status: "SUCCESS" },
flow: "SCAN",
})
// Start the scanner
const startScanner = async () => {
if (!codeReader.current || isScanning) return;
setIsScanning(true);

try {
const devices = await codeReader.current.getVideoInputDevices();
if (devices.length === 0) {
console.error("No camera devices found.");
setIsCameraBlocked(true);
setIsScanning(false);
return;
}

// Select the first camera device
// Find the back camera (if available)
const backCamera = devices.find(
(device) =>
device.label.toLowerCase().includes("back") ||
device.label.toLowerCase().includes("rear")
);
clearTimeout(timer);
},
[dispatch]
);
const firstDeviceId = backCamera
? backCamera.deviceId
: devices[0].deviceId;

await codeReader.current.decodeFromVideoDevice(
firstDeviceId,
videoRef.current!,
(result, err) => {
if (result) {
dispatch(
verificationInit({
qrReadResult: { qrData: result.getText(), status: "SUCCESS" },
flow: "SCAN",
})
);
clearTimeout(timer);
stopScanner();
}
if (err && !(err instanceof NotFoundException)) {
console.error("Error occurred:", err);
setIsCameraBlocked(true);
clearTimeout(timer);
}
}
);
} catch (e) {
console.error("Failed to start the scanner: " + e);
setIsCameraBlocked(true);
setIsScanning(false);
}
};

const onError = (e: any) => {
console.error("Error occurred:", e);
setIsCameraBlocked(true);
clearTimeout(timer);
// Stop the scanner
const stopScanner = () => {
if (codeReader.current) {
codeReader.current.reset();
setIsScanning(false);
}
};

useEffect(() => {
// Initialize the code reader when the component mounts
codeReader.current = new BrowserMultiFormatReader();
startScanner();
return () => {
// Cleanup: stop the scanner when the component unmounts
stopScanner();
};
}, []);

useEffect(() => {
timer = setTimeout(() => {
dispatch(goHomeScreen({}));
Expand All @@ -48,14 +102,13 @@ function QrScanner() {
severity: "error",
})
);
terminateScanning();
stopScanner();
}, ScanSessionExpiryTime);
initiateQrScanning(onSuccess, onError);
return () => {
console.log("Clearing timeout");
clearTimeout(timer);
};
}, [dispatch, onSuccess]);
}, [dispatch]);

useEffect(() => {
// Disable inbuilt border around the video
Expand All @@ -67,20 +120,37 @@ function QrScanner() {
}
}, [scannerRef]);

window.onpopstate = () => console.log("browser back===>>");

return (
<div ref={scannerRef} className="relative">
<div
ref={scannerRef}
className="fixed inset-0 flex items-center justify-center overflow-hidden lg:relative lg:overflow-visible"
>
{!isCameraBlocked && (
<div className="absolute top-[-15px] left-[-15px] h-[280px] w-[280px] lg:top-[-12px] lg:left-[-12px] lg:h-[340px] lg:w-[340px] flex items-center justify-center">
<div id="scanning-line" className="scanning-line"></div>
<div
id="scanning-line"
className="hidden lg:block scanning-line"
></div>
</div>
)}

<div
className="none relative h-[250px] w-[250px] lg:h-[316px] lg:w-[316px] rounded-lg overflow-hidden flex items-center justify-center"
id="reader"
/>
<div className="relative h-screen w-screen lg:h-[316px] lg:w-[316px] rounded-lg overflow-hidden flex items-center justify-center z-0">
<button
onClick={() => {
stopScanner();
dispatch(goHomeScreen({}));
}}
className="absolute top-4 right-4 lg:hidden bg-gray-800 text-white p-2 rounded-full hover:bg-gray-700 focus:outline-none z-20"
aria-label="Close Scanner"
>
</button>

<video
ref={videoRef}
className="h-full w-full object-cover rounded-lg"
/>
</div>

<CameraAccessDenied
open={isCameraBlocked}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { useAppDispatch } from "../../../redux/hooks";
import { goHomeScreen } from "../../../redux/features/verification/verification.slice";
import { VerificationSteps } from "../../../utils/config";
import { useVerificationFlowSelector } from "../../../redux/features/verification/verification.selector";
import { terminateScanning } from "../../../utils/qr-utils";

const Verification = () => {
const dispatch = useAppDispatch();
Expand All @@ -34,10 +33,7 @@ const Verification = () => {
<StyledButton
id="verification-back-button"
className="w-[100%] lg:w-[350px] max-w-[280px] lg:max-w-none mt-[18px]"
onClick={() => {
terminateScanning();
dispatch(goHomeScreen({}));
}}
onClick={() => dispatch(goHomeScreen({}))}
>
Back
</StyledButton>
Expand Down
32 changes: 0 additions & 32 deletions inji-verify/src/utils/qr-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,35 +41,3 @@ export const decodeQrData = (qrData) => {
};

export const encodeData = (data) => generateQRData(data);

let html5QrCode;

export const initiateQrScanning = (onSuccess, onError) => {
const config = {
fps: 10,
disableFlip: false,
aspectRatio: 1.0,
};
if (!html5QrCode?.getState()) {
html5QrCode = new Html5Qrcode("reader");
const qrCodeSuccessCallback = (decodedText) => {
onSuccess(decodedText);
html5QrCode.stop();
html5QrCode = null;
};

html5QrCode
.start({ facingMode: "environment" }, config, qrCodeSuccessCallback)
.catch((e) => {
onError(e);
html5QrCode = null;
});
}
};

export const terminateScanning = () => {
if (html5QrCode) {
html5QrCode.stop();
html5QrCode = null;
}
};
Loading