Skip to content

Commit

Permalink
Implement badge scanner with html5-qrcode
Browse files Browse the repository at this point in the history
- Still some weird `useEffect` issues with scanner opening twice
  • Loading branch information
taesungh committed Jan 26, 2024
1 parent 2151c09 commit db8983e
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 2 deletions.
52 changes: 50 additions & 2 deletions apps/site/src/app/admin/participants/components/CheckInModal.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import { useCallback, useEffect, useMemo, useState } from "react";

import Box from "@cloudscape-design/components/box";
import Button from "@cloudscape-design/components/button";
import Input from "@cloudscape-design/components/input";
import Modal from "@cloudscape-design/components/modal";
import SpaceBetween from "@cloudscape-design/components/space-between";
import TextContent from "@cloudscape-design/components/text-content";

import BadgeScanner from "@/lib/admin/BadgeScanner";
import { Participant } from "@/lib/admin/useParticipants";

export interface ActionModalProps {
Expand All @@ -13,7 +17,31 @@ export interface ActionModalProps {
}

function CheckInModal({ onDismiss, onConfirm, participant }: ActionModalProps) {
const [badgeNumber, setBadgeNumber] = useState(
participant?.badge_number ?? "",
);
const [showScanner, setShowScanner] = useState(true);

const onScanSuccess = useCallback((decodedText: string) => {
setBadgeNumber(decodedText);
setShowScanner(false);
}, []);

useEffect(() => {
console.log("new participant", participant);
setBadgeNumber(participant?.badge_number ?? "");
setShowScanner(participant?.badge_number === null);
}, [participant]);

const badgeScanner = useMemo(
() => <BadgeScanner onSuccess={onScanSuccess} onError={() => null} />,
[onScanSuccess],
);

if (participant === null) {
if (showScanner) {
setShowScanner(false);
}
return <Modal visible={false} />;
}

Expand All @@ -27,7 +55,15 @@ function CheckInModal({ onDismiss, onConfirm, participant }: ActionModalProps) {
<Button variant="link" onClick={onDismiss}>
Cancel
</Button>
<Button variant="primary" onClick={() => onConfirm(participant)}>
<Button
variant="primary"
onClick={() =>
onConfirm({
...participant,
badge_number: badgeNumber,
})
}
>
Check In
</Button>
</SpaceBetween>
Expand All @@ -45,7 +81,19 @@ function CheckInModal({ onDismiss, onConfirm, participant }: ActionModalProps) {
<li>Fill in badge and give to participant.</li>
</ul>
</TextContent>
{/* TODO: badge barcode input */}
{showScanner && badgeScanner}
<SpaceBetween direction="horizontal" size="xs">
<Input
onChange={({ detail }) => setBadgeNumber(detail.value)}
value={badgeNumber}
/>
<Button
iconName="video-on"
variant="icon"
onClick={() => setShowScanner(true)}
iconAlt="Scan with camera"
/>
</SpaceBetween>
</SpaceBetween>
</Modal>
);
Expand Down
56 changes: 56 additions & 0 deletions apps/site/src/lib/admin/BadgeScanner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { useEffect } from "react";

import {
Html5QrcodeScanner,
QrcodeErrorCallback,
QrcodeSuccessCallback,
} from "html5-qrcode";

const scannerRegionId = "badge-scanner-full-region";

interface BadgeScannerProps {
fps?: number;
qrbox?: number;
aspectRatio?: number;
disableFlip?: boolean;
verbose?: boolean;
onSuccess: QrcodeSuccessCallback;
onError: QrcodeErrorCallback;
}

function BadgeScanner(props: BadgeScannerProps) {
useEffect(() => {
const {
fps,
qrbox,
aspectRatio,
disableFlip,
verbose,
onSuccess,
onError,
} = props;

const html5QrcodeScanner = new Html5QrcodeScanner(
scannerRegionId,
{
fps: fps ?? 5,
qrbox: qrbox ?? 300,
aspectRatio: aspectRatio ?? 1,
disableFlip: disableFlip ?? true,
},
verbose ?? false,
);
html5QrcodeScanner.render(onSuccess, onError);

// Clean up when unmount
return () => {
html5QrcodeScanner.clear().catch((error) => {
console.error("Failed to clear html5QrcodeScanner. ", error);
});
};
}, [props]);

return <div id={scannerRegionId} />;
}

export default BadgeScanner;

0 comments on commit db8983e

Please sign in to comment.