diff --git a/.env.example b/.env.example index 1ad7baa7..03077acc 100644 --- a/.env.example +++ b/.env.example @@ -2,6 +2,9 @@ NEXT_PUBLIC_BASE_URL=https://ajudadana.es NEXT_PUBLIC_NODE_ENV=production NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_ANON_KEY= +# this key is restricted in google +NEXT_PUBLIC_GOOGLE_KEY= + +GEOCODING_API_KEY= SUPABASE_GOOGLE_AUTH_ID= SUPABASE_GOOGLE_AUTH_SECRET= -API_KEY= \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index e8be2e68..30d7b4e6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "next": "15.0.2", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-google-places-autocomplete": "^4.1.0", "react-map-gl": "^7.1.7", "sonner": "^1.7.0" }, @@ -68,6 +69,137 @@ "sortablejs": "~1.15.2" } }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.2.tgz", + "integrity": "sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==", + "dependencies": { + "@babel/parser": "^7.26.2", + "@babel/types": "^7.26.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", + "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "dependencies": { + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.2.tgz", + "integrity": "sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==", + "dependencies": { + "@babel/types": "^7.26.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", + "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", + "dependencies": { + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.0.tgz", + "integrity": "sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@deck.gl/aggregation-layers": { "version": "9.0.34", "license": "MIT", @@ -294,6 +426,109 @@ "node": ">=14.0.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "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.2.0", + "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/cache": { + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@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==" + }, + "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==" + }, + "node_modules/@emotion/react": { + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@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.2", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.2.tgz", + "integrity": "sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.1", + "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==" + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.1.tgz", + "integrity": "sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==" + }, + "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==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", "dev": true, @@ -424,7 +659,6 @@ "node_modules/@floating-ui/core": { "version": "1.6.8", "license": "MIT", - "peer": true, "dependencies": { "@floating-ui/utils": "^0.2.8" } @@ -432,7 +666,6 @@ "node_modules/@floating-ui/dom": { "version": "1.6.11", "license": "MIT", - "peer": true, "dependencies": { "@floating-ui/core": "^1.6.0", "@floating-ui/utils": "^0.2.8" @@ -440,8 +673,7 @@ }, "node_modules/@floating-ui/utils": { "version": "0.2.8", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@glideapps/ts-necessities": { "version": "2.2.3", @@ -945,7 +1177,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -958,7 +1189,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -966,7 +1196,6 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -974,12 +1203,10 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2383,6 +2610,11 @@ "version": "1.0.7", "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==" + }, "node_modules/@types/pbf": { "version": "3.0.5", "license": "MIT" @@ -2404,14 +2636,12 @@ }, "node_modules/@types/prop-types": { "version": "15.7.13", - "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.12", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -2426,6 +2656,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-transition-group": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/retry": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", @@ -3245,6 +3483,20 @@ "node": ">= 0.4" } }, + "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==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "dev": true, @@ -3442,7 +3694,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3773,6 +4024,11 @@ "node": "^14.18.0 || >=16.10.0" } }, + "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==" + }, "node_modules/cookie": { "version": "0.6.0", "license": "MIT", @@ -3795,6 +4051,29 @@ "version": "1.0.3", "license": "MIT" }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "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==", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-fetch": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", @@ -3862,7 +4141,6 @@ }, "node_modules/csstype": { "version": "3.1.3", - "dev": true, "license": "MIT" }, "node_modules/d3-array": { @@ -4005,7 +4283,6 @@ }, "node_modules/debug": { "version": "4.3.7", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4208,6 +4485,15 @@ "node": ">=6.0.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==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dotenv": { "version": "16.4.5", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", @@ -4259,6 +4545,19 @@ "node": ">=10.13.0" } }, + "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==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-ex/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==" + }, "node_modules/es-abstract": { "version": "1.23.3", "dev": true, @@ -4420,7 +4719,6 @@ }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -5101,6 +5399,11 @@ "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==" + }, "node_modules/find-up": { "version": "5.0.0", "dev": true, @@ -5287,7 +5590,6 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5753,7 +6055,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -5762,6 +6063,14 @@ "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==", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.5", "dev": true, @@ -5846,7 +6155,6 @@ }, "node_modules/import-fresh": { "version": "3.3.0", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -6026,7 +6334,6 @@ }, "node_modules/is-core-module": { "version": "2.15.1", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -6455,11 +6762,27 @@ "node": ">= 6.0.0" } }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "dev": true, "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==" + }, "node_modules/json-schema-library": { "version": "9.3.5", "resolved": "https://registry.npmjs.org/json-schema-library/-/json-schema-library-9.3.5.tgz", @@ -6661,7 +6984,6 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "dev": true, "license": "MIT" }, "node_modules/lit": { @@ -6873,6 +7195,11 @@ "is-buffer": "~1.1.6" } }, + "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==" + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -7100,7 +7427,6 @@ }, "node_modules/ms": { "version": "2.1.3", - "dev": true, "license": "MIT" }, "node_modules/multimatch": { @@ -7409,7 +7735,6 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7813,7 +8138,6 @@ }, "node_modules/parent-module": { "version": "1.0.1", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -7822,6 +8146,23 @@ "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==", + "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": { "version": "4.0.0", "dev": true, @@ -7848,7 +8189,6 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { @@ -7866,6 +8206,14 @@ "url": "https://github.com/sponsors/isaacs" } }, + "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==", + "engines": { + "node": ">=8" + } + }, "node_modules/pathe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", @@ -8418,7 +8766,6 @@ }, "node_modules/prop-types": { "version": "15.8.1", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -8589,9 +8936,23 @@ "react": "^18.3.1" } }, + "node_modules/react-google-places-autocomplete": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/react-google-places-autocomplete/-/react-google-places-autocomplete-4.1.0.tgz", + "integrity": "sha512-C+BOJ/2667DLAFpd9To/OZJm1+1MOp7J6fQihys/W89tDcXb0O7i5ea7zOZ58ZE0mydnz788WxWKpqBqQJHjJg==", + "dependencies": { + "@googlemaps/js-api-loader": "^1.14.3", + "@types/google.maps": "^3.50.4", + "react-select": "^5.7.4", + "use-debounce": "^3.4.3" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/react-is": { "version": "16.13.1", - "dev": true, "license": "MIT" }, "node_modules/react-map-gl": { @@ -8643,6 +9004,41 @@ "integrity": "sha512-Rc2suX5meI0S3bfdZuA7JMFBGkJ875ApfVyq2WHELjBiiG22My/l7/8zPpH/CfFVQHuVLd8NLR0nv6vi0BYYKA==", "license": "MIT" }, + "node_modules/react-select": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.2.tgz", + "integrity": "sha512-a/LkOckoI62710gGPQSQqUp7A10fGbH/ya3/IR49qaq3XoBvwymgD5mJgtiHxBDsutyEQfdKNycWVh8Cg8UCjw==", + "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.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.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==", + "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/read-cache": { "version": "1.0.0", "dev": true, @@ -8707,6 +9103,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, "node_modules/regexp.prototype.flags": { "version": "1.5.3", "dev": true, @@ -8741,7 +9142,6 @@ }, "node_modules/resolve": { "version": "1.22.8", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", @@ -8757,7 +9157,6 @@ }, "node_modules/resolve-from": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -9156,6 +9555,14 @@ "license": "MIT", "peer": true }, + "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==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "license": "BSD-3-Clause", @@ -9488,6 +9895,11 @@ } } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.35.0", "dev": true, @@ -9601,7 +10013,6 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10058,6 +10469,27 @@ "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", "dev": true }, + "node_modules/use-debounce": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/use-debounce/-/use-debounce-3.4.3.tgz", + "integrity": "sha512-nxy+opOxDccWfhMl36J5BSCTpvcj89iaQk2OZWLAtBJQj7ISCtx1gh+rFbdjGfMl6vtCZf6gke/kYvrkVfHMoA==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "license": "MIT" diff --git a/package.json b/package.json index 236884ba..af687522 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "next": "15.0.2", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-google-places-autocomplete": "^4.1.0", "react-map-gl": "^7.1.7", "sonner": "^1.7.0" }, diff --git a/src/app/api/address/route.ts b/src/app/api/address/route.ts index bd5dc153..43d17dc8 100644 --- a/src/app/api/address/route.ts +++ b/src/app/api/address/route.ts @@ -14,9 +14,11 @@ const mapsTranslationToDbTowns: { [key: string]: string } = { Alcudia: "L'Alcúdia", Guadasuar: 'Guadassuar', València: 'Valencia', + Almusafes: 'Almussafes', + Montroi: 'Montroy', }; -const GOOGLE_URL = `https://maps.googleapis.com/maps/api/geocode/json?key=${process.env.API_KEY}&latlng=`; +const GOOGLE_URL = `https://maps.googleapis.com/maps/api/geocode/json?key=${process.env.GEOCODING_API_KEY}&latlng=`; export type AddressAndTown = { address: string; town: string }; @@ -64,8 +66,19 @@ export async function POST(request: NextRequest) { } try { - const response = await fetch(`${GOOGLE_URL}${body.latitude},${body.longitude}`); - const extractedData = extractAddressAndTown(await response.json()); + const response = await fetch(`${GOOGLE_URL}${body.latitude},${body.longitude}`, { + headers: { + Referer: request.headers.get('Referer') ?? '', + }, + }).then((value) => value.json()); + + if (response.error_message) { + return Response.json({ + error: response.error_message, + }); + } + + const extractedData = extractAddressAndTown(response); return Response.json(extractedData); } catch (exception) { diff --git a/src/app/globals.css b/src/app/globals.css index f56d375e..27383388 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -11,3 +11,7 @@ body { color: rgb(var(--foreground-rgb)); background: rgb(var(--background-rgb)); } + +.maplibregl-ctrl-top-right div:nth-child(2) { + display: none; +} diff --git a/src/app/solicitar-ayuda/_components/Form/FormContainer.tsx b/src/app/solicitar-ayuda/_components/Form/FormContainer.tsx index 9d60ce6d..88861c64 100644 --- a/src/app/solicitar-ayuda/_components/Form/FormContainer.tsx +++ b/src/app/solicitar-ayuda/_components/Form/FormContainer.tsx @@ -4,14 +4,15 @@ import React, { FormEvent, useCallback, useMemo, useState } from 'react'; import { FormRenderer } from './FormRenderer'; import { FormData, Status } from '../types'; +import { helpRequestService, townService } from '@/lib/service'; import { formatPhoneNumber, isValidPhone, removeUrls } from '@/helpers/utils'; -import { helpRequestService } from '@/lib/service'; import { Database } from '@/types/database'; import { Enums } from '@/types/common'; import { useRouter } from 'next/navigation'; import { TIPOS_DE_AYUDA, TIPOS_DE_AYUDA_MAP } from '../constants'; import { useSession } from '@/context/SessionProvider'; +import { AddressDescriptor } from '../../../../components/AddressMap'; const mapHelpToEnum = (helpTypeMap: FormData['tiposDeAyuda']): Enums['help_type_enum'][] => Array.from(helpTypeMap).reduce( @@ -35,7 +36,6 @@ export function FormContainer({ session }: any) { const [formData, setFormData] = useState({ nombre: session?.user?.user_metadata?.full_name || session?.user?.user_metadata?.nombre || ''.split(' ')[0], - ubicacion: '', coordinates: null, tiposDeAyuda: new Map(TIPOS_DE_AYUDA.map(({ id }) => [id, false])), numeroDePersonas: undefined, @@ -44,8 +44,9 @@ export function FormContainer({ session }: any) { situacionEspecial: '', contacto: session?.user?.user_metadata?.telefono || '', consentimiento: false, - pueblo: '', email: session?.user?.user_metadata?.email || '', + ubicacion: '', + town: '', }); const [status, setStatus] = useState({ @@ -59,8 +60,8 @@ export function FormContainer({ session }: any) { e.preventDefault(); /* Form validation */ - if (!formData.ubicacion) { - alert('La ubicación es un campo obligatorio'); + if (!formData.coordinates) { + alert('Elige una ubicacion valida'); return; } @@ -82,12 +83,18 @@ export function FormContainer({ session }: any) { setStatus({ isSubmitting: true, error: null, success: false }); try { + const latitude = String(formData.coordinates.lat); + const longitude = String(formData.coordinates.lng); + + const { data: townResponse, error: townError } = await townService.createIfNotExists(formData.town); + if (townError) throw townError; + const helpRequestData: Database['public']['Tables']['help_requests']['Insert'] = { type: 'necesita', name: formData.nombre.split(' ')[0], location: formData.ubicacion, - latitude: formData.coordinates ? parseFloat(formData.coordinates.lat) : null, - longitude: formData.coordinates ? parseFloat(formData.coordinates.lng) : null, + latitude: formData.coordinates ? parseFloat(latitude) : null, + longitude: formData.coordinates ? parseFloat(longitude) : null, help_type: mapHelpToEnum(formData.tiposDeAyuda), description: removeUrls(formData.descripcion), urgency: formData.urgencia, @@ -98,7 +105,7 @@ export function FormContainer({ session }: any) { consent: true, email: formData.email, }, - town_id: parseInt(formData.pueblo), + town_id: townResponse[0].id, status: 'active', user_id: userId, }; @@ -108,7 +115,6 @@ export function FormContainer({ session }: any) { // Limpiar formulario setFormData({ nombre: '', - ubicacion: '', coordinates: null, tiposDeAyuda: new Map(), numeroDePersonas: undefined, @@ -116,16 +122,17 @@ export function FormContainer({ session }: any) { urgencia: 'alta', situacionEspecial: '', contacto: '', - pueblo: '', consentimiento: false, email: '', + ubicacion: '', + town: '', }); setStatus({ isSubmitting: false, error: null, success: true }); setStatus((prev) => ({ ...prev, success: false })); router.push('/casos-activos/solicitudes'); } catch (error: any) { - console.log('Error al enviar solicitud:', error.message); + console.error('Error al enviar solicitud:', error.message); setStatus({ isSubmitting: false, error: `Error al enviar la solicitud: ${error.message}`, @@ -160,16 +167,12 @@ export function FormContainer({ session }: any) { })); }, []); - const handleAddressSelection = useCallback((address: any) => { - setFormData((formData) => ({ - ...formData, - ubicacion: address.fullAddress, - coordinates: address.coordinates - ? { - lat: address.coordinates.lat, - lng: address.coordinates.lon, - } - : null, + const handleNewAddressDescriptor = useCallback((addressDescriptor: AddressDescriptor) => { + setFormData((prev) => ({ + ...prev, + town: addressDescriptor.town, + ubicacion: addressDescriptor.address, + coordinates: addressDescriptor.coordinates, })); }, []); @@ -199,14 +202,13 @@ export function FormContainer({ session }: any) { isUserLoggedIn={Boolean(session?.user)} handleConsentChange={handleInputElementChange} handleEmailChange={handleInputElementChange} - handleAddressSelection={handleAddressSelection} + handleNewAddressDescriptor={handleNewAddressDescriptor} handleDescriptionChange={handleTextAreaElementChange} handleNameChange={handleInputElementChange} handleNumberPeopleChange={handleInputElementChange} handlePhoneChange={handlePhoneChange} handleSituacionEspecialChange={handleTextAreaElementChange} handleTipoAyudaChange={handleHelpTypeChange} - handleTownChange={handleSelectElementChange} handleUrgencyChange={handleSelectElementChange} handleSubmit={handleSubmit} status={status} diff --git a/src/app/solicitar-ayuda/_components/Form/FormRenderer.tsx b/src/app/solicitar-ayuda/_components/Form/FormRenderer.tsx index 613cc079..e4e3154d 100644 --- a/src/app/solicitar-ayuda/_components/Form/FormRenderer.tsx +++ b/src/app/solicitar-ayuda/_components/Form/FormRenderer.tsx @@ -1,13 +1,12 @@ 'use client'; import React from 'react'; import { Check } from 'lucide-react'; - +import AddressMap, { AddressDescriptor } from '../../../../components/AddressMap'; import { PhoneInput } from '@/components/input/PhoneInput'; import AddressAutocomplete from '@/components/AddressAutocomplete.js'; import { TIPOS_DE_AYUDA } from '../constants'; import { TipoDeAyudaInputRenderer } from '../TipoDeAyudaInputRenderer'; import { FormData, HelpCategory, Status } from '../types'; -import { TownSelector } from '../TownSelector'; import { LimitedTextarea } from '@/components/input/LimitedTextarea'; type FormRendererProps = { @@ -17,11 +16,10 @@ type FormRendererProps = { selectedHelp: Map; handleSubmit: React.FormEventHandler; handlePhoneChange: (phoneNumber: string) => void; - handleAddressSelection: (address: string) => void; + handleNewAddressDescriptor: (addressDescriptor: AddressDescriptor) => void; handleSituacionEspecialChange: React.ChangeEventHandler; handleUrgencyChange: React.ChangeEventHandler; handleDescriptionChange: React.ChangeEventHandler; - handleTownChange: React.ChangeEventHandler; handleTipoAyudaChange: React.ChangeEventHandler; handleNameChange: React.ChangeEventHandler; handleEmailChange: React.ChangeEventHandler; @@ -35,11 +33,10 @@ export function FormRenderer({ formData, isUserLoggedIn, handlePhoneChange, - handleAddressSelection, + handleNewAddressDescriptor, handleSituacionEspecialChange, handleUrgencyChange, handleDescriptionChange, - handleTownChange, handleTipoAyudaChange, handleNameChange, handleEmailChange, @@ -96,19 +93,6 @@ export function FormRenderer({

)} -
- - -

