Files

165 lines
4.0 KiB
JavaScript

"use client";
import { useState, useRef } from "react";
export default function SimpleQRScanner({ onScan }) {
const [error, setError] = useState(null);
const [isCameraActive, setIsCameraActive] = useState(false);
const videoRef = useRef(null);
const startCamera = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: "environment" },
});
if (videoRef.current) {
videoRef.current.srcObject = stream;
setIsCameraActive(true);
}
} catch (err) {
console.error("Error accessing camera:", err);
setError(
"Could not access camera. Please make sure you've given camera permission."
);
}
};
const stopCamera = () => {
if (videoRef.current && videoRef.current.srcObject) {
const tracks = videoRef.current.srcObject.getTracks();
tracks.forEach((track) => track.stop());
videoRef.current.srcObject = null;
setIsCameraActive(false);
}
};
const handleManualInput = () => {
const code = prompt("Enter the QR code value manually (e.g. QR123):");
if (code && onScan) {
onScan(code);
}
};
return (
<div className="simple-scanner">
{error && <div className="scanner-error">{error}</div>}
{!isCameraActive ? (
<div className="scanner-controls">
<button className="scanner-button" onClick={startCamera}>
Open Camera to Scan QR Code
</button>
<button
className="scanner-button secondary"
onClick={handleManualInput}
>
Enter Code Manually
</button>
</div>
) : (
<div className="video-container">
<video
ref={videoRef}
autoPlay
playsInline
onCanPlay={() => videoRef.current.play()}
/>
<div className="scanner-overlay">
<div className="scanner-target"></div>
</div>
<button className="close-camera-button" onClick={stopCamera}>
Close Camera
</button>
</div>
)}
<style jsx>{`
.simple-scanner {
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
}
.scanner-error {
color: red;
margin-bottom: 15px;
text-align: center;
padding: 8px;
background-color: #ffebee;
border-radius: 4px;
width: 100%;
}
.scanner-controls {
display: flex;
flex-direction: column;
gap: 10px;
width: 100%;
}
.scanner-button {
padding: 12px;
background-color: #68543c;
color: white;
border: none;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
}
.scanner-button.secondary {
background-color: #999;
}
.video-container {
position: relative;
width: 300px;
height: 300px;
overflow: hidden;
border-radius: 8px;
border: 2px solid #ddd;
}
video {
width: 100%;
height: 100%;
object-fit: cover;
}
.scanner-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.2);
}
.scanner-target {
width: 200px;
height: 200px;
border: 2px solid #fff;
border-radius: 8px;
box-shadow: 0 0 0 4000px rgba(0, 0, 0, 0.3);
}
.close-camera-button {
position: absolute;
bottom: 10px;
right: 10px;
background-color: rgba(0, 0, 0, 0.5);
color: white;
border: none;
border-radius: 4px;
padding: 5px 10px;
cursor: pointer;
}
`}</style>
</div>
);
}