From 560120b0ebac9352bc695960e5e00d2bf19cccad Mon Sep 17 00:00:00 2001 From: Dominic H Date: Tue, 20 Aug 2024 14:54:17 +0200 Subject: [PATCH] Address feedback * Improve error handling * Improve torch switch-off handling * Remove unnecessary react fragements * Add visual feedback to torch button interactions --- src/Components/QrScanner/QrScannerPlugin.tsx | 30 +++++++++++++------- src/Components/QrScanner/TorchButton.tsx | 21 +++++++------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/Components/QrScanner/QrScannerPlugin.tsx b/src/Components/QrScanner/QrScannerPlugin.tsx index 8e9c72e..49ddc56 100644 --- a/src/Components/QrScanner/QrScannerPlugin.tsx +++ b/src/Components/QrScanner/QrScannerPlugin.tsx @@ -1,7 +1,8 @@ // file = QrScannerPlugin.jsx -import {MutableRefObject, useEffect, useRef, useState} from 'react'; +import {MutableRefObject, useEffect, useRef, useState, useCallback} from 'react'; import {ArrowUpTrayIcon} from '@heroicons/react/24/solid'; import {Html5Qrcode, Html5QrcodeScannerState, Html5QrcodeSupportedFormats} from 'html5-qrcode'; +import {useLogError} from '../../hooks/useError'; import {checkCameraPermissions} from '../../utils/media'; import {TorchButton} from './TorchButton'; import classes from './QrScanner.module.css'; @@ -53,18 +54,24 @@ export default function QrScannerPlugin({ const aspectRatio = calcAspectRatio(); const html5CustomScanner: MutableRefObject = useRef(null); const [canUseCamera, setCanUseCamera] = useState(true); + const logError = useLogError(); // Turn off the torch (if it is on) when navigating away from the scan page - async function switchOffTorch(html5CustomScanner: MutableRefObject) { - try { - const track = html5CustomScanner?.current?.getRunningTrackCameraCapabilities(); - if (track && track.torchFeature().value()) { - await track.torchFeature().apply(false); + const switchOffTorch = useCallback( + async function switchOffTorch(html5CustomScanner: MutableRefObject) { + try { + const track = html5CustomScanner?.current?.getRunningTrackCameraCapabilities(); + if (track && track.torchFeature().value()) { + await track.torchFeature().apply(false); + } + } catch (error) { + // This raises an error about invalid tracks - we have to catch it! (blame the library) + console.warn('Failed to disable torch:', error); + logError(`Failed to disable torch: ${error}`); } - } catch (error) { - console.warn('Failed to disable torch:', error); - } - } + }, + [logError] + ); useEffect(() => { const showQRCode = async () => { @@ -97,8 +104,8 @@ export default function QrScannerPlugin({ return () => { const stopQrScanner = async () => { + await switchOffTorch(html5CustomScanner); if (html5CustomScanner.current?.isScanning) { - switchOffTorch(html5CustomScanner); await html5CustomScanner.current.stop(); } html5CustomScanner.current?.clear(); @@ -117,6 +124,7 @@ export default function QrScannerPlugin({ qrCodeSuccessCallback, qrCodeErrorCallback, onPermRefused, + switchOffTorch, ]); return ( diff --git a/src/Components/QrScanner/TorchButton.tsx b/src/Components/QrScanner/TorchButton.tsx index 405efe0..e0bd7ca 100644 --- a/src/Components/QrScanner/TorchButton.tsx +++ b/src/Components/QrScanner/TorchButton.tsx @@ -2,6 +2,7 @@ import {MutableRefObject, useState, useEffect} from 'react'; import {BoltIcon, BoltSlashIcon, ExclamationCircleIcon} from '@heroicons/react/24/solid'; import {Html5Qrcode} from 'html5-qrcode'; import PropTypes from 'prop-types'; +import {useLogError} from '../../hooks/useError'; interface TorchButtonProps { html5CustomScanner: MutableRefObject; @@ -11,6 +12,7 @@ interface TorchButtonProps { export function TorchButton({html5CustomScanner, canUseCamera}: TorchButtonProps) { const [torchOn, setTorchOn] = useState(false); const [torchUnavailable, setTorchUnavailable] = useState(false); + const logError = useLogError(); useEffect(() => { const toggleTorch = async () => { @@ -25,11 +27,12 @@ export function TorchButton({html5CustomScanner, canUseCamera}: TorchButtonProps } catch (error) { setTorchUnavailable(true); console.warn('Failed to toggle torch:', error); + logError(`Failed to toggle torch: ${error}`); } }; toggleTorch(); - }, [torchOn, html5CustomScanner]); + }, [torchOn, html5CustomScanner, logError]); if (!canUseCamera) { return; @@ -37,21 +40,19 @@ export function TorchButton({html5CustomScanner, canUseCamera}: TorchButtonProps if (torchUnavailable) { return ( - <> -
- - - Your device's torch is unavailable - -
- +
+ + + Your device's torch is unavailable + +
); } return (
setTorchOn(prev => !prev)} - className="fit-content flex justify-center gap-1 bg-primary py-3 text-center text-white" + className="fit-content flex justify-center gap-1 bg-primary py-3 text-center text-white active:bg-blue-800 dark:bg-blue-600 dark:active:bg-blue-700" > {torchOn ? (