Modificaciones en error al escanear codigo qr

This commit is contained in:
santiago
2025-10-01 14:14:36 -06:00
parent 4c300a8e20
commit 509ff4255a
6 changed files with 435 additions and 75 deletions
+220 -9
View File
@@ -11,13 +11,15 @@
"@uiw/react-md-editor": "^4.0.7",
"@yudiel/react-qr-scanner": "^2.2.1",
"axios": "^1.8.4",
"bootstrap": "^5.3.3",
"bootstrap": "^5.3.8",
"bootstrap-icons": "^1.11.3",
"js-cookie": "^3.0.5",
"next": "15.3.3",
"react": "^19.0.0",
"react-bootstrap": "^2.10.10",
"react-dom": "^19.0.0",
"react-hot-toast": "^2.5.2",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"xlsx": "^0.18.5"
},
@@ -891,6 +893,75 @@
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/@react-aria/ssr": {
"version": "3.9.10",
"resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.10.tgz",
"integrity": "sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ==",
"license": "Apache-2.0",
"dependencies": {
"@swc/helpers": "^0.5.0"
},
"engines": {
"node": ">= 12"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1"
}
},
"node_modules/@restart/hooks": {
"version": "0.4.16",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz",
"integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==",
"license": "MIT",
"dependencies": {
"dequal": "^2.0.3"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@restart/ui": {
"version": "1.9.4",
"resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.9.4.tgz",
"integrity": "sha512-N4C7haUc3vn4LTwVUPlkJN8Ach/+yIMvRuTVIhjilNHqegY60SGLrzud6errOMNJwSnmYFnt1J0H/k8FE3A4KA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.26.0",
"@popperjs/core": "^2.11.8",
"@react-aria/ssr": "^3.5.0",
"@restart/hooks": "^0.5.0",
"@types/warning": "^3.0.3",
"dequal": "^2.0.3",
"dom-helpers": "^5.2.0",
"uncontrollable": "^8.0.4",
"warning": "^4.0.3"
},
"peerDependencies": {
"react": ">=16.14.0",
"react-dom": ">=16.14.0"
}
},
"node_modules/@restart/ui/node_modules/@restart/hooks": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.5.1.tgz",
"integrity": "sha512-EMoH04NHS1pbn07iLTjIjgttuqb7qu4+/EyhAx27MHpoENcB2ZdSsLTNxmKD+WEPnZigo62Qc8zjGnNxoSE/5Q==",
"license": "MIT",
"dependencies": {
"dequal": "^2.0.3"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/@restart/ui/node_modules/uncontrollable": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-8.0.4.tgz",
"integrity": "sha512-ulRWYWHvscPFc0QQXvyJjY6LIXU56f0h8pQFvhxiKk5V1fcI8gp9Ht9leVAhrVjzqMw0BgjspBINx9r6oyJUvQ==",
"license": "MIT",
"peerDependencies": {
"react": ">=16.14.0"
}
},
"node_modules/@rtsao/scc": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
@@ -1032,6 +1103,12 @@
"integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==",
"license": "MIT"
},
"node_modules/@types/prop-types": {
"version": "15.7.15",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz",
"integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==",
"license": "MIT"
},
"node_modules/@types/react": {
"version": "19.0.12",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz",
@@ -1051,12 +1128,27 @@
"@types/react": "^19.0.0"
}
},
"node_modules/@types/react-transition-group": {
"version": "4.4.12",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz",
"integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*"
}
},
"node_modules/@types/unist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
"license": "MIT"
},
"node_modules/@types/warning": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz",
"integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==",
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.29.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.0.tgz",
@@ -2002,9 +2094,9 @@
"license": "ISC"
},
"node_modules/bootstrap": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
"integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
"version": "5.3.8",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
"integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==",
"funding": [
{
"type": "github",
@@ -2268,6 +2360,12 @@
"node": ">= 6"
}
},
"node_modules/classnames": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
"license": "MIT"
},
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
@@ -2607,6 +2705,16 @@
"node": ">=0.10.0"
}
},
"node_modules/dom-helpers": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz",
"integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.8.7",
"csstype": "^3.0.2"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -4083,6 +4191,15 @@
"node": ">= 0.4"
}
},
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
@@ -4592,7 +4709,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/js-yaml": {
@@ -4739,7 +4855,6 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
@@ -5791,7 +5906,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -6132,7 +6246,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
@@ -6140,6 +6253,19 @@
"react-is": "^16.13.1"
}
},
"node_modules/prop-types-extra": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
"integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
"license": "MIT",
"dependencies": {
"react-is": "^16.3.2",
"warning": "^4.0.0"
},
"peerDependencies": {
"react": ">=0.14.0"
}
},
"node_modules/property-information": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz",
@@ -6196,6 +6322,37 @@
"node": ">=0.10.0"
}
},
"node_modules/react-bootstrap": {
"version": "2.10.10",
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.10.tgz",
"integrity": "sha512-gMckKUqn8aK/vCnfwoBpBVFUGT9SVQxwsYrp9yDHt0arXMamxALerliKBxr1TPbntirK/HGrUAHYbAeQTa9GHQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.24.7",
"@restart/hooks": "^0.4.9",
"@restart/ui": "^1.9.4",
"@types/prop-types": "^15.7.12",
"@types/react-transition-group": "^4.4.6",
"classnames": "^2.3.2",
"dom-helpers": "^5.2.1",
"invariant": "^2.2.4",
"prop-types": "^15.8.1",
"prop-types-extra": "^1.1.0",
"react-transition-group": "^4.4.5",
"uncontrollable": "^7.2.1",
"warning": "^4.0.3"
},
"peerDependencies": {
"@types/react": ">=16.14.8",
"react": ">=16.14.0",
"react-dom": ">=16.14.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-dom": {
"version": "19.1.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
@@ -6225,11 +6382,25 @@
"react-dom": ">=16"
}
},
"node_modules/react-icons": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
"license": "MIT",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true,
"license": "MIT"
},
"node_modules/react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
"license": "MIT"
},
"node_modules/react-markdown": {
@@ -6259,6 +6430,22 @@
"react": ">=18"
}
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
"integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==",
"license": "BSD-3-Clause",
"dependencies": {
"@babel/runtime": "^7.5.5",
"dom-helpers": "^5.0.1",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": ">=16.6.0",
"react-dom": ">=16.6.0"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
@@ -7509,6 +7696,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/uncontrollable": {
"version": "7.2.1",
"resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz",
"integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.6.3",
"@types/react": ">=16.9.11",
"invariant": "^2.2.4",
"react-lifecycles-compat": "^3.0.4"
},
"peerDependencies": {
"react": ">=15.0.0"
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
@@ -7693,6 +7895,15 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/warning": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
"integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
"license": "MIT",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/web-namespaces": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
+3 -1
View File
@@ -14,13 +14,15 @@
"@uiw/react-md-editor": "^4.0.7",
"@yudiel/react-qr-scanner": "^2.2.1",
"axios": "^1.8.4",
"bootstrap": "^5.3.3",
"bootstrap": "^5.3.8",
"bootstrap-icons": "^1.11.3",
"js-cookie": "^3.0.5",
"next": "15.3.3",
"react": "^19.0.0",
"react-bootstrap": "^2.10.10",
"react-dom": "^19.0.0",
"react-hot-toast": "^2.5.2",
"react-icons": "^5.5.0",
"react-markdown": "^10.1.0",
"xlsx": "^0.18.5"
},
@@ -0,0 +1,93 @@
'use client'
import axiosInstance from "@/utils/api-config";
import React, { useState } from "react";
import { Button, Form } from "react-bootstrap";
import { FaUpload } from "react-icons/fa";
export default function CargaMasiva() {
const [xlsx, setXlsx] = useState<File | null>(null)
const validarExt = (file: File | null) => {
if (!file) return
const extPermitidas = /(.xlsx)$/i
if (!extPermitidas.exec(file.name)) {
console.assert({ message: "Asegurate de ingresar un archivo .xlsx"})
setXlsx(null)
} else {
setXlsx(file)
}
}
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0] || null;
validarExt(file);
}
const enviarCargaMasiva = async () => {
if (!xlsx) return;
const formData = new FormData();
formData.append("file", xlsx);
try {
const res = await axiosInstance.post(
"/cuestionario/carga-masiva",
formData,
{
headers: { "Content-Type": "multipart/form-data" }
}
);
console.log("Carga masiva exitosa", res.data);
} catch (error) {
console.error("Carga masiva fallida", error);
}
};
return (
<div className="container-fluid my-4">
<div className="row mb-4">
<div className="col-12">
<div className="p-4 border rounded bg-light">
<h2 className="mb-2">Carga Masiva de Eventos</h2>
<p className="mb-0 text-muted">
Sube tu archivo excel para poder crear los ventos.
</p>
</div>
</div>
</div>
<Form.Group className="mb-3">
<Form.Label>Archivo Excel</Form.Label>
<div
className="border p-4 text-center rounded"
style={{ cursor: "pointer" }}
onClick={() => document.getElementById("xlsxInput")?.click()}
>
<FaUpload size={40} className="mb-2" />
<p className="mb-1">
{xlsx?.name || 'Arrastra aquí tu archivo o da click aquí para buscar'}
</p>
<p className="is-size-6">Tamaño máximo 20MB</p>
<p className="is-size-7">Si al momento de elegir uin archivo este no se selecciona, haga click en cancelar en la ventana emergente e intente de nuevo.</p>
</div>
<input
id="xlsxInput"
type="file"
accept=".xlsx"
style={{ display: 'none'}}
onChange={handleFileChange}
/>
</Form.Group>
<div className="d-flex gap-2">
<Button
variant="info"
disabled={!xlsx}
onClick={enviarCargaMasiva}>
Enviar archivo
</Button>
</div>
</div>
);
}
@@ -0,0 +1,7 @@
export default function CargaMasivaBanner() {
return (
<div>
Hola mundo
</div>
);
}
+59 -46
View File
@@ -23,34 +23,37 @@ export default function Page() {
console.log('QR Escaneado:', rawValue);
if (!enableScan) return;
try {
if (rawValue) {
try {
await axiosInstance.post(
`/participante-evento/decode-token`, {
token: rawValue
}
);
if (!rawValue) {
setStatusMessage('⚠️ El QR no contiene los campos requeridos');
return;
}
setToken(rawValue);
setTokenValid(true);
setShowModal(true);
setEnableScan(false);
} catch (err) {
console.warn('Participante no registrado en el cuestionario:', err);
setStatusMessage(
'❌ El participante no está registrado en este evento.'
);
}
try {
const response = await axiosInstance.post('/participante-evento/decode-token', { token: rawValue });
if (response.data.success) {
// Token válido
setToken(rawValue);
setTokenValid(true);
setShowModal(true);
setEnableScan(false);
} else {
setStatusMessage('⚠️ El QR no contiene los campos requeridos');
// Token caducado o cualquier otro error
setStatusMessage(`❌ Error el codigo qr ya caduco`);
setTokenValid(false);
setShowModal(true); // mostramos modal con el mensaje de error
setEnableScan(false);
}
} catch (err) {
console.error('QR malformado:', err);
setStatusMessage('❌ Error al leer el QR: formato inválido');
console.error('Error al decodificar el QR:', err);
setStatusMessage('❌ Error al leer el QR');
setTokenValid(false);
setShowModal(true);
setEnableScan(false);
}
};
const handleConfirm = async () => {
if (!tokenValid) return;
@@ -237,40 +240,50 @@ export default function Page() {
<div className="modal-body p-4">
{tokenValid ? (
<>
<div className="d-grid gap-2 d-md-flex justify-content-center">
// Modal de confirmación de asistencia
<div className="d-grid gap-2 d-md-flex justify-content-center">
<Button
variant="success"
onClick={handleConfirm}
className="px-4 py-2 rounded-pill fw-semibold"
>
<i className="bi bi-check2 me-2"></i>
Confirmar Asistencia
</Button>
<Button
variant="outline-secondary"
onClick={() => {
setShowModal(false);
setEnableScan(true);
setTokenValid(false);
setToken('');
}}
className="px-4 py-2 rounded-pill"
>
<i className="bi bi-x-lg me-2"></i>
Cancelar
</Button>
</div>
) : (
// Modal de error
<div className="py-4">
<div className="mb-3">
<i className="bi bi-exclamation-triangle-fill text-warning" style={{ fontSize: '2.5rem' }}></i>
</div>
<h6 className="text-danger mb-0">{statusMessage}</h6>
<div className="mt-3">
<Button
variant="success"
onClick={handleConfirm}
className="px-4 py-2 rounded-pill fw-semibold"
>
<i className="bi bi-check2 me-2"></i>
Confirmar Asistencia
</Button>
<Button
variant="outline-secondary"
variant="secondary"
onClick={() => {
setShowModal(false);
setEnableScan(true);
setTokenValid(false);
setToken('');
setStatusMessage('');
}}
className="px-4 py-2 rounded-pill"
>
<i className="bi bi-x-lg me-2"></i>
Cancelar
Cerrar
</Button>
</div>
</>
) : (
<div className="py-4">
<div className="mb-3">
<i
className="bi bi-exclamation-triangle-fill text-warning"
style={{ fontSize: '2.5rem' }}
></i>
</div>
<h6 className="text-danger mb-0">QR inválido o malformado</h6>
</div>
)}
</div>
+53 -19
View File
@@ -3,26 +3,43 @@ import React from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
type NavChild = {
href: string; // siempre string
label: string;
};
type NavItem =
| { href: string; label: string } // items normales
| { label: string; children: NavChild[] } // items con submenu
const Navbar: React.FC = () => {
const pathname = usePathname();
const tipo_usuario = sessionStorage.getItem('axxxd')?.replace(/"/g, '') || '';
const navItemsAdmin = [
const navItemsAdmin: NavItem[] = [
{ href: '/', label: 'Inicio' },
{ href: '/user/eventos', label: 'Eventos' },
{ href: '/user/qr', label: 'Lector de QRs' },
{ href: '/user/eventos/crear', label: 'Crear Evento' },
{
label: 'Carga Masiva',
children: [
{ href: '/user/eventos/carga_masiva', label: 'Carga Masiva Eventos' },
{ href: '/user/eventos/carga_masiva_banner', label: 'Carga Masiva Imagenes' },
],
},
{ href: '/user/usuarios', label: 'Usuarios' },
{ href: '/login', label: 'Cerrar sesión' },
];
const navItemsUser = [
const navItemsUser: NavItem[] = [
{ href: '/user/eventos', label: 'Eventos' },
{ href: '/user/qr', label: 'Lector de QRs' },
{ href: '/login', label: 'Cerrar sesión' },
];
const navItems = tipo_usuario === "administrador" ? navItemsAdmin : navItemsUser;
const navItems = tipo_usuario === 'administrador' ? navItemsAdmin : navItemsUser;
return (
<nav className="navbar navbar-expand-lg navbar-dark bg-azul">
@@ -54,24 +71,41 @@ const Navbar: React.FC = () => {
></button>
</div>
<div className="offcanvas-body align-items-center justify-content-between">
<h2 className="h5 mb-0 text-white">
Sistema de Registro de Eventos
</h2>
<h2 className="h5 mb-0 text-white">Sistema de Registro de Eventos</h2>
<ul className="navbar-nav gap-lg-5">
{navItems.map((item, index) => (
<li
key={index}
className={`nav-item`}
data-bs-dismiss="offcanvas"
>
<Link
className={`nav-link ${
pathname === item.href ? 'text-white' : ''
}`}
href={item.href}
>
{item.label}
</Link>
<li key={index} className="nav-item" data-bs-dismiss="offcanvas">
{'href' in item ? (
<Link
className={`nav-link ${
pathname === item.href ? 'text-white' : ''
}`}
href={item.href}
>
{item.label}
</Link>
) : (
<div className="nav-item dropdown">
<a
className="nav-link dropdown-toggle"
href="#"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
>
{item.label}
</a>
<ul className="dropdown-menu">
{item.children.map((child: NavChild, idx: number) => (
<li key={idx}>
<Link className="dropdown-item" href={child.href}>
{child.label}
</Link>
</li>
))}
</ul>
</div>
)}
</li>
))}
</ul>