Lectura qr

This commit is contained in:
jalvarado
2025-04-02 11:27:21 -06:00
parent d2759c0afe
commit 236522a637
13 changed files with 356 additions and 59 deletions
+98
View File
@@ -0,0 +1,98 @@
'use client';
import React, { useEffect, useRef } from 'react';
import { Modal as BootstrapModal } from 'bootstrap';
interface ModalProps {
children?: React.ReactNode;
isVisible: boolean;
closeButton?: boolean;
size: 'sm' | 'md' | 'lg' | 'xl';
className?: {
dialog?: string;
content?: string;
body?: string;
};
onClose: () => void;
}
export default function Modal({
children,
isVisible,
size,
className,
closeButton = true,
onClose,
}: ModalProps) {
const ref = useRef<HTMLDivElement | null>(null);
const modalInstance = useRef<BootstrapModal | null>(null);
const modalSizeClass = size ? `modal-${size}` : '';
useEffect(() => {
const node = ref.current;
if (node) {
modalInstance.current = new BootstrapModal(node);
const handleClose = () => {
const elements = document.querySelectorAll<HTMLDivElement>(
'.modal-backdrop.fade.show'
);
if (elements.length > 0) {
elements.forEach((element) => {
element.remove();
});
document.body.removeAttribute('style');
}
onClose();
};
node.addEventListener('hidden.bs.modal', handleClose);
return () => {
if (node) {
node.removeEventListener('hidden.bs.modal', handleClose);
}
};
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (isVisible) {
modalInstance.current?.show();
} else {
modalInstance.current?.hide();
}
}, [isVisible]);
return (
<div
ref={ref}
className="modal fade"
tabIndex={-1}
aria-labelledby="modal"
aria-hidden="true"
>
<div
className={`modal-dialog modal-dialog-centered ${className?.dialog ?? ''} ${modalSizeClass}`}
>
<div className={`modal-content ${className?.content}`}>
{closeButton && (
<div className="position-relative">
<button
type="button"
className="btn-close position-absolute top-0 end-0 m-2"
data-bs-dismiss="modal"
aria-label="Close"
style={{
zIndex: 999,
}}
></button>
</div>
)}
<div className={`modal-body ${className?.body}`}>{children}</div>
</div>
</div>
</div>
);
}
+41
View File
@@ -0,0 +1,41 @@
// components/QrScanner.tsx
'use client';
import { useEffect } from 'react';
import { Html5Qrcode } from 'html5-qrcode';
interface Props {
onScan: (text: string) => void;
}
export default function QrScanner({ onScan }: Props) {
useEffect(() => {
const scanner = new Html5Qrcode('qr-reader');
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));
return () => {
scanner.stop().then(() => scanner.clear());
};
}, [onScan]);
return (
<div
id='qr-reader'
style={{ width: '100%', maxWidth: 400, margin: '0 auto' }}
/>
);
}