- Incluya todos los detalles posibles para poder localizarle (campo obligatorio) -

-
@@ -175,8 +159,10 @@ export function FormRenderer({ placeholder="Personas mayores, niños pequeños, personas con movilidad reducida, necesidades médicas, mascotas..." />
- {/* Pueblos */} - + +
+ +
{/* Consentimiento */}
diff --git a/src/app/solicitar-ayuda/_components/types.ts b/src/app/solicitar-ayuda/_components/types.ts index 94bb4470..adbc0bb2 100644 --- a/src/app/solicitar-ayuda/_components/types.ts +++ b/src/app/solicitar-ayuda/_components/types.ts @@ -1,5 +1,6 @@ import { Town as SupabaseTown } from '@/types/Town'; import { Enums } from '@/types/common'; +import { LngLat } from '@/components/map/GeolocationMap'; export type FormData = { nombre: string; @@ -9,11 +10,11 @@ export type FormData = { descripcion: string; urgencia: string; situacionEspecial: string; - pueblo: string; consentimiento: boolean; - ubicacion: string; - coordinates: any; + coordinates: LngLat | null; tiposDeAyuda: Map; + ubicacion: string; + town: string; }; export type HelpCategory = { diff --git a/src/components/AddressMap.tsx b/src/components/AddressMap.tsx index d0b4de94..0c89fbab 100644 --- a/src/components/AddressMap.tsx +++ b/src/components/AddressMap.tsx @@ -1,50 +1,146 @@ 'use client'; import GeoLocationMap, { LngLat } from '@/components/map/GeolocationMap'; -import { useState } from 'react'; +import { useRef, useState } from 'react'; +import { locationService } from '../lib/service'; +import GooglePlacesAutocomplete from 'react-google-places-autocomplete'; + +import { useDebouncedFunction, useThrottledFunction } from '../helpers/hooks'; +import { OnChangeValue } from 'react-select'; -export type AddressDescriptopr = { address: string; town: string; coordinates: LngLat }; -export type AddressAndTownCallback = (addressAndTown: AddressDescriptopr) => void; export type AddressMapProps = { - onNewAddressCallback: AddressAndTownCallback; + onNewAddressDescriptor: (onNewAddressDescriptor: AddressDescriptor) => void; + initialAddressDescriptor?: AddressDescriptor; // when given we assume edit + titulo: string; +}; +export type AddressDescriptor = { + address: string; + town: string; + coordinates: LngLat | null; +}; + +type PlaceOption = { + label: string; + value: { + place_id: string; + description: string; + }; }; -export default function AddressMap({ onNewAddressCallback }: AddressMapProps) { - const [address, setAddress] = useState(''); - const [town, setTown] = useState(''); +const THROTTLE_MS = 2000; +const DEBOUNCE_MS = 400; - const onNewPosition = async (lngLat: LngLat) => { - if (address !== '') { - return; +export default function AddressMap({ onNewAddressDescriptor, initialAddressDescriptor, titulo }: AddressMapProps) { + const isEdit = useRef(Boolean(initialAddressDescriptor)); + const [status, setStatus] = useState('unknown'); + const [lngLat, setLngLat] = useState(initialAddressDescriptor?.coordinates ?? undefined); + const [addressDescriptor, setAddressDescriptor] = useState({ + address: '', + town: '', + coordinates: null, + }); + + const handleSelect = async (newValue: OnChangeValue) => { + if (newValue && newValue.value) { + const placeId = newValue.value.place_id; + + try { + const placesService = new google.maps.places.PlacesService(document.createElement('div')); + placesService.getDetails({ placeId }, (place: any, status: string) => { + if (status === google.maps.places.PlacesServiceStatus.OK) { + const location = place.geometry.location; + onNewPositionThrottledAndDebounced({ + lat: location.lat(), + lng: location.lng(), + }); + } + }); + } catch (exception) { + console.error('Places service exception:', exception); + } } + }; - const response = await fetch('/api/address', { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ - longitude: lngLat.lng, - latitude: lngLat.lat, - }), - }).then((res) => res.json()); - - setAddress(response.address); - setTown(response.town); - if (typeof onNewAddressCallback === 'function') { - onNewAddressCallback({ address: response.address, town: response.town, coordinates: lngLat }); + const onNewCoordinates = async (coordinates: LngLat, updateLngLat = true) => { + const { address, town, error } = await locationService.getFormattedAddress( + String(coordinates.lng), + String(coordinates.lat), + ); + if (error) { + throw { message: `Error inesperado con la api de google: ${error}` }; } + + const newAddressDescriptor: AddressDescriptor = { + address, + town, + coordinates, + }; + + setAddressDescriptor(newAddressDescriptor); + if (updateLngLat) { + setLngLat(coordinates); + } + if (!isEdit.current) { + onNewAddressDescriptor(newAddressDescriptor); + } + }; + + const debouncedValue = useDebouncedFunction(onNewCoordinates, DEBOUNCE_MS); // debounce + const onNewPositionThrottledAndDebounced = useThrottledFunction(debouncedValue, THROTTLE_MS); // throttle + + const onMapNewPosition = (coordinates: LngLat) => { + onNewPositionThrottledAndDebounced(coordinates, false); }; return (
- - {/* Address */} - setAddress(e.target.value)} - className="w-full p-2 border rounded focus:ring-2 focus:ring-green-500 focus:border-green-500" + + + {isEdit.current && ( +
+
+ {initialAddressDescriptor?.address || ''} +
+ +
+ )} + {/** Autocompletar */} + + {/* Mapa */} + { + setStatus(permission); + }} + onNewPositionCallback={onMapNewPosition} + inputCoordinates={lngLat} + zoom={16} /> + {/* Mensaje de error */} + {(status === 'denied' || status === 'prompt') && ( +
+

Debes activar la ubicación para que podamos localizarte

+
+ )}
); } diff --git a/src/components/RequestHelp.js b/src/components/RequestHelp.js index c7a514fc..b96f1112 100644 --- a/src/components/RequestHelp.js +++ b/src/components/RequestHelp.js @@ -5,10 +5,12 @@ import { Check, Mail } from 'lucide-react'; import AddressAutocomplete from '@/components/AddressAutocomplete'; import { mapToIdAndLabel, tiposAyudaOptions } from '@/helpers/constants'; import { formatPhoneNumber, isValidPhone } from '@/helpers/utils'; -import { helpRequestService } from '@/lib/service'; +import { helpRequestService, locationService, townService } from '@/lib/service'; import { PhoneInput } from '@/components/input/PhoneInput'; import { useRouter } from 'next/navigation'; +import { CallCenterLink } from '@/components/CallCenterLink'; +import AddressMap from './AddressMap'; import { useTowns } from '@/context/TownProvider'; import { useSession } from '@/context/SessionProvider'; @@ -27,7 +29,7 @@ export default function RequestHelp({ const [formData, setFormData] = useState({ nombre: data.name || '', ubicacion: data.location || '', - coordinates: { lat: 3, lng: 3 }, + coordinates: { lat: data.latitude || 3, lng: data.longitude || 3 }, tiposAyuda: data.help_type || [], numeroPersonas: data.number_of_people || '', descripcion: data.description || '', @@ -35,7 +37,8 @@ export default function RequestHelp({ situacionEspecial: data.additional_info?.special_situations || '', contacto: data.contact_info || '', consentimiento: data.additional_info?.consent || false, - pueblo: data.town_id || '', + pueblo: '', + town_id: data.town_id || '', email: data.additional_info?.email || '', status: data.status || 'active', }); @@ -58,8 +61,9 @@ export default function RequestHelp({ const handleSubmit = async (e) => { e.preventDefault(); - if (!formData.ubicacion) { - alert('La ubicación es un campo obligatorio'); + /* Form validation */ + if (!formData.coordinates) { + alert('Elige una ubicacion valida'); return; } @@ -76,12 +80,22 @@ export default function RequestHelp({ setStatus({ isSubmitting: true, error: null, success: false }); try { + const latitude = String(formData.coordinates.lat); + const longitude = String(formData.coordinates.lng); + let town_id = formData.town_id; + + if (formData.pueblo !== '') { + const { data: townResponse, error: townError } = await townService.createIfNotExists(formData.pueblo); + if (townError) throw townError; + town_id = townResponse[0].id; + } + const helpRequestData = { type: 'necesita', name: formData.nombre, location: formData.ubicacion, - latitude: formData.coordinates ? parseFloat(formData.coordinates.lat) : 3, - longitude: formData.coordinates ? parseFloat(formData.coordinates.lng) : 3, + latitude, + longitude, help_type: formData.tiposAyuda, description: formData.descripcion, urgency: formData.urgencia, @@ -92,7 +106,7 @@ export default function RequestHelp({ consent: true, email: formData.email, }, - town_id: formData.pueblo, + town_id, status: formData.status, user_id: userId, }; @@ -103,7 +117,6 @@ export default function RequestHelp({ } } if (submitType === 'edit') { - console.log('EDITAR'); const { error } = await helpRequestService.editRequest(helpRequestData, id); if (error) { throw new Error(error.message); @@ -130,7 +143,7 @@ export default function RequestHelp({ setStatus((prev) => ({ ...prev, success: false })); router.push(redirect); } catch (error) { - console.log('Error al enviar solicitud:', error.message); + console.error('Error al enviar solicitud:', error.message); setStatus({ isSubmitting: false, error: `Error al enviar la solicitud: ${error.message}`, @@ -139,6 +152,15 @@ export default function RequestHelp({ } }; + const handleOnNewAddressDescriptor = (addressDescriptor) => { + setFormData((prev) => ({ + ...prev, + coordinates: addressDescriptor.coordinates, + pueblo: addressDescriptor.town, + ubicacion: addressDescriptor.address, + })); + }; + const handleChange = (e) => { const { name, value, type, checked } = e.target; setFormData((prev) => ({ @@ -212,31 +234,6 @@ export default function RequestHelp({
)} -
- - { - setFormData({ - ...formData, - ubicacion: address.fullAddress, - coordinates: address.coordinates - ? { - lat: address.coordinates.lat, - lng: address.coordinates.lon, - } - : null, - }); - }} - placeholder="Calle, número, piso, ciudad..." - required - /> -

- Incluya todos los detalles posibles para poder localizarle (campo obligatorio) -

-
@@ -309,35 +306,19 @@ export default function RequestHelp({ placeholder="Personas mayores, niños pequeños, personas con movilidad reducida, necesidades médicas, mascotas..." />
- {/* Pueblos */} + {/* Mapa */}
- - +
+ {/* Consentimiento */}