From e81f81b7a7fd39506ec971175bb15bc2a13f168b Mon Sep 17 00:00:00 2001 From: Adrien Date: Sat, 22 Apr 2023 12:31:26 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=B8=20Add=20debounce=20mechanism=20to?= =?UTF-8?q?=20stop=20name=20input?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/stopsSearchMenu.tsx | 51 +++++++++++++++++++------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/frontend/src/stopsSearchMenu.tsx b/frontend/src/stopsSearchMenu.tsx index 5456a37..e978cf7 100644 --- a/frontend/src/stopsSearchMenu.tsx +++ b/frontend/src/stopsSearchMenu.tsx @@ -43,7 +43,6 @@ interface SearchStore { getSearchText: () => string; setSearchText: (text: string, businessDataStore: BusinessDataStore) => Promise; - isSearchInProgress: () => boolean; getFoundStops: () => Stop[]; setFoundStops: (stops: Stop[]) => void; @@ -65,11 +64,14 @@ interface SearchStore { const SearchContext = createContext(); + function SearchProvider(props: { children: JSX.Element }) { + const searchTextDelayMs = 1500; + type Store = { searchText: string; - searchInProgress: boolean; + searchPromise: Promise | undefined; foundStops: Stop[]; displayedPanelId: number; panels: PositionedPanel[]; @@ -79,7 +81,7 @@ function SearchProvider(props: { children: JSX.Element }) { const [store, setStore] = createStore({ searchText: "", - searchInProgress: false, + searchPromise: undefined, foundStops: [], displayedPanelId: 0, panels: [], @@ -91,22 +93,30 @@ function SearchProvider(props: { children: JSX.Element }) { return store.searchText; } - const setSearchText = async (text: string, businessDataStore: BusinessDataStore): Promise => { - setStore('searchInProgress', true); - - setStore('searchText', text); - - const { searchStopByName } = businessDataStore; - console.log("store.searchText=", store.searchText); - const stopsById = await searchStopByName(store.searchText); - console.log("stopsById=", stopsById); - setFoundStops(Object.values(stopsById)); - - setStore('searchInProgress', false); + const debounce = async (fn: (...args: any[]) => Promise, delayMs: number) => { + let timerId: number; + return new Promise((...args) => { + clearTimeout(timerId); + timerId = setTimeout(fn, delayMs, ...args); + }); } - const isSearchInProgress = (): boolean => { - return store.searchInProgress; + const setSearchText = async (text: string, businessDataStore: BusinessDataStore): Promise => { + setStore('searchText', text); + + if (store.searchPromise === undefined) { + const { searchStopByName } = businessDataStore; + const promise: Promise = debounce(async (onSuccess: () => void) => { + console.log(`Fetching data for "${store.searchText}" stop name`); + const stopsById = await searchStopByName(store.searchText); + console.log("stopsById=", stopsById); + setFoundStops(Object.values(stopsById)); + onSuccess(); + }, searchTextDelayMs).then(() => { + setStore('searchPromise', undefined); + }); + setStore('searchPromise', promise); + } } const getFoundStops = (): Stop[] => { @@ -161,7 +171,7 @@ function SearchProvider(props: { children: JSX.Element }) { return ( = (props) => if (businessDataStore === undefined || searchStore === undefined) return
; - const { isSearchInProgress, setSearchText } = searchStore; + const { setSearchText } = searchStore; const onStopNameInput: JSX.EventHandler = async (event): Promise => { /* TODO: Add a tempo before fetching stop for giving time to user to finish his request */ const stopName = event.currentTarget.value; if (stopName.length >= props.minCharsNb) { - console.log(`Fetching data for "${stopName}" stop name`); await setSearchText(stopName, businessDataStore); } } @@ -205,7 +214,7 @@ const Header: VoidComponent<{ title: string, minCharsNb: number }> = (props) =>
🚉 🚏 - +