@fanam-pkg/core-utils
Version:
Core Functions are managed here for quick web development
158 lines (137 loc) • 4.75 kB
text/typescript
import {useState, useEffect} from "react"
import {Loader} from "@googlemaps/js-api-loader"
import {
AutocompletePrediction,
CoreLibrary,
GeocoderAddressComponent,
GeocodingLibrary,
IDecodedAddress,
MapsLibrary,
PlacesLibrary,
} from "../model"
export const useMaps = () => {
const loader = new Loader({
apiKey: process.env.NEXT_PUBLIC_GOOGLE_API_KEY || "",
libraries: ["maps", "places", "geocoding", "core"],
})
const [maps, setMaps] = useState<MapsLibrary | null>(null)
const [places, setPlaces] = useState<PlacesLibrary | null>(null)
const [geocoding, setGeocoding] = useState<GeocodingLibrary | null>(null)
const [mapCore, setMapCore] = useState<CoreLibrary | null>(null)
useEffect(() => {
if (!maps) loadMaps()
if (!places) loadPlaces()
if (!geocoding) loadGeoCoding()
if (!mapCore) loadMapCore()
}, [])
const loadMaps = async () => {
const response = await loader.importLibrary("maps")
if (response) {
setMaps(response)
}
}
const loadPlaces = async () => {
const response = await loader.importLibrary("places")
if (response) {
setPlaces(response)
}
}
const loadGeoCoding = async () => {
const response = await loader.importLibrary("geocoding")
if (response) {
setGeocoding(response)
}
}
const loadMapCore = async () => {
const response = await loader.importLibrary("core")
if (response) {
setMapCore(response)
}
}
const decodeAddressComponents = (addressComponents: GeocoderAddressComponent[]) => {
const getAddressComponent = (type: string, value: "short_name" | "long_name" = "long_name") => {
const {short_name = "", long_name = ""} = addressComponents.find(({types}) => types.includes(type)) || {}
return value === "long_name" ? long_name : short_name
}
const doorAndFloorNo = getAddressComponent("premise")
const subLocality = addressComponents
.filter(it => it.types.includes("sublocality_level_1"))
.map(lMark => lMark.long_name)
.join(", ")
const city = getAddressComponent("locality") || getAddressComponent("political")
const state = getAddressComponent("administrative_area_level_1")
const country = getAddressComponent("country")
const countryCode = getAddressComponent("country")
const pinCode = getAddressComponent("postal_code")
return {
doorAndFloorNo,
subLocality,
city: city || subLocality,
state,
country,
countryCode,
pinCode,
}
}
const reverseGeoCode = async (lat: number, lng: number): Promise<IDecodedAddress | undefined> => {
if (geocoding) {
const {Geocoder} = geocoding
const geoCoder = new Geocoder()
const {results} = await geoCoder.geocode({location: {lat, lng}})
if (results[0]) {
const sorted = results?.find(result =>
result?.address_components?.find(addrComp => addrComp.types.includes("postal_code"))
)
const addressComponents = sorted?.address_components || []
/* const address = sorted?.formatted_address */
const data = decodeAddressComponents(addressComponents)
return {
...data,
latitude: Number(lat.toFixed(14)),
longitude: Number(lng.toFixed(14)),
}
}
}
}
const getCurrentLocationData = (callback: (addressData: IDecodedAddress | null) => void) => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
async position => {
const response = await reverseGeoCode(position.coords.latitude, position.coords.longitude)
callback(response || null)
},
err => {
console.error("User denied access to location >>>>>>>>>>", err)
callback(null)
},
{enableHighAccuracy: true}
)
} else {
console.error("Geolocation is not supported by this browser. >>>>>>>>>>")
callback(null)
}
}
const getPlacesPredictions = (searchText: string, onCallback: (predictions: AutocompletePrediction[]) => void) => {
if (places) {
const service = new places.AutocompleteService()
service.getPlacePredictions(
{input: searchText, componentRestrictions: {country: "in"}},
(predictions, status) => {
if (status === places.PlacesServiceStatus.OK) {
onCallback(predictions || [])
}
}
)
}
}
return {
loader,
maps,
places,
geocoding,
mapCore,
reverseGeoCode,
getCurrentLocationData,
getPlacesPredictions,
}
}