import React from 'react'; import TextField from '@material-ui/core/TextField'; import Autocomplete from '@material-ui/lab/Autocomplete'; import LocationOnIcon from '@material-ui/icons/LocationOn'; import Grid from '@material-ui/core/Grid'; import Typography from '@material-ui/core/Typography'; import { makeStyles } from '@material-ui/core/styles'; import parse from 'autosuggest-highlight/parse'; import throttle from 'lodash/throttle'; function loadScript(src: string, position: HTMLElement | null, id: string) { if (!position) { return; } const script = document.createElement('script'); script.setAttribute('async', ''); script.setAttribute('id', id); script.src = src; position.appendChild(script); } const autocompleteService = { current: null }; const useStyles = makeStyles((theme) => ({ icon: { color: theme.palette.text.secondary, marginRight: theme.spacing(2), }, })); interface PlaceType { description: string; structured_formatting: { main_text: string; secondary_text: string; main_text_matched_substrings: [ { offset: number; length: number; }, ]; }; } export default function GoogleMaps() { const classes = useStyles(); const [value, setValue] = React.useState(null); const [inputValue, setInputValue] = React.useState(''); const [options, setOptions] = React.useState([]); const loaded = React.useRef(false); if (typeof window !== 'undefined' && !loaded.current) { if (!document.querySelector('#google-maps')) { loadScript( 'https://maps.googleapis.com/maps/api/js?key=AIzaSyBwRp1e12ec1vOTtGiA4fcCt2sCUS78UYc&libraries=places', document.querySelector('head'), 'google-maps', ); } loaded.current = true; } const fetch = React.useMemo( () => throttle((request: { input: string }, callback: (results?: PlaceType[]) => void) => { (autocompleteService.current as any).getPlacePredictions(request, callback); }, 200), [], ); React.useEffect(() => { let active = true; if (!autocompleteService.current && (window as any).google) { autocompleteService.current = new (window as any).google.maps.places.AutocompleteService(); } if (!autocompleteService.current) { return undefined; } if (inputValue === '') { setOptions(value ? [value] : []); return undefined; } fetch({ input: inputValue }, (results?: PlaceType[]) => { if (active) { let newOptions = [] as PlaceType[]; if (value) { newOptions = [value]; } if (results) { newOptions = [...newOptions, ...results]; } setOptions(newOptions); } }); return () => { active = false; }; }, [value, inputValue, fetch]); return ( (typeof option === 'string' ? option : option.description)} filterOptions={(x) => x} options={options} autoComplete includeInputInList filterSelectedOptions value={value} onChange={(event: any, newValue: PlaceType | null) => { setOptions(newValue ? [newValue, ...options] : options); setValue(newValue); }} onInputChange={(event, newInputValue) => { setInputValue(newInputValue); }} renderInput={(params) => ( )} renderOption={(option) => { const matches = option.structured_formatting.main_text_matched_substrings; const parts = parse( option.structured_formatting.main_text, matches.map((match: any) => [match.offset, match.offset + match.length]), ); return ( {parts.map((part, index) => ( {part.text} ))} {option.structured_formatting.secondary_text} ); }} /> ); }