diff --git a/src/components/SearchBox/AutocompleteInput.tsx b/src/components/SearchBox/AutocompleteInput.tsx index 797f66d28..b95aa17ca 100644 --- a/src/components/SearchBox/AutocompleteInput.tsx +++ b/src/components/SearchBox/AutocompleteInput.tsx @@ -57,6 +57,7 @@ export const AutocompleteInput = ({ setInputValue, options, autocompleteRef, + setOverpassLoading, }) => { const { setFeature, setPreview } = useFeatureContext(); const { bbox, showToast } = useMapStateContext(); @@ -84,6 +85,7 @@ export const AutocompleteInput = ({ mobileMode, bbox, showToast, + setOverpassLoading, )} onHighlightChange={onHighlightFactory(setPreview)} getOptionDisabled={(o) => o.loader} diff --git a/src/components/SearchBox/SearchBox.tsx b/src/components/SearchBox/SearchBox.tsx index f2a1d9a81..c455af7be 100644 --- a/src/components/SearchBox/SearchBox.tsx +++ b/src/components/SearchBox/SearchBox.tsx @@ -1,4 +1,4 @@ -import React, { useRef, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import styled from 'styled-components'; import debounce from 'lodash/debounce'; import SearchIcon from '@material-ui/icons/Search'; @@ -7,6 +7,7 @@ import IconButton from '@material-ui/core/IconButton'; import Router from 'next/router'; import match from 'autosuggest-highlight/match'; +import { CircularProgress } from '@material-ui/core'; import { fetchJson } from '../../services/fetch'; import { useMapStateContext } from '../utils/MapStateContext'; import { useFeatureContext } from '../utils/FeatureContext'; @@ -55,6 +56,10 @@ const SearchIconButton = styled(IconButton)` } `; +const OverpassCircularProgress = styled(CircularProgress)` + padding: 10px; +`; + const PHOTON_SUPPORTED_LANGS = ['en', 'de', 'fr']; const getApiUrl = (inputValue, view) => { @@ -162,15 +167,9 @@ const fetchOptions = debounce( 400, ); -const SearchBox = () => { - const { featureShown, feature, setFeature, setPreview } = useFeatureContext(); +const useFetchOptions = (inputValue: string, setOptions) => { const { view } = useMapStateContext(); - const [inputValue, setInputValue] = useState(''); - const [options, setOptions] = useState([]); - const autocompleteRef = useRef(); - const mobileMode = useMobileMode(); - - React.useEffect(() => { + useEffect(() => { if (inputValue === '') { setOptions([]); return; @@ -190,8 +189,13 @@ const SearchBox = () => { fetchOptions(inputValue, view, setOptions); } }, [inputValue]); +}; - const closePanel = () => { +const useOnClosePanel = (setInputValue) => { + const { feature, setFeature, setPreview } = useFeatureContext(); + const mobileMode = useMobileMode(); + + return () => { setInputValue(''); if (mobileMode) { setPreview(feature); @@ -199,6 +203,17 @@ const SearchBox = () => { setFeature(null); Router.push(`/${window.location.hash}`); }; +}; + +const SearchBox = () => { + const { featureShown } = useFeatureContext(); + const [inputValue, setInputValue] = useState(''); + const [options, setOptions] = useState([]); + const [overpassLoading, setOverpassLoading] = useState(false); + const autocompleteRef = useRef(); + const onClosePanel = useOnClosePanel(setInputValue); + + useFetchOptions(inputValue, setOptions); return ( @@ -212,9 +227,11 @@ const SearchBox = () => { setInputValue={setInputValue} options={options} autocompleteRef={autocompleteRef} + setOverpassLoading={setOverpassLoading} /> - {featureShown && } + {featureShown && } + {overpassLoading && } ); diff --git a/src/components/SearchBox/onSelectedFactory.ts b/src/components/SearchBox/onSelectedFactory.ts index 5df9372ac..8dd6900e2 100644 --- a/src/components/SearchBox/onSelectedFactory.ts +++ b/src/components/SearchBox/onSelectedFactory.ts @@ -56,9 +56,15 @@ const fitBounds = (option, panelShown = false) => { }; export const onSelectedFactory = - (setFeature, setPreview, mobileMode, bbox, showToast) => (_, option) => { + (setFeature, setPreview, mobileMode, bbox, showToast, setOverpassLoading) => + (_, option) => { if (option.overpass || option.preset) { const tags = option.overpass || option.preset.presetForSearch.tags; + + const timeout = setTimeout(() => { + setOverpassLoading(true); + }, 300); + performOverpassSearch(bbox, tags) .then((geojson) => { const count = geojson.features.length; @@ -70,6 +76,10 @@ export const onSelectedFactory = const message = `${e}`.substring(0, 100); const content = t('searchbox.overpass_error', { message }); showToast({ content, type: 'error' }); + }) + .finally(() => { + clearTimeout(timeout); + setOverpassLoading(false); }); return; }