diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..936c6c2 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,11 @@ +{ + "semi": true, + "singleQuote": true, + "tabWidth": 2, + "useTabs": false, + "trailingComma": "es5", + "printWidth": 80, + "bracketSpacing": true, + "arrowParens": "always", + "endOfLine": "lf" +} diff --git a/data.json b/data.json new file mode 100644 index 0000000..d73170e --- /dev/null +++ b/data.json @@ -0,0 +1,249 @@ +{ + "pollutionMeasurements": { + "city": "Ciudad de M\\u00e9xico", + "cityCode": "MEX", + "country": "M\\u00e9xico", + "mesurementAgency": "SIMAT", + "unit": { "RH": "%", "TMP": "C", "WSP": "m/s", "WDR": "o" }, + "date": { + "2023-01-01 01:00": { + "RH": { + "ACO": "81", + "AJU": "100", + "MON": "56", + "CHO": "", + "CUA": "61", + "CUT": "73", + "FAC": "73", + "HGM": "58", + "MER": "66", + "NEZ": "57", + "PED": "63", + "SAG": "74", + "SFE": "", + "TAH": "65", + "TLA": "60", + "UAX": "71", + "UIZ": "74", + "VIF": "69", + "XAL": "", + "MGH": "", + "AJM": "64", + "MPA": "71", + "BJU": "66", + "INN": "87", + "GAM": "68", + "LAA": "70" + }, + "TMP": { + "ACO": "9.3", + "AJU": "2.5", + "MON": "13.9", + "CHO": "", + "CUA": "10.9", + "CUT": "8.4", + "FAC": "8.5", + "HGM": "13.2", + "MER": "13.1", + "NEZ": "13.8", + "PED": "10.9", + "SAG": "13.7", + "SFE": "", + "TAH": "9.3", + "TLA": "12.2", + "UAX": "10", + "UIZ": "12.7", + "VIF": "9.4", + "XAL": "", + "MGH": "", + "AJM": "7.2", + "MPA": "", + "BJU": "12.2", + "INN": "3.2", + "GAM": "13.3", + "LAA": "12.5" + }, + "WDR": { + "ACO": "319", + "AJU": "36", + "MON": "177", + "CHO": "", + "CUA": "258", + "CUT": "246", + "FAC": "245", + "HGM": "43", + "MER": "178", + "NEZ": "156", + "PED": "227", + "SAG": "247", + "SFE": "", + "TAH": "9", + "TLA": "347", + "UAX": "139", + "UIZ": "168", + "VIF": "269", + "XAL": "", + "MGH": "", + "AJM": "", + "MPA": "155", + "BJU": "170", + "INN": "105", + "GAM": "66", + "LAA": "58", + "FAR": "159", + "SAC": "141" + }, + "WSP": { + "ACO": "1.3", + "AJU": "2.4", + "MON": "1.8", + "CHO": "", + "CUA": "1.7", + "CUT": "1.4", + "FAC": "0.8", + "HGM": "1.4", + "MER": "0.9", + "NEZ": "2.2", + "PED": "1.9", + "SAG": "0", + "SFE": "", + "TAH": "0.3", + "TLA": "0.9", + "UAX": "1.3", + "UIZ": "0.6", + "VIF": "0", + "XAL": "", + "MGH": "", + "AJM": "", + "MPA": "3.1", + "BJU": "0.8", + "INN": "0.5", + "GAM": "0.3", + "LAA": "0.6", + "FAR": "1.4", + "SAC": "2.4" + }, + "PBa": { "MER": "" }, + "2023-01-01 02:00": { + "RH": { + "ACO": "85", + "AJU": "100", + "MON": "63", + "CHO": "", + "CUA": "67", + "CUT": "73", + "FAC": "78", + "HGM": "61", + "MER": "67", + "NEZ": "60", + "PED": "58", + "SAG": "79", + "SFE": "", + "TAH": "67", + "TLA": "62", + "UAX": "73", + "UIZ": "75", + "VIF": "72", + "XAL": "", + "MGH": "", + "AJM": "61", + "MPA": "73", + "BJU": "67", + "INN": "87", + "GAM": "69", + "LAA": "74" + }, + "TMP": { + "ACO": "8.2", + "AJU": "3.1", + "MON": "11.7", + "CHO": "", + "CUA": "10.6", + "CUT": "7.9", + "FAC": "7.2", + "HGM": "12.4", + "MER": "12.8", + "NEZ": "13.1", + "PED": "10.8", + "SAG": "12.7", + "SFE": "", + "TAH": "8.9", + "TLA": "11.1", + "UAX": "9.6", + "UIZ": "12.1", + "VIF": "8.5", + "XAL": "", + "MGH": "", + "AJM": "6.7", + "MPA": "", + "BJU": "11.7", + "INN": "3.2", + "GAM": "13", + "LAA": "11.6" + }, + "WDR": { + "ACO": "355", + "AJU": "6", + "MON": "49", + "CHO": "", + "CUA": "265", + "CUT": "223", + "FAC": "235", + "HGM": "39", + "MER": "208", + "NEZ": "205", + "PED": "212", + "SAG": "92", + "SFE": "", + "TAH": "288", + "TLA": "318", + "UAX": "184", + "UIZ": "196", + "VIF": "312", + "XAL": "", + "MGH": "", + "AJM": "", + "MPA": "165", + "BJU": "169", + "INN": "66", + "GAM": "37", + "LAA": "277", + "FAR": "59", + "SAC": "153" + }, + "WSP": { + "ACO": "1.3", + "AJU": "1.7", + "MON": "1.1", + "CHO": "", + "CUA": "2.4", + "CUT": "1.4", + "FAC": "1", + "HGM": "0.7", + "MER": "1.1", + "NEZ": "0.9", + "PED": "2.1", + "SAG": "0.1", + "SFE": "", + "TAH": "1.3", + "TLA": "1.3", + "UAX": "0.8", + "UIZ": "0.8", + "VIF": "0", + "XAL": "", + "MGH": "", + "AJM": "", + "MPA": "2", + "BJU": "0.9", + "INN": "0.2", + "GAM": "0", + "LAA": "0.2", + "FAR": "1.1", + "SAC": "1.7" + }, + "PBa": { "MER": "" } + } + } + } + } +} diff --git a/package-lock.json b/package-lock.json index 94737ae..75f04d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,14 +8,18 @@ "name": "formularios_front", "version": "0.1.0", "dependencies": { + "@yudiel/react-qr-scanner": "^2.2.1", + "axios": "^1.8.4", "bootstrap": "^5.3.3", "bootstrap-icons": "^1.11.3", "next": "15.2.4", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-hot-toast": "^2.5.2" }, "devDependencies": { "@eslint/eslintrc": "^3", + "@types/bootstrap": "^5.2.10", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", @@ -1157,7 +1161,6 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", - "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -1203,6 +1206,22 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/bootstrap": { + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/@types/bootstrap/-/bootstrap-5.2.10.tgz", + "integrity": "sha512-F2X+cd6551tep0MvVZ6nM8v7XgGN/twpdNDjqS1TUM7YFNEtQYWk+dKAnH+T1gr6QgCoGMPl487xw/9hXooa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@popperjs/core": "^2.9.2" + } + }, + "node_modules/@types/emscripten": { + "version": "1.40.1", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.40.1.tgz", + "integrity": "sha512-sr53lnYkQNhjHNN0oJDdUm5564biioI5DuOpycufDVK7D3y+GR3oUswe2rlwY1nPNyusHbrJ9WoTyIHl4/Bpwg==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -1703,6 +1722,20 @@ "win32" ] }, + "node_modules/@yudiel/react-qr-scanner": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@yudiel/react-qr-scanner/-/react-qr-scanner-2.2.1.tgz", + "integrity": "sha512-5tmzoi9d8mqqaxKTxfI9kulS3N3Kph75AOqwU2lnl4IMwjmLcTXS8IyecDUvzFNuoMNhCpofrqqGueXm8IXkjA==", + "license": "MIT", + "dependencies": { + "barcode-detector": "^3.0.0", + "webrtc-adapter": "9.0.1" + }, + "peerDependencies": { + "react": "^17 || ^18 || ^19", + "react-dom": "^17 || ^18 || ^19" + } + }, "node_modules/acorn": { "version": "8.14.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", @@ -1951,6 +1984,12 @@ "node": ">= 0.4" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -1977,6 +2016,17 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", + "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -1994,6 +2044,15 @@ "dev": true, "license": "MIT" }, + "node_modules/barcode-detector": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/barcode-detector/-/barcode-detector-3.0.1.tgz", + "integrity": "sha512-3fCzG/Py4SVgZJhubD1mt7rVprtHEVWrxQN4FUOG0oulPE4193evbgyptxcOYsfTNEtMlWc+Ec9tdxhjlR4/Ww==", + "license": "MIT", + "dependencies": { + "zxing-wasm": "^2.1.0" + } + }, "node_modules/bootstrap": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", @@ -2087,7 +2146,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2228,6 +2286,18 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2254,7 +2324,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -2379,6 +2448,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-libc": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", @@ -2406,7 +2484,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -2494,7 +2571,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2504,7 +2580,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2542,7 +2617,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -2555,7 +2629,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -3162,6 +3235,26 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -3178,11 +3271,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3223,7 +3330,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -3248,7 +3354,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -3332,11 +3437,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/goober": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/goober/-/goober-2.1.16.tgz", + "integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==", + "license": "MIT", + "peerDependencies": { + "csstype": "^3.0.10" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3408,7 +3521,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3421,7 +3533,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -3437,7 +3548,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -4086,7 +4196,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -4116,6 +4225,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4543,6 +4673,12 @@ "react-is": "^16.13.1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -4595,6 +4731,23 @@ "react": "^19.1.0" } }, + "node_modules/react-hot-toast": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.5.2.tgz", + "integrity": "sha512-Tun3BbCxzmXXM7C+NI4qiv6lT0uwGh4oAfeJyNOjYUejTsm35mK9iCaYLGv8cBz9L5YxZLx/2ii7zsIwPtPUdw==", + "license": "MIT", + "dependencies": { + "csstype": "^3.1.3", + "goober": "^2.1.16" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": ">=16", + "react-dom": ">=16" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -4818,6 +4971,12 @@ "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", "license": "MIT" }, + "node_modules/sdp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz", + "integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==", + "license": "MIT" + }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", @@ -5341,6 +5500,18 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "4.39.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.39.1.tgz", + "integrity": "sha512-uW9qzd66uyHYxwyVBYiwS4Oi0qZyUqwjU+Oevr6ZogYiXt99EOYtwvzMSLw1c3lYo2HzJsep/NB23iEVEgjG/w==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -5496,6 +5667,19 @@ "punycode": "^2.1.0" } }, + "node_modules/webrtc-adapter": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-9.0.1.tgz", + "integrity": "sha512-1AQO+d4ElfVSXyzNVTOewgGT/tAomwwztX/6e3totvyyzXPvXIIuUUjAmyZGbKBKbZOXauuJooZm3g6IuFuiNQ==", + "license": "BSD-3-Clause", + "dependencies": { + "sdp": "^3.2.0" + }, + "engines": { + "node": ">=6.0.0", + "npm": ">=3.10.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5623,6 +5807,19 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zxing-wasm": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/zxing-wasm/-/zxing-wasm-2.1.0.tgz", + "integrity": "sha512-CvuwDZHRHwg6PeCARaCDIp3dauD4cin0mbHrQQZtMDrr5mblPzCimAjdw/XMhD/Au10q/f5+SAupvYqYvUOg1Q==", + "license": "MIT", + "dependencies": { + "@types/emscripten": "^1.40.0", + "type-fest": "^4.35.0" + }, + "peerDependencies": { + "@types/emscripten": ">=1.39.6" + } } } } diff --git a/package.json b/package.json index a52fe6b..b0ba5d4 100644 --- a/package.json +++ b/package.json @@ -9,14 +9,18 @@ "lint": "next lint" }, "dependencies": { + "@yudiel/react-qr-scanner": "^2.2.1", + "axios": "^1.8.4", "bootstrap": "^5.3.3", "bootstrap-icons": "^1.11.3", "next": "15.2.4", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "react-hot-toast": "^2.5.2" }, "devDependencies": { "@eslint/eslintrc": "^3", + "@types/bootstrap": "^5.2.10", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", diff --git a/public/banner1.png b/public/banner1.png new file mode 100644 index 0000000..fea378a Binary files /dev/null and b/public/banner1.png differ diff --git a/public/banner2.png b/public/banner2.png new file mode 100644 index 0000000..5f83af9 Binary files /dev/null and b/public/banner2.png differ diff --git a/src/app/(admins)/administrador/crear-formulario/page.tsx b/src/app/(admins)/administrador/crear-formulario/page.tsx new file mode 100644 index 0000000..56ea72e --- /dev/null +++ b/src/app/(admins)/administrador/crear-formulario/page.tsx @@ -0,0 +1,585 @@ +'use client'; +import React, { useState } from 'react'; +import Pagination from '@/components/pagination'; +import Image from 'next/image'; +import axiosInstance from '@/utils/api-config'; +import Select from '@/components/select'; +import Input from '@/components/input'; +import Button from '@/components/button'; +import FloatingInput from '@/components/floating-input'; +import { plantillasDisponibles } from '@/data/plantillas'; +import { + FormularioCreacion, + PreguntaFormulario, + SeccionFormulario, +} from '@/types/crear-formulario'; +import toast from 'react-hot-toast'; + +export default function AdminFormPage() { + const [nombreFormulario, setNombreFormulario] = useState(''); + const [descripcion, setDescripcion] = useState(''); + const [secciones, setSecciones] = useState([]); + const [paginaActual, setPaginaActual] = useState(1); + const [bannerPreview, setBannerPreview] = useState(null); + const [tipoCuestionario, setTipoCuestionario] = useState(null); + const [fechaInicio, setFechaInicio] = useState(null); + const [fechaFin, setFechaFin] = useState(null); + const [loading, setLoading] = useState(false); + + const swapItems = (arr: T[], index1: number, index2: number): T[] => { + const result = [...arr]; + [result[index1], result[index2]] = [result[index2], result[index1]]; + return result; + }; + + const moverSeccion = (from: number, to: number) => { + if (to >= 0 && to < secciones.length) { + setSecciones((prev) => swapItems(prev, from, to)); + setPaginaActual(to + 1); + } + }; + + const moverPregunta = (seccionIndex: number, from: number, to: number) => { + const nuevas = [...secciones]; + const preguntas = nuevas[seccionIndex].preguntas; + if (to >= 0 && to < preguntas.length) { + nuevas[seccionIndex].preguntas = swapItems(preguntas, from, to); + setSecciones(nuevas); + } + }; + + const agregarSeccion = () => { + setSecciones((prev) => [ + ...prev, + { titulo: '', descripcion: '', preguntas: [] }, + ]); + setPaginaActual(secciones.length + 1); + }; + + const eliminarSeccion = (index: number) => { + const nuevas = secciones.filter((_, i) => i !== index); + setSecciones(nuevas); + setPaginaActual((prev) => + Math.max(1, prev > nuevas.length ? nuevas.length : prev) + ); + }; + + const actualizarSeccion = ( + index: number, + campo: K, + valor: SeccionFormulario[K] + ) => { + setSecciones((prev) => { + const nuevas = [...prev]; + nuevas[index][campo] = valor; + return nuevas; + }); + }; + + const agregarPregunta = (seccionIndex: number) => { + const nuevas = [...secciones]; + nuevas[seccionIndex].preguntas.push({ + titulo: '', + tipo: 'Abierta', + opciones: [], + obligatoria: false, + limite: 250, + validacion: undefined, + }); + setSecciones(nuevas); + }; + + const eliminarPregunta = (seccionIndex: number, preguntaIndex: number) => { + const nuevas = [...secciones]; + nuevas[seccionIndex].preguntas.splice(preguntaIndex, 1); + setSecciones(nuevas); + }; + + const actualizarPregunta = ( + seccionIndex: number, + preguntaIndex: number, + campo: keyof PreguntaFormulario, + valor: PreguntaFormulario[keyof PreguntaFormulario] + ) => { + setSecciones((prev) => { + const nuevas = [...prev]; + const pregunta = nuevas[seccionIndex].preguntas[preguntaIndex]; + nuevas[seccionIndex].preguntas[preguntaIndex] = { + ...pregunta, + [campo]: valor, + }; + return nuevas; + }); + }; + + const agregarOpcion = (seccionIndex: number, preguntaIndex: number) => { + const nuevas = [...secciones]; + if (nuevas[seccionIndex]?.preguntas[preguntaIndex]?.opciones) { + nuevas[seccionIndex].preguntas[preguntaIndex].opciones!.push({ + valor: '', + }); + } + setSecciones(nuevas); + }; + + const eliminarOpcion = ( + seccionIndex: number, + preguntaIndex: number, + opcionIndex: number + ) => { + const nuevas = [...secciones]; + nuevas[seccionIndex]?.preguntas[preguntaIndex]?.opciones?.splice( + opcionIndex, + 1 + ); + setSecciones(nuevas); + }; + + const actualizarOpcion = ( + seccionIndex: number, + preguntaIndex: number, + opcionIndex: number, + valor: string + ) => { + const nuevas = [...secciones]; + if ( + nuevas[seccionIndex]?.preguntas[preguntaIndex]?.opciones && + nuevas[seccionIndex].preguntas[preguntaIndex].opciones![opcionIndex] + ) { + nuevas[seccionIndex].preguntas[preguntaIndex].opciones![ + opcionIndex + ].valor = valor; + } + setSecciones(nuevas); + }; + + const guardarFormulario = async () => { + if (!fechaInicio || !fechaFin || !tipoCuestionario) { + alert('Todos los campos obligatorios deben estar llenos'); + return; + } + + const formatearFecha = (fecha: string, tipo: 'inicio' | 'fin'): string => { + const sufijo = tipo === 'inicio' ? 'T00:00:01' : 'T23:59:59'; + return `${fecha}${sufijo}`; + }; + + const formData: FormularioCreacion = { + nombre_form: nombreFormulario, + descripcion, + fecha_inicio: formatearFecha(fechaInicio, 'inicio'), + fecha_fin: formatearFecha(fechaFin, 'fin'), + id_tipo_cuestionario: tipoCuestionario, + evento: nombreFormulario, // temporalmente igual al nombre del form + secciones, + }; + + console.log('Formulario a guardar:', formData); + + setLoading(true); + await toast + .promise(axiosInstance.post('/cuestionario', formData), { + loading: 'Guardando formulario...', + success: 'Formulario guardado exitosamente!', + error: 'Error al guardar el formulario.', + }) + .then((res) => { + console.log('Formulario guardado:', res.data); + }) + .catch((error) => { + console.error('Error al guardar el formulario:', error); + }) + .finally(() => { + setLoading(false); + }); + }; + + const handleBannerChange = (e: React.ChangeEvent) => { + const file = e.target.files?.[0] || null; + if (file) { + const reader = new FileReader(); + reader.onload = () => setBannerPreview(reader.result as string); + reader.readAsDataURL(file); + } else { + setBannerPreview(null); + } + }; + + const seccionActual = secciones[paginaActual - 1]; + + return ( + <> +

Crear nuevo formulario

+ +
+ {secciones.length === 0 && + plantillasDisponibles.map((plantilla, index) => ( +
+

Plantillas

+
{ + const { + nombre_form, + descripcion, + fecha_inicio, + fecha_fin, + id_tipo_cuestionario, + secciones, + } = plantilla.datos; + setNombreFormulario(nombre_form); + setDescripcion(descripcion); + setFechaInicio(fecha_inicio.slice(0, 10)); + setFechaFin(fecha_fin.slice(0, 10)); + setTipoCuestionario(id_tipo_cuestionario); + setSecciones( + secciones.map((seccion) => ({ + ...seccion, + preguntas: seccion.preguntas.map((pregunta) => ({ + ...pregunta, + tipo: pregunta.tipo as + | 'Abierta' + | 'Cerrada' + | 'Multiple', + })), + })) + ); + setPaginaActual(1); + }} + > + {`Plantilla +
+
+ ))} +
+ +
+ + + {bannerPreview && ( +
+ Ejemplo de banner +
+ )} +
+ + setNombreFormulario(e.target.value)} + placeholder="Ingrese el nombre del formulario" + /> + +
+ +