UNPKG

autocomplete-gcba-component

Version:

Componente React de autocompletado de direcciones para GCBA

3 lines (2 loc) 16.4 kB
import{jsx as e,jsxs as a,Fragment as r}from"react/jsx-runtime";import{useState as t,useRef as o,useEffect as s,useCallback as i}from"react";import n from"axios";const c="https://servicios.usig.buenosaires.gob.ar";class l{debug;maxSuggestions;lastRequest;serverTimeout;constructor(e={}){this.debug=e.debug||!1,this.maxSuggestions=e.maxSuggestions||10,this.serverTimeout=e.serverTimeout||5e3,this.lastRequest=null}abort(){this.lastRequest&&(this.lastRequest.abort(),this.lastRequest=null,this.debug&&console.debug("Request aborted"))}async normalizar(e,a=this.maxSuggestions){this.debug&&console.debug(`ApiNormalizer.normalizar('${e}', ${a})`),this.abort(),this.lastRequest=new AbortController;try{let r=[];const t=await this.searchAddresses(e,a);r=[...r,...t];const o=this.parseCoordinates(e);if(o){const e=await this.reverseGeocode(o.x,o.y);r=[...r,...e]}return r.slice(0,a)}catch(e){return n.isCancel(e)?this.debug&&console.debug("Request was cancelled"):console.error("Error normalizing address:",e),[]}finally{this.lastRequest=null}}async searchAddresses(e,a){try{const r=`${c}/normalizar/?direccion=${encodeURIComponent(e)}&geocodificar=true&max=${a}`,t={headers:{Accept:"application/json"},signal:this.lastRequest?.signal,timeout:this.serverTimeout},o=await n.get(r,t);if(o.data.error)return this.debug&&console.error("API error:",o.data.error),[];if(o.data.direccionesNormalizadas&&o.data.direccionesNormalizadas.length>0){const e=o.data.direccionesNormalizadas.filter((e=>{const a=e.cod_partido?.toLowerCase(),r=e.nombre_partido?.toLowerCase(),t=e.nombre_localidad?.toLowerCase();return"caba"===a||"caba"===r||"caba"===t})),a=await Promise.all(e.map((async e=>{const a=await this.obtenerCoordenadas(e.cod_calle??"",Number(e.altura??0),{x:Number.parseFloat(e.coordenadas?.x??"0"),y:Number.parseFloat(e.coordenadas?.y??"0")});if(a){const{barrio:r,comuna:t}=await this.obtenerBarrioYComuna(a.y,a.x);return{...e,altura_par:a.altura_par,altura_impar:a.altura_impar,calle_alturas:a.calle_alturas,coordenadas:{x:a.x.toString(),y:a.y.toString(),srid:4326},barrio:r,comuna:t}}return e})));return this.processDireccionesNormalizadas(a)}return o.data.calles&&o.data.calles.length>0?this.processCalles(o.data.calles):[]}catch(e){return n.isCancel(e)?this.debug&&console.debug("Address search request was cancelled"):console.error("Error searching addresses:",e),[]}}async obtenerBarrioYComuna(e,a){try{const r=`https://ws.usig.buenosaires.gob.ar/datos_utiles/?x=${a}&y=${e}`,t=(await n.get(r)).data,o=t?.barrio,s=t?.comuna;return{barrio:o,comuna:s}}catch(e){return console.error("Error al obtener barrio y comuna:",e),{}}}async obtenerCoordenadas(e,a,r){try{if(r){const e=`https://ws.usig.buenosaires.gob.ar/geocoder/2.2/reversegeocoding?x=${r.x}&y=${r.y}`,a=`https://ws.usig.buenosaires.gob.ar/rest/convertir_coordenadas/?x=${r.x}&y=${r.y}&output=lonlat`,t=await n.get(a),o=(await n.get(e)).data.replace(/^\(|\)$/g,""),{calle_alturas:s,altura_impar:i,altura_par:c}=JSON.parse(o),{x:l,y:d}=t.data.resultado;return{y:d,x:l,altura_par:c,altura_impar:i,calle_alturas:s}}const t=`https://ws.usig.buenosaires.gob.ar/geocoder/2.2/geocoding?cod_calle=${encodeURIComponent(e)}&altura=${a}`,o=await n.get(t),s=o.data.replace(/^\(|\)$/g,""),i=JSON.parse(s),{x:c,y:l}=i,d=`https://ws.usig.buenosaires.gob.ar/geocoder/2.2/reversegeocoding?x=${c}&y=${l}`,u=`https://ws.usig.buenosaires.gob.ar/rest/convertir_coordenadas/?x=${c}&y=${l}&output=lonlat`,m=await n.get(u),p=(await n.get(d)).data.replace(/^\(|\)$/g,""),{calle_alturas:g,altura_impar:b,altura_par:h}=JSON.parse(p),{x:x,y:C}=m.data.resultado;return{y:C,x:x,altura_par:h,altura_impar:b,calle_alturas:g}}catch(e){return console.error("Error al obtener coordenadas:",e),null}}parseCoordinates(e){const a=e.trim().replace(/\s+/g,""),r=[/^(-?\d+\.?\d*),(-?\d+\.?\d*)$/,/x:?(-?\d+\.?\d*)[,\s]+y:?(-?\d+\.?\d*)/i,/y:?(-?\d+\.?\d*)[,\s]+x:?(-?\d+\.?\d*)/i];for(const e of r){const t=a.match(e);if(t){if(e===r[0])return{y:Number.parseFloat(t[1]),x:Number.parseFloat(t[2])};if(e===r[1])return{x:Number.parseFloat(t[1]),y:Number.parseFloat(t[2])};if(e===r[2])return{y:Number.parseFloat(t[1]),x:Number.parseFloat(t[2])}}}return null}async reverseGeocode(e,a){this.debug&&console.debug(`ApiNormalizer.reverseGeocode(${e}, ${a})`),this.abort(),this.lastRequest=new AbortController;try{const r=`${c}/reverseGeocoderLugares/?x=${e}&y=${a}&srid=4326`,t={headers:{Accept:"application/json"},signal:this.lastRequest.signal,timeout:this.serverTimeout},o=await n.get(r,t);if(o.data.error)return this.debug&&console.error("Reverse geocoding API error:",o.data.error),[];if(!o.data.direccion)return[];const s={codigo:o.data.cod_calle||"coord",nombre:o.data.nombre||o.data.direccion||"Coordenada",descripcion:o.data.direccion||"Coordenada",tipo:"CALLE",alturas:[{inicio:1,fin:1e4}]};let i=0;o.data.altura&&(i=Number.parseInt(o.data.altura,10));return[{calle:s,altura:i||1,tipoDireccion:"DIRECCION_CALLE_ALTURA",tipo:"DIRECCION",nombre:o.data.direccion||`Coordenada (${e.toFixed(6)}, ${a.toFixed(6)})`,descripcion:`Coordenada (${e.toFixed(6)}, ${a.toFixed(6)})`,coordenadas:{x:e,y:a,srid:o.data.coordenadas?.srid||4326},barrio:o.data.nombre_barrio,altura_par:o.data.altura_par,altura_impar:o.data.altura_impar,calle_alturas:o.data.calle_alturas,comuna:o.data.nombre_comuna}]}catch(e){return n.isCancel(e)?this.debug&&console.debug("Reverse geocoding request was cancelled"):console.error("Error in reverse geocoding:",e),[]}finally{this.lastRequest=null}}processDireccionesNormalizadas(e){if(!e)return Promise.resolve([]);const a=e.map((async e=>{if(!e.direccion||!e.cod_calle)return null;const a={codigo:e.cod_calle,nombre:e.nombre||e.direccion.split(" ")[0],descripcion:e.direccion,tipo:"CALLE",alturas:[{inicio:1,fin:1e4}]};let r;if(e.direccion.includes(" y ")){const t=e.direccion.split(" y ").map((e=>e.trim()));r={calle:a,calleCruce:{codigo:`${e.cod_calle}_cruce`,nombre:t[1]||"Calle cruce",descripcion:t[1]||"Calle cruce",tipo:"CALLE",alturas:[{inicio:1,fin:1e4}]},tipoDireccion:"DIRECCION_CALLE_Y_CALLE",tipo:"DIRECCION",nombre:e.direccion,descripcion:e.direccion,coordenadas:e.coordenadas?{x:Number.parseFloat(e.coordenadas.x),y:Number.parseFloat(e.coordenadas.y),srid:e.coordenadas.srid}:void 0,barrio:e.barrio,comuna:e.comuna,altura_par:e.altura_par,altura_impar:e.altura_impar,calle_alturas:e.calle_alturas}}else{const t=e.altura?Number.parseInt(e.altura,10):0;if(r={calle:a,altura:t,tipoDireccion:"DIRECCION_CALLE_ALTURA",tipo:"DIRECCION",nombre:e.direccion,descripcion:e.direccion,coordenadas:e.coordenadas?{x:Number.parseFloat(e.coordenadas.x),y:Number.parseFloat(e.coordenadas.y),srid:e.coordenadas.srid}:void 0,barrio:e.barrio,comuna:e.comuna,altura_par:e.altura_par,altura_impar:e.altura_impar,calle_alturas:e.calle_alturas},t>0)try{const a=await this.getSMP({nombre:e.direccion,descripcion:e.direccion||"",tipo:"DIRECCION",codigo:e.cod_calle,altura:e.altura,altura_par:e.altura_par,altura_impar:e.altura_impar,calle_alturas:e.calle_alturas,calle:{codigo:e.cod_calle}});a&&(r.smp=a)}catch(e){this.debug&&console.error("Error getting SMP:",e)}}return r}));return Promise.all(a).then((e=>e.filter(Boolean)))}processCalles(e){return e?e.map((e=>({codigo:e.cod_calle,nombre:e.nombre,descripcion:e.tipo?`${e.tipo} ${e.nombre}`:e.nombre,tipo:"CALLE",alturas:[{inicio:e.altura?.inicial||1,fin:e.altura?.final||1e4}],partido:e.partido,localidad:e.localidad}))):[]}async getCoordinates(e){try{this.abort(),this.lastRequest=new AbortController;const a=`${c}/normalizar/?direccion=${encodeURIComponent(e.nombre)},${encodeURIComponent(e.descripcion)}&geocodificar=true&srid=4326`,r={headers:{Accept:"application/json"},signal:this.lastRequest.signal,timeout:this.serverTimeout},t=await n.get(a,r),o=t.data.direccionesNormalizadas?.[0];if(o?.coordenadas){const e=o.coordenadas;return{x:Number.parseFloat(e.x),y:Number.parseFloat(e.y),srid:e.srid}}return}catch(e){return void(n.isCancel(e)?this.debug&&console.debug("Request was aborted"):console.error("Error fetching coordinates:",e))}finally{this.lastRequest=null}}async getSMP(e){try{this.abort(),this.lastRequest=new AbortController;const a=e.codigo||e.calle?.codigo;if(!a||!e.altura)return;const r=`https://epok.buenosaires.gob.ar/catastro/parcela/?codigo_calle=${encodeURIComponent(a)}&altura=${encodeURIComponent(String(e.altura))}&geocodificar=true&srid=4326`,t={headers:{Accept:"application/json"},signal:this.lastRequest.signal,timeout:this.serverTimeout};return(await n.get(r,t)).data.smp}catch(e){return void(n.isCancel(e)?this.debug&&console.debug("Request was aborted"):console.error("Error fetching catastro data:",e))}finally{this.lastRequest=null}}static inicializado(){return!0}}const d=({className:a="",size:r=24,color:t="currentColor"})=>e("svg",{width:r,height:r,viewBox:"0 0 24 24",fill:"none",stroke:t,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:a,children:e("path",{d:"M21 12a9 9 0 1 1-6.219-8.56"})}),u=({className:a="",size:r=24,color:t="currentColor"})=>e("svg",{width:r,height:r,viewBox:"0 0 24 24",fill:"none",stroke:t,strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",className:a,children:e("polygon",{points:"3,11 22,2 13,21 11,13 3,11"})}),m=({maxSuggestions:n=10,onAddressSelect:c,onAddressesRemove:m,placeholder:p="Buscar dirección o coordenadas...",debug:g=!1,className:b="",inputClassName:h="",selectedAddresses:x=[],suggestionsClassName:C="",suggestionItemClassName:_="",selectedAddressesClassName:N="",loadingClassName:y="",suggestionsContainerClassName:f="",selectedAddressesContainerClassName:$="",selectedAddressItemClassName:v="",removeButtonClassName:w="",errorClassName:A="",iconClassName:L="",titleClassName:R="",coordsClassName:E="",smpClassName:I="",serverTimeout:F=5e3,isDebug:T=!1})=>{const[S,D]=t(""),[q,z]=t([]),[B,O]=t(!1),[k,P]=t(!1),[U,j]=t(null),M=o(null),G=o(null);s((()=>(G.current=new l({debug:g,maxSuggestions:n,serverTimeout:F}),()=>{M.current&&clearTimeout(M.current),G.current&&G.current.abort()})),[g,n,F]);const J=e=>"CALLE"===e.tipo?{title:e.nombre,subTitle:e.descripcion||"CABA",type:"CALLE",category:"CALLE",suggesterName:"Direcciones",data:{nombre:e.nombre,descripcion:e.descripcion||"",tipo:"CALLE",codigo:e.codigo,altura_par:e.altura_par,altura_impar:e.altura_impar,calle_alturas:e.calle_alturas}}:{title:e.nombre,subTitle:e.descripcion||"CABA",type:e.tipoDireccion,category:e.tipoDireccion,suggesterName:"Direcciones",data:{nombre:e.nombre,descripcion:e.descripcion||"",tipo:e.tipo,codigo:e.calle.codigo,altura:"DIRECCION_CALLE_ALTURA"===e.tipoDireccion?e.altura:void 0,calle:{codigo:e.calle.codigo},coordenadas:e.coordenadas,smp:e.smp,barrio:e.barrio,comuna:e.comuna,altura_par:e.altura_par,altura_impar:e.altura_impar,calle_alturas:e.calle_alturas}},Y=i((async e=>{if(g&&console.debug(`getSuggestions('${e}')`),!G.current||!e||e.length<3)z([]);else try{O(!0),j(null);const a=(await G.current.normalizar(e,n)).map(J);z(a),P(!0),0===a.length&&j("No se encontraron resultados")}catch(e){console.error("Error getting suggestions:",e),z([]),j("Error al buscar direcciones")}finally{O(!1)}}),[g,n]);return a("div",{className:`w-full ${b}`,children:[a("div",{className:"relative max-w-[500px]",children:[e("input",{type:"text",value:S,onChange:e=>{const a=e.target.value;D(a),j(null),M.current&&clearTimeout(M.current),G.current&&G.current.abort(),a.length>=3?(P(!0),O(!0),M.current=setTimeout((()=>{Y(a)}),300)):(z([]),P(!1),O(!1))},onFocus:()=>{S.length>=3&&P(!0)},onBlur:()=>{setTimeout((()=>{P(!1)}),200)},placeholder:p,className:`w-full h-[24px] p-[8px] border rounded ${h}`}),B&&e("div",{className:`absolute right-[0] top-1/2 transform -translate-y-1/2 ${y}`,children:e(d,{className:"h-4 w-4 text-gray-500 animate-spin"})}),(k||B)&&e("div",{className:`absolute z-10 w-full bg-[#FFFFFF] border border-t-0 rounded shadow-lg max-h-[200px] overflow-auto px-[8px] ${f}`,children:B?a("div",{className:`p-[8px] flex items-center justify-center gap-[8px] text-gray-500 ${C}`,children:[e(d,{className:"h-5 w-2 animate-spin mb-2"}),e("span",{children:"Buscando direcciones..."})]}):q.length>0?q.map(((r,t)=>e("div",{className:`my-[8px] border-b border-[#b8b5b4] last:border-b-0 cursor-pointer hover:bg-[#dfe0e1] transition duration-300 ease-in-out bg-white rounded-[4px] w-[100%] ${_}`,onClick:()=>(e=>{x.some((a=>a.data?.nombre===e.data?.nombre))||c(e),D(""),z([]),P(!1)})(r),children:a("div",{className:"flex items-center gap-[8px]",children:[e("div",{children:e(u,{className:`h-4 text-[#0042ff] ${L}`})}),a("div",{className:"flex flex-center gap-[8px]",children:[a("span",{className:`font-medium text-[14px] truncate ${R}`,children:[r.title,"."]}),r.data.coordenadas&&a("span",{className:`text-xs text-gray-400 truncate ${E}`,children:["Coord: ",r.data.coordenadas.x.toFixed(6),","," ",r.data.coordenadas.y.toFixed(6)]}),r.data.smp&&a("span",{className:`text-xs text-gray-400 ${I}`,children:["SMP: ",r.data.smp]})]})]})},`${r.data.nombre}-${t}`))):S.length>=3?e("div",{className:`p-[8px] text-center text-red-500 ${A}`,children:U||"No se encontraron resultados"}):e("div",{className:`p-4 text-center text-gray-500 ${C}`,children:"Ingrese al menos 3 caracteres para buscar"})}),U&&!B&&!k&&e("div",{className:`mt-[8px] text-sm text-red-500 ${A}`,children:U})]}),T&&e(r,{children:x.length>0&&a("div",{className:`${N} ${$}`,children:[e("h3",{className:"text-sm font-medium mb-2",children:"Direcciones seleccionadas:"}),e("ul",{className:"space-y-2",children:x.map(((r,t)=>a("li",{className:`flex justify-between items-center p-2 bg-gray-50 rounded ${v}`,children:[a("div",{className:"flex items-center gap-[8px]",children:[e("div",{className:"mt-1",children:e(u,{className:`h-4 w-4 text-[#0042ff] ${L}`})}),a("div",{className:"flex flex-center gap-[8px]",children:[a("div",{className:`font-medium ${R}`,children:[r.title,"."]}),r.data.coordenadas&&a("div",{className:`text-xs text-gray-400 ${E}`,children:["Coord: ",r.data.coordenadas.x.toFixed(6),","," ",r.data.coordenadas.y.toFixed(6)]}),r.data.smp&&a("div",{className:`text-xs text-gray-400 ${I}`,children:["SMP: ",r.data.smp]})]})]}),e("button",{type:"button",onClick:()=>(e=>{m(e)})(t),className:`text-[#FFF] bg-[#ff0000] rounded-[4px] border-0 h-[24px] w-[24px] cursor-pointer transition duration-300 ease-in-out hover:scale-125 ${w}`,children:"×"})]},`selected-${t}`)))})]})})]})};function p(e={}){const{maxSuggestions:a=10,debug:r=!1,serverTimeout:n=5e3}=e,[c,d]=t(""),[u,m]=t([]),[p,g]=t([]),[b,h]=t(!1),[x,C]=t(null),[_,N]=t(!1),y=o(null),f=o(null);s((()=>(f.current=new l({debug:r,maxSuggestions:a,serverTimeout:n}),()=>{y.current&&clearTimeout(y.current),f.current&&f.current.abort()})),[r,a,n]);const $=e=>"CALLE"===e.tipo?{title:e.nombre,subTitle:e.descripcion||"CABA",type:"CALLE",category:"CALLE",suggesterName:"Direcciones",data:{nombre:e.nombre,descripcion:e.descripcion||"",tipo:"CALLE",codigo:e.codigo,altura_par:e.altura_par,altura_impar:e.altura_impar,calle_alturas:e.calle_alturas}}:{title:e.nombre,subTitle:e.descripcion||"CABA",type:e.tipoDireccion,category:e.tipoDireccion,suggesterName:"Direcciones",data:{nombre:e.nombre,descripcion:e.descripcion||"",tipo:e.tipo,codigo:e.calle.codigo,altura:"DIRECCION_CALLE_ALTURA"===e.tipoDireccion?e.altura:void 0,calle:{codigo:e.calle.codigo},coordenadas:e.coordenadas,altura_par:e.altura_par,altura_impar:e.altura_impar,calle_alturas:e.calle_alturas,smp:e.smp}},v=i((async e=>{if(r&&console.debug(`fetchSuggestions('${e}')`),!f.current||!e||e.length<3)m([]);else try{h(!0),C(null);const r=(await f.current.normalizar(e,a)).map($);m(r),0===r.length&&C("No se encontraron resultados")}catch(e){console.error("Error getting suggestions:",e),m([]),C("Error al buscar direcciones")}finally{h(!1)}}),[r,a]);return{searchText:c,setSearchText:d,suggestions:u,selectedAddresses:p,isLoading:b,error:x,showSuggestions:_,setShowSuggestions:N,handleInputChange:e=>{const a=e.target.value;d(a),C(null),y.current&&clearTimeout(y.current),f.current&&f.current.abort(),a.length>=3?y.current=setTimeout((()=>{v(a)}),300):m([])},handleSelectSuggestion:e=>{p.some((a=>a.data?.nombre===e.data.nombre))||g((a=>[...a,e])),d(""),m([]),N(!1)},handleRemoveAddress:e=>{g((a=>{const r=[...a];return r.splice(e,1),r}))},handleInputFocus:()=>{c.length>=3&&u.length>0&&N(!0)},handleInputBlur:()=>{setTimeout((()=>{N(!1)}),200)}}}export{m as AddressSearch,p as useAddressSearch}; //# sourceMappingURL=index.esm.js.map