import { Feature } from 'geojson' import { v4 } from 'uuid' import { DatabaseFeature, LayerGroups, NearbyQuery, } from '../../interfaces/gis.interface' import { isArrayLike } from '../../util/isArrayLike' import { Api, ApiResponse, create } from '../api' const GEOJSON_API = '/service/geojson' const GOOGLE_API = 'https://maps.googleapis.com/maps/api/' const googleApi = create({ baseURL: GOOGLE_API, }) export interface ElementFeaturePair { type: string identifierHash: string elementHash: string } interface GeocodingResponse { results: { address_components: { long_name: string short_name: string types: string[] }[] formatted_address: string geometry: { location: { lat: number lng: number } location_type: string viewport: { northeast: { lat: number lng: number } southeast: { lat: number lng: number } } } place_id: string plus_code: { compound_code: string global_code: string } types: string[] }[] status: string } interface AutocompleteResponse { status: string predictions: { description: string place_id: string }[] } export interface GetLayerGroupsResult { organization: string groups: LayerGroups } export interface ShowNearResult { features: DatabaseFeature[] per_page: number page: number results_count: number } interface NearOptions { awaitSync: boolean } interface EditData { layerName?: string organization?: string geojson?: Feature } export interface IncrementalUpdatesResponse { features: DatabaseFeature[] count: number perPage: number } export interface FeaturesQuery { organization: string query?: object layerName?: string | string[] | undefined properties?: { [prop: string]: string | number | string[] } bounds?: [[number, number], [number, number]] limit?: number sort?: { [prop: string]: number } } export class Geojson { api: Api sessionToken?: string googleKey?: string constructor(api: Api) { this.api = api this.generateSessionToken() } setGoogleKey(key: string) { this.googleKey = key } near( query: NearbyQuery, organization: string, layer: string | string[], page = 1, perPage = 200, paramOptions?: Partial, ): Promise> { const defaultOptions: NearOptions = { awaitSync: false, } const options = Object.assign({}, paramOptions, defaultOptions) const requestQuery = { organization, page, perPage, awaitSync: options.awaitSync, } let queryString = '' if (isArrayLike(layer) && layer.length > 0) { queryString = (layer as string[]).map((l) => `layer=${l}`).join('&') } return this.api.apisauce.get( `${GEOJSON_API}/near/${query.latitude}/${query.longitude}/${query.radius}?${queryString}`, requestQuery, { cache: false, }, ) } loadLayers(organization: string): Promise> { return this.api.apisauce.get(`${GEOJSON_API}/layers/${organization}`) } loadLayerGroups( organization: string, ): Promise> { return this.api.apisauce.get(`${GEOJSON_API}/layergroups/${organization}`) } getFeature(identifierHash: string): Promise> { return this.api.apisauce.get(`${GEOJSON_API}/feature/${identifierHash}`) } getIncrementalUpdates( organization: string, layers: string[], lastSyncAt: string, page = 1, ) { let queryString = '' if (layers && layers.length > 0) { queryString = layers.map((l) => `layer=${l}`).join('&') } return this.api.apisauce.get( `${GEOJSON_API}/incremental-updates/${organization}?${queryString}`, { date: lastSyncAt, page, }, { cache: false, }, ) } getFeaturesForElements( hashes: string[], ): Promise> { return this.api.apisauce.post(`${GEOJSON_API}/element/features`, { elementHashes: hashes, }) } addFeature( geojson: Feature, layerName: string, organization: string, ): Promise> { return this.api.apisauce.post(`${GEOJSON_API}/feature`, { geojson, layerName, organization, }) } createElementsForFeatures( organization: string, hashes: string | string[], ): Promise> { let features if (Array.isArray(hashes)) { features = hashes } else { features = [hashes] } return this.api.apisauce.post(`${GEOJSON_API}/element`, { organization, features, }) } queryFeatures(query: FeaturesQuery) { return this.api.apisauce.post( `${GEOJSON_API}/feature/query`, query, ) } editFeature(geoIdentifier: string, editData: EditData) { return this.api.apisauce.patch( `${GEOJSON_API}/feature/${geoIdentifier}`, editData, ) } geocodingQuery( query: string, metaData: { location?: string; radius?: number } = {}, ) { if (!query) { return } return googleApi.get('place/autocomplete/json', { input: query, inputtype: 'textquery', types: 'geocode', sessionToken: this.sessionToken, ...metaData, key: this.googleKey, }) } async getPlaceLocation(placeId: string) { return googleApi.get('geocode/json', { place_id: placeId, key: this.googleKey, }) } generateSessionToken() { this.sessionToken = v4() } }