diff --git a/next.config.ts b/next.config.ts index e9ffa30..3b38372 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,15 @@ -import type { NextConfig } from "next"; +import type { NextConfig } from 'next'; const nextConfig: NextConfig = { - /* config options here */ + images: { + remotePatterns: [ + { + protocol: 'http', + hostname: 'localhost', + port: '4200', + }, + ], + }, }; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index df52e89..1cac616 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "react-hot-toast": "^2.5.2", + "react-markdown": "^10.1.0", "xlsx": "^0.18.5" }, "devDependencies": { @@ -930,6 +931,15 @@ "@popperjs/core": "^2.9.2" } }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/emscripten": { "version": "1.40.1", "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.40.1.tgz", @@ -940,9 +950,26 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, "license": "MIT" }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, "node_modules/@types/js-cookie": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", @@ -964,6 +991,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "20.17.29", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.29.tgz", @@ -978,7 +1020,6 @@ "version": "19.0.12", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz", "integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==", - "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -994,6 +1035,12 @@ "@types/react": "^19.0.0" } }, + "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/@typescript-eslint/eslint-plugin": { "version": "8.29.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.0.tgz", @@ -1230,6 +1277,12 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, "node_modules/@unrs/resolver-binding-darwin-arm64": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.3.3.tgz", @@ -1781,6 +1834,16 @@ "node": ">= 0.4" } }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1959,6 +2022,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/cfb": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", @@ -1989,6 +2062,46 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -2099,6 +2212,16 @@ "node": ">= 0.8" } }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2204,7 +2327,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2218,6 +2340,19 @@ } } }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2270,6 +2405,15 @@ "node": ">=0.4.0" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/detect-libc": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", @@ -2280,6 +2424,19 @@ "node": ">=8" } }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -2913,6 +3070,16 @@ "node": ">=4.0" } }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -2923,6 +3090,12 @@ "node": ">=0.10.0" } }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3393,6 +3566,56 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3430,6 +3653,12 @@ "node": ">=0.8.19" } }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -3445,6 +3674,30 @@ "node": ">= 0.4" } }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", @@ -3610,6 +3863,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3668,6 +3931,16 @@ "node": ">=0.10.0" } }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -3708,6 +3981,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -4031,6 +4316,16 @@ "dev": true, "license": "MIT" }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4053,6 +4348,159 @@ "node": ">= 0.4" } }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -4063,6 +4511,448 @@ "node": ">= 8" } }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -4125,7 +5015,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -4421,6 +5310,31 @@ "node": ">=6" } }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4527,6 +5441,16 @@ "react-is": "^16.13.1" } }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", @@ -4609,6 +5533,33 @@ "dev": true, "license": "MIT" }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -4666,6 +5617,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -5047,6 +6031,16 @@ "node": ">=0.10.0" } }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", @@ -5187,6 +6181,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -5210,6 +6218,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-js": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", + "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.9" + } + }, + "node_modules/style-to-object": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, "node_modules/styled-jsx": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", @@ -5317,6 +6343,26 @@ "node": ">=8.0" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -5492,6 +6538,93 @@ "dev": true, "license": "MIT" }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unrs-resolver": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.3.3.tgz", @@ -5529,6 +6662,34 @@ "punycode": "^2.1.0" } }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/webrtc-adapter": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-9.0.1.tgz", @@ -5709,6 +6870,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/zxing-wasm": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-2.1.0.tgz", diff --git a/package.json b/package.json index bdf7cf6..7876d65 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "react-hot-toast": "^2.5.2", + "react-markdown": "^10.1.0", "xlsx": "^0.18.5" }, "devDependencies": { diff --git a/public/default-banner.png b/public/default-banner.png new file mode 100644 index 0000000..68a24fd Binary files /dev/null and b/public/default-banner.png differ diff --git a/src/app/(admins)/administrador/crear-evento/page.tsx b/src/app/(admins)/administrador/crear-evento/page.tsx index 9de2648..1b8af6d 100644 --- a/src/app/(admins)/administrador/crear-evento/page.tsx +++ b/src/app/(admins)/administrador/crear-evento/page.tsx @@ -7,8 +7,13 @@ import CreateEvento from '@/containers/create-evento'; import { plantillasDisponibles } from '@/data/plantillas'; import Image from 'next/image'; import CreateFormulario from '@/containers/create-formulario'; +import Button from '@/components/button'; +import axiosInstance from '@/utils/api-config'; +import toast from 'react-hot-toast'; +import { useRouter } from 'next/navigation'; export default function Page() { + const [eventoBanner, setEventoBanner] = useState(null); const [evento, setEvento] = useState({ tipo_evento: '', nombre_evento: '', @@ -16,6 +21,7 @@ export default function Page() { fecha_inicio: new Date(), fecha_fin: new Date(), }); + const router = useRouter(); const [datosFormulario, setDatosFormulario] = useState(null); @@ -31,7 +37,7 @@ export default function Page() { }; const handleBannerChange = (file: File | null) => { - console.log('Archivo seleccionado:', file); + setEventoBanner(file); }; const handleSeleccionarPlantilla = (plantillaId: string) => { @@ -44,6 +50,42 @@ export default function Page() { } }; + const handleCrearEventoYFormulario = async () => { + try { + const createEvento = await axiosInstance.post('/evento', evento); + + if (eventoBanner) { + const formData = new FormData(); + formData.append('banner', eventoBanner); + const bannercreated = await axiosInstance.post( + `/evento/${createEvento.data.id_evento}/banner`, + formData, + { + headers: { + 'Content-Type': 'multipart/form-data', + }, + } + ); + + console.log('Banner creado:', bannercreated.data); + } + const createFormulario = await axiosInstance.post('/cuestionario', { + id_evento: createEvento.data.id_evento, + ...datosFormulario, + }); + if (createFormulario.data.id_formulario) { + console.log('Formulario creado:', createFormulario.data); + } + + router.push(`/administrador`) + } catch (error) { + toast.error( + 'Error al crear el evento y el formulario. Por favor, inténtalo de nuevo.' + ); + console.error('Error al crear evento y formulario:', error); + } + }; + return (
@@ -108,6 +150,10 @@ export default function Page() { onChange={(nuevo) => setDatosFormulario({ ...nuevo })} /> )} + +
); } diff --git a/src/app/(public)/evento/[nombre_evento]/[id_evento]/[id_cuestionario]/page.tsx b/src/app/(public)/evento/[nombre_evento]/[id_evento]/[id_cuestionario]/page.tsx new file mode 100644 index 0000000..a7b3d34 --- /dev/null +++ b/src/app/(public)/evento/[nombre_evento]/[id_evento]/[id_cuestionario]/page.tsx @@ -0,0 +1,48 @@ +'use client'; +import MarkdownRenderer from '@/components/markdown-render'; +import FormularioRegistro from '@/containers/formulario/formulario-registro'; +import { useGetApi } from '@/hooks/use-get-api'; +import { GetEventoWithCuestionario } from '@/types/evento'; +import Image from 'next/image'; +import { useParams } from 'next/navigation'; +import React from 'react'; + +type Params = { + nombre_evento: string; + id_evento: string; + id_cuestionario: string; +}; + +export default function Page() { + const params = useParams(); + const { data, error } = useGetApi( + `/evento/${params.id_evento}/cuestionario/${params.id_cuestionario}` + ); + + if (error) { + return
Error al cargar el cuestionario: {error.message}
; + } + + return ( +
+
+ {data?.banner && ( + {data?.nombre_evento + )} +
+

{data?.nombre_evento}

+ {data?.descripcion_evento && ( + + )} + {data && ( + + )} +
+ ); +} diff --git a/src/app/(public)/page.tsx b/src/app/(public)/page.tsx index 8378add..79ab79d 100644 --- a/src/app/(public)/page.tsx +++ b/src/app/(public)/page.tsx @@ -1,89 +1,38 @@ 'use client'; import ClientCarousel from '@/client-components/client-carousel'; -import FormularioCard from '@/components/formulario-card'; -import { GetCuestionario } from '@/types/cuestionario'; -import { useEffect, useState } from 'react'; +import EventoCard from '@/components/evento-card'; +import { useGetApi } from '@/hooks/use-get-api'; +import { GetEventoWithCuestionarios } from '@/types/evento'; +import React from 'react'; export default function Page() { - const [eventos, setEventos] = useState([]); - const [error, setError] = useState(null); - const [loading, setLoading] = useState(true); - - useEffect(() => { - async function getEventos() { - try { - const res = await fetch( - `${process.env.NEXT_PUBLIC_API_URL}/cuestionario`, - { - method: 'GET', - headers: { - 'Content-Type': 'application/json', - }, - } - ); - - if (!res.ok) { - throw new Error(`Error ${res.status}: ${res.statusText}`); - } - - const data: GetCuestionario[] = await res.json(); - setEventos(data); - } catch (err) { - console.error('Error en getEventos:', err); - setError('No se pudieron cargar los cuestionarios.'); - } finally { - setLoading(false); - } - } - - getEventos(); - }, []); - - function slugify(text: string): string { - return text - .toString() - .normalize('NFD') - .replace(/[\u0300-\u036f]/g, '') - .toLowerCase() - .trim() - .replace(/[^a-z0-9]+/g, '-') - .replace(/^-+|-+$/g, ''); - } - - if (loading) - return
Cargando cuestionarios...
; - if (error) return
{error}
; + const { loading, data } = useGetApi( + '/evento/activos/cuestionarios' + ); return ( - <> +
- + ({ + src: item.banner + ? `${process.env.NEXT_PUBLIC_API_URL}/banners/${item.banner}` + : '/default-banner.jpg', + alt: item.nombre_evento, + }))} + />
-
-
-
- {eventos.map((cuestionario, index) => { - const slug = slugify(cuestionario.nombre_form); - const url = `/registro/${slug}-${cuestionario.id_cuestionario}`; - const fadeClass = `delay-${(index % 5) + 1}`; - - return ( -
- -
- ); - })} -
+ {loading &&
Cargando...
} + {data && ( +
+ {data.map((item, key) => ( +
+ +
+ ))}
-
- + )} +
); } diff --git a/src/app/(public)/registro/[slug]/page.tsx b/src/app/(public)/registro/[slug]/page.tsx deleted file mode 100644 index 3c2e217..0000000 --- a/src/app/(public)/registro/[slug]/page.tsx +++ /dev/null @@ -1,80 +0,0 @@ -'use client'; -import Button from '@/components/button'; -import Formulario from '@/containers/formulario'; -import { CuestionarioResponse } from '@/types/responder-formulario'; -import axiosInstance from '@/utils/api-config'; -import Image from 'next/image'; -import { useParams, useRouter } from 'next/navigation'; -import React, { useEffect, useState } from 'react'; - -export default function Page() { - const router = useRouter(); - const params = useParams<{ slug: string }>(); - const slug = params?.slug; - - const id_formulario = slug?.split('-').pop(); // Toma el último fragmento como ID - const [cuestionario, setCuestionario] = useState( - null - ); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchData = async () => { - try { - setLoading(true); - const { data } = await axiosInstance.get( - `/cuestionario/${id_formulario}/formulario` - ); - if (data) { - console.log(data); - setCuestionario(data); - } else { - setError('Error fetching data'); - } - } catch (error) { - console.error('Error fetching data:', error); - setError('Error de conexión'); - } finally { - setLoading(false); - } - }; - - if (id_formulario) fetchData(); - }, [id_formulario]); - - if (loading) return

Cargando...

; - if (error) return

{error}

; - if (!cuestionario) return

No hay datos

; - - return ( -
- -
- Ejemplo de banner -
-
-

{cuestionario.cuestionario.nombre_form}

-

{cuestionario.cuestionario.descripcion}

- - -
-
- ); -} diff --git a/src/client-components/client-carousel.tsx b/src/client-components/client-carousel.tsx index 6eaa395..0e7d78b 100644 --- a/src/client-components/client-carousel.tsx +++ b/src/client-components/client-carousel.tsx @@ -1,10 +1,11 @@ 'use client'; +import { CarouselProps } from '@/components/carousel'; import dynamic from 'next/dynamic'; import React from 'react'; const Carousel = dynamic(() => import('@/components/carousel'), { ssr: false, }); -export default function ClientCarousel() { - return ; +export default function ClientCarousel(props: CarouselProps) { + return ; } diff --git a/src/components/carousel.tsx b/src/components/carousel.tsx index 557fc27..0a5642b 100644 --- a/src/components/carousel.tsx +++ b/src/components/carousel.tsx @@ -1,7 +1,7 @@ import Image from 'next/image'; import React from 'react'; -interface CarouselProps { +export interface CarouselProps { id?: string; images?: { src: string; @@ -9,15 +9,9 @@ interface CarouselProps { }[]; } -export default function Carousel({ - id = 'carouselExample', - images = [ - { - src: '/feriasex.png', - alt: 'Imagen de ejemplo', - }, - ], -}: CarouselProps) { +export default function Carousel({ id, images }: CarouselProps) { + console.log('Carousel images:', images); + if (!images || images.length === 0) { return
No hay imágenes para mostrar
; } @@ -31,11 +25,17 @@ export default function Carousel({ className={`carousel-item ${index === 0 ? 'active' : ''}`} > Ejemplo de banner
))} diff --git a/src/components/evento-card.tsx b/src/components/evento-card.tsx new file mode 100644 index 0000000..a142ada --- /dev/null +++ b/src/components/evento-card.tsx @@ -0,0 +1,65 @@ +import { GetEventoWithCuestionarios } from '@/types/evento'; +import Image from 'next/image'; +import Link from 'next/link'; +import React, { useState } from 'react'; +import MarkdownRenderer from './markdown-render'; + +export default function EventoCard({ + evento, +}: { + evento: GetEventoWithCuestionarios; +}) { + const [verMas, setVerMas] = useState(false); + const descripcion = evento.descripcion_evento; + const limite = 100; + + const descripcionRecortada = + descripcion.length > limite && !verMas + ? `${descripcion.slice(0, limite)}...` + : descripcion; + + return ( +
+
+
+ + Banner formulario +
{evento.nombre_evento}
+ +
+
+
+
+ + {descripcion.length > limite && ( + + )} +
+ {evento.cuestionarios.length > 0 && + evento.cuestionarios.map((cuestionario) => ( +
+ + {cuestionario.nombre_form} + +
+ ))} +
+
+
+ ); +} diff --git a/src/components/markdown-render.tsx b/src/components/markdown-render.tsx new file mode 100644 index 0000000..197bd63 --- /dev/null +++ b/src/components/markdown-render.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import ReactMarkdown from 'react-markdown'; + +type MarkdownRendererProps = { + markdown: string; +}; + +const MarkdownRenderer: React.FC = ({ markdown }) => ( +

, + }} + > + {markdown} + +); + +export default MarkdownRenderer; diff --git a/src/containers/formulario.tsx b/src/containers/formulario.tsx deleted file mode 100644 index 22e9768..0000000 --- a/src/containers/formulario.tsx +++ /dev/null @@ -1,416 +0,0 @@ -'use client'; - -import React, { useEffect, useState } from 'react'; -import { CuestionarioSeccion } from '@/types/responder-formulario'; -import RadioOptionGroup, { RadioOption } from '@/components/radio-option-group'; -import Input from '@/components/input'; -import Button from '@/components/button'; -import { validarRespuesta } from '@/utils/validador'; -import toast from 'react-hot-toast'; -import axiosInstance from '@/utils/api-config'; -import { useRouter } from 'next/navigation'; -import { getAxiosError } from '@/utils/errors-utils'; - -interface GetAlumnoResponse { - id_ncuenta: number; - nombre: string; - apellidos: string; - carrera: string; - genero: 'M' | 'F'; -} - -export default function Formulario({ - id_formulario, - secciones, -}: { - id_formulario: number; - secciones: CuestionarioSeccion[]; -}) { - const router = useRouter(); - const [esDeFES, setEsDeFES] = useState(null); - const [cuenta, setCuenta] = useState(''); - const [datosAuto, setDatosAuto] = useState(null); - const [respuestas, setRespuestas] = useState>({}); - const [isSubmitting, setIsSubmitting] = useState(false); // New state for submission - - const actualizarRespuesta = (idPregunta: string, valor: string) => { - setRespuestas((prev) => ({ ...prev, [idPregunta]: valor })); - }; - - useEffect(() => { - if (esDeFES && cuenta.length === 9) { - (async () => { - try { - setDatosAuto(null); - const { data } = await axiosInstance.get( - `/alumnos/${cuenta}` - ); - console.log('Datos del alumno:', data); - if (data) { - setDatosAuto({ - nombre: data.nombre.toString(), - apellidos: data.apellidos.toString(), - correo: data.id_ncuenta + '@pcpuma.acatlan.unam.mx', - genero: data.genero, - carrera: data.carrera, - }); - } - } catch (err) { - const msg = getAxiosError(err); - toast.error(msg.message); - setDatosAuto(null); - } - })(); - } - }, [cuenta, esDeFES]); - - useEffect(() => { - if (esDeFES && datosAuto) { - const nuevasRespuestas: Record = {}; - - secciones.forEach((seccion) => { - seccion.preguntas.forEach(({ pregunta }) => { - const id = pregunta.id_pregunta; - - if (pregunta.validacion === 'nombre') { - nuevasRespuestas[`pregunta_${id}`] = pregunta.pregunta - .toLowerCase() - .includes('apellido') - ? datosAuto.apellidos.toString() - : datosAuto.nombre.toString(); - } - - if (pregunta.validacion === 'correo') { - nuevasRespuestas[`pregunta_${id}`] = datosAuto.correo; - } - - if (pregunta.validacion === 'cuenta_alumno') { - nuevasRespuestas[`pregunta_${id}`] = cuenta; - } - - if ( - pregunta.pregunta - .toLowerCase() - .includes('institución de procedencia') - ) { - nuevasRespuestas[`pregunta_${id}`] = 'FES Acatlán'; - } - - if (pregunta.pregunta.toLowerCase().includes('carrera')) { - nuevasRespuestas[`pregunta_${id}`] = datosAuto.carrera; - } - }); - }); - - setRespuestas((prev) => ({ - ...prev, - ...nuevasRespuestas, - })); - } - }, [datosAuto, esDeFES, cuenta, secciones]); - - // Encuentra preguntas por texto o validación - const todasPreguntas = secciones.flatMap((s) => - s.preguntas.map((p) => p.pregunta) - ); - const preguntaFES = todasPreguntas.find( - (p) => p.pregunta === '¿Eres parte de la comunidad de la FES Acatlán?' - ); - const preguntaCuenta = todasPreguntas.find( - (p) => p.validacion === 'cuenta_alumno' - ); - const preguntasRestantes = todasPreguntas.filter( - (p) => - ![preguntaFES?.id_pregunta, preguntaCuenta?.id_pregunta].includes( - p.id_pregunta - ) - ); - const respuestaFES = respuestas[`pregunta_${preguntaFES?.id_pregunta}`]; - - const formatearRespuestas = async () => { - if (!validarRespuestasObligatorias()) return; - - const respuestasArray = Object.entries(respuestas).flatMap( - ([key, valor]) => { - const idNumerico = Number(key.replace('pregunta_', '')); - const pregunta = secciones - .flatMap((s) => s.preguntas) - .find((p) => p.pregunta.id_pregunta === idNumerico); - - const tipo = pregunta?.pregunta.tipo_pregunta.tipo_pregunta; - - // Si es múltiple, convertir cada valor individual si corresponde - if (Array.isArray(valor)) { - return valor.map((v) => ({ - id_pregunta: idNumerico, - valor: tipo === 'Cerrada' || tipo === 'Multiple' ? Number(v) : v, - })); - } - - return [ - { - id_pregunta: idNumerico, - valor: tipo === 'Cerrada' ? Number(valor) : valor, - }, - ]; - } - ); - - const correoEntry = respuestasArray.find( - (r) => - typeof r.valor === 'string' && - /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(r.valor) - ); - - const resultado = { - id_formulario: Number(id_formulario), - correo: correoEntry?.valor || 'correo@no-encontrado.com', - respuestas: respuestasArray, - fecha_envio: new Date().toISOString(), - }; - - console.log('Resultado a enviar:', resultado); - - setIsSubmitting(true); - toast - .promise( - axiosInstance.post('/cuestionario-respondido/submit', resultado), - { - loading: 'Enviando formulario...', - success: 'Formulario enviado con éxito!', - error: 'Error al enviar el formulario.', - } - ) - .then(() => router.push('/')) - .finally(() => setIsSubmitting(false)); - }; - - const validarRespuestasObligatorias = (): boolean => { - const faltantes: number[] = []; - const errores: { id: number; mensaje: string }[] = []; - - secciones.forEach((seccion) => { - seccion.preguntas.forEach(({ pregunta }) => { - const id = pregunta.id_pregunta; - const valor = respuestas[`pregunta_${id}`]; - const tipo = pregunta.tipo_pregunta.tipo_pregunta; - const validacion = pregunta.validacion; - - console.log('Validando pregunta:', pregunta.pregunta, ' ---------- '); - console.table({ - id, - valor, - tipo, - validacion, - }); - - const respondida = - (tipo === 'Abierta' && - typeof valor === 'string' && - valor.trim() !== '') || - (tipo === 'Cerrada' && valor !== undefined) || - (tipo === 'Multiple' && Array.isArray(valor) && valor.length > 0); - - if (!respondida && pregunta.obligatoria) { - faltantes.push(id); - } - - if (tipo === 'Abierta' && validacion && typeof valor === 'string') { - const resultado = validarRespuesta(valor, validacion); - if (!resultado.valido) { - errores.push({ id, mensaje: resultado.mensaje }); - } - } - }); - }); - if (faltantes.length > 0) { - console.log('Faltan preguntas obligatorias:', faltantes); - toast.error('Responde todas las preguntas obligatorias antes de enviar.'); - return false; - } - - if (errores.length > 0) { - toast.error( - `Corrige las respuestas con error de formato:\n${errores - .map((e) => `• ${e.mensaje}`) - .join('\n')}` - ); - return false; - } - - return true; - }; - - return ( -

- {/* Pregunta inicial */} - {preguntaFES && ( -
- - ({ - label: op.opcion.opcion, - value: op.id_opcion, - }))} - selectedValue={respuestaFES ? Number(respuestaFES) : undefined} - onChange={(opt) => { - const id = opt.value; - const value = opt?.label ?? ''; - - setEsDeFES(value === 'Si'); // Se actualiza esDeFES con el texto - setCuenta(''); - setDatosAuto(null); - - actualizarRespuesta( - `pregunta_${preguntaFES.id_pregunta}`, - String(id) - ); - }} - /> -
- )} - - {/* Si dijo que sí, pedir número de cuenta */} - {esDeFES && preguntaCuenta && ( - { - const value = e.target.value; - setCuenta(value); - actualizarRespuesta( - `pregunta_${preguntaCuenta.id_pregunta}`, - value - ); // ✅ Guarda la respuesta - }} - /> - )} - - {/* Si ya tiene datos o dijo que no es de la FES, mostrar el resto */} - {(esDeFES === false || (esDeFES && datosAuto)) && - preguntasRestantes.map((p) => { - if (p.tipo_pregunta.tipo_pregunta === 'Abierta') { - let defaultValue = ''; - let disabled = false; - - if (esDeFES && datosAuto) { - if (p.validacion === 'nombre') { - defaultValue = p.pregunta.toLowerCase().includes('apellido') - ? datosAuto.apellidos - : datosAuto.nombre; - disabled = true; - } - if (p.validacion === 'correo') { - defaultValue = datosAuto.correo; - disabled = true; - } - if (p.validacion === 'cuenta_alumno') { - defaultValue = cuenta; - disabled = true; - } - if ( - p.pregunta.toLowerCase().includes('institución de procedencia') - ) { - defaultValue = 'FES Acatlán'; - disabled = true; - } - if (p.pregunta.toLowerCase().includes('carrera')) { - defaultValue = datosAuto.carrera; - disabled = true; - } - } - - return ( - - { - console.log('Respuesta:', e.target.value); - actualizarRespuesta( - `pregunta_${p.id_pregunta}`, - e.target.value - ); - }} - /> - {p.validacion === 'correo' && ( -
- Este es el correo donde enviaremos la validación de registro{' '} -
- )} -
- ); - } - - if (p.tipo_pregunta.tipo_pregunta === 'Cerrada') { - const opciones: RadioOption[] = p.opciones.map((op) => ({ - label: op.opcion.opcion, - value: op.id_opcion, - })); - - let respuestaActual = respuestas[`pregunta_${p.id_pregunta}`]; - - // Si es de FES y hay datos automáticos, intentar preseleccionar género - if ( - esDeFES && - datosAuto && - !respuestaActual && - p.pregunta.toLowerCase().includes('género') - ) { - const generoTexto = - datosAuto.genero === 'M' ? 'Masculino' : 'Femenino'; - const opcionGenero = p.opciones.find( - (op) => - op.opcion.opcion.toLowerCase() === generoTexto.toLowerCase() - ); - if (opcionGenero) { - respuestaActual = String(opcionGenero.id_opcion); - actualizarRespuesta( - `pregunta_${p.id_pregunta}`, - String(respuestaActual) - ); - } - } - - return ( -
- - - actualizarRespuesta( - `pregunta_${p.id_pregunta}`, - String(opt.value) - ) - } - /> -
- ); - } - - return null; - })} - - {/* Botón de enviar */} - - - ); -} diff --git a/src/containers/formulario/formulario-registro.tsx b/src/containers/formulario/formulario-registro.tsx new file mode 100644 index 0000000..4c41487 --- /dev/null +++ b/src/containers/formulario/formulario-registro.tsx @@ -0,0 +1,471 @@ +import React, { useState, useEffect } from 'react'; +import MarkdownRenderer from '@/components/markdown-render'; +import { useGetApi } from '@/hooks/use-get-api'; +import { GetCuestionario } from '@/types/evento'; +import SimpleInput from '@/components/input'; +import RadioOptionGroup, { RadioOption } from '@/components/radio-option-group'; +import axiosInstance from '@/utils/api-config'; +import PrefetchAbiertaCorta from './prefetch-abierta-corta'; +import Button from '@/components/button'; +import toast from 'react-hot-toast'; +import { useRouter } from 'next/navigation'; +import { getAxiosError } from '@/utils/errors-utils'; + +type UsuarioData = { + nombre: string; + apellidos: string; + correo: string; + genero: 'M' | 'F'; + carrera: string; +}; + +const confirmativeOption = ['Sí', 'Si', 'Si, claro', 'Claro que sí']; +const negativeOption = ['No', 'No, gracias', 'No, de momento']; + +type RespuestaFormulario = Record; // id_pregunta: respuesta + +export default function FormularioRegistro({ + id_cuestionario, +}: { + id_cuestionario: number; +}) { + // ------------------------ + // Estados + // ------------------------ + const [isComunidad, setIsComunidad] = useState>(); + const [respuestas, setRespuestas] = useState({}); + const [cuentaInfo, setCuentaInfo] = useState(null); + const [isSending, setIsSending] = useState(false); + const router = useRouter(); + + // ------------------------ + // Carga del cuestionario + // ------------------------ + const { data, error } = useGetApi( + `/cuestionario/${id_cuestionario}/formulario` + ); + // ------------------------ + // Extracción de preguntas clave + // ------------------------ + const preguntas = data?.cuestionario.secciones.flatMap((seccion) => + seccion.preguntas.map((pregunta) => pregunta.pregunta) + ); + + const preguntaComunidad = preguntas?.find( + (pregunta) => + pregunta.validacion === 'comunidad_alumno' || + pregunta.validacion === 'comunidad_trabajador' + ); + + const preguntaCuenta = preguntas?.find( + (pregunta) => + pregunta.validacion === 'cuenta_alumno' || + pregunta.validacion === 'cuenta_trabajador' + ); + + // ------------------------ + // Efecto: buscar información de cuenta + // ------------------------ + useEffect(() => { + const cuenta = respuestas[preguntaCuenta?.id_pregunta ?? '']; + + const esCuentaAlumno = preguntaCuenta?.validacion === 'cuenta_alumno'; + const esCuentaTrabajador = + preguntaCuenta?.validacion === 'cuenta_trabajador'; + + const puedeBuscar = + cuenta && + typeof cuenta === 'string' && + ((esCuentaAlumno && cuenta.length === 9) || esCuentaTrabajador); + + const fetchCuentaInfo = async () => { + try { + const endpoint = esCuentaAlumno + ? `/alumnos/${cuenta}` + : `/trabajadores/${cuenta}`; + + console.log('Buscando información de cuenta:', endpoint); + + // Usar datos fake para pruebas + setCuentaInfo({ + nombre: 'Juan', + apellidos: 'Pérez', + correo: '421010301@pcpuma.acatlan.unam.mx', + genero: 'M', + carrera: 'Ingeniería', + }); + } catch (error) { + console.error('Error al obtener datos de cuenta:', error); + setCuentaInfo(null); + } + }; + + if (puedeBuscar) { + fetchCuentaInfo(); + } else { + setCuentaInfo(null); + } + }, [respuestas[preguntaCuenta?.id_pregunta ?? '']]); + + // ------------------------ + // Efecto: precargar respuestas si hay cuentaInfo + // ------------------------ + useEffect(() => { + if (!cuentaInfo) { + if (preguntas) { + const idsPrefetch = preguntas + .filter((pregunta) => + [ + 'nombre', + 'apellidos', + 'correo', + 'institucion', + 'carrera', + 'genero', + ].includes(pregunta.validacion) + ) + .map((pregunta) => pregunta.id_pregunta); + + setRespuestas((prev) => { + const nuevas = { ...prev }; + idsPrefetch.forEach((id) => { + delete nuevas[id]; + }); + return nuevas; + }); + } + return; + } + + const nuevasRespuestas: RespuestaFormulario = {}; + + if (preguntas) { + for (const pregunta of preguntas) { + const id = pregunta.id_pregunta; + switch (pregunta.validacion) { + case 'nombre': + nuevasRespuestas[id] = cuentaInfo.nombre; + break; + case 'apellidos': + nuevasRespuestas[id] = cuentaInfo.apellidos; + break; + case 'correo': + nuevasRespuestas[id] = cuentaInfo.correo; + break; + case 'institucion': + nuevasRespuestas[id] = 'FES Acatlán'; + break; + case 'carrera': + nuevasRespuestas[id] = cuentaInfo.carrera; + break; + case 'genero': + const generoTexto = + cuentaInfo.genero === 'M' ? 'Masculino' : 'Femenino'; + const opcion = pregunta.opciones?.find( + (op) => + op.opcion.opcion.toLowerCase() === generoTexto.toLowerCase() + ); + if (opcion) { + nuevasRespuestas[id] = String(opcion.id_opcion); + } + break; + } + } + + setRespuestas((prev) => ({ + ...prev, + ...nuevasRespuestas, + })); + } + }, [cuentaInfo]); + + // ------------------------ + // Funciones auxiliares + // ------------------------ + const actualizarRespuesta = (idPregunta: string, valor: string) => { + setRespuestas((prev) => ({ ...prev, [idPregunta]: valor })); + }; + + const handleOnSubmit = async () => { + setIsSending(true); + if (!data?.cuestionario.id_cuestionario) { + alert('No se ha cargado correctamente el formulario'); + return; + } + + const preguntasObligatorias = + data?.cuestionario.secciones.flatMap((seccion) => + seccion.preguntas + .filter((pregunta) => pregunta.pregunta.obligatoria) + .map((pregunta) => pregunta.pregunta) + ) || []; + + const faltantes = preguntasObligatorias.filter( + (pregunta) => + respuestas[pregunta.id_pregunta] === undefined || + respuestas[pregunta.id_pregunta] === '' || + respuestas[pregunta.id_pregunta] === null + ); + + if (faltantes.length > 0) { + toast.error('Por favor responde todas las preguntas obligatorias.'); + return; + } + + // Buscar un posible correo en las respuestas si no hay cuentaInfo + let correo = cuentaInfo?.correo; + if (!correo) { + // Buscar en las respuestas una que parezca correo + const correoRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + for (const valor of Object.values(respuestas)) { + if (typeof valor === 'string' && correoRegex.test(valor)) { + correo = valor; + break; + } + } + } + + const payload = { + id_cuestionario: id_cuestionario, + correo: correo || '', + fecha_envio: new Date().toISOString(), + respuestas: Object.entries(respuestas).map(([id_pregunta, valor]) => ({ + id_pregunta: Number(id_pregunta), + valor: isNaN(Number(valor)) ? valor : Number(valor), + })), + }; + + console.log('Payload para enviar:', payload); + + try { + const res = await axiosInstance.post( + '/cuestionario-respondido/submit', + payload + ); + toast.success(res.data.message || 'Formulario enviado correctamente'); + } catch (error) { + console.log(getAxiosError(error)); + toast.error('Hubo un error al enviar el formulario'); + } finally { + // Redirigir al usuario después de enviar el formulario + router.push('/'); + } + }; + + // ------------------------ + // Condición para mostrar el formulario + // ------------------------ + const mostrarFormularioRestante = + (isComunidad && + confirmativeOption.includes(isComunidad.label) && + !!cuentaInfo) || + (isComunidad && negativeOption.includes(isComunidad.label)); + + if (error) { + console.error('Error al cargar el cuestionario:', error); + return
Error al cargar el cuestionario
; + } + + return ( +
+
+

{data?.cuestionario.nombre_form}

+ {data?.cuestionario.descripcion && ( + + )} + + {preguntaComunidad && ( +
+ + ({ + label: op.opcion.opcion, + value: op.id_opcion, + }))} + selectedValue={isComunidad?.value} + onChange={(opt) => { + console.log('Opción comunidad seleccionada:', opt); + setIsComunidad(opt); + actualizarRespuesta( + preguntaComunidad.id_pregunta.toString(), + String(opt.value) + ); + }} + /> +
+ )} + + {isComunidad && + confirmativeOption.includes(isComunidad?.label) && + preguntaCuenta && ( +
+ + + setRespuestas((prev) => ({ + ...prev, + [preguntaCuenta.id_pregunta]: e.target.value, + })) + } + /> +
+ )} + + {mostrarFormularioRestante && + data?.cuestionario.secciones.map((seccion, i) => ( +
+ {seccion.preguntas.map((pregunta) => { + // Evitar renderizar las preguntas ya manejadas + if ( + pregunta.pregunta.id_pregunta === + preguntaComunidad?.id_pregunta || + pregunta.pregunta.id_pregunta === preguntaCuenta?.id_pregunta + ) + return null; + + if ( + pregunta.pregunta.tipo_pregunta.tipo_pregunta === + 'Abierta (Respuesta corta)' + ) { + return ( + + ); + } + + if ( + pregunta.pregunta.tipo_pregunta.tipo_pregunta === + 'Abierta (Parrafo)' + ) { + return ( +
+ + + setRespuestas((prev) => ({ + ...prev, + [pregunta.pregunta.id_pregunta]: e.target.value, + })) + } + /> +
+ ); + } + + if (pregunta.pregunta.tipo_pregunta.tipo_pregunta === 'Cerrada') { + const opciones: RadioOption[] = + pregunta.pregunta.opciones.map((op) => ({ + label: op.opcion.opcion, + value: op.id_opcion, + })); + let respuestaActual = + respuestas[`${pregunta.pregunta.id_pregunta}`]; + + if ( + confirmativeOption.includes(isComunidad?.label) && + cuentaInfo && + respuestaActual === undefined // solo si no ha respondido + ) { + if (pregunta.pregunta.validacion === 'genero') { + const generoTexto = + cuentaInfo.genero === 'M' ? 'Masculino' : 'Femenino'; + + const opcionGenero = pregunta.pregunta.opciones.find( + (op) => + op.opcion.opcion.toLowerCase() === + generoTexto.toLowerCase() + ); + if (opcionGenero) { + respuestaActual = String(opcionGenero.id_opcion); + } + } + } + + return ( +
+ + { + actualizarRespuesta( + `${pregunta.pregunta.id_pregunta}`, + String(opt.value) + ); + }} + /> +
+ ); + } + + return ( +
+ +
+ ); + })} +
+ ))} + + +
+ ); +} diff --git a/src/containers/formulario/prefetch-abierta-corta.tsx b/src/containers/formulario/prefetch-abierta-corta.tsx new file mode 100644 index 0000000..683bac9 --- /dev/null +++ b/src/containers/formulario/prefetch-abierta-corta.tsx @@ -0,0 +1,75 @@ +import React from 'react'; +import SimpleInput from '@/components/input'; + +type Props = { + idPregunta: number; + enunciado: string; + obligatorio?: boolean; + validacion?: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + respuestas: Record; + cuentaInfo: { + nombre: string; + apellidos: string; + correo: string; + genero: 'M' | 'F'; + carrera: string; + } | null; + isComunidad: string | undefined; + onChange: (id: string, valor: string) => void; +}; + +const confirmativeOption = ['Sí', 'Si', 'Si, claro', 'Claro que sí']; + +export default function PrefetchAbiertaCorta({ + idPregunta, + enunciado, + validacion, + respuestas, + cuentaInfo, + isComunidad, + obligatorio, + onChange, +}: Props) { + let defaultValue = ''; + let disabled = false; + + if (confirmativeOption.includes(isComunidad ?? '') && cuentaInfo) { + if (validacion === 'nombre') { + defaultValue = cuentaInfo.nombre; + disabled = true; + } + if (validacion === 'apellidos') { + defaultValue = cuentaInfo.apellidos; + disabled = true; + } + if (validacion === 'correo') { + defaultValue = cuentaInfo.correo; + disabled = true; + } + if (validacion === 'institucion') { + defaultValue = 'FES Acatlán'; + disabled = true; + } + if (validacion === 'carrera') { + defaultValue = cuentaInfo.carrera; + disabled = true; + } + } + + return ( +
+ + onChange(idPregunta.toString(), e.target.value)} + /> +
+ ); +} diff --git a/src/data/plantillas.ts b/src/data/plantillas.ts index c3abd7e..1e79dc9 100644 --- a/src/data/plantillas.ts +++ b/src/data/plantillas.ts @@ -49,16 +49,19 @@ export const plantillasDisponibles: Plantilla[] = [ titulo: 'Nombre(s)', tipo: 'Abierta (Respuesta corta)', obligatoria: true, + validacion: 'nombre' }, { titulo: 'Apellidos', tipo: 'Abierta (Respuesta corta)', obligatoria: true, + validacion: 'apellidos' }, { titulo: 'Género', tipo: 'Cerrada', obligatoria: true, + validacion: 'genero', opciones: [ { valor: 'Masculino' }, { valor: 'Femenino' }, @@ -111,16 +114,19 @@ export const plantillasDisponibles: Plantilla[] = [ titulo: 'Nombre(s)', tipo: 'Abierta (Respuesta corta)', obligatoria: true, + validacion: 'nombre', }, { titulo: 'Apellidos', tipo: 'Abierta (Respuesta corta)', obligatoria: true, + validacion: 'apellidos', }, { titulo: 'Género', tipo: 'Cerrada', obligatoria: true, + validacion: 'genero', opciones: [ { valor: 'Masculino' }, { valor: 'Femenino' }, @@ -130,11 +136,13 @@ export const plantillasDisponibles: Plantilla[] = [ { titulo: 'Institución de procedencia', tipo: 'Abierta (Respuesta corta)', + validacion: 'institucion', obligatoria: true, }, { titulo: 'Carrera', tipo: 'Abierta (Respuesta corta)', + validacion: 'carrera', obligatoria: true, }, ], diff --git a/src/hooks/use-get-api.tsx b/src/hooks/use-get-api.tsx new file mode 100644 index 0000000..49c4728 --- /dev/null +++ b/src/hooks/use-get-api.tsx @@ -0,0 +1,31 @@ +import axiosInstance from '@/utils/api-config'; +import { getAxiosError } from '@/utils/errors-utils'; +import { useEffect, useState } from 'react'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export const useGetApi = (url: string, params?: Record) => { + const [data, setData] = useState(); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchData = async () => { + try { + const res = await axiosInstance.get(url, { params }); + setData(res.data); + setError(null); + } catch (err) { + console.error(err); + const message = getAxiosError(err); + + setError(message); + } finally { + setLoading(false); + } + }; + + fetchData(); + }, [url, params]); + + return { data, setData, loading, error }; +}; diff --git a/src/styles/sass/bootstrap.scss b/src/styles/sass/bootstrap.scss index df4672d..b46a696 100644 --- a/src/styles/sass/bootstrap.scss +++ b/src/styles/sass/bootstrap.scss @@ -30,6 +30,12 @@ $theme-colors: map-merge($theme-colors, $custom-colors); @import 'animation'; @import './global.scss'; +.carousel-control-prev-icon, +.carousel-control-next-icon { + filter: invert(100%) sepia(100%) saturate(0%) hue-rotate(0deg) + brightness(200%); +} + //Add additional custom code here @include media-breakpoint-up(lg) { @@ -73,6 +79,7 @@ ul.list-unstyled li { position: relative; overflow: hidden; margin: -1.5rem 1rem 0; + cursor: pointer; @extend .rounded; @extend .shadow; @@ -83,7 +90,7 @@ ul.list-unstyled li { left: 0; width: 100%; height: 80%; // ajusta según el tamaño deseado - background: linear-gradient(to top, rgba(0, 0, 0, 0.4), transparent); + background: linear-gradient(to top, rgba(0, 0, 0, 0.5), transparent); pointer-events: none; z-index: 1; } @@ -98,13 +105,20 @@ ul.list-unstyled li { .card-caption { position: absolute; - bottom: 15px; + bottom: 5px; left: 15px; color: #fff; + font-weight: bold; font-size: 1.25rem; text-shadow: 0 2px 5px rgba(33, 33, 33, 0.5); z-index: 2; } + + .card-description { + > p { + margin: 0; + } + } } .table { @@ -139,3 +153,14 @@ ul.list-unstyled li { input { --bs-body-bg: #fff; } + +.required { + position: relative; + &::after { + content: '*'; + position: absolute; + color: red; + font-weight: bold; + margin-left: 10px; + } +} \ No newline at end of file diff --git a/src/types/create-formulario.d.ts b/src/types/create-formulario.d.ts index 77f10ab..aa91477 100644 --- a/src/types/create-formulario.d.ts +++ b/src/types/create-formulario.d.ts @@ -4,11 +4,15 @@ export type TiposValidacion = | 'telefono' | 'nombre' | 'entero' + | 'apellidos' | 'decimal' | 'comunidad_alumno' | 'cuenta_alumno' | 'comunidad_trabajador' - | 'cuenta_trabajador'; + | 'cuenta_trabajador' + | 'genero' + | 'carrera' + | 'institucion' export type TipoPregunta = | 'Abierta (Respuesta corta)' diff --git a/src/types/evento.d.ts b/src/types/evento.d.ts new file mode 100644 index 0000000..dddd4e2 --- /dev/null +++ b/src/types/evento.d.ts @@ -0,0 +1,85 @@ +import { TipoPregunta, TiposValidacion } from "./create-formulario"; + +export interface GetEvento { + id_evento: number; + nombre_evento: string; + descripcion_evento: string; + tipo_evento: string; + fecha_inicio: string; // formato ISO 8601 + fecha_fin: string; // formato ISO 8601 + // eslint-disable-next-line @typescript-eslint/no-explicit-any + asistencias: any | null; + banner: string | null; +} + +export interface Cuestionario { + id_cuestionario: number; + nombre_form: string; + banner: string | null; + contador_secciones: number; + descripcion: string; + editable: boolean; + fecha_inicio: string; // formato ISO 8601 + fecha_fin: string; // formato ISO 8601 + id_tipo_cuestionario: number; + id_evento: number; + tipoCuestionario: { + id_tipo_cuestionario: number; + tipo_cuestionario: string; + }; +} + +export interface GetCuestionario { + tipo_cuestionario: { + id_tipo_cuestionario: number; + tipo_cuestionario: string; + }; + evento: GetEvento; + cuestionario: CuestionarioWithSecciones; +} + +export interface CuestionarioWithSecciones extends Cuestionario { + secciones: { + id_cuestionario_seccion: number; + posicion: number; + seccion: { + id_seccion: number; + titulo: string; + contador_pregunta: number; + descripcion: string; + }; + preguntas: { + id_seccion_pregunta: number; + posicion: number; + pregunta: { + id_pregunta: number; + pregunta: string; + contador_opcion: number; + obligatoria: boolean; + id_tipo_pregunta: number; + validacion: TiposValidacion; + tipo_pregunta: { + id_tipo: number; + tipo_pregunta: TipoPregunta; + }; + opciones: { + id_pregunta_opcion: number; + posicion: number; + id_opcion: number; + opcion: { + id_opcion: number; + opcion: string; + }; + }[]; + }; + }[]; + }[]; +} + +export interface GetEventoWithCuestionarios extends GetEvento { + cuestionarios: Cuestionario[]; +} + +export interface GetEventoWithCuestionario extends GetEvento { + cuestionario: Cuestionario; +} diff --git a/src/types/system.d.ts b/src/types/system.d.ts index 45c8193..d72eef8 100644 --- a/src/types/system.d.ts +++ b/src/types/system.d.ts @@ -7,8 +7,9 @@ interface User { carrera?: string; } + interface ErrorState { status: boolean; message: string; code: number; -} +} \ No newline at end of file