UNPKG

places-autocomplete-hook

Version:
1 lines 9.49 kB
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { useState, useCallback, useEffect, useRef } from 'react';\nimport {\n UsePlacesAutocompleteOptions,\n UsePlacesAutocompleteResult,\n PlacePrediction,\n PlaceDetails,\n AddressComponent,\n} from './types';\n\nexport function usePlacesAutocomplete({\n apiKey,\n debounceMs = 300,\n language = 'en',\n types,\n sessionToken,\n location,\n setSelectedPlace,\n}: UsePlacesAutocompleteOptions): UsePlacesAutocompleteResult {\n const [value, setValue] = useState('');\n const [predictions, setPredictions] = useState<PlacePrediction[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const debounceTimer = useRef<NodeJS.Timeout | null>(null);\n\n const clear = useCallback(() => {\n setPredictions([]);\n setError(null);\n setValue('');\n }, []);\n\n const extractAddressComponent = (\n components: AddressComponent[],\n type: string,\n ): string | undefined => {\n const component = components.find(comp => comp.types.includes(type));\n return component?.longText;\n };\n\n const getPlaceDetails = useCallback(\n async (placeId: string): Promise<PlaceDetails> => {\n try {\n const response = await fetch(\n `https://places.googleapis.com/v1/places/${placeId}?key=${apiKey}&languageCode=${language}`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Goog-FieldMask': 'formattedAddress,addressComponents,location',\n ...(sessionToken && { 'X-Goog-Api-Key': apiKey }),\n },\n },\n );\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`);\n }\n\n const data = await response.json();\n const addressComponents = data.addressComponents || [];\n\n return {\n placeId: placeId,\n formattedAddress: data.formattedAddress,\n addressComponents,\n location: data.location,\n streetNumber: extractAddressComponent(addressComponents, 'street_number'),\n streetName: extractAddressComponent(addressComponents, 'route'),\n city: extractAddressComponent(addressComponents, 'locality'),\n state: extractAddressComponent(addressComponents, 'administrative_area_level_1'),\n country: extractAddressComponent(addressComponents, 'country'),\n postalCode: extractAddressComponent(addressComponents, 'postal_code'),\n };\n } catch (err) {\n throw err instanceof Error\n ? err\n : new Error('An error occurred while fetching place details');\n }\n },\n [apiKey, language, sessionToken],\n );\n\n const handlePlaceSelect = useCallback(\n async (placeId: string) => {\n setSelectedPlace?.(placeId);\n },\n [setSelectedPlace],\n );\n\n const search = useCallback(\n async (input: string) => {\n if (!input.trim()) {\n clear();\n return;\n }\n\n try {\n setLoading(true);\n setError(null);\n\n const requestBody: any = {\n input: input,\n languageCode: language,\n };\n\n if (types) {\n requestBody.types = types;\n }\n\n if (location) {\n requestBody.locationBias = {\n circle: {\n center: {\n latitude: location.lat,\n longitude: location.lng,\n },\n radius: location.radius,\n },\n };\n }\n\n const response = await fetch(\n `https://places.googleapis.com/v1/places:autocomplete?key=${apiKey}`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'X-Goog-FieldMask':\n 'suggestions.placePrediction.place,suggestions.placePrediction.placeId,suggestions.placePrediction.text,suggestions.placePrediction.structuredFormat,suggestions.placePrediction.types',\n ...(sessionToken && { 'X-Goog-Api-Key': apiKey }),\n },\n body: JSON.stringify(requestBody),\n },\n );\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error?.message || `HTTP error! status: ${response.status}`);\n }\n\n const data = await response.json();\n setPredictions(data.suggestions.map((suggestion: any) => suggestion.placePrediction) || []);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('An error occurred'));\n setPredictions([]);\n } finally {\n setLoading(false);\n }\n },\n [apiKey, language, sessionToken, types, location, clear],\n );\n\n const debouncedSearch = useCallback(\n async (input: string) => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n\n return new Promise<void>(resolve => {\n debounceTimer.current = setTimeout(async () => {\n await search(input);\n resolve();\n }, debounceMs);\n });\n },\n [search, debounceMs],\n );\n\n useEffect(() => {\n return () => {\n if (debounceTimer.current) {\n clearTimeout(debounceTimer.current);\n }\n };\n }, []);\n\n return {\n value,\n suggestions: {\n status: error\n ? 'ERROR'\n : loading\n ? 'LOADING'\n : predictions.length > 0\n ? 'OK'\n : 'ZERO_RESULTS',\n data: predictions,\n },\n setValue: (newValue: string, shouldFetchData = true) => {\n setValue(newValue);\n if (shouldFetchData) {\n debouncedSearch(newValue);\n }\n },\n clearSuggestions: clear,\n search: debouncedSearch,\n loading,\n error,\n getPlaceDetails,\n handlePlaceSelect,\n };\n}\n\nexport type {\n PlacePrediction,\n UsePlacesAutocompleteOptions,\n UsePlacesAutocompleteResult,\n PlaceDetails,\n};\n"],"mappings":"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","names":[]}