QR lector

This commit is contained in:
jorgemike
2025-04-02 12:38:05 -06:00
parent 236522a637
commit b55eacf856
3 changed files with 117 additions and 63 deletions
+55 -30
View File
@@ -1,51 +1,76 @@
'use client';
import Header from '@/components/layout/header';
import QrScanner from '@/components/qr-scanner';
import dynamic from 'next/dynamic';
import React, { useState } from 'react';
import Header from "@/components/layout/header";
import React from "react";
import dynamic from "next/dynamic";
import Button from "@/components/button";
const Html5QrcodePlugin = dynamic(() => import('@/components/qr-scanner'), {
ssr: false,
});
const Modal = dynamic(() => import('@/components/modal'), {
ssr: false,
});
export default function Page() {
const [resultado, setResultado] = useState<string | null>(null);
const [mostrarModal, setMostrarModal] = useState(false);
const [text, setText] = React.useState<string>("");
const [showModal, setShowModal] = React.useState<boolean>(false);
const handleScan = (text: string) => {
setResultado(text);
setMostrarModal(true);
const onScanSuccess = (decodedText: string) => {
setText(decodedText);
setShowModal(true); // Muestra el modal al escanear
};
const handleConfirm = () => {
// Aquí haces algo con el QR (guardar, redirigir, etc)
alert('Confirmado: ' + resultado);
setMostrarModal(false);
setResultado(null); // Limpiar para volver a escanear
const onScanError = (errorMessage: string) => {
console.warn("QR Error:", errorMessage);
};
const handleCloseModal = () => {
setShowModal(false);
};
return (
<div className='d-flex flex-column min-vh-100'>
<div className="d-flex flex-column min-vh-100">
<Header small />
<main className='py-3'>
<div className='container text-center'>
<h1 className='mb-4'>Lectura de QRs</h1>
{!resultado && <QrScanner onScan={handleScan} />}
<main className="py-3">
<div className="container text-center">
<h1 className="mb-4">Lectura de QRs</h1>
<Modal
isVisible={mostrarModal}
onClose={() => setMostrarModal(false)}
size='md'
>
<h5 className='mb-3'>Resultado del QR</h5>
<pre className='bg-light p-2 rounded'>{resultado}</pre>
<button className='btn btn-primary mt-3' onClick={handleConfirm}>
Confirmar
</button>
</Modal>
<div className="mb-4">
<Html5QrcodePlugin
fps={10}
qrbox={500}
qrCodeSuccessCallback={onScanSuccess}
qrCodeErrorCallback={onScanError}
/>
</div>
<p className="mt-4">
{text
? `Texto escaneado: ${text}`
: "Escanea un código QR para ver el texto aquí."}
</p>
</div>
</main>
<Modal
isVisible={showModal}
size="md"
onClose={handleCloseModal}
closeButton
className={{
content: "p-3",
body: "text-center",
}}
>
<h5 className="mb-3">Texto escaneado</h5>
<p>{text}</p>
<Button variant="success" onClick={handleCloseModal}>
Confirmar lectura
</Button>
</Modal>
</div>
);
}
+1 -1
View File
@@ -74,7 +74,7 @@ export default function Modal({
aria-hidden="true"
>
<div
className={`modal-dialog modal-dialog-centered ${className?.dialog ?? ''} ${modalSizeClass}`}
className={`modal-dialog modal-dialog-centered ${className?.dialog} ${modalSizeClass}`}
>
<div className={`modal-content ${className?.content}`}>
{closeButton && (
+61 -32
View File
@@ -1,41 +1,70 @@
// components/QrScanner.tsx
'use client';
// file: Html5QrcodePlugin.tsx
"use client";
import { useEffect } from 'react';
import { Html5Qrcode } from 'html5-qrcode';
import { Html5QrcodeScanner, Html5QrcodeCameraScanConfig } from "html5-qrcode";
import { useEffect } from "react";
interface Props {
onScan: (text: string) => void;
const qrcodeRegionId = "html5qr-code-full-region";
interface Html5QrcodePluginProps extends Partial<Html5QrcodeCameraScanConfig> {
verbose?: boolean;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
qrCodeSuccessCallback: (decodedText: string, decodedResult: any) => void;
qrCodeErrorCallback?: (errorMessage: string) => void;
}
export default function QrScanner({ onScan }: Props) {
useEffect(() => {
const scanner = new Html5Qrcode('qr-reader');
const createConfig = (
props: Html5QrcodePluginProps
): Html5QrcodeCameraScanConfig => {
const config: Html5QrcodeCameraScanConfig = { fps: 10 }; // Default fps value set to 10
scanner
.start(
{ facingMode: 'environment' },
{ fps: 10, qrbox: 250 },
(decodedText) => {
onScan(decodedText);
scanner.stop().then(() => scanner.clear());
},
(error) => {
// puedes ignorar errores de escaneo frecuentes
console.error('Error de escaneo:', error);
}
)
.catch((err) => console.error('Error al iniciar el lector QR:', err));
if (props.fps !== undefined) {
config.fps = props.fps;
}
if (props.qrbox !== undefined) {
config.qrbox = props.qrbox;
}
if (props.aspectRatio !== undefined) {
config.aspectRatio = props.aspectRatio;
}
if (props.disableFlip !== undefined) {
config.disableFlip = props.disableFlip;
}
return config;
};
const Html5QrcodePlugin: React.FC<Html5QrcodePluginProps> = (props) => {
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
// Previene ejecución en SSR
if (typeof window === "undefined") return;
const config = createConfig(props);
const verbose = props.verbose === true;
if (!props.qrCodeSuccessCallback) {
throw new Error("qrCodeSuccessCallback is required.");
}
const html5QrcodeScanner = new Html5QrcodeScanner(
qrcodeRegionId,
config,
verbose
);
html5QrcodeScanner.render(
props.qrCodeSuccessCallback,
props.qrCodeErrorCallback
);
return () => {
scanner.stop().then(() => scanner.clear());
html5QrcodeScanner.clear().catch((error) => {
console.error("Failed to clear html5QrcodeScanner: ", error);
});
};
}, [onScan]);
}, []);
return (
<div
id='qr-reader'
style={{ width: '100%', maxWidth: 400, margin: '0 auto' }}
/>
);
}
return <div id={qrcodeRegionId} />;
};
export default Html5QrcodePlugin;