From 40ebb30fc22263fdad871cd63e58a58b4da9edc2 Mon Sep 17 00:00:00 2001 From: Henri Nieminen <118905702+henrinie-nc@users.noreply.github.com> Date: Mon, 5 Aug 2024 09:35:32 +0300 Subject: [PATCH] Replace geocoder address search with servicemap (#508) * Replace geocoder address search with servicemap * Remove extra & from url * bring typing similar to public-ui Can't yet upgrade dependencies, therefore copied over types * utilize SERVICE_MAP_URL and move that to utils/constants --- package.json | 2 +- .../address-search/AddressSearchInput.tsx | 3 +- src/components/map/GeoSearch.ts | 2 +- src/components/map/HelsinkiProvider.ts | 42 ++++++------ src/components/map/types.ts | 64 ++++++++++++++++++- src/util/constants.ts | 9 ++- yarn.lock | 28 +++++--- 7 files changed, 117 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index 468a6cdc8..94eb3d2a0 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "react-dom": "16.8.6", "react-dual-listbox": "^2.0.0", "react-foundation": "^0.9.6", - "react-leaflet": "^2.4.0", + "react-leaflet": "^2.8.0", "react-leaflet-draw": "^0.19.0", "react-leaflet-fullscreen": "1.0.1", "react-redux": "^7.1.0", diff --git a/src/components/address-search/AddressSearchInput.tsx b/src/components/address-search/AddressSearchInput.tsx index 989f354da..696ebe76a 100644 --- a/src/components/address-search/AddressSearchInput.tsx +++ b/src/components/address-search/AddressSearchInput.tsx @@ -8,7 +8,8 @@ import LoaderWrapper from "components/loader/LoaderWrapper"; import { stringifyQuery } from "api/createUrl"; import { KeyCodes } from "enums"; import { findFromOcdString } from "util/helpers"; -const SERVICE_MAP_URL = 'https://api.hel.fi/servicemap/v2'; +import { SERVICE_MAP_URL } from "util/constants"; + type Language = "fi" | "sv"; const MINIMUM_SEARCH_STRING = 3; const DEBOUNCE_TIME_MILLISECONDS = 500; diff --git a/src/components/map/GeoSearch.ts b/src/components/map/GeoSearch.ts index 35c84792b..7a1c30341 100644 --- a/src/components/map/GeoSearch.ts +++ b/src/components/map/GeoSearch.ts @@ -1,7 +1,7 @@ import { MapControl, withLeaflet } from "react-leaflet"; import { GeoSearchControl } from "leaflet-geosearch"; import HelsinkiProvider from "./HelsinkiProvider"; -type LeafletElement = GeoSearchControl; +type LeafletElement = typeof GeoSearchControl; class GeoSearch extends MapControl { createLeafletElement() { diff --git a/src/components/map/HelsinkiProvider.ts b/src/components/map/HelsinkiProvider.ts index f2ba2ff49..742e6ee62 100644 --- a/src/components/map/HelsinkiProvider.ts +++ b/src/components/map/HelsinkiProvider.ts @@ -1,7 +1,11 @@ -export default class Provider { +import { Provider } from 'leaflet-geosearch'; +import { SERVICE_MAP_URL } from 'util/constants'; +import type { AddressResult, ServiceMapResponse, ParseArgument, SearchArgument, SearchResult } from './types'; +export default class HelsinkiProvider extends Provider { options: Record; - - constructor(options: Record = {}) { + + constructor(options: Record = {}) { + super(options); this.options = options; } @@ -11,15 +15,12 @@ export default class Provider { async search({ query - }: Record) { - // eslint-disable-next-line no-bitwise - const protocol = ~location.protocol.indexOf('http') ? location.protocol : 'https:'; + }: SearchArgument): Promise> { const url = this.endpoint({ - query, - protocol + query }); const request = await fetch(url); - const json = await request.json(); + const json = await request.json() as ServiceMapResponse; return this.parse({ data: json }); @@ -27,27 +28,28 @@ export default class Provider { endpoint({ query - }: any = {}) { + }: { query: string }) { const { params } = this.options; - const paramString = this.getParamString({ ...params, - name: query + const paramString = this.getParamString({ + ...params, + q: query }); - const proto = 'https:'; - return `${proto}//dev.hel.fi/geocoder/v1/address/?${paramString}&municipality=91`; + return `${SERVICE_MAP_URL}/search/?${paramString}&type=address&municipality=helsinki`; } parse({ data - }: any) { - return data.objects.map(r => { + }: ParseArgument): Array { + return data.results?.map(address => { return { - x: r.location.coordinates[0], - y: r.location.coordinates[1], - label: r.name + x: address.location?.coordinates[0] ?? 0, + y: address.location?.coordinates[1] ?? 0, + label: address.name?.fi ?? '', + bounds: null, + raw: address, }; }); } - } \ No newline at end of file diff --git a/src/components/map/types.ts b/src/components/map/types.ts index ee96fc756..c20765977 100644 --- a/src/components/map/types.ts +++ b/src/components/map/types.ts @@ -1 +1,63 @@ -export type ControlPosition = "topleft" | "topright" | "bottomleft" | "bottomright"; \ No newline at end of file +export type ControlPosition = "topleft" | "topright" | "bottomleft" | "bottomright"; + +interface ServiceMapAddress { + object_type: "address"; + name: { + fi: string; + sv: string; + en: string; + }; + number: string; + number_end: string; + letter: string; + modified_at: string; + municipality: { + id: string; + name: { + fi: string; + sv: string; + }; + }; + street: { + name: { + fi: string; + sv?: string; + en?: string; + }; + }; + location: { + type: "Point"; + coordinates: [number, number]; + }; +}; + +export interface ServiceMapResponse { + count: number; + next: string | null; + previous: string | null; + results: Array; + }; + +export interface AddressResult { + x: number; + y: number; + label: string; +}; + +export interface ParseArgument { + data: TData; +}; + +export interface SearchArgument { + query: string; +}; + +export declare type PointTuple = [number, number]; +export declare type BoundsTuple = [PointTuple, PointTuple]; +export interface SearchResult { + x: number; + y: number; + label: string; + bounds: BoundsTuple | null; + raw: TRawResult; +} \ No newline at end of file diff --git a/src/util/constants.ts b/src/util/constants.ts index 2bb88be56..38a10ec74 100644 --- a/src/util/constants.ts +++ b/src/util/constants.ts @@ -55,4 +55,11 @@ export const DELETE_MODAL_BUTTON_TEXT = 'Poista'; * @readonly * @const {number} */ -export const LIST_TABLE_PAGE_SIZE = 25; \ No newline at end of file +export const LIST_TABLE_PAGE_SIZE = 25; + +/** + * Base url for Service Map API + * @readonly + * @const {string} + */ +export const SERVICE_MAP_URL = 'https://api.hel.fi/servicemap/v2'; \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 3318440b7..34565ae1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1699,6 +1699,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.12.1": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" + integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/runtime@^7.7.6": version "7.24.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" @@ -6808,7 +6815,12 @@ locate-path@^7.1.0: dependencies: p-locate "^6.0.0" -lodash-es@^4.17.10, lodash-es@^4.17.15: +lodash-es@^4.17.10: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash-es@^4.17.15: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78" integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ== @@ -6816,7 +6828,7 @@ lodash-es@^4.17.10, lodash-es@^4.17.15: lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== lodash.escape@^4.0.1: version "4.0.1" @@ -8517,13 +8529,13 @@ react-leaflet-fullscreen@1.0.1: leaflet.fullscreen "1.4.5" prop-types "^15.6.x" -react-leaflet@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/react-leaflet/-/react-leaflet-2.7.0.tgz#0e0e452a4903029f0bb564771eab8cf9db8e4517" - integrity sha512-pMf5eRyWU8RH9HohM2i0NZymcWHraJA1m6iMFYu94/01PAaBJpOyxORZJmN6cV9dBzkVWaLjAAHTNmxbwIpcfw== +react-leaflet@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/react-leaflet/-/react-leaflet-2.8.0.tgz#14bfc77b6ae8263d3a62e0ba7a39539c05973c6f" + integrity sha512-Y7oHtNrrlRH8muDttXf+jZ2Ga/X7jneSGi1GN8uEdeCfLProTqgG2Zoa5TfloS3ZnY20v7w+DIenMG59beFsQw== dependencies: - "@babel/runtime" "^7.9.2" - fast-deep-equal "^3.1.1" + "@babel/runtime" "^7.12.1" + fast-deep-equal "^3.1.3" hoist-non-react-statics "^3.3.2" warning "^4.0.3"