Compare commits
	
		
			3 Commits
		
	
	
		
			12860f2406
			...
			f961f9d8e7
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f961f9d8e7 | |||
| da581d9714 | |||
| 271a86b632 | 
							
								
								
									
										506
									
								
								Elecciones-Web/frontend-admin/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										506
									
								
								Elecciones-Web/frontend-admin/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -13,12 +13,14 @@ | |||||||
|         "@tanstack/react-query": "^5.85.5", |         "@tanstack/react-query": "^5.85.5", | ||||||
|         "axios": "^1.11.0", |         "axios": "^1.11.0", | ||||||
|         "react": "^19.1.1", |         "react": "^19.1.1", | ||||||
|         "react-dom": "^19.1.1" |         "react-dom": "^19.1.1", | ||||||
|  |         "react-select": "^5.10.2" | ||||||
|       }, |       }, | ||||||
|       "devDependencies": { |       "devDependencies": { | ||||||
|         "@eslint/js": "^9.33.0", |         "@eslint/js": "^9.33.0", | ||||||
|         "@types/react": "^19.1.10", |         "@types/react": "^19.1.10", | ||||||
|         "@types/react-dom": "^19.1.7", |         "@types/react-dom": "^19.1.7", | ||||||
|  |         "@types/react-select": "^5.0.0", | ||||||
|         "@vitejs/plugin-react": "^5.0.0", |         "@vitejs/plugin-react": "^5.0.0", | ||||||
|         "eslint": "^9.33.0", |         "eslint": "^9.33.0", | ||||||
|         "eslint-plugin-react-hooks": "^5.2.0", |         "eslint-plugin-react-hooks": "^5.2.0", | ||||||
| @@ -47,7 +49,6 @@ | |||||||
|       "version": "7.27.1", |       "version": "7.27.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", |       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", | ||||||
|       "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", |       "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/helper-validator-identifier": "^7.27.1", |         "@babel/helper-validator-identifier": "^7.27.1", | ||||||
| @@ -103,7 +104,6 @@ | |||||||
|       "version": "7.28.3", |       "version": "7.28.3", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", |       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", | ||||||
|       "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", |       "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/parser": "^7.28.3", |         "@babel/parser": "^7.28.3", | ||||||
| @@ -137,7 +137,6 @@ | |||||||
|       "version": "7.28.0", |       "version": "7.28.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", | ||||||
|       "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", |       "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
| @@ -147,7 +146,6 @@ | |||||||
|       "version": "7.27.1", |       "version": "7.27.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", | ||||||
|       "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", |       "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/traverse": "^7.27.1", |         "@babel/traverse": "^7.27.1", | ||||||
| @@ -189,7 +187,6 @@ | |||||||
|       "version": "7.27.1", |       "version": "7.27.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", | ||||||
|       "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", |       "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
| @@ -199,7 +196,6 @@ | |||||||
|       "version": "7.27.1", |       "version": "7.27.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", | ||||||
|       "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", |       "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
| @@ -233,7 +229,6 @@ | |||||||
|       "version": "7.28.3", |       "version": "7.28.3", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", |       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", | ||||||
|       "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", |       "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/types": "^7.28.2" |         "@babel/types": "^7.28.2" | ||||||
| @@ -277,11 +272,19 @@ | |||||||
|         "@babel/core": "^7.0.0-0" |         "@babel/core": "^7.0.0-0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@babel/runtime": { | ||||||
|  |       "version": "7.28.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", | ||||||
|  |       "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=6.9.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@babel/template": { |     "node_modules/@babel/template": { | ||||||
|       "version": "7.27.2", |       "version": "7.27.2", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", |       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", | ||||||
|       "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", |       "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/code-frame": "^7.27.1", |         "@babel/code-frame": "^7.27.1", | ||||||
| @@ -296,7 +299,6 @@ | |||||||
|       "version": "7.28.3", |       "version": "7.28.3", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", |       "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", | ||||||
|       "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", |       "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/code-frame": "^7.27.1", |         "@babel/code-frame": "^7.27.1", | ||||||
| @@ -315,7 +317,6 @@ | |||||||
|       "version": "7.28.2", |       "version": "7.28.2", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", |       "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", | ||||||
|       "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", |       "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/helper-string-parser": "^7.27.1", |         "@babel/helper-string-parser": "^7.27.1", | ||||||
| @@ -378,6 +379,126 @@ | |||||||
|         "react": ">=16.8.0" |         "react": ">=16.8.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@emotion/babel-plugin": { | ||||||
|  |       "version": "11.13.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", | ||||||
|  |       "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/helper-module-imports": "^7.16.7", | ||||||
|  |         "@babel/runtime": "^7.18.3", | ||||||
|  |         "@emotion/hash": "^0.9.2", | ||||||
|  |         "@emotion/memoize": "^0.9.0", | ||||||
|  |         "@emotion/serialize": "^1.3.3", | ||||||
|  |         "babel-plugin-macros": "^3.1.0", | ||||||
|  |         "convert-source-map": "^1.5.0", | ||||||
|  |         "escape-string-regexp": "^4.0.0", | ||||||
|  |         "find-root": "^1.1.0", | ||||||
|  |         "source-map": "^0.5.7", | ||||||
|  |         "stylis": "4.2.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { | ||||||
|  |       "version": "1.9.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", | ||||||
|  |       "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/cache": { | ||||||
|  |       "version": "11.14.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", | ||||||
|  |       "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@emotion/memoize": "^0.9.0", | ||||||
|  |         "@emotion/sheet": "^1.4.0", | ||||||
|  |         "@emotion/utils": "^1.4.2", | ||||||
|  |         "@emotion/weak-memoize": "^0.4.0", | ||||||
|  |         "stylis": "4.2.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/hash": { | ||||||
|  |       "version": "0.9.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", | ||||||
|  |       "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/memoize": { | ||||||
|  |       "version": "0.9.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", | ||||||
|  |       "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/react": { | ||||||
|  |       "version": "11.14.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", | ||||||
|  |       "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.18.3", | ||||||
|  |         "@emotion/babel-plugin": "^11.13.5", | ||||||
|  |         "@emotion/cache": "^11.14.0", | ||||||
|  |         "@emotion/serialize": "^1.3.3", | ||||||
|  |         "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", | ||||||
|  |         "@emotion/utils": "^1.4.2", | ||||||
|  |         "@emotion/weak-memoize": "^0.4.0", | ||||||
|  |         "hoist-non-react-statics": "^3.3.1" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": ">=16.8.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "@types/react": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/serialize": { | ||||||
|  |       "version": "1.3.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", | ||||||
|  |       "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@emotion/hash": "^0.9.2", | ||||||
|  |         "@emotion/memoize": "^0.9.0", | ||||||
|  |         "@emotion/unitless": "^0.10.0", | ||||||
|  |         "@emotion/utils": "^1.4.2", | ||||||
|  |         "csstype": "^3.0.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/sheet": { | ||||||
|  |       "version": "1.4.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", | ||||||
|  |       "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/unitless": { | ||||||
|  |       "version": "0.10.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", | ||||||
|  |       "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/use-insertion-effect-with-fallbacks": { | ||||||
|  |       "version": "1.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", | ||||||
|  |       "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": ">=16.8.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/utils": { | ||||||
|  |       "version": "1.4.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", | ||||||
|  |       "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/weak-memoize": { | ||||||
|  |       "version": "0.4.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", | ||||||
|  |       "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/@esbuild/aix-ppc64": { |     "node_modules/@esbuild/aix-ppc64": { | ||||||
|       "version": "0.25.9", |       "version": "0.25.9", | ||||||
|       "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", |       "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", | ||||||
| @@ -974,6 +1095,31 @@ | |||||||
|         "node": "^18.18.0 || ^20.9.0 || >=21.1.0" |         "node": "^18.18.0 || ^20.9.0 || >=21.1.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@floating-ui/core": { | ||||||
|  |       "version": "1.7.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", | ||||||
|  |       "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@floating-ui/utils": "^0.2.10" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@floating-ui/dom": { | ||||||
|  |       "version": "1.7.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", | ||||||
|  |       "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@floating-ui/core": "^1.7.3", | ||||||
|  |         "@floating-ui/utils": "^0.2.10" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@floating-ui/utils": { | ||||||
|  |       "version": "0.2.10", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", | ||||||
|  |       "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/@humanfs/core": { |     "node_modules/@humanfs/core": { | ||||||
|       "version": "0.19.1", |       "version": "0.19.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", |       "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", | ||||||
| @@ -1044,7 +1190,6 @@ | |||||||
|       "version": "0.3.13", |       "version": "0.3.13", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", | ||||||
|       "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", |       "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@jridgewell/sourcemap-codec": "^1.5.0", |         "@jridgewell/sourcemap-codec": "^1.5.0", | ||||||
| @@ -1055,7 +1200,6 @@ | |||||||
|       "version": "3.1.2", |       "version": "3.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", | ||||||
|       "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", |       "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.0.0" |         "node": ">=6.0.0" | ||||||
| @@ -1065,14 +1209,12 @@ | |||||||
|       "version": "1.5.5", |       "version": "1.5.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", | ||||||
|       "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", |       "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/@jridgewell/trace-mapping": { |     "node_modules/@jridgewell/trace-mapping": { | ||||||
|       "version": "0.3.30", |       "version": "0.3.30", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", | ||||||
|       "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", |       "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@jridgewell/resolve-uri": "^3.1.0", |         "@jridgewell/resolve-uri": "^3.1.0", | ||||||
| @@ -1489,11 +1631,16 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/parse-json": { | ||||||
|  |       "version": "4.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", | ||||||
|  |       "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/@types/react": { |     "node_modules/@types/react": { | ||||||
|       "version": "19.1.11", |       "version": "19.1.11", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.11.tgz", |       "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.11.tgz", | ||||||
|       "integrity": "sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ==", |       "integrity": "sha512-lr3jdBw/BGj49Eps7EvqlUaoeA0xpj3pc0RoJkHpYaCHkVK7i28dKyImLQb3JVlqs3aYSXf7qYuWOW/fgZnTXQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "csstype": "^3.0.2" |         "csstype": "^3.0.2" | ||||||
| @@ -1509,6 +1656,25 @@ | |||||||
|         "@types/react": "^19.0.0" |         "@types/react": "^19.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/react-select": { | ||||||
|  |       "version": "5.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-5.0.0.tgz", | ||||||
|  |       "integrity": "sha512-vddLcBpzUMVpVNmnBtpC5cyZ2ajaHx/g6SHUo6lmMw0FIiOzrtmoSQ4UI6TRl+sm8TGGT+Oir8NRMZfYQtgr8Q==", | ||||||
|  |       "dev": true, | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "react-select": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@types/react-transition-group": { | ||||||
|  |       "version": "4.4.12", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", | ||||||
|  |       "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "@types/react": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@typescript-eslint/eslint-plugin": { |     "node_modules/@typescript-eslint/eslint-plugin": { | ||||||
|       "version": "8.41.0", |       "version": "8.41.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.41.0.tgz", |       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.41.0.tgz", | ||||||
| @@ -1881,6 +2047,21 @@ | |||||||
|         "proxy-from-env": "^1.1.0" |         "proxy-from-env": "^1.1.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/babel-plugin-macros": { | ||||||
|  |       "version": "3.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", | ||||||
|  |       "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.12.5", | ||||||
|  |         "cosmiconfig": "^7.0.0", | ||||||
|  |         "resolve": "^1.19.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=10", | ||||||
|  |         "npm": ">=6" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/balanced-match": { |     "node_modules/balanced-match": { | ||||||
|       "version": "1.0.2", |       "version": "1.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", | ||||||
| @@ -1962,7 +2143,6 @@ | |||||||
|       "version": "3.1.0", |       "version": "3.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", |       "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", | ||||||
|       "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", |       "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6" |         "node": ">=6" | ||||||
| @@ -2052,6 +2232,31 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/cosmiconfig": { | ||||||
|  |       "version": "7.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", | ||||||
|  |       "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@types/parse-json": "^4.0.0", | ||||||
|  |         "import-fresh": "^3.2.1", | ||||||
|  |         "parse-json": "^5.0.0", | ||||||
|  |         "path-type": "^4.0.0", | ||||||
|  |         "yaml": "^1.10.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=10" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/cosmiconfig/node_modules/yaml": { | ||||||
|  |       "version": "1.10.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", | ||||||
|  |       "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", | ||||||
|  |       "license": "ISC", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 6" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/cross-spawn": { |     "node_modules/cross-spawn": { | ||||||
|       "version": "7.0.6", |       "version": "7.0.6", | ||||||
|       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", |       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", | ||||||
| @@ -2071,14 +2276,12 @@ | |||||||
|       "version": "3.1.3", |       "version": "3.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", |       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", | ||||||
|       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", |       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/debug": { |     "node_modules/debug": { | ||||||
|       "version": "4.4.1", |       "version": "4.4.1", | ||||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", |       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", | ||||||
|       "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", |       "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "ms": "^2.1.3" |         "ms": "^2.1.3" | ||||||
| @@ -2108,6 +2311,16 @@ | |||||||
|         "node": ">=0.4.0" |         "node": ">=0.4.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/dom-helpers": { | ||||||
|  |       "version": "5.2.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", | ||||||
|  |       "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.8.7", | ||||||
|  |         "csstype": "^3.0.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/dunder-proto": { |     "node_modules/dunder-proto": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", | ||||||
| @@ -2129,6 +2342,15 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "ISC" |       "license": "ISC" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/error-ex": { | ||||||
|  |       "version": "1.3.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", | ||||||
|  |       "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "is-arrayish": "^0.2.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/es-define-property": { |     "node_modules/es-define-property": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", | ||||||
| @@ -2230,7 +2452,6 @@ | |||||||
|       "version": "4.0.0", |       "version": "4.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", | ||||||
|       "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", |       "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=10" |         "node": ">=10" | ||||||
| @@ -2504,6 +2725,12 @@ | |||||||
|         "node": ">=8" |         "node": ">=8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/find-root": { | ||||||
|  |       "version": "1.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", | ||||||
|  |       "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/find-up": { |     "node_modules/find-up": { | ||||||
|       "version": "5.0.0", |       "version": "5.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", |       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", | ||||||
| @@ -2743,6 +2970,15 @@ | |||||||
|         "node": ">= 0.4" |         "node": ">= 0.4" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/hoist-non-react-statics": { | ||||||
|  |       "version": "3.3.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", | ||||||
|  |       "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", | ||||||
|  |       "license": "BSD-3-Clause", | ||||||
|  |       "dependencies": { | ||||||
|  |         "react-is": "^16.7.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/ignore": { |     "node_modules/ignore": { | ||||||
|       "version": "5.3.2", |       "version": "5.3.2", | ||||||
|       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", |       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", | ||||||
| @@ -2757,7 +2993,6 @@ | |||||||
|       "version": "3.3.1", |       "version": "3.3.1", | ||||||
|       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", |       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", | ||||||
|       "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", |       "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "parent-module": "^1.0.0", |         "parent-module": "^1.0.0", | ||||||
| @@ -2780,6 +3015,27 @@ | |||||||
|         "node": ">=0.8.19" |         "node": ">=0.8.19" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/is-arrayish": { | ||||||
|  |       "version": "0.2.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", | ||||||
|  |       "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/is-core-module": { | ||||||
|  |       "version": "2.16.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", | ||||||
|  |       "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "hasown": "^2.0.2" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 0.4" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/ljharb" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/is-extglob": { |     "node_modules/is-extglob": { | ||||||
|       "version": "2.1.1", |       "version": "2.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", |       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", | ||||||
| @@ -2824,7 +3080,6 @@ | |||||||
|       "version": "4.0.0", |       "version": "4.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", | ||||||
|       "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", |       "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/js-yaml": { |     "node_modules/js-yaml": { | ||||||
| @@ -2844,7 +3099,6 @@ | |||||||
|       "version": "3.1.0", |       "version": "3.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", |       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", | ||||||
|       "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", |       "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "bin": { |       "bin": { | ||||||
|         "jsesc": "bin/jsesc" |         "jsesc": "bin/jsesc" | ||||||
| @@ -2860,6 +3114,12 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/json-parse-even-better-errors": { | ||||||
|  |       "version": "2.3.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", | ||||||
|  |       "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/json-schema-traverse": { |     "node_modules/json-schema-traverse": { | ||||||
|       "version": "0.4.1", |       "version": "0.4.1", | ||||||
|       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", |       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", | ||||||
| @@ -2911,6 +3171,12 @@ | |||||||
|         "node": ">= 0.8.0" |         "node": ">= 0.8.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/lines-and-columns": { | ||||||
|  |       "version": "1.2.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", | ||||||
|  |       "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/locate-path": { |     "node_modules/locate-path": { | ||||||
|       "version": "6.0.0", |       "version": "6.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", |       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", | ||||||
| @@ -2934,6 +3200,18 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/loose-envify": { | ||||||
|  |       "version": "1.4.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", | ||||||
|  |       "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "js-tokens": "^3.0.0 || ^4.0.0" | ||||||
|  |       }, | ||||||
|  |       "bin": { | ||||||
|  |         "loose-envify": "cli.js" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/lru-cache": { |     "node_modules/lru-cache": { | ||||||
|       "version": "5.1.1", |       "version": "5.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", |       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", | ||||||
| @@ -2953,6 +3231,12 @@ | |||||||
|         "node": ">= 0.4" |         "node": ">= 0.4" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/memoize-one": { | ||||||
|  |       "version": "6.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", | ||||||
|  |       "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/merge2": { |     "node_modules/merge2": { | ||||||
|       "version": "1.4.1", |       "version": "1.4.1", | ||||||
|       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", |       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", | ||||||
| @@ -3015,7 +3299,6 @@ | |||||||
|       "version": "2.1.3", |       "version": "2.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | ||||||
|       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", |       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/nanoid": { |     "node_modules/nanoid": { | ||||||
| @@ -3051,6 +3334,15 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/object-assign": { | ||||||
|  |       "version": "4.1.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | ||||||
|  |       "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=0.10.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/optionator": { |     "node_modules/optionator": { | ||||||
|       "version": "0.9.4", |       "version": "0.9.4", | ||||||
|       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", |       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", | ||||||
| @@ -3105,7 +3397,6 @@ | |||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", | ||||||
|       "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", |       "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "callsites": "^3.0.0" |         "callsites": "^3.0.0" | ||||||
| @@ -3114,6 +3405,24 @@ | |||||||
|         "node": ">=6" |         "node": ">=6" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/parse-json": { | ||||||
|  |       "version": "5.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", | ||||||
|  |       "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/code-frame": "^7.0.0", | ||||||
|  |         "error-ex": "^1.3.1", | ||||||
|  |         "json-parse-even-better-errors": "^2.3.0", | ||||||
|  |         "lines-and-columns": "^1.1.6" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/sindresorhus" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/path-exists": { |     "node_modules/path-exists": { | ||||||
|       "version": "4.0.0", |       "version": "4.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", | ||||||
| @@ -3134,11 +3443,25 @@ | |||||||
|         "node": ">=8" |         "node": ">=8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/path-parse": { | ||||||
|  |       "version": "1.0.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", | ||||||
|  |       "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/path-type": { | ||||||
|  |       "version": "4.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", | ||||||
|  |       "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/picocolors": { |     "node_modules/picocolors": { | ||||||
|       "version": "1.1.1", |       "version": "1.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", |       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", | ||||||
|       "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", |       "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "ISC" |       "license": "ISC" | ||||||
|     }, |     }, | ||||||
|     "node_modules/picomatch": { |     "node_modules/picomatch": { | ||||||
| @@ -3193,6 +3516,17 @@ | |||||||
|         "node": ">= 0.8.0" |         "node": ">= 0.8.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/prop-types": { | ||||||
|  |       "version": "15.8.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", | ||||||
|  |       "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "loose-envify": "^1.4.0", | ||||||
|  |         "object-assign": "^4.1.1", | ||||||
|  |         "react-is": "^16.13.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/proxy-from-env": { |     "node_modules/proxy-from-env": { | ||||||
|       "version": "1.1.0", |       "version": "1.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", |       "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", | ||||||
| @@ -3251,6 +3585,12 @@ | |||||||
|         "react": "^19.1.1" |         "react": "^19.1.1" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/react-is": { | ||||||
|  |       "version": "16.13.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", | ||||||
|  |       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/react-refresh": { |     "node_modules/react-refresh": { | ||||||
|       "version": "0.17.0", |       "version": "0.17.0", | ||||||
|       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", |       "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", | ||||||
| @@ -3261,11 +3601,67 @@ | |||||||
|         "node": ">=0.10.0" |         "node": ">=0.10.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/react-select": { | ||||||
|  |       "version": "5.10.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.2.tgz", | ||||||
|  |       "integrity": "sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.12.0", | ||||||
|  |         "@emotion/cache": "^11.4.0", | ||||||
|  |         "@emotion/react": "^11.8.1", | ||||||
|  |         "@floating-ui/dom": "^1.0.1", | ||||||
|  |         "@types/react-transition-group": "^4.4.0", | ||||||
|  |         "memoize-one": "^6.0.0", | ||||||
|  |         "prop-types": "^15.6.0", | ||||||
|  |         "react-transition-group": "^4.3.0", | ||||||
|  |         "use-isomorphic-layout-effect": "^1.2.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", | ||||||
|  |         "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/react-transition-group": { | ||||||
|  |       "version": "4.4.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", | ||||||
|  |       "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", | ||||||
|  |       "license": "BSD-3-Clause", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.5.5", | ||||||
|  |         "dom-helpers": "^5.0.1", | ||||||
|  |         "loose-envify": "^1.4.0", | ||||||
|  |         "prop-types": "^15.6.2" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": ">=16.6.0", | ||||||
|  |         "react-dom": ">=16.6.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/resolve": { | ||||||
|  |       "version": "1.22.10", | ||||||
|  |       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", | ||||||
|  |       "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "is-core-module": "^2.16.0", | ||||||
|  |         "path-parse": "^1.0.7", | ||||||
|  |         "supports-preserve-symlinks-flag": "^1.0.0" | ||||||
|  |       }, | ||||||
|  |       "bin": { | ||||||
|  |         "resolve": "bin/resolve" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 0.4" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/ljharb" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/resolve-from": { |     "node_modules/resolve-from": { | ||||||
|       "version": "4.0.0", |       "version": "4.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", | ||||||
|       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", |       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=4" |         "node": ">=4" | ||||||
| @@ -3385,6 +3781,15 @@ | |||||||
|         "node": ">=8" |         "node": ">=8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/source-map": { | ||||||
|  |       "version": "0.5.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", | ||||||
|  |       "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", | ||||||
|  |       "license": "BSD-3-Clause", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=0.10.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/source-map-js": { |     "node_modules/source-map-js": { | ||||||
|       "version": "1.2.1", |       "version": "1.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", |       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", | ||||||
| @@ -3408,6 +3813,12 @@ | |||||||
|         "url": "https://github.com/sponsors/sindresorhus" |         "url": "https://github.com/sponsors/sindresorhus" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/stylis": { | ||||||
|  |       "version": "4.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", | ||||||
|  |       "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/supports-color": { |     "node_modules/supports-color": { | ||||||
|       "version": "7.2.0", |       "version": "7.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", |       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", | ||||||
| @@ -3421,6 +3832,18 @@ | |||||||
|         "node": ">=8" |         "node": ">=8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/supports-preserve-symlinks-flag": { | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", | ||||||
|  |       "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 0.4" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/ljharb" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/tinyglobby": { |     "node_modules/tinyglobby": { | ||||||
|       "version": "0.2.14", |       "version": "0.2.14", | ||||||
|       "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", |       "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", | ||||||
| @@ -3593,6 +4016,20 @@ | |||||||
|         "punycode": "^2.1.0" |         "punycode": "^2.1.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/use-isomorphic-layout-effect": { | ||||||
|  |       "version": "1.2.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", | ||||||
|  |       "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "@types/react": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/vite": { |     "node_modules/vite": { | ||||||
|       "version": "7.1.3", |       "version": "7.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", |       "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", | ||||||
| @@ -3732,6 +4169,21 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "ISC" |       "license": "ISC" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/yaml": { | ||||||
|  |       "version": "2.8.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", | ||||||
|  |       "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", | ||||||
|  |       "dev": true, | ||||||
|  |       "license": "ISC", | ||||||
|  |       "optional": true, | ||||||
|  |       "peer": true, | ||||||
|  |       "bin": { | ||||||
|  |         "yaml": "bin.mjs" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 14.6" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/yocto-queue": { |     "node_modules/yocto-queue": { | ||||||
|       "version": "0.1.0", |       "version": "0.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", |       "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", | ||||||
|   | |||||||
| @@ -15,12 +15,14 @@ | |||||||
|     "@tanstack/react-query": "^5.85.5", |     "@tanstack/react-query": "^5.85.5", | ||||||
|     "axios": "^1.11.0", |     "axios": "^1.11.0", | ||||||
|     "react": "^19.1.1", |     "react": "^19.1.1", | ||||||
|     "react-dom": "^19.1.1" |     "react-dom": "^19.1.1", | ||||||
|  |     "react-select": "^5.10.2" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@eslint/js": "^9.33.0", |     "@eslint/js": "^9.33.0", | ||||||
|     "@types/react": "^19.1.10", |     "@types/react": "^19.1.10", | ||||||
|     "@types/react-dom": "^19.1.7", |     "@types/react-dom": "^19.1.7", | ||||||
|  |     "@types/react-select": "^5.0.0", | ||||||
|     "@vitejs/plugin-react": "^5.0.0", |     "@vitejs/plugin-react": "^5.0.0", | ||||||
|     "eslint": "^9.33.0", |     "eslint": "^9.33.0", | ||||||
|     "eslint-plugin-react-hooks": "^5.2.0", |     "eslint-plugin-react-hooks": "^5.2.0", | ||||||
|   | |||||||
| @@ -52,11 +52,22 @@ export const AgrupacionesManager = () => { | |||||||
|     const handleLogoChange = (agrupacionId: string, categoriaId: number, value: string) => { |     const handleLogoChange = (agrupacionId: string, categoriaId: number, value: string) => { | ||||||
|         setEditedLogos(prev => { |         setEditedLogos(prev => { | ||||||
|             const newLogos = [...prev]; |             const newLogos = [...prev]; | ||||||
|             const existing = newLogos.find(l => l.agrupacionPoliticaId === agrupacionId && l.categoriaId === categoriaId); |             const existing = newLogos.find(l => | ||||||
|  |                 l.agrupacionPoliticaId === agrupacionId && | ||||||
|  |                 l.categoriaId === categoriaId && | ||||||
|  |                 l.ambitoGeograficoId == null | ||||||
|  |             ); | ||||||
|  |  | ||||||
|             if (existing) { |             if (existing) { | ||||||
|                 existing.logoUrl = value; |                 existing.logoUrl = value; | ||||||
|             } else { |             } else { | ||||||
|                 newLogos.push({ id: 0, agrupacionPoliticaId: agrupacionId, categoriaId, logoUrl: value }); |                 newLogos.push({ | ||||||
|  |                     id: 0, | ||||||
|  |                     agrupacionPoliticaId: agrupacionId, | ||||||
|  |                     categoriaId, | ||||||
|  |                     logoUrl: value, | ||||||
|  |                     ambitoGeograficoId: null | ||||||
|  |                 }); | ||||||
|             } |             } | ||||||
|             return newLogos; |             return newLogos; | ||||||
|         }); |         }); | ||||||
| @@ -91,7 +102,11 @@ export const AgrupacionesManager = () => { | |||||||
|     const isLoading = isLoadingAgrupaciones || isLoadingLogos; |     const isLoading = isLoadingAgrupaciones || isLoadingLogos; | ||||||
|  |  | ||||||
|     const getLogoUrl = (agrupacionId: string, categoriaId: number) => { |     const getLogoUrl = (agrupacionId: string, categoriaId: number) => { | ||||||
|         return editedLogos.find(l => l.agrupacionPoliticaId === agrupacionId && l.categoriaId === categoriaId)?.logoUrl || ''; |         return editedLogos.find(l => | ||||||
|  |             l.agrupacionPoliticaId === agrupacionId && | ||||||
|  |             l.categoriaId === categoriaId && | ||||||
|  |             l.ambitoGeograficoId == null | ||||||
|  |         )?.logoUrl || ''; | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     return ( |     return ( | ||||||
|   | |||||||
| @@ -104,11 +104,11 @@ export const ConfiguracionGeneral = () => { | |||||||
|                 </p> |                 </p> | ||||||
|             </div> |             </div> | ||||||
|             <div className="form-group" style={{ marginTop: '2rem' }}> |             <div className="form-group" style={{ marginTop: '2rem' }}> | ||||||
|                 <label htmlFor="ticker-cantidad">Cantidad en Ticker (Dip/Sen)</label> |                 <label htmlFor="ticker-cantidad">Cantidad en Ticker (Dip/Sen) (Sumar 1 para "Otros")</label> | ||||||
|                 <input id="ticker-cantidad" type="number" value={tickerCantidad} onChange={e => setTickerCantidad(e.target.value)} /> |                 <input id="ticker-cantidad" type="number" value={tickerCantidad} onChange={e => setTickerCantidad(e.target.value)} /> | ||||||
|             </div> |             </div> | ||||||
|             <div className="form-group" style={{ marginTop: '2rem' }}> |             <div className="form-group" style={{ marginTop: '2rem' }}> | ||||||
|                 <label htmlFor="concejales-cantidad">Cantidad en Widget Concejales</label> |                 <label htmlFor="concejales-cantidad">Cantidad en Widget Concejales (Sumar 1 para "Otros")</label> | ||||||
|                 <input  |                 <input  | ||||||
|                     id="concejales-cantidad" |                     id="concejales-cantidad" | ||||||
|                     type="number"  |                     type="number"  | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import { OrdenDiputadosManager } from './OrdenDiputadosManager'; | |||||||
| import { OrdenSenadoresManager } from './OrdenSenadoresManager'; | import { OrdenSenadoresManager } from './OrdenSenadoresManager'; | ||||||
| import { ConfiguracionGeneral } from './ConfiguracionGeneral'; | import { ConfiguracionGeneral } from './ConfiguracionGeneral'; | ||||||
| import { BancasManager } from './BancasManager'; | import { BancasManager } from './BancasManager'; | ||||||
|  | import { LogoOverridesManager } from './LogoOverridesManager'; | ||||||
|  |  | ||||||
| export const DashboardPage = () => { | export const DashboardPage = () => { | ||||||
|     const { logout } = useAuth(); |     const { logout } = useAuth(); | ||||||
| @@ -17,6 +18,7 @@ export const DashboardPage = () => { | |||||||
|             </header> |             </header> | ||||||
|             <main style={{ marginTop: '2rem' }}>    |             <main style={{ marginTop: '2rem' }}>    | ||||||
|                 <AgrupacionesManager /> |                 <AgrupacionesManager /> | ||||||
|  |                 <LogoOverridesManager /> | ||||||
|                 <div style={{ display: 'flex', gap: '2rem', flexWrap: 'wrap', marginTop: '2rem' }}> |                 <div style={{ display: 'flex', gap: '2rem', flexWrap: 'wrap', marginTop: '2rem' }}> | ||||||
|                     <div style={{ flex: '1 1 400px' }}> |                     <div style={{ flex: '1 1 400px' }}> | ||||||
|                         <OrdenDiputadosManager /> |                         <OrdenDiputadosManager /> | ||||||
|   | |||||||
| @@ -0,0 +1,83 @@ | |||||||
|  | // src/components/LogoOverridesManager.tsx | ||||||
|  | import { useState, useMemo, useEffect } from 'react'; | ||||||
|  | import { useQuery, useQueryClient } from '@tanstack/react-query'; | ||||||
|  | import Select from 'react-select'; | ||||||
|  | import { getMunicipiosForAdmin, getAgrupaciones, getLogos, updateLogos } from '../services/apiService'; | ||||||
|  | import type { MunicipioSimple, AgrupacionPolitica, LogoAgrupacionCategoria } from '../types'; | ||||||
|  |  | ||||||
|  | // --- AÑADIMOS LAS CATEGORÍAS PARA EL SELECTOR --- | ||||||
|  | const CATEGORIAS_OPTIONS = [ | ||||||
|  |     { value: 5, label: 'Senadores' }, | ||||||
|  |     { value: 6, label: 'Diputados' }, | ||||||
|  |     { value: 7, label: 'Concejales' } | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | export const LogoOverridesManager = () => { | ||||||
|  |     const queryClient = useQueryClient(); | ||||||
|  |     const { data: municipios = [] } = useQuery<MunicipioSimple[]>({ queryKey: ['municipiosForAdmin'], queryFn: getMunicipiosForAdmin }); | ||||||
|  |     const { data: agrupaciones = [] } = useQuery<AgrupacionPolitica[]>({ queryKey: ['agrupaciones'], queryFn: getAgrupaciones }); | ||||||
|  |     const { data: logos = [] } = useQuery<LogoAgrupacionCategoria[]>({ queryKey: ['logos'], queryFn: getLogos }); | ||||||
|  |  | ||||||
|  |     // --- NUEVO ESTADO PARA LA CATEGORÍA --- | ||||||
|  |     const [selectedCategoria, setSelectedCategoria] = useState<{ value: number; label: string } | null>(null); | ||||||
|  |     const [selectedMunicipio, setSelectedMunicipio] = useState<{ value: string; label: string } | null>(null); | ||||||
|  |     const [selectedAgrupacion, setSelectedAgrupacion] = useState<{ value: string; label: string } | null>(null); | ||||||
|  |     const [logoUrl, setLogoUrl] = useState(''); | ||||||
|  |  | ||||||
|  |     const municipioOptions = useMemo(() => municipios.map(m => ({ value: m.id, label: m.nombre })), [municipios]); | ||||||
|  |     const agrupacionOptions = useMemo(() => agrupaciones.map(a => ({ value: a.id, label: a.nombre })), [agrupaciones]); | ||||||
|  |  | ||||||
|  |     const currentLogo = useMemo(() => { | ||||||
|  |         // La búsqueda ahora depende de los 3 selectores | ||||||
|  |         if (!selectedMunicipio || !selectedAgrupacion || !selectedCategoria) return ''; | ||||||
|  |         return logos.find(l =>  | ||||||
|  |             l.ambitoGeograficoId === parseInt(selectedMunicipio.value) &&  | ||||||
|  |             l.agrupacionPoliticaId === selectedAgrupacion.value && | ||||||
|  |             l.categoriaId === selectedCategoria.value | ||||||
|  |         )?.logoUrl || ''; | ||||||
|  |     }, [logos, selectedMunicipio, selectedAgrupacion, selectedCategoria]); | ||||||
|  |      | ||||||
|  |     useEffect(() => { setLogoUrl(currentLogo) }, [currentLogo]); | ||||||
|  |  | ||||||
|  |     const handleSave = async () => { | ||||||
|  |         if (!selectedMunicipio || !selectedAgrupacion || !selectedCategoria) return; | ||||||
|  |         const newLogoEntry: LogoAgrupacionCategoria = { | ||||||
|  |             id: 0, | ||||||
|  |             agrupacionPoliticaId: selectedAgrupacion.value, | ||||||
|  |             categoriaId: selectedCategoria.value, | ||||||
|  |             ambitoGeograficoId: parseInt(selectedMunicipio.value), | ||||||
|  |             logoUrl: logoUrl || null | ||||||
|  |         }; | ||||||
|  |         try { | ||||||
|  |             await updateLogos([newLogoEntry]); | ||||||
|  |             queryClient.invalidateQueries({ queryKey: ['logos'] }); | ||||||
|  |             alert('Override de logo guardado.'); | ||||||
|  |         } catch { alert('Error al guardar.'); } | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     return ( | ||||||
|  |         <div className="admin-module"> | ||||||
|  |             <h3>Overrides de Logos por Municipio y Categoría</h3> | ||||||
|  |             <p>Configure una imagen específica para un partido en un municipio y categoría determinados.</p> | ||||||
|  |             <div style={{ display: 'flex', gap: '1rem', alignItems: 'flex-end' }}> | ||||||
|  |                 <div style={{ flex: 1 }}> | ||||||
|  |                     <label>Categoría</label> | ||||||
|  |                     <Select options={CATEGORIAS_OPTIONS} value={selectedCategoria} onChange={setSelectedCategoria} isClearable placeholder="Seleccione..."/> | ||||||
|  |                 </div> | ||||||
|  |                 <div style={{ flex: 1 }}> | ||||||
|  |                     <label>Municipio</label> | ||||||
|  |                     <Select options={municipioOptions} value={selectedMunicipio} onChange={setSelectedMunicipio} isClearable placeholder="Seleccione..."/> | ||||||
|  |                 </div> | ||||||
|  |                 <div style={{ flex: 1 }}> | ||||||
|  |                     <label>Agrupación</label> | ||||||
|  |                     <Select options={agrupacionOptions} value={selectedAgrupacion} onChange={setSelectedAgrupacion} isClearable placeholder="Seleccione..."/> | ||||||
|  |                 </div> | ||||||
|  |                 <div style={{ flex: 2 }}> | ||||||
|  |                     <label>URL del Logo Específico</label> | ||||||
|  |                     <input type="text" value={logoUrl} onChange={e => setLogoUrl(e.target.value)} style={{ width: '100%' }} disabled={!selectedMunicipio || !selectedAgrupacion || !selectedCategoria} /> | ||||||
|  |                 </div> | ||||||
|  |                 <button onClick={handleSave} disabled={!selectedMunicipio || !selectedAgrupacion || !selectedCategoria}>Guardar</button> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     ); | ||||||
|  | }; | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| // src/services/apiService.ts | // src/services/apiService.ts | ||||||
| import axios from 'axios'; | import axios from 'axios'; | ||||||
| import { triggerLogout } from '../context/authUtils'; | import { triggerLogout } from '../context/authUtils'; | ||||||
| import type { AgrupacionPolitica, UpdateAgrupacionData, Bancada, LogoAgrupacionCategoria } from '../types'; | import type { AgrupacionPolitica, UpdateAgrupacionData, Bancada, LogoAgrupacionCategoria, MunicipioSimple } from '../types'; | ||||||
|  |  | ||||||
| const AUTH_API_URL = 'http://localhost:5217/api/auth'; | const AUTH_API_URL = 'http://localhost:5217/api/auth'; | ||||||
| const ADMIN_API_URL = 'http://localhost:5217/api/admin'; | const ADMIN_API_URL = 'http://localhost:5217/api/admin'; | ||||||
| @@ -10,7 +10,7 @@ const adminApiClient = axios.create({ | |||||||
|   baseURL: ADMIN_API_URL, |   baseURL: ADMIN_API_URL, | ||||||
| }); | }); | ||||||
|  |  | ||||||
| // --- INTERCEPTORES (una sola vez) --- | // --- INTERCEPTORES --- | ||||||
|  |  | ||||||
| // Interceptor de Peticiones: Añade el token JWT a cada llamada | // Interceptor de Peticiones: Añade el token JWT a cada llamada | ||||||
| adminApiClient.interceptors.request.use( | adminApiClient.interceptors.request.use( | ||||||
| @@ -104,3 +104,10 @@ export const getLogos = async (): Promise<LogoAgrupacionCategoria[]> => { | |||||||
| export const updateLogos = async (data: LogoAgrupacionCategoria[]): Promise<void> => { | export const updateLogos = async (data: LogoAgrupacionCategoria[]): Promise<void> => { | ||||||
|   await adminApiClient.put('/logos', data); |   await adminApiClient.put('/logos', data); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | export const getMunicipiosForAdmin = async (): Promise<MunicipioSimple[]> => { | ||||||
|  |     // Ahora usa adminApiClient, que apunta a /api/admin/ | ||||||
|  |     // La URL final será /api/admin/catalogos/municipios | ||||||
|  |     const response = await adminApiClient.get('/catalogos/municipios'); | ||||||
|  |     return response.data; | ||||||
|  | }; | ||||||
| @@ -45,4 +45,7 @@ export interface LogoAgrupacionCategoria { | |||||||
|     agrupacionPoliticaId: string; |     agrupacionPoliticaId: string; | ||||||
|     categoriaId: number; |     categoriaId: number; | ||||||
|     logoUrl: string | null; |     logoUrl: string | null; | ||||||
|  |     ambitoGeograficoId: number | null; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface MunicipioSimple { id: string; nombre: string; } | ||||||
							
								
								
									
										445
									
								
								Elecciones-Web/frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										445
									
								
								Elecciones-Web/frontend/package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -18,6 +18,7 @@ | |||||||
|         "react": "^19.1.1", |         "react": "^19.1.1", | ||||||
|         "react-dom": "^19.1.1", |         "react-dom": "^19.1.1", | ||||||
|         "react-pdf": "^10.1.0", |         "react-pdf": "^10.1.0", | ||||||
|  |         "react-select": "^5.10.2", | ||||||
|         "react-simple-maps": "github:ozimmortal/react-simple-maps#feat/react-19-support", |         "react-simple-maps": "github:ozimmortal/react-simple-maps#feat/react-19-support", | ||||||
|         "react-tooltip": "^5.29.1" |         "react-tooltip": "^5.29.1" | ||||||
|       }, |       }, | ||||||
| @@ -26,6 +27,7 @@ | |||||||
|         "@types/geojson": "^7946.0.16", |         "@types/geojson": "^7946.0.16", | ||||||
|         "@types/react": "^19.1.10", |         "@types/react": "^19.1.10", | ||||||
|         "@types/react-dom": "^19.1.7", |         "@types/react-dom": "^19.1.7", | ||||||
|  |         "@types/react-select": "^5.0.0", | ||||||
|         "@vitejs/plugin-react": "^5.0.0", |         "@vitejs/plugin-react": "^5.0.0", | ||||||
|         "eslint": "^9.33.0", |         "eslint": "^9.33.0", | ||||||
|         "eslint-plugin-react-hooks": "^5.2.0", |         "eslint-plugin-react-hooks": "^5.2.0", | ||||||
| @@ -54,7 +56,6 @@ | |||||||
|       "version": "7.27.1", |       "version": "7.27.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", |       "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", | ||||||
|       "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", |       "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/helper-validator-identifier": "^7.27.1", |         "@babel/helper-validator-identifier": "^7.27.1", | ||||||
| @@ -110,7 +111,6 @@ | |||||||
|       "version": "7.28.3", |       "version": "7.28.3", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", |       "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", | ||||||
|       "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", |       "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/parser": "^7.28.3", |         "@babel/parser": "^7.28.3", | ||||||
| @@ -144,7 +144,6 @@ | |||||||
|       "version": "7.28.0", |       "version": "7.28.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", | ||||||
|       "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", |       "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
| @@ -154,7 +153,6 @@ | |||||||
|       "version": "7.27.1", |       "version": "7.27.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", | ||||||
|       "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", |       "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/traverse": "^7.27.1", |         "@babel/traverse": "^7.27.1", | ||||||
| @@ -196,7 +194,6 @@ | |||||||
|       "version": "7.27.1", |       "version": "7.27.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", | ||||||
|       "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", |       "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
| @@ -206,7 +203,6 @@ | |||||||
|       "version": "7.27.1", |       "version": "7.27.1", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", |       "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", | ||||||
|       "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", |       "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
| @@ -240,7 +236,6 @@ | |||||||
|       "version": "7.28.3", |       "version": "7.28.3", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", |       "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.3.tgz", | ||||||
|       "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", |       "integrity": "sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/types": "^7.28.2" |         "@babel/types": "^7.28.2" | ||||||
| @@ -284,11 +279,19 @@ | |||||||
|         "@babel/core": "^7.0.0-0" |         "@babel/core": "^7.0.0-0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@babel/runtime": { | ||||||
|  |       "version": "7.28.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", | ||||||
|  |       "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=6.9.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@babel/template": { |     "node_modules/@babel/template": { | ||||||
|       "version": "7.27.2", |       "version": "7.27.2", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", |       "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", | ||||||
|       "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", |       "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/code-frame": "^7.27.1", |         "@babel/code-frame": "^7.27.1", | ||||||
| @@ -303,7 +306,6 @@ | |||||||
|       "version": "7.28.3", |       "version": "7.28.3", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", |       "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.3.tgz", | ||||||
|       "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", |       "integrity": "sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/code-frame": "^7.27.1", |         "@babel/code-frame": "^7.27.1", | ||||||
| @@ -322,7 +324,6 @@ | |||||||
|       "version": "7.28.2", |       "version": "7.28.2", | ||||||
|       "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", |       "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", | ||||||
|       "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", |       "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@babel/helper-string-parser": "^7.27.1", |         "@babel/helper-string-parser": "^7.27.1", | ||||||
| @@ -332,6 +333,126 @@ | |||||||
|         "node": ">=6.9.0" |         "node": ">=6.9.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@emotion/babel-plugin": { | ||||||
|  |       "version": "11.13.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", | ||||||
|  |       "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/helper-module-imports": "^7.16.7", | ||||||
|  |         "@babel/runtime": "^7.18.3", | ||||||
|  |         "@emotion/hash": "^0.9.2", | ||||||
|  |         "@emotion/memoize": "^0.9.0", | ||||||
|  |         "@emotion/serialize": "^1.3.3", | ||||||
|  |         "babel-plugin-macros": "^3.1.0", | ||||||
|  |         "convert-source-map": "^1.5.0", | ||||||
|  |         "escape-string-regexp": "^4.0.0", | ||||||
|  |         "find-root": "^1.1.0", | ||||||
|  |         "source-map": "^0.5.7", | ||||||
|  |         "stylis": "4.2.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { | ||||||
|  |       "version": "1.9.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", | ||||||
|  |       "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/cache": { | ||||||
|  |       "version": "11.14.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", | ||||||
|  |       "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@emotion/memoize": "^0.9.0", | ||||||
|  |         "@emotion/sheet": "^1.4.0", | ||||||
|  |         "@emotion/utils": "^1.4.2", | ||||||
|  |         "@emotion/weak-memoize": "^0.4.0", | ||||||
|  |         "stylis": "4.2.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/hash": { | ||||||
|  |       "version": "0.9.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", | ||||||
|  |       "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/memoize": { | ||||||
|  |       "version": "0.9.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", | ||||||
|  |       "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/react": { | ||||||
|  |       "version": "11.14.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", | ||||||
|  |       "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.18.3", | ||||||
|  |         "@emotion/babel-plugin": "^11.13.5", | ||||||
|  |         "@emotion/cache": "^11.14.0", | ||||||
|  |         "@emotion/serialize": "^1.3.3", | ||||||
|  |         "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", | ||||||
|  |         "@emotion/utils": "^1.4.2", | ||||||
|  |         "@emotion/weak-memoize": "^0.4.0", | ||||||
|  |         "hoist-non-react-statics": "^3.3.1" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": ">=16.8.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "@types/react": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/serialize": { | ||||||
|  |       "version": "1.3.3", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", | ||||||
|  |       "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@emotion/hash": "^0.9.2", | ||||||
|  |         "@emotion/memoize": "^0.9.0", | ||||||
|  |         "@emotion/unitless": "^0.10.0", | ||||||
|  |         "@emotion/utils": "^1.4.2", | ||||||
|  |         "csstype": "^3.0.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/sheet": { | ||||||
|  |       "version": "1.4.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", | ||||||
|  |       "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/unitless": { | ||||||
|  |       "version": "0.10.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", | ||||||
|  |       "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/use-insertion-effect-with-fallbacks": { | ||||||
|  |       "version": "1.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", | ||||||
|  |       "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": ">=16.8.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/utils": { | ||||||
|  |       "version": "1.4.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", | ||||||
|  |       "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/@emotion/weak-memoize": { | ||||||
|  |       "version": "0.4.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", | ||||||
|  |       "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/@esbuild/aix-ppc64": { |     "node_modules/@esbuild/aix-ppc64": { | ||||||
|       "version": "0.25.9", |       "version": "0.25.9", | ||||||
|       "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", |       "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", | ||||||
| @@ -1023,7 +1144,6 @@ | |||||||
|       "version": "0.3.13", |       "version": "0.3.13", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", | ||||||
|       "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", |       "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@jridgewell/sourcemap-codec": "^1.5.0", |         "@jridgewell/sourcemap-codec": "^1.5.0", | ||||||
| @@ -1034,7 +1154,6 @@ | |||||||
|       "version": "3.1.2", |       "version": "3.1.2", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", | ||||||
|       "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", |       "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6.0.0" |         "node": ">=6.0.0" | ||||||
| @@ -1057,14 +1176,12 @@ | |||||||
|       "version": "1.5.5", |       "version": "1.5.5", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", | ||||||
|       "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", |       "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/@jridgewell/trace-mapping": { |     "node_modules/@jridgewell/trace-mapping": { | ||||||
|       "version": "0.3.30", |       "version": "0.3.30", | ||||||
|       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", |       "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.30.tgz", | ||||||
|       "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", |       "integrity": "sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "@jridgewell/resolve-uri": "^3.1.0", |         "@jridgewell/resolve-uri": "^3.1.0", | ||||||
| @@ -2026,11 +2143,16 @@ | |||||||
|         "undici-types": "~7.10.0" |         "undici-types": "~7.10.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/parse-json": { | ||||||
|  |       "version": "4.0.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", | ||||||
|  |       "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/@types/react": { |     "node_modules/@types/react": { | ||||||
|       "version": "19.1.10", |       "version": "19.1.10", | ||||||
|       "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz", |       "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.10.tgz", | ||||||
|       "integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==", |       "integrity": "sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==", | ||||||
|       "devOptional": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "csstype": "^3.0.2" |         "csstype": "^3.0.2" | ||||||
| @@ -2046,6 +2168,25 @@ | |||||||
|         "@types/react": "^19.0.0" |         "@types/react": "^19.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/@types/react-select": { | ||||||
|  |       "version": "5.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/react-select/-/react-select-5.0.0.tgz", | ||||||
|  |       "integrity": "sha512-vddLcBpzUMVpVNmnBtpC5cyZ2ajaHx/g6SHUo6lmMw0FIiOzrtmoSQ4UI6TRl+sm8TGGT+Oir8NRMZfYQtgr8Q==", | ||||||
|  |       "dev": true, | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "react-select": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/@types/react-transition-group": { | ||||||
|  |       "version": "4.4.12", | ||||||
|  |       "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", | ||||||
|  |       "integrity": "sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "@types/react": "*" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/@typescript-eslint/eslint-plugin": { |     "node_modules/@typescript-eslint/eslint-plugin": { | ||||||
|       "version": "8.40.0", |       "version": "8.40.0", | ||||||
|       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.40.0.tgz", |       "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.40.0.tgz", | ||||||
| @@ -2418,6 +2559,21 @@ | |||||||
|         "proxy-from-env": "^1.1.0" |         "proxy-from-env": "^1.1.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/babel-plugin-macros": { | ||||||
|  |       "version": "3.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", | ||||||
|  |       "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.12.5", | ||||||
|  |         "cosmiconfig": "^7.0.0", | ||||||
|  |         "resolve": "^1.19.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=10", | ||||||
|  |         "npm": ">=6" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/balanced-match": { |     "node_modules/balanced-match": { | ||||||
|       "version": "1.0.2", |       "version": "1.0.2", | ||||||
|       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", |       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", | ||||||
| @@ -2508,7 +2664,6 @@ | |||||||
|       "version": "3.1.0", |       "version": "3.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", |       "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", | ||||||
|       "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", |       "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=6" |         "node": ">=6" | ||||||
| @@ -2613,6 +2768,31 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/cosmiconfig": { | ||||||
|  |       "version": "7.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", | ||||||
|  |       "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@types/parse-json": "^4.0.0", | ||||||
|  |         "import-fresh": "^3.2.1", | ||||||
|  |         "parse-json": "^5.0.0", | ||||||
|  |         "path-type": "^4.0.0", | ||||||
|  |         "yaml": "^1.10.0" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=10" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     "node_modules/cosmiconfig/node_modules/yaml": { | ||||||
|  |       "version": "1.10.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", | ||||||
|  |       "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", | ||||||
|  |       "license": "ISC", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 6" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/cross-spawn": { |     "node_modules/cross-spawn": { | ||||||
|       "version": "7.0.6", |       "version": "7.0.6", | ||||||
|       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", |       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", | ||||||
| @@ -2632,7 +2812,6 @@ | |||||||
|       "version": "3.1.3", |       "version": "3.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", |       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", | ||||||
|       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", |       "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", | ||||||
|       "devOptional": true, |  | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/d3-array": { |     "node_modules/d3-array": { | ||||||
| @@ -2851,7 +3030,6 @@ | |||||||
|       "version": "4.4.1", |       "version": "4.4.1", | ||||||
|       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", |       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", | ||||||
|       "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", |       "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "ms": "^2.1.3" |         "ms": "^2.1.3" | ||||||
| @@ -2890,6 +3068,16 @@ | |||||||
|         "node": ">=6" |         "node": ">=6" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/dom-helpers": { | ||||||
|  |       "version": "5.2.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", | ||||||
|  |       "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.8.7", | ||||||
|  |         "csstype": "^3.0.2" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/dunder-proto": { |     "node_modules/dunder-proto": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", | ||||||
| @@ -2911,6 +3099,15 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "ISC" |       "license": "ISC" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/error-ex": { | ||||||
|  |       "version": "1.3.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", | ||||||
|  |       "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "is-arrayish": "^0.2.1" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/es-define-property": { |     "node_modules/es-define-property": { | ||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", | ||||||
| @@ -3012,7 +3209,6 @@ | |||||||
|       "version": "4.0.0", |       "version": "4.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", | ||||||
|       "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", |       "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=10" |         "node": ">=10" | ||||||
| @@ -3286,6 +3482,12 @@ | |||||||
|         "node": ">=8" |         "node": ">=8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/find-root": { | ||||||
|  |       "version": "1.1.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", | ||||||
|  |       "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/find-up": { |     "node_modules/find-up": { | ||||||
|       "version": "5.0.0", |       "version": "5.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", |       "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", | ||||||
| @@ -3525,6 +3727,15 @@ | |||||||
|         "node": ">= 0.4" |         "node": ">= 0.4" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/hoist-non-react-statics": { | ||||||
|  |       "version": "3.3.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", | ||||||
|  |       "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", | ||||||
|  |       "license": "BSD-3-Clause", | ||||||
|  |       "dependencies": { | ||||||
|  |         "react-is": "^16.7.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/ignore": { |     "node_modules/ignore": { | ||||||
|       "version": "5.3.2", |       "version": "5.3.2", | ||||||
|       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", |       "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", | ||||||
| @@ -3539,7 +3750,6 @@ | |||||||
|       "version": "3.3.1", |       "version": "3.3.1", | ||||||
|       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", |       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", | ||||||
|       "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", |       "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "parent-module": "^1.0.0", |         "parent-module": "^1.0.0", | ||||||
| @@ -3571,6 +3781,27 @@ | |||||||
|         "node": ">=12" |         "node": ">=12" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/is-arrayish": { | ||||||
|  |       "version": "0.2.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", | ||||||
|  |       "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/is-core-module": { | ||||||
|  |       "version": "2.16.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", | ||||||
|  |       "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "hasown": "^2.0.2" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 0.4" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/ljharb" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/is-extglob": { |     "node_modules/is-extglob": { | ||||||
|       "version": "2.1.1", |       "version": "2.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", |       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", | ||||||
| @@ -3634,7 +3865,6 @@ | |||||||
|       "version": "3.1.0", |       "version": "3.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", |       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", | ||||||
|       "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", |       "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "bin": { |       "bin": { | ||||||
|         "jsesc": "bin/jsesc" |         "jsesc": "bin/jsesc" | ||||||
| @@ -3650,6 +3880,12 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/json-parse-even-better-errors": { | ||||||
|  |       "version": "2.3.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", | ||||||
|  |       "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/json-schema-traverse": { |     "node_modules/json-schema-traverse": { | ||||||
|       "version": "0.4.1", |       "version": "0.4.1", | ||||||
|       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", |       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", | ||||||
| @@ -3701,6 +3937,12 @@ | |||||||
|         "node": ">= 0.8.0" |         "node": ">= 0.8.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/lines-and-columns": { | ||||||
|  |       "version": "1.2.4", | ||||||
|  |       "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", | ||||||
|  |       "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/locate-path": { |     "node_modules/locate-path": { | ||||||
|       "version": "6.0.0", |       "version": "6.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", |       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", | ||||||
| @@ -3779,6 +4021,12 @@ | |||||||
|         "node": ">= 0.4" |         "node": ">= 0.4" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/memoize-one": { | ||||||
|  |       "version": "6.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", | ||||||
|  |       "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/merge-refs": { |     "node_modules/merge-refs": { | ||||||
|       "version": "2.0.0", |       "version": "2.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-2.0.0.tgz", |       "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-2.0.0.tgz", | ||||||
| @@ -3858,7 +4106,6 @@ | |||||||
|       "version": "2.1.3", |       "version": "2.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", |       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", | ||||||
|       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", |       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT" |       "license": "MIT" | ||||||
|     }, |     }, | ||||||
|     "node_modules/nanoid": { |     "node_modules/nanoid": { | ||||||
| @@ -3899,7 +4146,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", |       "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | ||||||
|       "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", |       "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "peer": true, |  | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=0.10.0" |         "node": ">=0.10.0" | ||||||
|       } |       } | ||||||
| @@ -3958,7 +4204,6 @@ | |||||||
|       "version": "1.0.1", |       "version": "1.0.1", | ||||||
|       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", |       "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", | ||||||
|       "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", |       "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "callsites": "^3.0.0" |         "callsites": "^3.0.0" | ||||||
| @@ -3967,6 +4212,24 @@ | |||||||
|         "node": ">=6" |         "node": ">=6" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/parse-json": { | ||||||
|  |       "version": "5.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", | ||||||
|  |       "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/code-frame": "^7.0.0", | ||||||
|  |         "error-ex": "^1.3.1", | ||||||
|  |         "json-parse-even-better-errors": "^2.3.0", | ||||||
|  |         "lines-and-columns": "^1.1.6" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/sindresorhus" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/path-exists": { |     "node_modules/path-exists": { | ||||||
|       "version": "4.0.0", |       "version": "4.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", | ||||||
| @@ -3987,6 +4250,21 @@ | |||||||
|         "node": ">=8" |         "node": ">=8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/path-parse": { | ||||||
|  |       "version": "1.0.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", | ||||||
|  |       "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|  |     "node_modules/path-type": { | ||||||
|  |       "version": "4.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", | ||||||
|  |       "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=8" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/pdfjs-dist": { |     "node_modules/pdfjs-dist": { | ||||||
|       "version": "5.3.93", |       "version": "5.3.93", | ||||||
|       "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.3.93.tgz", |       "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.3.93.tgz", | ||||||
| @@ -4003,7 +4281,6 @@ | |||||||
|       "version": "1.1.1", |       "version": "1.1.1", | ||||||
|       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", |       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", | ||||||
|       "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", |       "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "ISC" |       "license": "ISC" | ||||||
|     }, |     }, | ||||||
|     "node_modules/picomatch": { |     "node_modules/picomatch": { | ||||||
| @@ -4063,7 +4340,6 @@ | |||||||
|       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", |       "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", | ||||||
|       "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", |       "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "peer": true, |  | ||||||
|       "dependencies": { |       "dependencies": { | ||||||
|         "loose-envify": "^1.4.0", |         "loose-envify": "^1.4.0", | ||||||
|         "object-assign": "^4.1.1", |         "object-assign": "^4.1.1", | ||||||
| @@ -4132,8 +4408,7 @@ | |||||||
|       "version": "16.13.1", |       "version": "16.13.1", | ||||||
|       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", |       "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", | ||||||
|       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", |       "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", | ||||||
|       "license": "MIT", |       "license": "MIT" | ||||||
|       "peer": true |  | ||||||
|     }, |     }, | ||||||
|     "node_modules/react-pdf": { |     "node_modules/react-pdf": { | ||||||
|       "version": "10.1.0", |       "version": "10.1.0", | ||||||
| @@ -4174,6 +4449,27 @@ | |||||||
|         "node": ">=0.10.0" |         "node": ">=0.10.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/react-select": { | ||||||
|  |       "version": "5.10.2", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.10.2.tgz", | ||||||
|  |       "integrity": "sha512-Z33nHdEFWq9tfnfVXaiM12rbJmk+QjFEztWLtmXqQhz6Al4UZZ9xc0wiatmGtUOCCnHN0WizL3tCMYRENX4rVQ==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.12.0", | ||||||
|  |         "@emotion/cache": "^11.4.0", | ||||||
|  |         "@emotion/react": "^11.8.1", | ||||||
|  |         "@floating-ui/dom": "^1.0.1", | ||||||
|  |         "@types/react-transition-group": "^4.4.0", | ||||||
|  |         "memoize-one": "^6.0.0", | ||||||
|  |         "prop-types": "^15.6.0", | ||||||
|  |         "react-transition-group": "^4.3.0", | ||||||
|  |         "use-isomorphic-layout-effect": "^1.2.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", | ||||||
|  |         "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/react-simple-maps": { |     "node_modules/react-simple-maps": { | ||||||
|       "version": "3.0.0", |       "version": "3.0.0", | ||||||
|       "resolved": "git+ssh://git@github.com/ozimmortal/react-simple-maps.git#f2b342ae277569b751fa1c9b6638e06ad05ab617", |       "resolved": "git+ssh://git@github.com/ozimmortal/react-simple-maps.git#f2b342ae277569b751fa1c9b6638e06ad05ab617", | ||||||
| @@ -4206,6 +4502,22 @@ | |||||||
|         "react-dom": ">=16.14.0" |         "react-dom": ">=16.14.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/react-transition-group": { | ||||||
|  |       "version": "4.4.5", | ||||||
|  |       "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", | ||||||
|  |       "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", | ||||||
|  |       "license": "BSD-3-Clause", | ||||||
|  |       "dependencies": { | ||||||
|  |         "@babel/runtime": "^7.5.5", | ||||||
|  |         "dom-helpers": "^5.0.1", | ||||||
|  |         "loose-envify": "^1.4.0", | ||||||
|  |         "prop-types": "^15.6.2" | ||||||
|  |       }, | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": ">=16.6.0", | ||||||
|  |         "react-dom": ">=16.6.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/react-virtualized-auto-sizer": { |     "node_modules/react-virtualized-auto-sizer": { | ||||||
|       "version": "1.0.26", |       "version": "1.0.26", | ||||||
|       "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz", |       "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.26.tgz", | ||||||
| @@ -4216,11 +4528,30 @@ | |||||||
|         "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0" |         "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/resolve": { | ||||||
|  |       "version": "1.22.10", | ||||||
|  |       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", | ||||||
|  |       "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "dependencies": { | ||||||
|  |         "is-core-module": "^2.16.0", | ||||||
|  |         "path-parse": "^1.0.7", | ||||||
|  |         "supports-preserve-symlinks-flag": "^1.0.0" | ||||||
|  |       }, | ||||||
|  |       "bin": { | ||||||
|  |         "resolve": "bin/resolve" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 0.4" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/ljharb" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/resolve-from": { |     "node_modules/resolve-from": { | ||||||
|       "version": "4.0.0", |       "version": "4.0.0", | ||||||
|       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", |       "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", | ||||||
|       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", |       "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", | ||||||
|       "dev": true, |  | ||||||
|       "license": "MIT", |       "license": "MIT", | ||||||
|       "engines": { |       "engines": { | ||||||
|         "node": ">=4" |         "node": ">=4" | ||||||
| @@ -4340,6 +4671,15 @@ | |||||||
|         "node": ">=8" |         "node": ">=8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/source-map": { | ||||||
|  |       "version": "0.5.7", | ||||||
|  |       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", | ||||||
|  |       "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", | ||||||
|  |       "license": "BSD-3-Clause", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">=0.10.0" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/source-map-js": { |     "node_modules/source-map-js": { | ||||||
|       "version": "1.2.1", |       "version": "1.2.1", | ||||||
|       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", |       "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", | ||||||
| @@ -4388,6 +4728,12 @@ | |||||||
|         "url": "https://github.com/sponsors/sindresorhus" |         "url": "https://github.com/sponsors/sindresorhus" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/stylis": { | ||||||
|  |       "version": "4.2.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", | ||||||
|  |       "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", | ||||||
|  |       "license": "MIT" | ||||||
|  |     }, | ||||||
|     "node_modules/supports-color": { |     "node_modules/supports-color": { | ||||||
|       "version": "7.2.0", |       "version": "7.2.0", | ||||||
|       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", |       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", | ||||||
| @@ -4401,6 +4747,18 @@ | |||||||
|         "node": ">=8" |         "node": ">=8" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/supports-preserve-symlinks-flag": { | ||||||
|  |       "version": "1.0.0", | ||||||
|  |       "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", | ||||||
|  |       "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 0.4" | ||||||
|  |       }, | ||||||
|  |       "funding": { | ||||||
|  |         "url": "https://github.com/sponsors/ljharb" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/terser": { |     "node_modules/terser": { | ||||||
|       "version": "5.43.1", |       "version": "5.43.1", | ||||||
|       "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", |       "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", | ||||||
| @@ -4644,6 +5002,20 @@ | |||||||
|         "react": "*" |         "react": "*" | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/use-isomorphic-layout-effect": { | ||||||
|  |       "version": "1.2.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", | ||||||
|  |       "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", | ||||||
|  |       "license": "MIT", | ||||||
|  |       "peerDependencies": { | ||||||
|  |         "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" | ||||||
|  |       }, | ||||||
|  |       "peerDependenciesMeta": { | ||||||
|  |         "@types/react": { | ||||||
|  |           "optional": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/vite": { |     "node_modules/vite": { | ||||||
|       "version": "7.1.3", |       "version": "7.1.3", | ||||||
|       "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", |       "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.3.tgz", | ||||||
| @@ -4792,6 +5164,21 @@ | |||||||
|       "dev": true, |       "dev": true, | ||||||
|       "license": "ISC" |       "license": "ISC" | ||||||
|     }, |     }, | ||||||
|  |     "node_modules/yaml": { | ||||||
|  |       "version": "2.8.1", | ||||||
|  |       "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", | ||||||
|  |       "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", | ||||||
|  |       "dev": true, | ||||||
|  |       "license": "ISC", | ||||||
|  |       "optional": true, | ||||||
|  |       "peer": true, | ||||||
|  |       "bin": { | ||||||
|  |         "yaml": "bin.mjs" | ||||||
|  |       }, | ||||||
|  |       "engines": { | ||||||
|  |         "node": ">= 14.6" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     "node_modules/yocto-queue": { |     "node_modules/yocto-queue": { | ||||||
|       "version": "0.1.0", |       "version": "0.1.0", | ||||||
|       "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", |       "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ | |||||||
|     "react": "^19.1.1", |     "react": "^19.1.1", | ||||||
|     "react-dom": "^19.1.1", |     "react-dom": "^19.1.1", | ||||||
|     "react-pdf": "^10.1.0", |     "react-pdf": "^10.1.0", | ||||||
|  |     "react-select": "^5.10.2", | ||||||
|     "react-simple-maps": "github:ozimmortal/react-simple-maps#feat/react-19-support", |     "react-simple-maps": "github:ozimmortal/react-simple-maps#feat/react-19-support", | ||||||
|     "react-tooltip": "^5.29.1" |     "react-tooltip": "^5.29.1" | ||||||
|   }, |   }, | ||||||
| @@ -28,6 +29,7 @@ | |||||||
|     "@types/geojson": "^7946.0.16", |     "@types/geojson": "^7946.0.16", | ||||||
|     "@types/react": "^19.1.10", |     "@types/react": "^19.1.10", | ||||||
|     "@types/react-dom": "^19.1.7", |     "@types/react-dom": "^19.1.7", | ||||||
|  |     "@types/react-select": "^5.0.0", | ||||||
|     "@vitejs/plugin-react": "^5.0.0", |     "@vitejs/plugin-react": "^5.0.0", | ||||||
|     "eslint": "^9.33.0", |     "eslint": "^9.33.0", | ||||||
|     "eslint-plugin-react-hooks": "^5.2.0", |     "eslint-plugin-react-hooks": "^5.2.0", | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -6,6 +6,7 @@ import MapaBsAs from './components/MapaBsAs' | |||||||
| import { TickerWidget } from './components/TickerWidget' | import { TickerWidget } from './components/TickerWidget' | ||||||
| import { TelegramaWidget } from './components/TelegramaWidget' | import { TelegramaWidget } from './components/TelegramaWidget' | ||||||
| import { ConcejalesWidget } from './components/ConcejalesWidget' | import { ConcejalesWidget } from './components/ConcejalesWidget' | ||||||
|  | import MapaBsAsSecciones from './components/MapaBsAsSecciones' | ||||||
|  |  | ||||||
| function App() { | function App() { | ||||||
|   return ( |   return ( | ||||||
| @@ -17,6 +18,7 @@ function App() { | |||||||
|         <CongresoWidget /> |         <CongresoWidget /> | ||||||
|         <BancasWidget /> |         <BancasWidget /> | ||||||
|         <MapaBsAs /> |         <MapaBsAs /> | ||||||
|  |         <MapaBsAsSecciones /> | ||||||
|         <TelegramaWidget /> |         <TelegramaWidget /> | ||||||
|       </main> |       </main> | ||||||
|     </> |     </> | ||||||
|   | |||||||
| @@ -60,6 +60,14 @@ export interface ConfiguracionPublica { | |||||||
|   // ... otras claves públicas que pueda añadir en el futuro |   // ... otras claves públicas que pueda añadir en el futuro | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface ResultadoDetalleSeccion { | ||||||
|  |   id: string; // ID de la agrupación para la key | ||||||
|  |   nombre: string; | ||||||
|  |   votos: number; | ||||||
|  |   porcentaje: number; | ||||||
|  |   color: string | null; | ||||||
|  | } | ||||||
|  |  | ||||||
| export const getResumenProvincial = async (): Promise<CategoriaResumen[]> => { | export const getResumenProvincial = async (): Promise<CategoriaResumen[]> => { | ||||||
|   const response = await apiClient.get('/resultados/provincia/02'); |   const response = await apiClient.get('/resultados/provincia/02'); | ||||||
|   return response.data; |   return response.data; | ||||||
| @@ -130,3 +138,20 @@ export const getResultadosConcejales = async (seccionId: string): Promise<Result | |||||||
|   const response = await apiClient.get(`/resultados/concejales/${seccionId}`); |   const response = await apiClient.get(`/resultados/concejales/${seccionId}`); | ||||||
|   return response.data; |   return response.data; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | export const getDetalleSeccion = async (seccionId: string, categoriaId: number): Promise<ResultadoDetalleSeccion[]> => { | ||||||
|  |     const response = await apiClient.get(`/resultados/seccion/${seccionId}?categoriaId=${categoriaId}`); | ||||||
|  |     return response.data; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const getResultadosConcejalesPorMunicipio = async (municipioId: string): Promise<ResultadoTicker[]> => { | ||||||
|  |   // Usamos el endpoint 'partido' que, según la aclaración de la API, busca por municipio | ||||||
|  |   const response = await apiClient.get(`/resultados/partido/${municipioId}`); | ||||||
|  |   // La API devuelve un objeto, nosotros extraemos el array de resultados | ||||||
|  |   return response.data.resultados; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const getMunicipios = async (): Promise<MunicipioSimple[]> => { | ||||||
|  |   const response = await apiClient.get('/catalogos/municipios'); | ||||||
|  |   return response.data; | ||||||
|  | }; | ||||||
| @@ -1,86 +1,104 @@ | |||||||
| // src/components/ConcejalesWidget.tsx | // src/components/ConcejalesWidget.tsx | ||||||
| import { useState, useEffect } from 'react'; | import { useState, useMemo, useEffect } from 'react'; | ||||||
| import { useQuery } from '@tanstack/react-query'; | import { useQuery } from '@tanstack/react-query'; | ||||||
| import { getSeccionesElectorales, getResultadosConcejales, getConfiguracionPublica } from '../apiService'; | import Select from 'react-select'; // <-- 1. Importar react-select | ||||||
|  | import { getMunicipios, getResultadosConcejalesPorMunicipio, getConfiguracionPublica } from '../apiService'; | ||||||
| import type { MunicipioSimple, ResultadoTicker } from '../types/types'; | import type { MunicipioSimple, ResultadoTicker } from '../types/types'; | ||||||
| import { ImageWithFallback } from './ImageWithFallback'; | import { ImageWithFallback } from './ImageWithFallback'; | ||||||
| import './TickerWidget.css'; // Reutilizamos los estilos del ticker | import './TickerWidget.css'; | ||||||
|  |  | ||||||
| const formatPercent = (num: number) => `${(num || 0).toFixed(2).replace('.', ',')}%`; | const formatPercent = (num: number) => `${(num || 0).toFixed(2).replace('.', ',')}%`; | ||||||
|  |  | ||||||
| export const ConcejalesWidget = () => { | // Estilos personalizados para que el selector se vea bien | ||||||
|   const [secciones, setSecciones] = useState<MunicipioSimple[]>([]); | const customSelectStyles = { | ||||||
|   const [seccionActualId, setSeccionActualId] = useState<string>(''); |   control: (base: any) => ({ ...base, minWidth: '220px', border: '1px solid #ced4da' }), | ||||||
|  |   menu: (base: any) => ({ ...base, zIndex: 10 }), // Para que el menú se superponga | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export const ConcejalesWidget = () => { | ||||||
|  |   // 2. Cambiamos el estado para que se adapte a react-select | ||||||
|  |   const [selectedMunicipio, setSelectedMunicipio] = useState<{ value: string; label: string } | null>(null); | ||||||
|  |  | ||||||
|   // Query para la configuración (para saber cuántos resultados mostrar) |  | ||||||
|   const { data: configData } = useQuery({ |   const { data: configData } = useQuery({ | ||||||
|     queryKey: ['configuracionPublica'], |     queryKey: ['configuracionPublica'], | ||||||
|     queryFn: getConfiguracionPublica, |     queryFn: getConfiguracionPublica, | ||||||
|     staleTime: 0, |     staleTime: 0, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   // Calculamos la cantidad a mostrar desde la configuración |   // Usamos la clave de configuración correcta | ||||||
|   const cantidadAMostrar = parseInt(configData?.ConcejalesResultadosCantidad || '5', 10) + 1; |   const cantidadAMostrar = parseInt(configData?.ConcejalesResultadosCantidad || '5', 10); | ||||||
|  |  | ||||||
|  |   // 3. Query para obtener la lista de MUNICIPIOS | ||||||
|  |   const { data: municipios = [], isLoading: isLoadingMunicipios } = useQuery<MunicipioSimple[]>({ | ||||||
|  |     queryKey: ['municipios'], | ||||||
|  |     queryFn: getMunicipios, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   // Este useEffect se encarga de establecer el valor por defecto | ||||||
|   useEffect(() => { |   useEffect(() => { | ||||||
|     getSeccionesElectorales().then(seccionesData => { |     // Se ejecuta solo si tenemos la lista de municipios y aún no hemos seleccionado nada | ||||||
|       if (seccionesData && seccionesData.length > 0) { |     if (municipios.length > 0 && !selectedMunicipio) { | ||||||
|         const orden = new Map([ |       // Buscamos "LA PLATA" en la lista (insensible a mayúsculas/minúsculas) | ||||||
|           ['Capital', 0], ['Primera', 1], ['Segunda', 2], ['Tercera', 3], |       const laPlata = municipios.find(m => m.nombre.toUpperCase() === 'LA PLATA'); | ||||||
|           ['Cuarta', 4], ['Quinta', 5], ['Sexta', 6], ['Séptima', 7] |  | ||||||
|         ]); |       // Si lo encontramos, lo establecemos como el municipio seleccionado | ||||||
|         const getOrden = (nombre: string) => { |       if (laPlata) { | ||||||
|           const match = nombre.match(/Capital|Primera|Segunda|Tercera|Cuarta|Quinta|Sexta|Séptima/); |         setSelectedMunicipio({ value: laPlata.id, label: laPlata.nombre }); | ||||||
|           return match ? orden.get(match[0]) ?? 99 : 99; |  | ||||||
|         }; |  | ||||||
|         seccionesData.sort((a, b) => getOrden(a.nombre) - getOrden(b.nombre)); |  | ||||||
|         setSecciones(seccionesData); |  | ||||||
|         // Al estar los datos ya ordenados, el [0] será "Sección Capital" |  | ||||||
|         setSeccionActualId(seccionesData[0].id); |  | ||||||
|       } |       } | ||||||
|     }); |     } | ||||||
|   }, []); // El array de dependencias vacío asegura que esto solo se ejecute una vez |   }, [municipios, selectedMunicipio]); // Se ejecuta cuando 'municipios' o 'selectedMunicipio' cambian | ||||||
|  |  | ||||||
|   // Query para obtener los resultados de la sección seleccionada |   // 4. Transformamos los datos para react-select | ||||||
|   const { data: resultados, isLoading } = useQuery<ResultadoTicker[]>({ |   const municipioOptions = useMemo(() => | ||||||
|     queryKey: ['resultadosConcejales', seccionActualId], |     municipios | ||||||
|     queryFn: () => getResultadosConcejales(seccionActualId), |       .map(m => ({ value: m.id, label: m.nombre })) | ||||||
|     enabled: !!seccionActualId, |       .sort((a, b) => a.label.localeCompare(b.label)), // Orden alfabético | ||||||
|  |     [municipios]); | ||||||
|  |  | ||||||
|  |   // 5. Query para obtener los resultados del MUNICIPIO seleccionado | ||||||
|  |   const { data: resultados, isLoading: isLoadingResultados } = useQuery<ResultadoTicker[]>({ | ||||||
|  |     queryKey: ['resultadosConcejalesPorMunicipio', selectedMunicipio?.value], | ||||||
|  |     queryFn: () => getResultadosConcejalesPorMunicipio(selectedMunicipio!.value), | ||||||
|  |     enabled: !!selectedMunicipio, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   // --- INICIO DE LA LÓGICA DE PROCESAMIENTO "OTROS" --- |   // 6. Lógica para "Otros" (sin cambios funcionales) | ||||||
|   let displayResults: ResultadoTicker[] = resultados || []; |   let displayResults: ResultadoTicker[] = resultados || []; | ||||||
|   if (resultados && resultados.length > cantidadAMostrar) { |   if (resultados && resultados.length > cantidadAMostrar) { | ||||||
|     const topParties = resultados.slice(0, cantidadAMostrar - 1); |     const topParties = resultados.slice(0, cantidadAMostrar - 1); | ||||||
|     const otherParties = resultados.slice(cantidadAMostrar - 1); |     const otherParties = resultados.slice(cantidadAMostrar - 1); | ||||||
|     const otrosPorcentaje = otherParties.reduce((sum, party) => sum + (party.votosPorcentaje || 0), 0); |     const otrosPorcentaje = otherParties.reduce((sum, party) => sum + (party.porcentaje || 0), 0); | ||||||
|  |  | ||||||
|     const otrosEntry: ResultadoTicker = { |     const otrosEntry: ResultadoTicker = { | ||||||
|       id: `otros-concejales-${seccionActualId}`, |       id: `otros-concejales-${selectedMunicipio?.value}`, | ||||||
|       nombre: 'Otros', |       nombre: 'Otros', | ||||||
|       nombreCorto: 'Otros', |       nombreCorto: 'Otros', | ||||||
|       color: '#888888', |       color: '#888888', | ||||||
|       logoUrl: null, |       logoUrl: null, | ||||||
|       votos: 0, // No es relevante para la visualización del porcentaje |       votos: 0, | ||||||
|       votosPorcentaje: otrosPorcentaje, |       porcentaje: otrosPorcentaje, | ||||||
|     }; |     }; | ||||||
|     displayResults = [...topParties, otrosEntry]; |     displayResults = [...topParties, otrosEntry]; | ||||||
|   } else if (resultados) { |   } else if (resultados) { | ||||||
|     displayResults = resultados.slice(0, cantidadAMostrar); |     displayResults = resultados.slice(0, cantidadAMostrar); | ||||||
|   } |   } | ||||||
|   // --- FIN DE LA LÓGICA DE PROCESAMIENTO "OTROS" --- |  | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <div className="ticker-card" style={{ gridColumn: '1 / -1' }}> |     <div className="ticker-card" style={{ gridColumn: '1 / -1' }}> | ||||||
|       <div className="ticker-header"> |       <div className="ticker-header"> | ||||||
|         <h3>CONCEJALES - LA PLATA</h3> |         <h3>CONCEJALES POR MUNICIPIO</h3> | ||||||
|         <select value={seccionActualId} onChange={e => setSeccionActualId(e.target.value)} disabled={secciones.length === 0}> |         <Select | ||||||
|           {secciones.map(s => <option key={s.id} value={s.id}>{s.nombre}</option>)} |           options={municipioOptions} | ||||||
|         </select> |           value={selectedMunicipio} | ||||||
|  |           onChange={(option) => setSelectedMunicipio(option)} | ||||||
|  |           isLoading={isLoadingMunicipios} | ||||||
|  |           placeholder="Buscar y seleccionar un municipio..." | ||||||
|  |           styles={customSelectStyles} | ||||||
|  |         /> | ||||||
|       </div> |       </div> | ||||||
|       <div className="ticker-results"> |       <div className="ticker-results"> | ||||||
|         {isLoading ? <p>Cargando...</p> : |         {(isLoadingMunicipios || (isLoadingResultados && selectedMunicipio)) && <p>Cargando...</p>} | ||||||
|           displayResults.map(partido => ( |         {!selectedMunicipio && !isLoadingMunicipios && <p style={{textAlign: 'center', color: '#666'}}>Seleccione un municipio.</p>} | ||||||
|  |         {displayResults.map(partido => ( | ||||||
|           <div key={partido.id} className="ticker-party"> |           <div key={partido.id} className="ticker-party"> | ||||||
|             <div className="party-logo"> |             <div className="party-logo"> | ||||||
|               <ImageWithFallback src={partido.logoUrl || undefined} fallbackSrc="/default-avatar.png" alt={`Logo de ${partido.nombre}`} /> |               <ImageWithFallback src={partido.logoUrl || undefined} fallbackSrc="/default-avatar.png" alt={`Logo de ${partido.nombre}`} /> | ||||||
| @@ -88,15 +106,14 @@ export const ConcejalesWidget = () => { | |||||||
|             <div className="party-details"> |             <div className="party-details"> | ||||||
|               <div className="party-info"> |               <div className="party-info"> | ||||||
|                 <span className="party-name">{partido.nombreCorto || partido.nombre}</span> |                 <span className="party-name">{partido.nombreCorto || partido.nombre}</span> | ||||||
|                   <span className="party-percent">{formatPercent(partido.votosPorcentaje)}</span> |                 <span className="party-percent">{formatPercent(partido.porcentaje)}</span> | ||||||
|               </div> |               </div> | ||||||
|               <div className="party-bar-background"> |               <div className="party-bar-background"> | ||||||
|                   <div className="party-bar-foreground" style={{ width: `${partido.votosPorcentaje}%`, backgroundColor: partido.color || '#888' }}></div> |                 <div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor: partido.color || '#888' }}></div> | ||||||
|               </div> |               </div> | ||||||
|             </div> |             </div> | ||||||
|           </div> |           </div> | ||||||
|           )) |         ))} | ||||||
|         } |  | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
|   ); |   ); | ||||||
|   | |||||||
| @@ -76,7 +76,7 @@ | |||||||
|   min-height: 0; |   min-height: 0; | ||||||
|   background-color: var(--background-panel-color); |   background-color: var(--background-panel-color); | ||||||
|   border-radius: 8px; |   border-radius: 8px; | ||||||
|   padding: 1.5rem; |   padding: 1rem; | ||||||
|   border: none; |   border: none; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -195,3 +195,51 @@ | |||||||
|     font-size: 1em; |     font-size: 1em; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* --- ESTILOS PARA EL SELECTOR DE CATEGORÍA --- */ | ||||||
|  | .mapa-categoria-selector { | ||||||
|  |   display: flex; | ||||||
|  |   margin-bottom: 1.5rem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .mapa-categoria-combobox { | ||||||
|  |   width: 100%; | ||||||
|  |   padding: 0.75rem 1rem; | ||||||
|  |   font-size: 1em; | ||||||
|  |   font-weight: 500; | ||||||
|  |   color: var(--text-color); | ||||||
|  |   background-color: #f8f9fa; | ||||||
|  |   border: 1px solid var(--border-color); | ||||||
|  |   border-radius: 6px; | ||||||
|  |   cursor: pointer; | ||||||
|  |   appearance: none; | ||||||
|  |   background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%230073e6%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.4-12.9z%22%2F%3E%3C%2Fsvg%3E'); | ||||||
|  |   background-repeat: no-repeat; | ||||||
|  |   background-position: right 1rem center; | ||||||
|  |   background-size: 0.8em; | ||||||
|  |   transition: all 0.2s ease-in-out; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .mapa-categoria-combobox:hover { | ||||||
|  |   border-color: var(--primary-accent-color); | ||||||
|  |   background-color: #e9ecef; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .mapa-categoria-combobox:focus { | ||||||
|  |   outline: none; | ||||||
|  |   border-color: var(--primary-accent-color); | ||||||
|  |   box-shadow: 0 0 0 2px rgba(0, 115, 230, 0.25); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* --- ESTILOS PARA SECCIONES NO CLICLEABLES --- */ | ||||||
|  | .rsm-geography.no-results { | ||||||
|  |     pointer-events: none; /* Ignora todos los eventos del ratón (click, hover, etc.) */ | ||||||
|  |     cursor: default;      /* Muestra el cursor por defecto en lugar de la mano */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Opcional pero recomendado: modificar la regla :hover para que no afecte a las secciones no clicleables */ | ||||||
|  | .rsm-geography:not(.no-results):hover { | ||||||
|  |     stroke: var(--primary-accent-color); | ||||||
|  |     stroke-width: 1.5px; | ||||||
|  |     filter: brightness(1.05); | ||||||
|  | } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| // src/components/MapaBsAs.tsx | // src/components/MapaBsAs.tsx | ||||||
| import { useState, useMemo, useCallback, useEffect } from 'react'; | import { useState, useMemo, useCallback, useEffect } from 'react'; | ||||||
| import type { MouseEvent } from 'react'; |  | ||||||
| import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps'; | import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps'; | ||||||
| import { Tooltip } from 'react-tooltip'; | import { Tooltip } from 'react-tooltip'; | ||||||
| import { useQuery } from '@tanstack/react-query'; | import { useQuery } from '@tanstack/react-query'; | ||||||
| @@ -24,7 +23,7 @@ interface ResultadoDetalladoMunicipio { | |||||||
|   ultimaActualizacion: string; |   ultimaActualizacion: string; | ||||||
|   porcentajeEscrutado: number; |   porcentajeEscrutado: number; | ||||||
|   porcentajeParticipacion: number; |   porcentajeParticipacion: number; | ||||||
|   resultados: { nombre: string; votos: number; porcentaje: number }[]; |   resultados: { id: string; nombre: string; votos: number; porcentaje: number; color: string | null; }[]; | ||||||
|   votosAdicionales: { enBlanco: number; nulos: number; recurridos: number }; |   votosAdicionales: { enBlanco: number; nulos: number; recurridos: number }; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -33,11 +32,13 @@ interface Agrupacion { | |||||||
|   nombre: string; |   nombre: string; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | interface Categoria { | ||||||
|  |   id: number; | ||||||
|  |   nombre: string; | ||||||
|  | } | ||||||
|  |  | ||||||
| interface PartidoProperties { | interface PartidoProperties { | ||||||
|   id: string; |  | ||||||
|   departamento: string; |   departamento: string; | ||||||
|   cabecera: string; |  | ||||||
|   provincia: string; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| type PartidoGeography = Feature<Geometry, PartidoProperties> & { rsmKey: string }; | type PartidoGeography = Feature<Geometry, PartidoProperties> & { rsmKey: string }; | ||||||
| @@ -50,52 +51,57 @@ const TRANSLATE_EXTENT: [[number, number], [number, number]] = [[-100, -600], [1 | |||||||
| const INITIAL_POSITION = { center: [-60.5, -37.2] as PointTuple, zoom: MIN_ZOOM }; | const INITIAL_POSITION = { center: [-60.5, -37.2] as PointTuple, zoom: MIN_ZOOM }; | ||||||
| const DEFAULT_MAP_COLOR = '#E0E0E0'; | const DEFAULT_MAP_COLOR = '#E0E0E0'; | ||||||
|  |  | ||||||
|  | const CATEGORIAS: Categoria[] = [ | ||||||
|  |   { id: 5, nombre: 'Senadores' }, | ||||||
|  |   { id: 6, nombre: 'Diputados' }, | ||||||
|  |   { id: 7, nombre: 'Concejales' } | ||||||
|  | ]; | ||||||
|  |  | ||||||
| // --- Componente Principal --- | // --- Componente Principal --- | ||||||
| const MapaBsAs = () => { | const MapaBsAs = () => { | ||||||
|   const [position, setPosition] = useState(INITIAL_POSITION); |   const [position, setPosition] = useState(INITIAL_POSITION); | ||||||
|   const [selectedAmbitoId, setSelectedAmbitoId] = useState<number | null>(null); |   const [selectedAmbitoId, setSelectedAmbitoId] = useState<number | null>(null); | ||||||
|  |   const [selectedCategoriaId, setSelectedCategoriaId] = useState<number>(6); | ||||||
|  |   const [tooltipContent, setTooltipContent] = useState(''); | ||||||
|  |  | ||||||
|   const { data: resultadosData, isLoading: isLoadingResultados } = useQuery<ResultadoMapa[]>({ |   const { data: resultadosData, isLoading: isLoadingResultados } = useQuery<ResultadoMapa[]>({ | ||||||
|     queryKey: ['mapaResultados'], |     queryKey: ['mapaResultadosPorMunicipio', selectedCategoriaId], | ||||||
|     queryFn: async () => (await axios.get(`${API_BASE_URL}/Resultados/mapa`)).data, |     queryFn: async () => (await axios.get(`${API_BASE_URL}/Resultados/mapa-por-municipio?categoriaId=${selectedCategoriaId}`)).data, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   const { data: geoData, isLoading: isLoadingGeo } = useQuery<any>({ |   const { data: geoData, isLoading: isLoadingGeo } = useQuery<any>({ | ||||||
|     queryKey: ['mapaGeoData'], |     queryKey: ['mapaGeoData'], | ||||||
|     queryFn: async () => (await axios.get('/partidos-bsas.topojson')).data, |     queryFn: async () => (await axios.get('/partidos-bsas.topojson')).data, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   const { data: agrupacionesData, isLoading: isLoadingAgrupaciones } = useQuery<Agrupacion[]>({ |   const { data: agrupacionesData, isLoading: isLoadingAgrupaciones } = useQuery<Agrupacion[]>({ | ||||||
|     queryKey: ['catalogoAgrupaciones'], |     queryKey: ['catalogoAgrupaciones'], | ||||||
|     queryFn: async () => (await axios.get(`${API_BASE_URL}/Catalogos/agrupaciones`)).data, |     queryFn: async () => (await axios.get(`${API_BASE_URL}/Catalogos/agrupaciones`)).data, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   // --- SU SOLUCIÓN CORRECTA INTEGRADA --- |  | ||||||
|   const { nombresAgrupaciones, resultadosPorDepartamento } = useMemo<{ |   const { nombresAgrupaciones, resultadosPorDepartamento } = useMemo<{ | ||||||
|     nombresAgrupaciones: Map<string, string>; |     nombresAgrupaciones: Map<string, string>; | ||||||
|     resultadosPorDepartamento: Map<string, ResultadoMapa>; |     resultadosPorDepartamento: Map<string, ResultadoMapa>; | ||||||
|   }>(() => { |   }>(() => { | ||||||
|     const nombresMap = new Map<string, string>(); |     const nombresMap = new Map<string, string>(); | ||||||
|     const resultadosMap = new Map<string, ResultadoMapa>(); |     const resultadosMap = new Map<string, ResultadoMapa>(); | ||||||
|  |  | ||||||
|     if (agrupacionesData) { |     if (agrupacionesData) { | ||||||
|       agrupacionesData.forEach((agrupacion) => { |       agrupacionesData.forEach((agrupacion) => { | ||||||
|         nombresMap.set(agrupacion.id, agrupacion.nombre); |         nombresMap.set(agrupacion.id, agrupacion.nombre); | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     if (resultadosData) { |     if (resultadosData) { | ||||||
|           resultadosData.forEach(r => resultadosMap.set(r.departamentoNombre.toUpperCase(), r)); |       resultadosData.forEach(r => { | ||||||
|  |         if (r.departamentoNombre) { | ||||||
|  |           resultadosMap.set(r.departamentoNombre.toUpperCase(), r) | ||||||
|         } |         } | ||||||
|  |       }); | ||||||
|       return { |     } | ||||||
|         nombresAgrupaciones: nombresMap, |     return { nombresAgrupaciones: nombresMap, resultadosPorDepartamento: resultadosMap }; | ||||||
|         resultadosPorDepartamento: resultadosMap |  | ||||||
|       }; |  | ||||||
|   }, [agrupacionesData, resultadosData]); |   }, [agrupacionesData, resultadosData]); | ||||||
|  |  | ||||||
|   const isLoading = isLoadingResultados || isLoadingAgrupaciones || isLoadingGeo; |   const isLoading = isLoadingResultados || isLoadingAgrupaciones || isLoadingGeo; | ||||||
|  |  | ||||||
|   // ... (el resto del componente no necesita cambios) |  | ||||||
|    |  | ||||||
|   const handleReset = useCallback(() => { |   const handleReset = useCallback(() => { | ||||||
|     setSelectedAmbitoId(null); |     setSelectedAmbitoId(null); | ||||||
|     setPosition(INITIAL_POSITION); |     setPosition(INITIAL_POSITION); | ||||||
| @@ -142,25 +148,44 @@ const MapaBsAs = () => { | |||||||
|  |  | ||||||
|   const getPartyFillColor = (departamentoNombre: string) => { |   const getPartyFillColor = (departamentoNombre: string) => { | ||||||
|     const resultado = resultadosPorDepartamento.get(departamentoNombre.toUpperCase()); |     const resultado = resultadosPorDepartamento.get(departamentoNombre.toUpperCase()); | ||||||
|     if (!resultado || !resultado.colorGanador) { |     return resultado?.colorGanador || DEFAULT_MAP_COLOR; | ||||||
|       return DEFAULT_MAP_COLOR; |  | ||||||
|     } |  | ||||||
|     return resultado.colorGanador; |  | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|   const handleMouseEnter = (e: MouseEvent<SVGPathElement>) => { |   // --- Helper de Renderizado --- | ||||||
|     const path = e.target as SVGPathElement; |   const renderGeography = (geo: PartidoGeography, isSelectedGeo: boolean = false) => { | ||||||
|     if (path.parentNode) { |     const departamentoNombre = geo.properties.departamento.toUpperCase(); | ||||||
|       path.parentNode.appendChild(path); |     const resultado = resultadosPorDepartamento.get(departamentoNombre); | ||||||
|     } |     const isClickable = !!resultado; | ||||||
|   }; |     const isSelected = isSelectedGeo || (selectedAmbitoId !== null && selectedAmbitoId === resultado?.ambitoId); | ||||||
|  |     const isFaded = !isSelectedGeo && selectedAmbitoId !== null && !isSelected; | ||||||
|  |     const nombreAgrupacionGanadora = resultado ? nombresAgrupaciones.get(resultado.agrupacionGanadoraId) : 'Sin datos'; | ||||||
|  |  | ||||||
|   if (isLoading) return <div className="loading-container">Cargando datos del mapa...</div>; |     return ( | ||||||
|  |       <Geography | ||||||
|  |         key={geo.rsmKey + (isSelectedGeo ? '-selected' : '')} | ||||||
|  |         geography={geo} | ||||||
|  |         data-tooltip-id="partido-tooltip" | ||||||
|  |         data-tooltip-content={`${geo.properties.departamento}: ${nombreAgrupacionGanadora}`} | ||||||
|  |         className={`rsm-geography ${isSelected ? 'selected' : ''} ${isFaded ? 'faded' : ''} ${!isClickable ? 'no-results' : ''}`} | ||||||
|  |         fill={getPartyFillColor(geo.properties.departamento)} | ||||||
|  |         onClick={isClickable ? () => handleGeographyClick(geo) : undefined} | ||||||
|  |         onMouseEnter={() => setTooltipContent(`${geo.properties.departamento}: ${nombreAgrupacionGanadora}`)} | ||||||
|  |         onMouseLeave={() => setTooltipContent("")} | ||||||
|  |       /> | ||||||
|  |     ); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|   return ( |   return ( | ||||||
|     <div className="mapa-wrapper"> |     <div className="mapa-wrapper"> | ||||||
|       <div className="mapa-container"> |       <div className="mapa-container"> | ||||||
|         <ComposableMap projection="geoMercator" projectionConfig={{ scale: 4400, center: [-60.5, -37.2] }} className="rsm-svg"> |         {isLoading ? <div className="spinner"></div> : ( | ||||||
|  |           <ComposableMap | ||||||
|  |             key={selectedCategoriaId} | ||||||
|  |             projection="geoMercator" | ||||||
|  |             projectionConfig={{ scale: 4400, center: [-60.5, -37.2] }} | ||||||
|  |             className="rsm-svg" | ||||||
|  |             data-tooltip-id="partido-tooltip" | ||||||
|  |           > | ||||||
|             <ZoomableGroup |             <ZoomableGroup | ||||||
|               center={position.center} |               center={position.center} | ||||||
|               zoom={position.zoom} |               zoom={position.zoom} | ||||||
| @@ -180,37 +205,47 @@ const MapaBsAs = () => { | |||||||
|             > |             > | ||||||
|               {geoData && ( |               {geoData && ( | ||||||
|                 <Geographies geography={geoData}> |                 <Geographies geography={geoData}> | ||||||
|                 {({ geographies }: { geographies: PartidoGeography[] }) => |                   {({ geographies }: { geographies: PartidoGeography[] }) => { | ||||||
|                   geographies.map((geo) => { |                     const selectedGeo = selectedAmbitoId | ||||||
|                     const departamentoNombre = geo.properties.departamento.toUpperCase(); |                       ? geographies.find(geo => { | ||||||
|                     const resultado = resultadosPorDepartamento.get(departamentoNombre); |                         const resultado = resultadosPorDepartamento.get(geo.properties.departamento.toUpperCase()); | ||||||
|                     const isSelected = resultado ? selectedAmbitoId === resultado.ambitoId : false; |                         return resultado?.ambitoId === selectedAmbitoId; | ||||||
|                     const isFaded = selectedAmbitoId !== null && !isSelected; |                       }) | ||||||
|                     const nombreAgrupacionGanadora = resultado ? nombresAgrupaciones.get(resultado.agrupacionGanadoraId) : 'Sin datos'; |                       : null; | ||||||
|  |  | ||||||
|                     return ( |                     return ( | ||||||
|                       <Geography |                       <> | ||||||
|                         key={geo.rsmKey} |                         {geographies.map(geo => (!selectedGeo || geo.rsmKey !== selectedGeo.rsmKey) ? renderGeography(geo) : null)} | ||||||
|                         geography={geo} |                         {selectedGeo && renderGeography(selectedGeo, true)} | ||||||
|                         data-tooltip-id="partido-tooltip" |                       </> | ||||||
|                         data-tooltip-content={`${geo.properties.departamento}: ${nombreAgrupacionGanadora}`} |  | ||||||
|                         className={`rsm-geography ${isSelected ? 'selected' : ''} ${isFaded ? 'faded' : ''}`} |  | ||||||
|                         fill={getPartyFillColor(geo.properties.departamento)} |  | ||||||
|                         onClick={() => handleGeographyClick(geo)} |  | ||||||
|                         onMouseEnter={handleMouseEnter} |  | ||||||
|                       /> |  | ||||||
|                     ); |                     ); | ||||||
|                   }) |                   }} | ||||||
|                 } |  | ||||||
|                 </Geographies> |                 </Geographies> | ||||||
|               )} |               )} | ||||||
|             </ZoomableGroup> |             </ZoomableGroup> | ||||||
|           </ComposableMap> |           </ComposableMap> | ||||||
|         <Tooltip id="partido-tooltip" variant="light" /> |         )} | ||||||
|  |         <Tooltip id="partido-tooltip" content={tooltipContent} /> | ||||||
|         {selectedAmbitoId !== null && <ControlesMapa onReset={handleReset} />} |         {selectedAmbitoId !== null && <ControlesMapa onReset={handleReset} />} | ||||||
|       </div> |       </div> | ||||||
|       <div className="info-panel"> |       <div className="info-panel"> | ||||||
|         <DetalleMunicipio ambitoId={selectedAmbitoId} onReset={handleReset} /> |         <div className="mapa-categoria-selector"> | ||||||
|  |           <select | ||||||
|  |             className="mapa-categoria-combobox" | ||||||
|  |             value={selectedCategoriaId} | ||||||
|  |             onChange={(e) => { | ||||||
|  |               setSelectedCategoriaId(Number(e.target.value)); | ||||||
|  |               handleReset(); | ||||||
|  |             }} | ||||||
|  |           > | ||||||
|  |             {CATEGORIAS.map(cat => ( | ||||||
|  |               <option key={cat.id} value={cat.id}> | ||||||
|  |                 {cat.nombre} | ||||||
|  |               </option> | ||||||
|  |             ))} | ||||||
|  |           </select> | ||||||
|  |         </div> | ||||||
|  |         <DetalleMunicipio ambitoId={selectedAmbitoId} onReset={handleReset} categoriaId={selectedCategoriaId} /> | ||||||
|         <Legend resultados={resultadosPorDepartamento} nombresAgrupaciones={nombresAgrupaciones} /> |         <Legend resultados={resultadosPorDepartamento} nombresAgrupaciones={nombresAgrupaciones} /> | ||||||
|       </div> |       </div> | ||||||
|     </div> |     </div> | ||||||
| @@ -224,10 +259,10 @@ const ControlesMapa = ({ onReset }: { onReset: () => void }) => ( | |||||||
|   </div> |   </div> | ||||||
| ); | ); | ||||||
|  |  | ||||||
| const DetalleMunicipio = ({ ambitoId, onReset }: { ambitoId: number | null; onReset: () => void }) => { | const DetalleMunicipio = ({ ambitoId, onReset, categoriaId }: { ambitoId: number | null; onReset: () => void; categoriaId: number; }) => { | ||||||
|   const { data, isLoading, error } = useQuery<ResultadoDetalladoMunicipio>({ |   const { data, isLoading, error } = useQuery<ResultadoDetalladoMunicipio>({ | ||||||
|     queryKey: ['municipioDetalle', ambitoId], |     queryKey: ['municipioDetalle', ambitoId, categoriaId], | ||||||
|     queryFn: async () => (await axios.get(`${API_BASE_URL}/Resultados/municipio/${ambitoId}`)).data, |     queryFn: async () => (await axios.get(`${API_BASE_URL}/Resultados/municipio/${ambitoId}?categoriaId=${categoriaId}`)).data, | ||||||
|     enabled: !!ambitoId, |     enabled: !!ambitoId, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
| @@ -240,18 +275,24 @@ const DetalleMunicipio = ({ ambitoId, onReset }: { ambitoId: number | null; onRe | |||||||
|       <button className="reset-button-panel" onClick={onReset}>← VOLVER</button> |       <button className="reset-button-panel" onClick={onReset}>← VOLVER</button> | ||||||
|       <h3>{data?.municipioNombre}</h3> |       <h3>{data?.municipioNombre}</h3> | ||||||
|       <div className="detalle-metricas"> |       <div className="detalle-metricas"> | ||||||
|         <span><strong>Escrutado:</strong> {data?.porcentajeEscrutado.toFixed(2)}%</span> |         <span><strong>Escrutado:</strong> {(data?.porcentajeEscrutado ?? 0).toFixed(2)}%</span> | ||||||
|         <span><strong>Participación:</strong> {data?.porcentajeParticipacion.toFixed(2)}%</span> |         <span><strong>Participación:</strong> {(data?.porcentajeParticipacion ?? 0).toFixed(2)}%</span> | ||||||
|       </div> |       </div> | ||||||
|       <ul className="resultados-lista"> |       <ul className="resultados-lista"> | ||||||
|         {data?.resultados.map((r, index) => ( |         {(data?.resultados ?? []).map((r, index) => ( | ||||||
|           <li key={`${r.nombre}-${index}`}> |           <li key={`${r.nombre}-${index}`}> | ||||||
|             <div className="resultado-info"> |             <div className="resultado-info"> | ||||||
|               <span className="partido-nombre">{r.nombre}</span> |               <span className="partido-nombre">{r.nombre}</span> | ||||||
|               <span className="partido-votos">{r.votos.toLocaleString('es-AR')} ({r.porcentaje.toFixed(2)}%)</span> |               <span className="partido-votos">{r.votos.toLocaleString('es-AR')} ({r.porcentaje.toFixed(2)}%)</span> | ||||||
|             </div> |             </div> | ||||||
|             <div className="progress-bar"> |             <div className="progress-bar"> | ||||||
|               <div className="progress-fill" style={{ width: `${r.porcentaje}%` }}></div> |               <div | ||||||
|  |                 className="progress-fill" | ||||||
|  |                 style={{ | ||||||
|  |                   width: `${r.porcentaje}%`, | ||||||
|  |                   backgroundColor: r.color || DEFAULT_MAP_COLOR | ||||||
|  |                 }} | ||||||
|  |               ></div> | ||||||
|             </div> |             </div> | ||||||
|           </li> |           </li> | ||||||
|         ))} |         ))} | ||||||
|   | |||||||
							
								
								
									
										303
									
								
								Elecciones-Web/frontend/src/components/MapaBsAsSecciones.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								Elecciones-Web/frontend/src/components/MapaBsAsSecciones.tsx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,303 @@ | |||||||
|  | // src/components/MapaBsAsSecciones.tsx | ||||||
|  | import { useState, useMemo, useCallback, useEffect } from 'react'; | ||||||
|  | import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps'; | ||||||
|  | import { Tooltip } from 'react-tooltip'; | ||||||
|  | import { useQuery } from '@tanstack/react-query'; | ||||||
|  | import axios from 'axios'; | ||||||
|  | import { geoCentroid } from 'd3-geo'; | ||||||
|  | import { getDetalleSeccion } from '../apiService'; | ||||||
|  | import type { ResultadoDetalleSeccion } from '../apiService'; | ||||||
|  | import './MapaBsAs.css'; | ||||||
|  |  | ||||||
|  | // --- Interfaces y Tipos --- | ||||||
|  | type PointTuple = [number, number]; | ||||||
|  | interface ResultadoMapaSeccion { | ||||||
|  |   seccionId: string; | ||||||
|  |   seccionNombre: string; | ||||||
|  |   agrupacionGanadoraId: string | null; | ||||||
|  |   colorGanador: string | null; | ||||||
|  | } | ||||||
|  | interface Agrupacion { id: string; nombre: string; } | ||||||
|  | interface Categoria { id: number; nombre: string; } | ||||||
|  | type SeccionGeography = { | ||||||
|  |   rsmKey: string; | ||||||
|  |   properties: { seccion: string; fna: string; }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // --- Constantes --- | ||||||
|  | const API_BASE_URL = 'http://localhost:5217/api'; | ||||||
|  | const DEFAULT_MAP_COLOR = '#E0E0E0'; | ||||||
|  | const CATEGORIAS: Categoria[] = [{ id: 5, nombre: 'Senadores' }, { id: 6, nombre: 'Diputados' }]; | ||||||
|  | const SECCION_ID_TO_ROMAN: Record<string, string> = { '1': 'I', '2': 'II', '3': 'III', '4': 'IV', '5': 'V', '6': 'VI', '7': 'VII', '8': 'VIII' }; | ||||||
|  | const ROMAN_TO_SECCION_ID: Record<string, string> = { 'I': '1', 'II': '2', 'III': '3', 'IV': '4', 'V': '5', 'VI': '6', 'VII': '7', 'VIII': '8' }; | ||||||
|  | // --- CORRECCIÓN 1: Mover NOMBRES_SECCIONES aquí para que sea global al archivo --- | ||||||
|  | const NOMBRES_SECCIONES: Record<string, string> = { | ||||||
|  |     'I': 'Sección Primera', 'II': 'Sección Segunda', 'III': 'Sección Tercera', 'IV': 'Sección Cuarta', | ||||||
|  |     'V': 'Sección Quinta', 'VI': 'Sección Sexta', 'VII': 'Sección Séptima', 'VIII': 'Sección Capital' | ||||||
|  | }; | ||||||
|  | const MIN_ZOOM = 1; | ||||||
|  | const MAX_ZOOM = 5; | ||||||
|  | const TRANSLATE_EXTENT: [[number, number], [number, number]] = [[-100, -600], [1100, 300]]; | ||||||
|  | const INITIAL_POSITION = { center: [-60.5, -37.2] as PointTuple, zoom: MIN_ZOOM }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // --- Componente de Detalle --- | ||||||
|  | const DetalleSeccion = ({ seccion, categoriaId, onReset }: { seccion: SeccionGeography | null, categoriaId: number, onReset: () => void }) => { | ||||||
|  |   const seccionId = seccion ? ROMAN_TO_SECCION_ID[seccion.properties.seccion] : null; | ||||||
|  |  | ||||||
|  |   const { data: resultadosDetalle, isLoading, error } = useQuery<ResultadoDetalleSeccion[]>({ | ||||||
|  |     queryKey: ['detalleSeccion', seccionId, categoriaId], | ||||||
|  |     queryFn: () => getDetalleSeccion(seccionId!, categoriaId), | ||||||
|  |     enabled: !!seccionId, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   if (!seccion) { | ||||||
|  |     return ( | ||||||
|  |       <div className="detalle-placeholder"> | ||||||
|  |         <h3>Resultados por Sección</h3> | ||||||
|  |         <p>Haga clic en una sección del mapa para ver los resultados detallados.</p> | ||||||
|  |       </div> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   if (isLoading) return (<div className="detalle-loading"><div className="spinner"></div><p>Cargando resultados de la sección...</p></div>); | ||||||
|  |   if (error) return <div className="detalle-error">Error al cargar los datos de la sección.</div>; | ||||||
|  |  | ||||||
|  |   const nombreSeccionLegible = NOMBRES_SECCIONES[seccion.properties.seccion] || "Sección Desconocida"; | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <div className="detalle-content"> | ||||||
|  |       <button className="reset-button-panel" onClick={onReset}>← VOLVER</button> | ||||||
|  |       <h3>{nombreSeccionLegible}</h3> | ||||||
|  |       <ul className="resultados-lista"> | ||||||
|  |         {resultadosDetalle?.map((r) => ( | ||||||
|  |           <li key={r.id}> | ||||||
|  |             <div className="resultado-info"> | ||||||
|  |               <span className="partido-nombre">{r.nombre}</span> | ||||||
|  |               <span className="partido-votos">{r.votos.toLocaleString('es-AR')} ({r.porcentaje.toFixed(2)}%)</span> | ||||||
|  |             </div> | ||||||
|  |             <div className="progress-bar"> | ||||||
|  |               {/* --- CORRECCIÓN 2: Usar el color de la API --- */} | ||||||
|  |               <div className="progress-fill" style={{ width: `${r.porcentaje}%`, backgroundColor: r.color || DEFAULT_MAP_COLOR }}></div> | ||||||
|  |             </div> | ||||||
|  |           </li> | ||||||
|  |         ))} | ||||||
|  |       </ul> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // --- Componente de Controles del Mapa --- | ||||||
|  | const ControlesMapa = ({ onReset }: { onReset: () => void }) => ( | ||||||
|  |   <div className="map-controls"> | ||||||
|  |     <button onClick={onReset}>← VOLVER</button> | ||||||
|  |   </div> | ||||||
|  | ); | ||||||
|  |  | ||||||
|  | // --- Componente Principal --- | ||||||
|  | const MapaBsAsSecciones = () => { | ||||||
|  |   const [position, setPosition] = useState(INITIAL_POSITION); | ||||||
|  |   const [selectedCategoriaId, setSelectedCategoriaId] = useState<number>(6); | ||||||
|  |   const [clickedSeccion, setClickedSeccion] = useState<SeccionGeography | null>(null); | ||||||
|  |   const [tooltipContent, setTooltipContent] = useState(''); | ||||||
|  |  | ||||||
|  |   const { data: geoData, isLoading: isLoadingGeo } = useQuery<any>({ | ||||||
|  |     queryKey: ['mapaGeoDataSecciones'], | ||||||
|  |     queryFn: async () => (await axios.get('./secciones-electorales-pba.topojson')).data, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const { data: resultadosData, isLoading: isLoadingResultados } = useQuery<ResultadoMapaSeccion[]>({ | ||||||
|  |     queryKey: ['mapaResultadosPorSeccion', selectedCategoriaId], | ||||||
|  |     queryFn: async () => (await axios.get(`${API_BASE_URL}/Resultados/mapa-por-seccion?categoriaId=${selectedCategoriaId}`)).data, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const { data: agrupacionesData, isLoading: isLoadingAgrupaciones } = useQuery<Agrupacion[]>({ | ||||||
|  |     queryKey: ['catalogoAgrupaciones'], | ||||||
|  |     queryFn: async () => (await axios.get(`${API_BASE_URL}/Catalogos/agrupaciones`)).data, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   const { nombresAgrupaciones, resultadosPorSeccionRomana } = useMemo<{ | ||||||
|  |     nombresAgrupaciones: Map<string, string>; | ||||||
|  |     resultadosPorSeccionRomana: Map<string, ResultadoMapaSeccion>; | ||||||
|  |   }>(() => { | ||||||
|  |     const nombresMap = new Map<string, string>(); | ||||||
|  |     const resultadosMap = new Map<string, ResultadoMapaSeccion>(); | ||||||
|  |  | ||||||
|  |     if (agrupacionesData) { | ||||||
|  |       agrupacionesData.forEach(a => nombresMap.set(a.id, a.nombre)); | ||||||
|  |     } | ||||||
|  |     if (resultadosData) { | ||||||
|  |       resultadosData.forEach(r => { | ||||||
|  |         const roman = SECCION_ID_TO_ROMAN[r.seccionId]; | ||||||
|  |         if (roman) resultadosMap.set(roman, r); | ||||||
|  |       }); | ||||||
|  |     } | ||||||
|  |     return { nombresAgrupaciones: nombresMap, resultadosPorSeccionRomana: resultadosMap }; | ||||||
|  |   }, [agrupacionesData, resultadosData]); | ||||||
|  |  | ||||||
|  |   const isLoading = isLoadingGeo || isLoadingResultados || isLoadingAgrupaciones; | ||||||
|  |  | ||||||
|  |   const handleReset = useCallback(() => { | ||||||
|  |     setClickedSeccion(null); | ||||||
|  |     setPosition(INITIAL_POSITION); | ||||||
|  |   }, []); | ||||||
|  |  | ||||||
|  |   const handleGeographyClick = useCallback((geo: SeccionGeography) => { | ||||||
|  |     if (clickedSeccion?.rsmKey === geo.rsmKey) { | ||||||
|  |       handleReset(); | ||||||
|  |     } else { | ||||||
|  |       const centroid = geoCentroid(geo as any) as PointTuple; | ||||||
|  |       setPosition({ center: centroid, zoom: 2 }); | ||||||
|  |       setClickedSeccion(geo); | ||||||
|  |     } | ||||||
|  |   }, [clickedSeccion, handleReset]); | ||||||
|  |  | ||||||
|  |   const handleMoveEnd = (newPosition: { coordinates: PointTuple; zoom: number }) => { | ||||||
|  |     if (newPosition.zoom <= MIN_ZOOM) { | ||||||
|  |       if (position.zoom > MIN_ZOOM || clickedSeccion !== null) { | ||||||
|  |         handleReset(); | ||||||
|  |       } | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     if (newPosition.zoom < position.zoom && clickedSeccion !== null) { | ||||||
|  |       setClickedSeccion(null); | ||||||
|  |     } | ||||||
|  |     setPosition({ center: newPosition.coordinates, zoom: newPosition.zoom }); | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   useEffect(() => { | ||||||
|  |     const handleKeyDown = (e: KeyboardEvent) => e.key === 'Escape' && handleReset(); | ||||||
|  |     window.addEventListener('keydown', handleKeyDown); | ||||||
|  |     return () => window.removeEventListener('keydown', handleKeyDown); | ||||||
|  |   }, [handleReset]); | ||||||
|  |  | ||||||
|  |   const getSectionFillColor = (seccionRomana: string) => { | ||||||
|  |     return resultadosPorSeccionRomana.get(seccionRomana)?.colorGanador || DEFAULT_MAP_COLOR; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   const handleZoomIn = () => { | ||||||
|  |     if (position.zoom < MAX_ZOOM) { | ||||||
|  |       setPosition(p => ({ ...p, zoom: Math.min(p.zoom * 1.5, MAX_ZOOM) })); | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <div className="mapa-wrapper"> | ||||||
|  |       <div className="mapa-container"> | ||||||
|  |         {isLoading ? <div className="spinner"></div> : ( | ||||||
|  |           <ComposableMap | ||||||
|  |             key={selectedCategoriaId} | ||||||
|  |             projection="geoMercator" | ||||||
|  |             projectionConfig={{ scale: 4400, center: [-60.5, -37.2] }} | ||||||
|  |             className="rsm-svg" | ||||||
|  |             data-tooltip-id="seccion-tooltip" | ||||||
|  |           > | ||||||
|  |             <ZoomableGroup | ||||||
|  |               center={position.center} | ||||||
|  |               zoom={position.zoom} | ||||||
|  |               onMoveEnd={handleMoveEnd} | ||||||
|  |               minZoom={MIN_ZOOM} | ||||||
|  |               maxZoom={MAX_ZOOM} | ||||||
|  |               translateExtent={TRANSLATE_EXTENT} | ||||||
|  |               style={{ transition: "transform 400ms ease-in-out" }} | ||||||
|  |               filterZoomEvent={(e: WheelEvent) => { | ||||||
|  |                 if (e.deltaY > 0) { | ||||||
|  |                   handleReset(); | ||||||
|  |                 } else if (e.deltaY < 0) { | ||||||
|  |                   handleZoomIn(); | ||||||
|  |                 } | ||||||
|  |                 return true; | ||||||
|  |               }} | ||||||
|  |             > | ||||||
|  |               {geoData && ( | ||||||
|  |                 <Geographies geography={geoData}> | ||||||
|  |                   {({ geographies }: { geographies: SeccionGeography[] }) => | ||||||
|  |                     geographies.map((geo) => { | ||||||
|  |                       const seccionRomana = geo.properties.seccion; | ||||||
|  |                       const resultado = resultadosPorSeccionRomana.get(seccionRomana); | ||||||
|  |                       const nombreGanador = resultado?.agrupacionGanadoraId ? nombresAgrupaciones.get(resultado.agrupacionGanadoraId) : 'Sin datos'; | ||||||
|  |                       const isSelected = clickedSeccion?.rsmKey === geo.rsmKey; | ||||||
|  |                       const isFaded = clickedSeccion && !isSelected; | ||||||
|  |                       const isClickable = !!resultado; | ||||||
|  |  | ||||||
|  |                       return ( | ||||||
|  |                         <Geography | ||||||
|  |                           key={geo.rsmKey + (isSelected ? '-selected' : '')} | ||||||
|  |                           geography={geo as any} | ||||||
|  |                           data-tooltip-id="seccion-tooltip" | ||||||
|  |                           onClick={isClickable ? () => handleGeographyClick(geo) : undefined} | ||||||
|  |                           onMouseEnter={() => { | ||||||
|  |                             if (isClickable) { | ||||||
|  |                               // --- CORRECCIÓN 3: Tooltip con nombre de sección --- | ||||||
|  |                               const nombreSeccionLegible = NOMBRES_SECCIONES[geo.properties.seccion] || "Sección Desconocida"; | ||||||
|  |                               setTooltipContent(`${nombreSeccionLegible}: ${nombreGanador}`); | ||||||
|  |                             } | ||||||
|  |                           }} | ||||||
|  |                           onMouseLeave={() => setTooltipContent("")} | ||||||
|  |                           className={`rsm-geography ${isSelected ? 'selected' : ''} ${isFaded ? 'faded' : ''} ${!isClickable ? 'no-results' : ''}`} | ||||||
|  |                           fill={getSectionFillColor(seccionRomana)} | ||||||
|  |                         /> | ||||||
|  |                       ); | ||||||
|  |                     }) | ||||||
|  |                   } | ||||||
|  |                 </Geographies> | ||||||
|  |               )} | ||||||
|  |             </ZoomableGroup> | ||||||
|  |           </ComposableMap> | ||||||
|  |         )} | ||||||
|  |         {clickedSeccion && <ControlesMapa onReset={handleReset} />} | ||||||
|  |         <Tooltip id="seccion-tooltip" content={tooltipContent} /> | ||||||
|  |       </div> | ||||||
|  |       <div className="info-panel"> | ||||||
|  |         <div className="mapa-categoria-selector"> | ||||||
|  |           <select | ||||||
|  |             className="mapa-categoria-combobox" | ||||||
|  |             value={selectedCategoriaId} | ||||||
|  |             onChange={(e) => { | ||||||
|  |               setSelectedCategoriaId(Number(e.target.value)); | ||||||
|  |               handleReset(); | ||||||
|  |             }} | ||||||
|  |           > | ||||||
|  |             {CATEGORIAS.map(cat => ( | ||||||
|  |               <option key={cat.id} value={cat.id}> | ||||||
|  |                 {cat.nombre} | ||||||
|  |               </option> | ||||||
|  |             ))} | ||||||
|  |           </select> | ||||||
|  |         </div> | ||||||
|  |         <DetalleSeccion seccion={clickedSeccion} categoriaId={selectedCategoriaId} onReset={handleReset} /> | ||||||
|  |         <LegendSecciones resultados={resultadosPorSeccionRomana} nombresAgrupaciones={nombresAgrupaciones} /> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | // --- Sub-componente para la Leyenda --- | ||||||
|  | const LegendSecciones = ({ resultados, nombresAgrupaciones }: { resultados: Map<string, ResultadoMapaSeccion>, nombresAgrupaciones: Map<string, string> }) => { | ||||||
|  |   const legendItems = useMemo(() => { | ||||||
|  |     const ganadoresUnicos = new Map<string, { nombre: string; color: string }>(); | ||||||
|  |     resultados.forEach(resultado => { | ||||||
|  |       if (resultado.agrupacionGanadoraId && resultado.colorGanador && !ganadoresUnicos.has(resultado.agrupacionGanadoraId)) { | ||||||
|  |         ganadoresUnicos.set(resultado.agrupacionGanadoraId, { | ||||||
|  |           nombre: nombresAgrupaciones.get(resultado.agrupacionGanadoraId) || 'Desconocido', | ||||||
|  |           color: resultado.colorGanador | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     }); | ||||||
|  |     return Array.from(ganadoresUnicos.values()); | ||||||
|  |   }, [resultados, nombresAgrupaciones]); | ||||||
|  |  | ||||||
|  |   return ( | ||||||
|  |     <div className="legend"> | ||||||
|  |       <h4>Ganadores por Sección</h4> | ||||||
|  |       {legendItems.map(item => ( | ||||||
|  |         <div key={item.nombre} className="legend-item"> | ||||||
|  |           <div className="legend-color-box" style={{ backgroundColor: item.color }} /> | ||||||
|  |           <span>{item.nombre}</span> | ||||||
|  |         </div> | ||||||
|  |       ))} | ||||||
|  |     </div> | ||||||
|  |   ); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | export default MapaBsAsSecciones; | ||||||
| @@ -96,8 +96,8 @@ | |||||||
| } | } | ||||||
| .party-logo { | .party-logo { | ||||||
|     flex-shrink: 0; |     flex-shrink: 0; | ||||||
|     width: 50px; |     width: 75px; | ||||||
|     height: 50px; |     height: 75px; | ||||||
| } | } | ||||||
| .party-logo img { | .party-logo img { | ||||||
|     width: 100%; |     width: 100%; | ||||||
|   | |||||||
| @@ -4,6 +4,7 @@ import { getResumenProvincial, getConfiguracionPublica } from '../apiService'; | |||||||
| import type { CategoriaResumen, ResultadoTicker } from '../types/types'; | import type { CategoriaResumen, ResultadoTicker } from '../types/types'; | ||||||
| import { ImageWithFallback } from './ImageWithFallback'; | import { ImageWithFallback } from './ImageWithFallback'; | ||||||
| import './TickerWidget.css'; | import './TickerWidget.css'; | ||||||
|  | import { useMemo } from 'react'; | ||||||
|  |  | ||||||
| const formatPercent = (num: number) => `${(num || 0).toFixed(2).replace('.', ',')}%`; | const formatPercent = (num: number) => `${(num || 0).toFixed(2).replace('.', ',')}%`; | ||||||
|  |  | ||||||
| @@ -20,7 +21,9 @@ export const TickerWidget = () => { | |||||||
|     staleTime: 0, |     staleTime: 0, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   const cantidadAMostrar = parseInt(configData?.TickerResultadosCantidad || '5', 10) + 1; |   const cantidadAMostrar = useMemo(() => { | ||||||
|  |     return parseInt(configData?.TickerResultadosCantidad || '5', 10); | ||||||
|  |   }, [configData]); | ||||||
|  |  | ||||||
|   if (isLoading) return <div className="ticker-wrapper loading">Cargando resumen...</div>; |   if (isLoading) return <div className="ticker-wrapper loading">Cargando resumen...</div>; | ||||||
|   if (error || !categorias) return <div className="ticker-wrapper error">No hay datos disponibles.</div>; |   if (error || !categorias) return <div className="ticker-wrapper error">No hay datos disponibles.</div>; | ||||||
| @@ -36,7 +39,7 @@ export const TickerWidget = () => { | |||||||
|         if (categoria.resultados.length > cantidadAMostrar) { |         if (categoria.resultados.length > cantidadAMostrar) { | ||||||
|           const topParties = categoria.resultados.slice(0, cantidadAMostrar - 1); |           const topParties = categoria.resultados.slice(0, cantidadAMostrar - 1); | ||||||
|           const otherParties = categoria.resultados.slice(cantidadAMostrar - 1); |           const otherParties = categoria.resultados.slice(cantidadAMostrar - 1); | ||||||
|           const otrosPorcentaje = otherParties.reduce((sum, party) => sum + party.votosPorcentaje, 0); |           const otrosPorcentaje = otherParties.reduce((sum, party) => sum + party.porcentaje, 0); | ||||||
|  |  | ||||||
|           const otrosEntry: ResultadoTicker = { |           const otrosEntry: ResultadoTicker = { | ||||||
|             id: `otros-${categoria.categoriaId}`, |             id: `otros-${categoria.categoriaId}`, | ||||||
| @@ -45,7 +48,7 @@ export const TickerWidget = () => { | |||||||
|             color: '#888888', |             color: '#888888', | ||||||
|             logoUrl: null, |             logoUrl: null, | ||||||
|             votos: 0, |             votos: 0, | ||||||
|             votosPorcentaje: otrosPorcentaje, |             porcentaje: otrosPorcentaje, | ||||||
|           }; |           }; | ||||||
|  |  | ||||||
|           displayResults = [...topParties, otrosEntry]; |           displayResults = [...topParties, otrosEntry]; | ||||||
| @@ -75,10 +78,10 @@ export const TickerWidget = () => { | |||||||
|                   <div className="party-details"> |                   <div className="party-details"> | ||||||
|                     <div className="party-info"> |                     <div className="party-info"> | ||||||
|                       <span className="party-name">{partido.nombreCorto || partido.nombre}</span> |                       <span className="party-name">{partido.nombreCorto || partido.nombre}</span> | ||||||
|                       <span className="party-percent">{formatPercent(partido.votosPorcentaje)}</span> |                       <span className="party-percent">{formatPercent(partido.porcentaje)}</span> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div className="party-bar-background"> |                     <div className="party-bar-background"> | ||||||
|                       <div className="party-bar-foreground" style={{ width: `${partido.votosPorcentaje}%`, backgroundColor: partido.color || '#888' }}></div> |                       <div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor: partido.color || '#888' }}></div> | ||||||
|                     </div> |                     </div> | ||||||
|                   </div> |                   </div> | ||||||
|                 </div> |                 </div> | ||||||
|   | |||||||
| @@ -48,7 +48,7 @@ export interface ResultadoTicker { | |||||||
|   color: string | null; |   color: string | null; | ||||||
|   logoUrl: string | null; |   logoUrl: string | null; | ||||||
|   votos: number; |   votos: number; | ||||||
|   votosPorcentaje: number; |   porcentaje: number; | ||||||
| } | } | ||||||
|  |  | ||||||
| export interface EstadoRecuentoTicker { | export interface EstadoRecuentoTicker { | ||||||
|   | |||||||
| @@ -187,22 +187,52 @@ public class AdminController : ControllerBase | |||||||
|   [HttpPut("logos")] |   [HttpPut("logos")] | ||||||
|   public async Task<IActionResult> UpdateLogos([FromBody] List<LogoAgrupacionCategoria> logos) |   public async Task<IActionResult> UpdateLogos([FromBody] List<LogoAgrupacionCategoria> logos) | ||||||
|   { |   { | ||||||
|     // Lógica de "Upsert" |  | ||||||
|     foreach (var logo in logos) |     foreach (var logo in logos) | ||||||
|     { |     { | ||||||
|       var logoExistente = await _dbContext.LogosAgrupacionesCategorias |       var logoExistente = await _dbContext.LogosAgrupacionesCategorias | ||||||
|           .FirstOrDefaultAsync(l => l.AgrupacionPoliticaId == logo.AgrupacionPoliticaId && l.CategoriaId == logo.CategoriaId); |           .FirstOrDefaultAsync(l => | ||||||
|  |               l.AgrupacionPoliticaId == logo.AgrupacionPoliticaId && | ||||||
|  |               l.CategoriaId == logo.CategoriaId && | ||||||
|  |               l.AmbitoGeograficoId == logo.AmbitoGeograficoId); | ||||||
|  |  | ||||||
|       if (logoExistente != null) |       if (logoExistente != null) | ||||||
|       { |       { | ||||||
|  |         // Si encontramos el registro exacto, solo actualizamos su URL. | ||||||
|         logoExistente.LogoUrl = logo.LogoUrl; |         logoExistente.LogoUrl = logo.LogoUrl; | ||||||
|       } |       } | ||||||
|       else if (!string.IsNullOrEmpty(logo.LogoUrl)) |       else if (!string.IsNullOrEmpty(logo.LogoUrl)) | ||||||
|       { |       { | ||||||
|         _dbContext.LogosAgrupacionesCategorias.Add(logo); |         // Si no se encontró un registro exacto (es un override nuevo), | ||||||
|  |         // lo añadimos a la base de datos. | ||||||
|  |         _dbContext.LogosAgrupacionesCategorias.Add(new LogoAgrupacionCategoria | ||||||
|  |         { | ||||||
|  |           AgrupacionPoliticaId = logo.AgrupacionPoliticaId, | ||||||
|  |           CategoriaId = logo.CategoriaId, | ||||||
|  |           AmbitoGeograficoId = logo.AmbitoGeograficoId, | ||||||
|  |           LogoUrl = logo.LogoUrl | ||||||
|  |         }); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     await _dbContext.SaveChangesAsync(); |     await _dbContext.SaveChangesAsync(); | ||||||
|     return NoContent(); |     return NoContent(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   [HttpGet("catalogos/municipios")] | ||||||
|  |   public async Task<IActionResult> GetMunicipiosForAdmin() | ||||||
|  |   { | ||||||
|  |     var municipios = await _dbContext.AmbitosGeograficos | ||||||
|  |         .AsNoTracking() | ||||||
|  |         .Where(a => a.NivelId == 30) // Nivel 30 = Municipio | ||||||
|  |         .OrderBy(a => a.Nombre) | ||||||
|  |         .Select(a => new | ||||||
|  |         { | ||||||
|  |           // Devolvemos el ID de la base de datos como un string, | ||||||
|  |           // que es lo que el componente Select espera. | ||||||
|  |           Id = a.Id.ToString(), | ||||||
|  |           Nombre = a.Nombre | ||||||
|  |         }) | ||||||
|  |         .ToListAsync(); | ||||||
|  |  | ||||||
|  |     return Ok(municipios); | ||||||
|  |   } | ||||||
| } | } | ||||||
| @@ -22,13 +22,11 @@ public class ResultadosController : ControllerBase | |||||||
|         _configuration = configuration; |         _configuration = configuration; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     [HttpGet("partido/{seccionId}")] |     [HttpGet("partido/{seccionId}")] // 'seccionId' es el ID del municipio | ||||||
|     public async Task<IActionResult> GetResultadosPorPartido(string seccionId) |     public async Task<IActionResult> GetResultadosPorPartido(string seccionId) | ||||||
|     { |     { | ||||||
|         // 1. Buscamos el ámbito geográfico correspondiente al PARTIDO (Nivel 30) |  | ||||||
|         var ambito = await _dbContext.AmbitosGeograficos |         var ambito = await _dbContext.AmbitosGeograficos | ||||||
|             .AsNoTracking() |             .AsNoTracking() | ||||||
|             // CAMBIO CLAVE: Buscamos por SeccionId y NivelId para ser precisos |  | ||||||
|             .FirstOrDefaultAsync(a => a.SeccionId == seccionId && a.NivelId == 30); |             .FirstOrDefaultAsync(a => a.SeccionId == seccionId && a.NivelId == 30); | ||||||
|  |  | ||||||
|         if (ambito == null) |         if (ambito == null) | ||||||
| @@ -36,14 +34,12 @@ public class ResultadosController : ControllerBase | |||||||
|             return NotFound(new { message = $"No se encontró el partido con ID {seccionId}" }); |             return NotFound(new { message = $"No se encontró el partido con ID {seccionId}" }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 2. Buscamos el estado del recuento para ese ámbito |  | ||||||
|         var estadoRecuento = await _dbContext.EstadosRecuentos |         var estadoRecuento = await _dbContext.EstadosRecuentos | ||||||
|             .AsNoTracking() |             .AsNoTracking() | ||||||
|             .FirstOrDefaultAsync(e => e.AmbitoGeograficoId == ambito.Id); |             .FirstOrDefaultAsync(e => e.AmbitoGeograficoId == ambito.Id); | ||||||
|  |  | ||||||
|         if (estadoRecuento == null) |         if (estadoRecuento == null) | ||||||
|         { |         { | ||||||
|             // Devolvemos una respuesta vacía pero válida para el frontend |  | ||||||
|             return Ok(new MunicipioResultadosDto |             return Ok(new MunicipioResultadosDto | ||||||
|             { |             { | ||||||
|                 MunicipioNombre = ambito.Nombre, |                 MunicipioNombre = ambito.Nombre, | ||||||
| @@ -55,28 +51,57 @@ public class ResultadosController : ControllerBase | |||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 3. Buscamos todos los votos para ese ámbito |         // 1. Obtenemos los IDs de las agrupaciones que tienen resultados en este municipio | ||||||
|  |         var agrupacionIds = await _dbContext.ResultadosVotos | ||||||
|  |             .Where(rv => rv.AmbitoGeograficoId == ambito.Id) | ||||||
|  |             .Select(rv => rv.AgrupacionPoliticaId) | ||||||
|  |             .Distinct() | ||||||
|  |             .ToListAsync(); | ||||||
|  |  | ||||||
|  |         // 2. Buscamos TODOS los logos relevantes en una sola consulta: | ||||||
|  |         //    - Los que son para la categoría Concejales (7) | ||||||
|  |         //    - Y pertenecen a los partidos que compiten aquí | ||||||
|  |         //    - Y son genéricos (sin ámbito) O específicos para ESTE municipio | ||||||
|  |         var logosRelevantes = await _dbContext.LogosAgrupacionesCategorias | ||||||
|  |             .AsNoTracking() | ||||||
|  |             .Where(l => l.CategoriaId == 7 && | ||||||
|  |                         agrupacionIds.Contains(l.AgrupacionPoliticaId) && | ||||||
|  |                         (l.AmbitoGeograficoId == null || l.AmbitoGeograficoId == ambito.Id)) | ||||||
|  |             .ToListAsync(); | ||||||
|  |  | ||||||
|         var resultadosVotos = await _dbContext.ResultadosVotos |         var resultadosVotos = await _dbContext.ResultadosVotos | ||||||
|             .AsNoTracking() |             .AsNoTracking() | ||||||
|             .Include(rv => rv.AgrupacionPolitica) |             .Include(rv => rv.AgrupacionPolitica) | ||||||
|             .Where(rv => rv.AmbitoGeograficoId == ambito.Id) |             .Where(rv => rv.AmbitoGeograficoId == ambito.Id) | ||||||
|             .ToListAsync(); |             .ToListAsync(); | ||||||
|  |  | ||||||
|         // 4. Calculamos el total de votos positivos |  | ||||||
|         long totalVotosPositivos = resultadosVotos.Sum(r => r.CantidadVotos); |         long totalVotosPositivos = resultadosVotos.Sum(r => r.CantidadVotos); | ||||||
|  |  | ||||||
|         // 5. Mapeamos al DTO de respuesta |  | ||||||
|         var respuestaDto = new MunicipioResultadosDto |         var respuestaDto = new MunicipioResultadosDto | ||||||
|         { |         { | ||||||
|             MunicipioNombre = ambito.Nombre, |             MunicipioNombre = ambito.Nombre, | ||||||
|             UltimaActualizacion = estadoRecuento.FechaTotalizacion, |             UltimaActualizacion = estadoRecuento.FechaTotalizacion, | ||||||
|             PorcentajeEscrutado = estadoRecuento.MesasTotalizadasPorcentaje, |             PorcentajeEscrutado = estadoRecuento.MesasTotalizadasPorcentaje, | ||||||
|             PorcentajeParticipacion = estadoRecuento.ParticipacionPorcentaje, |             PorcentajeParticipacion = estadoRecuento.ParticipacionPorcentaje, | ||||||
|             Resultados = resultadosVotos.Select(rv => new AgrupacionResultadoDto |             Resultados = resultadosVotos.Select(rv => | ||||||
|             { |             { | ||||||
|  |                 // --- LÓGICA DE FALLBACK --- | ||||||
|  |                 var logoUrl = | ||||||
|  |                     // 1. Buscamos primero el logo específico para este municipio. | ||||||
|  |                     logosRelevantes.FirstOrDefault(l => l.AgrupacionPoliticaId == rv.AgrupacionPoliticaId && l.AmbitoGeograficoId == ambito.Id)?.LogoUrl | ||||||
|  |                     // 2. Si no lo encontramos, buscamos el logo genérico (sin ámbito). | ||||||
|  |                     ?? logosRelevantes.FirstOrDefault(l => l.AgrupacionPoliticaId == rv.AgrupacionPoliticaId && l.AmbitoGeograficoId == null)?.LogoUrl; | ||||||
|  |  | ||||||
|  |                 return new AgrupacionResultadoDto | ||||||
|  |                 { | ||||||
|  |                     Id = rv.AgrupacionPolitica.Id, | ||||||
|                     Nombre = rv.AgrupacionPolitica.Nombre, |                     Nombre = rv.AgrupacionPolitica.Nombre, | ||||||
|  |                     NombreCorto = rv.AgrupacionPolitica.NombreCorto, | ||||||
|  |                     Color = rv.AgrupacionPolitica.Color, | ||||||
|  |                     LogoUrl = logoUrl, // Asignamos el logo encontrado | ||||||
|                     Votos = rv.CantidadVotos, |                     Votos = rv.CantidadVotos, | ||||||
|                     Porcentaje = totalVotosPositivos > 0 ? (rv.CantidadVotos * 100.0m / totalVotosPositivos) : 0 |                     Porcentaje = totalVotosPositivos > 0 ? (rv.CantidadVotos * 100.0m / totalVotosPositivos) : 0 | ||||||
|  |                 }; | ||||||
|             }).OrderByDescending(r => r.Votos).ToList(), |             }).OrderByDescending(r => r.Votos).ToList(), | ||||||
|             VotosAdicionales = new VotosAdicionalesDto |             VotosAdicionales = new VotosAdicionalesDto | ||||||
|             { |             { | ||||||
| @@ -95,15 +120,10 @@ public class ResultadosController : ControllerBase | |||||||
|         var provincia = await _dbContext.AmbitosGeograficos.AsNoTracking() |         var provincia = await _dbContext.AmbitosGeograficos.AsNoTracking() | ||||||
|             .FirstOrDefaultAsync(a => a.DistritoId == distritoId && a.NivelId == 10); |             .FirstOrDefaultAsync(a => a.DistritoId == distritoId && a.NivelId == 10); | ||||||
|  |  | ||||||
|         var todosLosResumenes = await _dbContext.ResumenesVotos.AsNoTracking() |         if (provincia == null) | ||||||
|             .Include(r => r.AgrupacionPolitica) |         { | ||||||
|             .ToListAsync(); |             return NotFound($"No se encontró la provincia con distritoId {distritoId}"); | ||||||
|  |         } | ||||||
|         // OBTENER TODOS LOS LOGOS EN UNA SOLA CONSULTA |  | ||||||
|         var logosLookup = (await _dbContext.LogosAgrupacionesCategorias.AsNoTracking().ToListAsync()) |  | ||||||
|             .ToLookup(l => $"{l.AgrupacionPoliticaId}-{l.CategoriaId}"); |  | ||||||
|  |  | ||||||
|         if (provincia == null) return NotFound($"No se encontró la provincia con distritoId {distritoId}"); |  | ||||||
|  |  | ||||||
|         var estadosPorCategoria = await _dbContext.EstadosRecuentosGenerales.AsNoTracking() |         var estadosPorCategoria = await _dbContext.EstadosRecuentosGenerales.AsNoTracking() | ||||||
|             .Include(e => e.CategoriaElectoral) |             .Include(e => e.CategoriaElectoral) | ||||||
| @@ -113,43 +133,50 @@ public class ResultadosController : ControllerBase | |||||||
|         var resultadosPorMunicipio = await _dbContext.ResultadosVotos |         var resultadosPorMunicipio = await _dbContext.ResultadosVotos | ||||||
|             .AsNoTracking() |             .AsNoTracking() | ||||||
|             .Include(r => r.AgrupacionPolitica) |             .Include(r => r.AgrupacionPolitica) | ||||||
|             .Where(r => r.AmbitoGeografico.NivelId == 30) |             .Where(r => r.AmbitoGeografico.NivelId == 30) // Nivel 30 = Municipio | ||||||
|             .ToListAsync(); |             .ToListAsync(); | ||||||
|  |  | ||||||
|  |         var logos = await _dbContext.LogosAgrupacionesCategorias.AsNoTracking().ToListAsync(); | ||||||
|  |  | ||||||
|         var resultadosAgrupados = resultadosPorMunicipio |         var resultadosAgrupados = resultadosPorMunicipio | ||||||
|             .GroupBy(r => r.CategoriaId) |             .GroupBy(r => r.CategoriaId) | ||||||
|             .Select(g => new |             .Select(g => new | ||||||
|             { |             { | ||||||
|                 CategoriaId = g.Key, |                 CategoriaId = g.Key, | ||||||
|  |                 CategoriaNombre = estadosPorCategoria.ContainsKey(g.Key) ? estadosPorCategoria[g.Key].CategoriaElectoral.Nombre : "Desconocido", | ||||||
|  |                 EstadoRecuento = estadosPorCategoria.GetValueOrDefault(g.Key), | ||||||
|                 TotalVotosCategoria = g.Sum(r => r.CantidadVotos), |                 TotalVotosCategoria = g.Sum(r => r.CantidadVotos), | ||||||
|                 // Agrupamos por el ID de la agrupación, no por el objeto |                 Resultados = g | ||||||
|                 Resultados = g.GroupBy(r => r.AgrupacionPoliticaId) |                     .GroupBy(r => r.AgrupacionPolitica) | ||||||
|                     .Select(partidoGroup => new |                     .Select(partidoGroup => new | ||||||
|                     { |                     { | ||||||
|                                   // El objeto Agrupacion lo tomamos del primer elemento del grupo |                         Agrupacion = partidoGroup.Key, | ||||||
|                                   Agrupacion = partidoGroup.First().AgrupacionPolitica, |  | ||||||
|                         Votos = partidoGroup.Sum(r => r.CantidadVotos) |                         Votos = partidoGroup.Sum(r => r.CantidadVotos) | ||||||
|                     }) |                     }) | ||||||
|  |                     .OrderByDescending(r => r.Votos) | ||||||
|                     .ToList() |                     .ToList() | ||||||
|             }) |             }) | ||||||
|             .Select(g => new |             .Select(g => new | ||||||
|             { |             { | ||||||
|                 g.CategoriaId, |                 g.CategoriaId, | ||||||
|                 CategoriaNombre = estadosPorCategoria.ContainsKey(g.CategoriaId) ? estadosPorCategoria[g.CategoriaId].CategoriaElectoral.Nombre : "Desconocido", |                 g.CategoriaNombre, | ||||||
|                 EstadoRecuento = estadosPorCategoria.GetValueOrDefault(g.CategoriaId), |                 g.EstadoRecuento, | ||||||
|                 Resultados = g.Resultados |                 Resultados = g.Resultados.Select(r => | ||||||
|                               .Select(r => new |  | ||||||
|                 { |                 { | ||||||
|                                   r.Agrupacion.Id, |                     var logoUrl = logos.FirstOrDefault(l => l.AgrupacionPoliticaId == r.Agrupacion.Id && l.CategoriaId == g.CategoriaId && l.AmbitoGeograficoId != null)?.LogoUrl | ||||||
|  |                                ?? logos.FirstOrDefault(l => l.AgrupacionPoliticaId == r.Agrupacion.Id && l.CategoriaId == g.CategoriaId && l.AmbitoGeograficoId == null)?.LogoUrl; | ||||||
|  |  | ||||||
|  |                     return new | ||||||
|  |                     { | ||||||
|  |                         Id = r.Agrupacion.Id, | ||||||
|                         r.Agrupacion.Nombre, |                         r.Agrupacion.Nombre, | ||||||
|                         r.Agrupacion.NombreCorto, |                         r.Agrupacion.NombreCorto, | ||||||
|                         r.Agrupacion.Color, |                         r.Agrupacion.Color, | ||||||
|                                   LogoUrl = logosLookup[$"{r.Agrupacion.Id}-{g.CategoriaId}"].FirstOrDefault()?.LogoUrl, |                         LogoUrl = logoUrl, | ||||||
|                         r.Votos, |                         r.Votos, | ||||||
|                                   VotosPorcentaje = g.TotalVotosCategoria > 0 ? ((decimal)r.Votos * 100 / g.TotalVotosCategoria) : 0 |                         Porcentaje = g.TotalVotosCategoria > 0 ? ((decimal)r.Votos * 100 / g.TotalVotosCategoria) : 0 | ||||||
|                               }) |                     }; | ||||||
|                               .OrderByDescending(r => r.Votos) |                 }).ToList() | ||||||
|                               .ToList() |  | ||||||
|             }) |             }) | ||||||
|             .OrderBy(c => c.CategoriaId) |             .OrderBy(c => c.CategoriaId) | ||||||
|             .ToList(); |             .ToList(); | ||||||
| @@ -235,63 +262,60 @@ public class ResultadosController : ControllerBase | |||||||
|         return Ok(resultadosGanadores); |         return Ok(resultadosGanadores); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     [HttpGet("municipio/{ambitoId}")] // Cambiamos el nombre del parámetro de ruta |     [HttpGet("municipio/{ambitoId}")] | ||||||
|     public async Task<IActionResult> GetResultadosPorMunicipio(int ambitoId) // Cambiamos el tipo de string a int |     public async Task<IActionResult> GetResultadosPorMunicipio(int ambitoId, [FromQuery] int categoriaId) | ||||||
|     { |     { | ||||||
|         _logger.LogInformation("Buscando resultados para AmbitoGeograficoId: {AmbitoId}", ambitoId); |         _logger.LogInformation("Buscando resultados para AmbitoGeograficoId: {AmbitoId}, CategoriaId: {CategoriaId}", ambitoId, categoriaId); | ||||||
|  |  | ||||||
|         // PASO 1: Buscar el Ámbito Geográfico directamente por su CLAVE PRIMARIA (AmbitoGeograficoId). |  | ||||||
|         var ambito = await _dbContext.AmbitosGeograficos |  | ||||||
|             .AsNoTracking() |  | ||||||
|             .FirstOrDefaultAsync(a => a.Id == ambitoId && a.NivelId == 30); // Usamos a.Id == ambitoId |  | ||||||
|  |  | ||||||
|  |         // Validamos que el ámbito exista | ||||||
|  |         var ambito = await _dbContext.AmbitosGeograficos.AsNoTracking() | ||||||
|  |             .FirstOrDefaultAsync(a => a.Id == ambitoId && a.NivelId == 30); | ||||||
|         if (ambito == null) |         if (ambito == null) | ||||||
|         { |         { | ||||||
|             _logger.LogWarning("No se encontró el ámbito para el ID interno: {AmbitoId} o no es Nivel 30.", ambitoId); |             _logger.LogWarning("No se encontró el municipio con ID: {AmbitoId}", ambitoId); | ||||||
|             return NotFound(new { message = $"No se encontró el municipio con ID interno {ambitoId}" }); |             return NotFound($"No se encontró el municipio con ID {ambitoId}"); | ||||||
|         } |         } | ||||||
|         _logger.LogInformation("Ámbito encontrado: Id={AmbitoId}, Nombre={AmbitoNombre}", ambito.Id, ambito.Nombre); |  | ||||||
|  |  | ||||||
|         // PASO 2: Usar la CLAVE PRIMARIA (ambito.Id) para buscar el estado del recuento. |         // Obtenemos el estado del recuento para el ámbito | ||||||
|         var estadoRecuento = await _dbContext.EstadosRecuentos |         var estadoRecuento = await _dbContext.EstadosRecuentos | ||||||
|             .AsNoTracking() |             .AsNoTracking() | ||||||
|             .FirstOrDefaultAsync(e => e.AmbitoGeograficoId == ambito.Id); |             .FirstOrDefaultAsync(e => e.AmbitoGeograficoId == ambito.Id); | ||||||
|  |  | ||||||
|         if (estadoRecuento == null) |         // Obtenemos los votos para ESE municipio y ESA categoría | ||||||
|         { |  | ||||||
|             _logger.LogWarning("No se encontró EstadoRecuento para AmbitoGeograficoId: {AmbitoId}", ambito.Id); |  | ||||||
|             return NotFound(new { message = $"No se han encontrado resultados de recuento para el municipio {ambito.Nombre}" }); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         // PASO 3: Usar la CLAVE PRIMARIA (ambito.Id) para buscar los votos. |  | ||||||
|         var resultadosVotos = await _dbContext.ResultadosVotos |         var resultadosVotos = await _dbContext.ResultadosVotos | ||||||
|             .AsNoTracking() |             .AsNoTracking() | ||||||
|             .Include(rv => rv.AgrupacionPolitica) // Incluimos el nombre del partido |             .Include(rv => rv.AgrupacionPolitica) | ||||||
|             .Where(rv => rv.AmbitoGeograficoId == ambito.Id) |             .Where(rv => rv.AmbitoGeograficoId == ambitoId && rv.CategoriaId == categoriaId) | ||||||
|             .OrderByDescending(rv => rv.CantidadVotos) |  | ||||||
|             .ToListAsync(); |             .ToListAsync(); | ||||||
|  |  | ||||||
|         // PASO 4: Calcular el total de votos positivos para el porcentaje. |         // Calculamos el total de votos solo para esta selección | ||||||
|         long totalVotosPositivos = resultadosVotos.Sum(r => r.CantidadVotos); |         var totalVotosPositivos = (decimal)resultadosVotos.Sum(r => r.CantidadVotos); | ||||||
|  |  | ||||||
|         // PASO 5: Mapear todo al DTO de respuesta que el frontend espera. |         // Mapeamos los resultados de los partidos | ||||||
|  |         var resultadosPartidosDto = resultadosVotos | ||||||
|  |             .OrderByDescending(r => r.CantidadVotos) | ||||||
|  |             .Select(rv => new AgrupacionResultadoDto // Assuming AgrupacionResultadoDto is the correct DTO for individual party results | ||||||
|  |             { | ||||||
|  |                 Id = rv.AgrupacionPolitica.Id, | ||||||
|  |                 Nombre = rv.AgrupacionPolitica.NombreCorto ?? rv.AgrupacionPolitica.Nombre, | ||||||
|  |                 Color = rv.AgrupacionPolitica.Color, | ||||||
|  |                 Votos = rv.CantidadVotos, | ||||||
|  |                 Porcentaje = totalVotosPositivos > 0 ? (rv.CantidadVotos / totalVotosPositivos) * 100 : 0 | ||||||
|  |             }).ToList(); | ||||||
|  |  | ||||||
|  |         // Construimos la respuesta completa del DTO | ||||||
|         var respuestaDto = new MunicipioResultadosDto |         var respuestaDto = new MunicipioResultadosDto | ||||||
|         { |         { | ||||||
|             MunicipioNombre = ambito.Nombre, |             MunicipioNombre = ambito.Nombre, | ||||||
|             UltimaActualizacion = estadoRecuento.FechaTotalizacion, |             UltimaActualizacion = estadoRecuento?.FechaTotalizacion ?? DateTime.UtcNow, // Use null-conditional operator | ||||||
|             PorcentajeEscrutado = estadoRecuento.MesasTotalizadasPorcentaje, |             PorcentajeEscrutado = estadoRecuento?.MesasTotalizadasPorcentaje ?? 0, | ||||||
|             PorcentajeParticipacion = estadoRecuento.ParticipacionPorcentaje, |             PorcentajeParticipacion = estadoRecuento?.ParticipacionPorcentaje ?? 0, | ||||||
|             Resultados = resultadosVotos.Select(rv => new AgrupacionResultadoDto |             Resultados = resultadosPartidosDto, | ||||||
|  |             VotosAdicionales = new VotosAdicionalesDto // Assuming default constructor is fine | ||||||
|             { |             { | ||||||
|                 Nombre = rv.AgrupacionPolitica.Nombre, |                 EnBlanco = estadoRecuento?.VotosEnBlanco ?? 0, | ||||||
|                 Votos = rv.CantidadVotos, |                 Nulos = estadoRecuento?.VotosNulos ?? 0, | ||||||
|                 Porcentaje = totalVotosPositivos > 0 ? (rv.CantidadVotos * 100.0m / totalVotosPositivos) : 0 |                 Recurridos = estadoRecuento?.VotosRecurridos ?? 0 | ||||||
|             }).ToList(), |  | ||||||
|             VotosAdicionales = new VotosAdicionalesDto |  | ||||||
|             { |  | ||||||
|                 EnBlanco = estadoRecuento.VotosEnBlanco, |  | ||||||
|                 Nulos = estadoRecuento.VotosNulos, |  | ||||||
|                 Recurridos = estadoRecuento.VotosRecurridos |  | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
| @@ -537,11 +561,10 @@ public class ResultadosController : ControllerBase | |||||||
|     [HttpGet("concejales/{seccionId}")] |     [HttpGet("concejales/{seccionId}")] | ||||||
|     public async Task<IActionResult> GetResultadosConcejalesPorSeccion(string seccionId) |     public async Task<IActionResult> GetResultadosConcejalesPorSeccion(string seccionId) | ||||||
|     { |     { | ||||||
|         // 1. Encontrar todos los municipios (Nivel 30) que pertenecen a la sección dada (Nivel 20) |  | ||||||
|         var municipiosDeLaSeccion = await _dbContext.AmbitosGeograficos |         var municipiosDeLaSeccion = await _dbContext.AmbitosGeograficos | ||||||
|             .AsNoTracking() |             .AsNoTracking() | ||||||
|             .Where(a => a.NivelId == 30 && a.SeccionProvincialId == seccionId) |             .Where(a => a.NivelId == 30 && a.SeccionProvincialId == seccionId) | ||||||
|             .Select(a => a.Id) // Solo necesitamos sus IDs |             .Select(a => a.Id) | ||||||
|             .ToListAsync(); |             .ToListAsync(); | ||||||
|  |  | ||||||
|         if (!municipiosDeLaSeccion.Any()) |         if (!municipiosDeLaSeccion.Any()) | ||||||
| @@ -549,7 +572,6 @@ public class ResultadosController : ControllerBase | |||||||
|             return Ok(new List<object>()); |             return Ok(new List<object>()); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 2. Obtener todos los resultados de la categoría Concejales (ID 7) para esos municipios |  | ||||||
|         var resultadosMunicipales = await _dbContext.ResultadosVotos |         var resultadosMunicipales = await _dbContext.ResultadosVotos | ||||||
|             .AsNoTracking() |             .AsNoTracking() | ||||||
|             .Include(r => r.AgrupacionPolitica) |             .Include(r => r.AgrupacionPolitica) | ||||||
| @@ -561,29 +583,159 @@ public class ResultadosController : ControllerBase | |||||||
|             .Where(l => l.CategoriaId == 7) |             .Where(l => l.CategoriaId == 7) | ||||||
|             .ToDictionaryAsync(l => l.AgrupacionPoliticaId); |             .ToDictionaryAsync(l => l.AgrupacionPoliticaId); | ||||||
|  |  | ||||||
|         // 3. Agrupar y sumar en memoria para obtener el total por partido para la sección |         var totalVotosSeccion = (decimal)resultadosMunicipales.Sum(r => r.CantidadVotos); | ||||||
|         var totalVotosSeccion = resultadosMunicipales.Sum(r => r.CantidadVotos); |  | ||||||
|  |  | ||||||
|         var resultadosFinales = resultadosMunicipales |         var resultadosFinales = resultadosMunicipales | ||||||
|             .GroupBy(r => r.AgrupacionPolitica) |             // 1. Agrupamos por el ID del partido para evitar duplicados. | ||||||
|  |             .GroupBy(r => r.AgrupacionPoliticaId) | ||||||
|             .Select(g => new |             .Select(g => new | ||||||
|             { |             { | ||||||
|                 Agrupacion = g.Key, |                 // 2. Obtenemos la entidad completa del primer elemento del grupo. | ||||||
|  |                 Agrupacion = g.First().AgrupacionPolitica, | ||||||
|                 Votos = g.Sum(r => r.CantidadVotos) |                 Votos = g.Sum(r => r.CantidadVotos) | ||||||
|             }) |             }) | ||||||
|             .OrderByDescending(r => r.Votos) |             .OrderByDescending(r => r.Votos) | ||||||
|             .Select(r => new |             .Select(r => new | ||||||
|             { |             { | ||||||
|                 r.Agrupacion.Id, |                 Id = r.Agrupacion.Id, // Aseguramos que el Id esté en el objeto final | ||||||
|                 r.Agrupacion.Nombre, |                 r.Agrupacion.Nombre, | ||||||
|                 r.Agrupacion.NombreCorto, |                 r.Agrupacion.NombreCorto, | ||||||
|                 r.Agrupacion.Color, |                 r.Agrupacion.Color, | ||||||
|                 LogoUrl = logosConcejales.GetValueOrDefault(r.Agrupacion.Id)?.LogoUrl, |                 LogoUrl = logosConcejales.GetValueOrDefault(r.Agrupacion.Id)?.LogoUrl, | ||||||
|                 r.Votos, |                 Votos = r.Votos, | ||||||
|                 votosPorcentaje = totalVotosSeccion > 0 ? ((decimal)r.Votos * 100 / totalVotosSeccion) : 0 |                 // --- CORRECCIÓN CLAVE --- | ||||||
|  |                 // 3. Usamos el nombre de propiedad correcto que el frontend espera: 'votosPorcentaje' | ||||||
|  |                 VotosPorcentaje = totalVotosSeccion > 0 ? ((decimal)r.Votos * 100 / totalVotosSeccion) : 0 | ||||||
|             }) |             }) | ||||||
|             .ToList(); |             .ToList(); | ||||||
|  |  | ||||||
|         return Ok(resultadosFinales); |         return Ok(resultadosFinales); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     [HttpGet("mapa-por-seccion")] | ||||||
|  |     public async Task<IActionResult> GetResultadosMapaPorSeccion([FromQuery] int categoriaId) | ||||||
|  |     { | ||||||
|  |         // 1. Obtenemos todos los resultados a nivel de MUNICIPIO para la categoría dada. | ||||||
|  |         var resultadosMunicipales = await _dbContext.ResultadosVotos | ||||||
|  |             .AsNoTracking() | ||||||
|  |             .Include(r => r.AmbitoGeografico) | ||||||
|  |             .Include(r => r.AgrupacionPolitica) | ||||||
|  |             .Where(r => r.CategoriaId == categoriaId && r.AmbitoGeografico.NivelId == 30) | ||||||
|  |             .ToListAsync(); | ||||||
|  |  | ||||||
|  |         // 2. Agrupamos en memoria por Sección Electoral y sumamos los votos. | ||||||
|  |         var ganadoresPorSeccion = resultadosMunicipales | ||||||
|  |             .GroupBy(r => r.AmbitoGeografico.SeccionProvincialId) | ||||||
|  |             .Select(g => | ||||||
|  |             { | ||||||
|  |                 // Para cada sección, encontramos al partido con más votos. | ||||||
|  |                 var ganador = g | ||||||
|  |                     .GroupBy(r => r.AgrupacionPolitica) | ||||||
|  |                     .Select(pg => new { Agrupacion = pg.Key, TotalVotos = pg.Sum(r => r.CantidadVotos) }) | ||||||
|  |                     .OrderByDescending(x => x.TotalVotos) | ||||||
|  |                     .FirstOrDefault(); | ||||||
|  |  | ||||||
|  |                 // Buscamos el nombre de la sección | ||||||
|  |                 var seccionInfo = _dbContext.AmbitosGeograficos | ||||||
|  |                     .FirstOrDefault(a => a.SeccionProvincialId == g.Key && a.NivelId == 20); | ||||||
|  |  | ||||||
|  |                 return new | ||||||
|  |                 { | ||||||
|  |                     SeccionId = g.Key, | ||||||
|  |                     SeccionNombre = seccionInfo?.Nombre, | ||||||
|  |                     AgrupacionGanadoraId = ganador?.Agrupacion.Id, | ||||||
|  |                     ColorGanador = ganador?.Agrupacion.Color | ||||||
|  |                 }; | ||||||
|  |             }) | ||||||
|  |             .Where(r => r.SeccionId != null) // Filtramos cualquier posible nulo | ||||||
|  |             .ToList(); | ||||||
|  |  | ||||||
|  |         return Ok(ganadoresPorSeccion); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet("seccion/{seccionId}")] | ||||||
|  |     public async Task<IActionResult> GetResultadosDetallePorSeccion(string seccionId, [FromQuery] int categoriaId) | ||||||
|  |     { | ||||||
|  |         var municipiosDeLaSeccion = await _dbContext.AmbitosGeograficos | ||||||
|  |             .AsNoTracking() | ||||||
|  |             .Where(a => a.NivelId == 30 && a.SeccionProvincialId == seccionId) | ||||||
|  |             .Select(a => a.Id) | ||||||
|  |             .ToListAsync(); | ||||||
|  |  | ||||||
|  |         if (!municipiosDeLaSeccion.Any()) return Ok(new List<object>()); | ||||||
|  |  | ||||||
|  |         var resultadosMunicipales = await _dbContext.ResultadosVotos | ||||||
|  |             .AsNoTracking() | ||||||
|  |             .Include(r => r.AgrupacionPolitica) | ||||||
|  |             .Where(r => r.CategoriaId == categoriaId && municipiosDeLaSeccion.Contains(r.AmbitoGeograficoId)) | ||||||
|  |             .ToListAsync(); | ||||||
|  |  | ||||||
|  |         var totalVotosSeccion = (decimal)resultadosMunicipales.Sum(r => r.CantidadVotos); | ||||||
|  |  | ||||||
|  |         var resultadosFinales = resultadosMunicipales | ||||||
|  |             // 1. Agrupamos por el ID del partido para evitar duplicados. | ||||||
|  |             .GroupBy(r => r.AgrupacionPoliticaId) | ||||||
|  |             .Select(g => new | ||||||
|  |             { | ||||||
|  |                 // 2. Tomamos la entidad completa del primer elemento del grupo. | ||||||
|  |                 Agrupacion = g.First().AgrupacionPolitica, | ||||||
|  |                 Votos = g.Sum(r => r.CantidadVotos) | ||||||
|  |             }) | ||||||
|  |             .OrderByDescending(r => r.Votos) | ||||||
|  |             .Select(r => new | ||||||
|  |             { | ||||||
|  |                 id = r.Agrupacion.Id, | ||||||
|  |                 nombre = r.Agrupacion.NombreCorto ?? r.Agrupacion.Nombre, | ||||||
|  |                 votos = r.Votos, | ||||||
|  |                 porcentaje = totalVotosSeccion > 0 ? ((decimal)r.Votos * 100 / totalVotosSeccion) : 0, | ||||||
|  |                 // 3. Añadimos el color a la respuesta. | ||||||
|  |                 color = r.Agrupacion.Color | ||||||
|  |             }) | ||||||
|  |             .ToList(); | ||||||
|  |  | ||||||
|  |         return Ok(resultadosFinales); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     [HttpGet("mapa-por-municipio")] | ||||||
|  |     public async Task<IActionResult> GetResultadosMapaPorMunicipio([FromQuery] int categoriaId) | ||||||
|  |     { | ||||||
|  |         // Obtenemos los votos primero | ||||||
|  |         var votosPorMunicipio = await _dbContext.ResultadosVotos | ||||||
|  |             .AsNoTracking() | ||||||
|  |             .Where(r => r.CategoriaId == categoriaId && r.AmbitoGeografico.NivelId == 30) | ||||||
|  |             .ToListAsync(); | ||||||
|  |  | ||||||
|  |         // Luego, los agrupamos en memoria | ||||||
|  |         var ganadores = votosPorMunicipio | ||||||
|  |             .GroupBy(r => r.AmbitoGeograficoId) | ||||||
|  |             .Select(g => g.OrderByDescending(r => r.CantidadVotos).First()) | ||||||
|  |             .ToList(); | ||||||
|  |  | ||||||
|  |         // Ahora, obtenemos los detalles necesarios en una sola consulta adicional | ||||||
|  |         var idsAgrupacionesGanadoras = ganadores.Select(g => g.AgrupacionPoliticaId).ToList(); | ||||||
|  |         var idsAmbitosGanadores = ganadores.Select(g => g.AmbitoGeograficoId).ToList(); | ||||||
|  |  | ||||||
|  |         var agrupacionesInfo = await _dbContext.AgrupacionesPoliticas | ||||||
|  |             .AsNoTracking() | ||||||
|  |             .Where(a => idsAgrupacionesGanadoras.Contains(a.Id)) | ||||||
|  |             .ToDictionaryAsync(a => a.Id); | ||||||
|  |  | ||||||
|  |         var ambitosInfo = await _dbContext.AmbitosGeograficos | ||||||
|  |             .AsNoTracking() | ||||||
|  |             .Where(a => idsAmbitosGanadores.Contains(a.Id)) | ||||||
|  |             .ToDictionaryAsync(a => a.Id); | ||||||
|  |  | ||||||
|  |         // Finalmente, unimos todo en memoria | ||||||
|  |         var resultadoFinal = ganadores.Select(g => new | ||||||
|  |         { | ||||||
|  |             AmbitoId = g.AmbitoGeograficoId, | ||||||
|  |             DepartamentoNombre = ambitosInfo.GetValueOrDefault(g.AmbitoGeograficoId)?.Nombre, | ||||||
|  |             AgrupacionGanadoraId = g.AgrupacionPoliticaId, | ||||||
|  |             ColorGanador = agrupacionesInfo.GetValueOrDefault(g.AgrupacionPoliticaId)?.Color | ||||||
|  |         }) | ||||||
|  |         .Where(r => r.DepartamentoNombre != null) // Filtramos por si acaso | ||||||
|  |         .ToList(); | ||||||
|  |  | ||||||
|  |         return Ok(resultadoFinal); | ||||||
|  |     } | ||||||
| } | } | ||||||
| @@ -1,6 +1,5 @@ | |||||||
| @Elecciones.Api_HostAddress = http://localhost:5217 | @Elecciones.Api_HostAddress = http://localhost:5217 | ||||||
|  |  | ||||||
| GET {{Elecciones.Api_HostAddress}}/weatherforecast/ |  | ||||||
| Accept: application/json | Accept: application/json | ||||||
|  |  | ||||||
| ### | ### | ||||||
|   | |||||||
| @@ -14,7 +14,7 @@ using System.Reflection; | |||||||
| [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")] | [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")] | ||||||
| [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | ||||||
| [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | ||||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+608ae655bedf6c59be5fec1e14fc308871d2fd62")] | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+271a86b63211dff88fb7188d1db7b390e6c53efb")] | ||||||
| [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")] | [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")] | ||||||
| [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")] | [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")] | ||||||
| [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | ||||||
|   | |||||||
| @@ -1 +1 @@ | |||||||
| {"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","khGrM2Rl22MsVh9N6\u002B7todRrMuJ6o3ljuHxZF/aubqE=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","6xYke/2SzNspypSwIgizeNUH7b\u002Bfoz3wYfKk6z1tMsw="],"CachedAssets":{},"CachedCopyCandidates":{}} | {"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","PmrFmFQepAv9NhtsO0l45PPk3BWugccwJ3ysTKcw7bM=","6CAjHexjcmVc1caYyfNvMfhJRU6qtmi57Siv1ysirg0=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","\u002BgTea2HWyPcSQvQyVe0ghcDwqBGkKZIDd2\u002BlGKdxL2U="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||||
| @@ -1 +1 @@ | |||||||
| {"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","khGrM2Rl22MsVh9N6\u002B7todRrMuJ6o3ljuHxZF/aubqE=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","6xYke/2SzNspypSwIgizeNUH7b\u002Bfoz3wYfKk6z1tMsw="],"CachedAssets":{},"CachedCopyCandidates":{}} | {"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","PmrFmFQepAv9NhtsO0l45PPk3BWugccwJ3ysTKcw7bM=","6CAjHexjcmVc1caYyfNvMfhJRU6qtmi57Siv1ysirg0=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","\u002BgTea2HWyPcSQvQyVe0ghcDwqBGkKZIDd2\u002BlGKdxL2U="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||||
| @@ -0,0 +1,28 @@ | |||||||
|  | <?xml version="1.0" encoding="utf-8"?> | ||||||
|  | <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||||||
|  |   <Target Name="GetEFProjectMetadata"> | ||||||
|  |     <MSBuild Condition=" '$(TargetFramework)' == '' " | ||||||
|  |              Projects="$(MSBuildProjectFile)" | ||||||
|  |              Targets="GetEFProjectMetadata" | ||||||
|  |              Properties="TargetFramework=$(TargetFrameworks.Split(';')[0]);EFProjectMetadataFile=$(EFProjectMetadataFile)" /> | ||||||
|  |     <ItemGroup Condition=" '$(TargetFramework)' != '' "> | ||||||
|  |       <EFProjectMetadata Include="AssemblyName: $(AssemblyName)" /> | ||||||
|  |       <EFProjectMetadata Include="Language: $(Language)" /> | ||||||
|  |       <EFProjectMetadata Include="OutputPath: $(OutputPath)" /> | ||||||
|  |       <EFProjectMetadata Include="Platform: $(Platform)" /> | ||||||
|  |       <EFProjectMetadata Include="PlatformTarget: $(PlatformTarget)" /> | ||||||
|  |       <EFProjectMetadata Include="ProjectAssetsFile: $(ProjectAssetsFile)" /> | ||||||
|  |       <EFProjectMetadata Include="ProjectDir: $(ProjectDir)" /> | ||||||
|  |       <EFProjectMetadata Include="RootNamespace: $(RootNamespace)" /> | ||||||
|  |       <EFProjectMetadata Include="RuntimeFrameworkVersion: $(RuntimeFrameworkVersion)" /> | ||||||
|  |       <EFProjectMetadata Include="TargetFileName: $(TargetFileName)" /> | ||||||
|  |       <EFProjectMetadata Include="TargetFrameworkMoniker: $(TargetFrameworkMoniker)" /> | ||||||
|  |       <EFProjectMetadata Include="Nullable: $(Nullable)" /> | ||||||
|  |       <EFProjectMetadata Include="TargetFramework: $(TargetFramework)" /> | ||||||
|  |       <EFProjectMetadata Include="TargetPlatformIdentifier: $(TargetPlatformIdentifier)" /> | ||||||
|  |     </ItemGroup> | ||||||
|  |     <WriteLinesToFile Condition=" '$(TargetFramework)' != '' " | ||||||
|  |                       File="$(EFProjectMetadataFile)" | ||||||
|  |                       Lines="@(EFProjectMetadata)" /> | ||||||
|  |   </Target> | ||||||
|  | </Project> | ||||||
| @@ -3,7 +3,11 @@ namespace Elecciones.Core.DTOs.ApiResponses; | |||||||
|  |  | ||||||
| public class AgrupacionResultadoDto | public class AgrupacionResultadoDto | ||||||
| { | { | ||||||
|  |     public required string? Id { get; set; } | ||||||
|     public string Nombre { get; set; } = null!; |     public string Nombre { get; set; } = null!; | ||||||
|  |     public string? NombreCorto { get; set; } = null!; | ||||||
|  |     public string? Color { get; set; } = null!; | ||||||
|  |     public string? LogoUrl { get; set; } = null!; | ||||||
|     public long Votos { get; set; } |     public long Votos { get; set; } | ||||||
|     public decimal Porcentaje { get; set; } |     public decimal Porcentaje { get; set; } | ||||||
| } | } | ||||||
| @@ -13,7 +13,7 @@ using System.Reflection; | |||||||
| [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")] | [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")] | ||||||
| [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | ||||||
| [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | ||||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+608ae655bedf6c59be5fec1e14fc308871d2fd62")] | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+271a86b63211dff88fb7188d1db7b390e6c53efb")] | ||||||
| [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")] | [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")] | ||||||
| [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")] | [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")] | ||||||
| [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | ||||||
|   | |||||||
| @@ -78,7 +78,8 @@ public class EleccionesDbContext(DbContextOptions<EleccionesDbContext> options) | |||||||
|         }); |         }); | ||||||
|         modelBuilder.Entity<LogoAgrupacionCategoria>(entity => |         modelBuilder.Entity<LogoAgrupacionCategoria>(entity => | ||||||
|         { |         { | ||||||
|             entity.HasIndex(l => new { l.AgrupacionPoliticaId, l.CategoriaId }).IsUnique(); |             // La combinación de las tres columnas debe ser única. | ||||||
|  |             entity.HasIndex(l => new { l.AgrupacionPoliticaId, l.CategoriaId, l.AmbitoGeograficoId }).IsUnique(); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -7,12 +7,10 @@ public class LogoAgrupacionCategoria | |||||||
| { | { | ||||||
|     [Key] |     [Key] | ||||||
|     public int Id { get; set; } |     public int Id { get; set; } | ||||||
|  |  | ||||||
|     [Required] |     [Required] | ||||||
|     public string AgrupacionPoliticaId { get; set; } = null!; |     public string AgrupacionPoliticaId { get; set; } = null!; | ||||||
|      |  | ||||||
|     [Required] |     [Required] | ||||||
|     public int CategoriaId { get; set; } |     public int CategoriaId { get; set; } | ||||||
|  |  | ||||||
|     public string? LogoUrl { get; set; } |     public string? LogoUrl { get; set; } | ||||||
|  |     public int? AmbitoGeograficoId { get; set; } | ||||||
| } | } | ||||||
| @@ -0,0 +1,556 @@ | |||||||
|  | // <auto-generated /> | ||||||
|  | using System; | ||||||
|  | using Elecciones.Database; | ||||||
|  | using Microsoft.EntityFrameworkCore; | ||||||
|  | using Microsoft.EntityFrameworkCore.Infrastructure; | ||||||
|  | using Microsoft.EntityFrameworkCore.Metadata; | ||||||
|  | using Microsoft.EntityFrameworkCore.Migrations; | ||||||
|  | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; | ||||||
|  |  | ||||||
|  | #nullable disable | ||||||
|  |  | ||||||
|  | namespace Elecciones.Database.Migrations | ||||||
|  | { | ||||||
|  |     [DbContext(typeof(EleccionesDbContext))] | ||||||
|  |     [Migration("20250902155740_AddAmbitoToLogosWithCorrectIndex")] | ||||||
|  |     partial class AddAmbitoToLogosWithCorrectIndex | ||||||
|  |     { | ||||||
|  |         /// <inheritdoc /> | ||||||
|  |         protected override void BuildTargetModel(ModelBuilder modelBuilder) | ||||||
|  |         { | ||||||
|  | #pragma warning disable 612, 618 | ||||||
|  |             modelBuilder | ||||||
|  |                 .UseCollation("Modern_Spanish_CI_AS") | ||||||
|  |                 .HasAnnotation("ProductVersion", "9.0.8") | ||||||
|  |                 .HasAnnotation("Relational:MaxIdentifierLength", 128); | ||||||
|  |  | ||||||
|  |             SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.AdminUser", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("Id") | ||||||
|  |                         .ValueGeneratedOnAdd() | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("PasswordHash") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("PasswordSalt") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("Username") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasMaxLength(100) | ||||||
|  |                         .HasColumnType("nvarchar(100)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("AdminUsers"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.AgrupacionPolitica", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<string>("Id") | ||||||
|  |                         .HasColumnType("nvarchar(450)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("Color") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("IdTelegrama") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("Nombre") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("NombreCorto") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int?>("OrdenDiputados") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int?>("OrdenSenadores") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("AgrupacionesPoliticas"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.AmbitoGeografico", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("Id") | ||||||
|  |                         .ValueGeneratedOnAdd() | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("CircuitoId") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("DistritoId") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("EstablecimientoId") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("MesaId") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("MunicipioId") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("NivelId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("Nombre") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("SeccionId") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("SeccionProvincialId") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("AmbitosGeograficos"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.Bancada", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("Id") | ||||||
|  |                         .ValueGeneratedOnAdd() | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("AgrupacionPoliticaId") | ||||||
|  |                         .HasColumnType("nvarchar(450)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("Camara") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("NumeroBanca") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("AgrupacionPoliticaId"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("Bancadas"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.CategoriaElectoral", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("Id") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("Nombre") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("Orden") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("CategoriasElectorales"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.Configuracion", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<string>("Clave") | ||||||
|  |                         .HasMaxLength(100) | ||||||
|  |                         .HasColumnType("nvarchar(100)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("Valor") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasMaxLength(100) | ||||||
|  |                         .HasColumnType("nvarchar(100)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Clave"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("Configuraciones"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("AmbitoGeograficoId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CategoriaId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CantidadElectores") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CantidadVotantes") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<DateTime>("FechaTotalizacion") | ||||||
|  |                         .HasColumnType("datetime2"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("MesasEsperadas") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("MesasTotalizadas") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("MesasTotalizadasPorcentaje") | ||||||
|  |                         .HasPrecision(5, 2) | ||||||
|  |                         .HasColumnType("decimal(5,2)"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("ParticipacionPorcentaje") | ||||||
|  |                         .HasPrecision(5, 2) | ||||||
|  |                         .HasColumnType("decimal(5,2)"); | ||||||
|  |  | ||||||
|  |                     b.Property<long>("VotosEnBlanco") | ||||||
|  |                         .HasColumnType("bigint"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("VotosEnBlancoPorcentaje") | ||||||
|  |                         .HasPrecision(18, 4) | ||||||
|  |                         .HasColumnType("decimal(18,4)"); | ||||||
|  |  | ||||||
|  |                     b.Property<long>("VotosNulos") | ||||||
|  |                         .HasColumnType("bigint"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("VotosNulosPorcentaje") | ||||||
|  |                         .HasPrecision(18, 4) | ||||||
|  |                         .HasColumnType("decimal(18,4)"); | ||||||
|  |  | ||||||
|  |                     b.Property<long>("VotosRecurridos") | ||||||
|  |                         .HasColumnType("bigint"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("VotosRecurridosPorcentaje") | ||||||
|  |                         .HasPrecision(18, 4) | ||||||
|  |                         .HasColumnType("decimal(18,4)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("AmbitoGeograficoId", "CategoriaId"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("EstadosRecuentos"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("AmbitoGeograficoId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CategoriaId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CantidadElectores") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CantidadVotantes") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<DateTime>("FechaTotalizacion") | ||||||
|  |                         .HasColumnType("datetime2"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("MesasEsperadas") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("MesasTotalizadas") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("MesasTotalizadasPorcentaje") | ||||||
|  |                         .HasPrecision(5, 2) | ||||||
|  |                         .HasColumnType("decimal(5,2)"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("ParticipacionPorcentaje") | ||||||
|  |                         .HasPrecision(5, 2) | ||||||
|  |                         .HasColumnType("decimal(5,2)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("AmbitoGeograficoId", "CategoriaId"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("CategoriaId"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("EstadosRecuentosGenerales"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.LogoAgrupacionCategoria", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("Id") | ||||||
|  |                         .ValueGeneratedOnAdd() | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("AgrupacionPoliticaId") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(450)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int?>("AmbitoGeograficoId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CategoriaId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("LogoUrl") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("AgrupacionPoliticaId", "CategoriaId", "AmbitoGeograficoId") | ||||||
|  |                         .IsUnique() | ||||||
|  |                         .HasFilter("[AmbitoGeograficoId] IS NOT NULL"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("LogosAgrupacionesCategorias"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.OcupanteBanca", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("Id") | ||||||
|  |                         .ValueGeneratedOnAdd() | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("BancadaId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("FotoUrl") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("NombreOcupante") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("Periodo") | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("BancadaId") | ||||||
|  |                         .IsUnique(); | ||||||
|  |  | ||||||
|  |                     b.ToTable("OcupantesBancas"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.ProyeccionBanca", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("Id") | ||||||
|  |                         .ValueGeneratedOnAdd() | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("AgrupacionPoliticaId") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(450)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("AmbitoGeograficoId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CategoriaId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<DateTime>("FechaTotalizacion") | ||||||
|  |                         .HasColumnType("datetime2"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("NroBancas") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("AgrupacionPoliticaId"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("AmbitoGeograficoId", "CategoriaId", "AgrupacionPoliticaId") | ||||||
|  |                         .IsUnique(); | ||||||
|  |  | ||||||
|  |                     b.ToTable("ProyeccionesBancas"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.ResultadoVoto", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<long>("Id") | ||||||
|  |                         .ValueGeneratedOnAdd() | ||||||
|  |                         .HasColumnType("bigint"); | ||||||
|  |  | ||||||
|  |                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id")); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("AgrupacionPoliticaId") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(450)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("AmbitoGeograficoId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<long>("CantidadVotos") | ||||||
|  |                         .HasColumnType("bigint"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("CategoriaId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("PorcentajeVotos") | ||||||
|  |                         .HasPrecision(18, 4) | ||||||
|  |                         .HasColumnType("decimal(18,4)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("AgrupacionPoliticaId"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("AmbitoGeograficoId", "CategoriaId", "AgrupacionPoliticaId") | ||||||
|  |                         .IsUnique(); | ||||||
|  |  | ||||||
|  |                     b.ToTable("ResultadosVotos"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.ResumenVoto", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<int>("Id") | ||||||
|  |                         .ValueGeneratedOnAdd() | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("AgrupacionPoliticaId") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(450)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("AmbitoGeograficoId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<long>("Votos") | ||||||
|  |                         .HasColumnType("bigint"); | ||||||
|  |  | ||||||
|  |                     b.Property<decimal>("VotosPorcentaje") | ||||||
|  |                         .HasPrecision(5, 2) | ||||||
|  |                         .HasColumnType("decimal(5,2)"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.HasIndex("AgrupacionPoliticaId"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("ResumenesVotos"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.Telegrama", b => | ||||||
|  |                 { | ||||||
|  |                     b.Property<string>("Id") | ||||||
|  |                         .HasColumnType("nvarchar(450)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int>("AmbitoGeograficoId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|  |                     b.Property<string>("ContenidoBase64") | ||||||
|  |                         .IsRequired() | ||||||
|  |                         .HasColumnType("nvarchar(max)"); | ||||||
|  |  | ||||||
|  |                     b.Property<DateTime>("FechaEscaneo") | ||||||
|  |                         .HasColumnType("datetime2"); | ||||||
|  |  | ||||||
|  |                     b.Property<DateTime>("FechaTotalizacion") | ||||||
|  |                         .HasColumnType("datetime2"); | ||||||
|  |  | ||||||
|  |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|  |                     b.ToTable("Telegramas"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.Bancada", b => | ||||||
|  |                 { | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica") | ||||||
|  |                         .WithMany() | ||||||
|  |                         .HasForeignKey("AgrupacionPoliticaId"); | ||||||
|  |  | ||||||
|  |                     b.Navigation("AgrupacionPolitica"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b => | ||||||
|  |                 { | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico") | ||||||
|  |                         .WithMany() | ||||||
|  |                         .HasForeignKey("AmbitoGeograficoId") | ||||||
|  |                         .OnDelete(DeleteBehavior.Cascade) | ||||||
|  |                         .IsRequired(); | ||||||
|  |  | ||||||
|  |                     b.Navigation("AmbitoGeografico"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b => | ||||||
|  |                 { | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.CategoriaElectoral", "CategoriaElectoral") | ||||||
|  |                         .WithMany() | ||||||
|  |                         .HasForeignKey("CategoriaId") | ||||||
|  |                         .OnDelete(DeleteBehavior.Cascade) | ||||||
|  |                         .IsRequired(); | ||||||
|  |  | ||||||
|  |                     b.Navigation("CategoriaElectoral"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.OcupanteBanca", b => | ||||||
|  |                 { | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.Bancada", "Bancada") | ||||||
|  |                         .WithOne("Ocupante") | ||||||
|  |                         .HasForeignKey("Elecciones.Database.Entities.OcupanteBanca", "BancadaId") | ||||||
|  |                         .OnDelete(DeleteBehavior.Cascade) | ||||||
|  |                         .IsRequired(); | ||||||
|  |  | ||||||
|  |                     b.Navigation("Bancada"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.ProyeccionBanca", b => | ||||||
|  |                 { | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica") | ||||||
|  |                         .WithMany() | ||||||
|  |                         .HasForeignKey("AgrupacionPoliticaId") | ||||||
|  |                         .OnDelete(DeleteBehavior.Cascade) | ||||||
|  |                         .IsRequired(); | ||||||
|  |  | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico") | ||||||
|  |                         .WithMany() | ||||||
|  |                         .HasForeignKey("AmbitoGeograficoId") | ||||||
|  |                         .OnDelete(DeleteBehavior.Cascade) | ||||||
|  |                         .IsRequired(); | ||||||
|  |  | ||||||
|  |                     b.Navigation("AgrupacionPolitica"); | ||||||
|  |  | ||||||
|  |                     b.Navigation("AmbitoGeografico"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.ResultadoVoto", b => | ||||||
|  |                 { | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica") | ||||||
|  |                         .WithMany() | ||||||
|  |                         .HasForeignKey("AgrupacionPoliticaId") | ||||||
|  |                         .OnDelete(DeleteBehavior.Cascade) | ||||||
|  |                         .IsRequired(); | ||||||
|  |  | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico") | ||||||
|  |                         .WithMany() | ||||||
|  |                         .HasForeignKey("AmbitoGeograficoId") | ||||||
|  |                         .OnDelete(DeleteBehavior.Cascade) | ||||||
|  |                         .IsRequired(); | ||||||
|  |  | ||||||
|  |                     b.Navigation("AgrupacionPolitica"); | ||||||
|  |  | ||||||
|  |                     b.Navigation("AmbitoGeografico"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.ResumenVoto", b => | ||||||
|  |                 { | ||||||
|  |                     b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica") | ||||||
|  |                         .WithMany() | ||||||
|  |                         .HasForeignKey("AgrupacionPoliticaId") | ||||||
|  |                         .OnDelete(DeleteBehavior.Cascade) | ||||||
|  |                         .IsRequired(); | ||||||
|  |  | ||||||
|  |                     b.Navigation("AgrupacionPolitica"); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  |             modelBuilder.Entity("Elecciones.Database.Entities.Bancada", b => | ||||||
|  |                 { | ||||||
|  |                     b.Navigation("Ocupante"); | ||||||
|  |                 }); | ||||||
|  | #pragma warning restore 612, 618 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,49 @@ | |||||||
|  | using Microsoft.EntityFrameworkCore.Migrations; | ||||||
|  |  | ||||||
|  | #nullable disable | ||||||
|  |  | ||||||
|  | namespace Elecciones.Database.Migrations | ||||||
|  | { | ||||||
|  |     /// <inheritdoc /> | ||||||
|  |     public partial class AddAmbitoToLogosWithCorrectIndex : Migration | ||||||
|  |     { | ||||||
|  |         /// <inheritdoc /> | ||||||
|  |         protected override void Up(MigrationBuilder migrationBuilder) | ||||||
|  |         { | ||||||
|  |             migrationBuilder.DropIndex( | ||||||
|  |                 name: "IX_LogosAgrupacionesCategorias_AgrupacionPoliticaId_CategoriaId", | ||||||
|  |                 table: "LogosAgrupacionesCategorias"); | ||||||
|  |  | ||||||
|  |             migrationBuilder.AddColumn<int>( | ||||||
|  |                 name: "AmbitoGeograficoId", | ||||||
|  |                 table: "LogosAgrupacionesCategorias", | ||||||
|  |                 type: "int", | ||||||
|  |                 nullable: true); | ||||||
|  |  | ||||||
|  |             migrationBuilder.CreateIndex( | ||||||
|  |                 name: "IX_LogosAgrupacionesCategorias_AgrupacionPoliticaId_CategoriaId_AmbitoGeograficoId", | ||||||
|  |                 table: "LogosAgrupacionesCategorias", | ||||||
|  |                 columns: new[] { "AgrupacionPoliticaId", "CategoriaId", "AmbitoGeograficoId" }, | ||||||
|  |                 unique: true, | ||||||
|  |                 filter: "[AmbitoGeograficoId] IS NOT NULL"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         /// <inheritdoc /> | ||||||
|  |         protected override void Down(MigrationBuilder migrationBuilder) | ||||||
|  |         { | ||||||
|  |             migrationBuilder.DropIndex( | ||||||
|  |                 name: "IX_LogosAgrupacionesCategorias_AgrupacionPoliticaId_CategoriaId_AmbitoGeograficoId", | ||||||
|  |                 table: "LogosAgrupacionesCategorias"); | ||||||
|  |  | ||||||
|  |             migrationBuilder.DropColumn( | ||||||
|  |                 name: "AmbitoGeograficoId", | ||||||
|  |                 table: "LogosAgrupacionesCategorias"); | ||||||
|  |  | ||||||
|  |             migrationBuilder.CreateIndex( | ||||||
|  |                 name: "IX_LogosAgrupacionesCategorias_AgrupacionPoliticaId_CategoriaId", | ||||||
|  |                 table: "LogosAgrupacionesCategorias", | ||||||
|  |                 columns: new[] { "AgrupacionPoliticaId", "CategoriaId" }, | ||||||
|  |                 unique: true); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -284,6 +284,9 @@ namespace Elecciones.Database.Migrations | |||||||
|                         .IsRequired() |                         .IsRequired() | ||||||
|                         .HasColumnType("nvarchar(450)"); |                         .HasColumnType("nvarchar(450)"); | ||||||
|  |  | ||||||
|  |                     b.Property<int?>("AmbitoGeograficoId") | ||||||
|  |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
|                     b.Property<int>("CategoriaId") |                     b.Property<int>("CategoriaId") | ||||||
|                         .HasColumnType("int"); |                         .HasColumnType("int"); | ||||||
|  |  | ||||||
| @@ -292,8 +295,9 @@ namespace Elecciones.Database.Migrations | |||||||
|  |  | ||||||
|                     b.HasKey("Id"); |                     b.HasKey("Id"); | ||||||
|  |  | ||||||
|                     b.HasIndex("AgrupacionPoliticaId", "CategoriaId") |                     b.HasIndex("AgrupacionPoliticaId", "CategoriaId", "AmbitoGeograficoId") | ||||||
|                         .IsUnique(); |                         .IsUnique() | ||||||
|  |                         .HasFilter("[AmbitoGeograficoId] IS NOT NULL"); | ||||||
|  |  | ||||||
|                     b.ToTable("LogosAgrupacionesCategorias"); |                     b.ToTable("LogosAgrupacionesCategorias"); | ||||||
|                 }); |                 }); | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ using System.Reflection; | |||||||
| [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")] | [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")] | ||||||
| [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | ||||||
| [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | ||||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3b8c6bf754cff6ace486ae8fe850ed4d69233280")] | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+271a86b63211dff88fb7188d1db7b390e6c53efb")] | ||||||
| [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")] | [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")] | ||||||
| [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")] | [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")] | ||||||
| [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ using System.Reflection; | |||||||
| [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")] | [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")] | ||||||
| [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | ||||||
| [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | ||||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+608ae655bedf6c59be5fec1e14fc308871d2fd62")] | [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+271a86b63211dff88fb7188d1db7b390e6c53efb")] | ||||||
| [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")] | [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")] | ||||||
| [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")] | [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")] | ||||||
| [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user