🚸 Add debounce mechanism to stop name input
This commit is contained in:
@@ -43,7 +43,6 @@ interface SearchStore {
|
||||
|
||||
getSearchText: () => string;
|
||||
setSearchText: (text: string, businessDataStore: BusinessDataStore) => Promise<void>;
|
||||
isSearchInProgress: () => boolean;
|
||||
|
||||
getFoundStops: () => Stop[];
|
||||
setFoundStops: (stops: Stop[]) => void;
|
||||
@@ -65,11 +64,14 @@ interface SearchStore {
|
||||
|
||||
const SearchContext = createContext<SearchStore>();
|
||||
|
||||
|
||||
function SearchProvider(props: { children: JSX.Element }) {
|
||||
|
||||
const searchTextDelayMs = 1500;
|
||||
|
||||
type Store = {
|
||||
searchText: string;
|
||||
searchInProgress: boolean;
|
||||
searchPromise: Promise<void> | undefined;
|
||||
foundStops: Stop[];
|
||||
displayedPanelId: number;
|
||||
panels: PositionedPanel[];
|
||||
@@ -79,7 +81,7 @@ function SearchProvider(props: { children: JSX.Element }) {
|
||||
|
||||
const [store, setStore] = createStore<Store>({
|
||||
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<void> => {
|
||||
setStore('searchInProgress', true);
|
||||
const debounce = async (fn: (...args: any[]) => Promise<void>, delayMs: number) => {
|
||||
let timerId: number;
|
||||
return new Promise((...args) => {
|
||||
clearTimeout(timerId);
|
||||
timerId = setTimeout(fn, delayMs, ...args);
|
||||
});
|
||||
}
|
||||
|
||||
const setSearchText = async (text: string, businessDataStore: BusinessDataStore): Promise<void> => {
|
||||
setStore('searchText', text);
|
||||
|
||||
if (store.searchPromise === undefined) {
|
||||
const { searchStopByName } = businessDataStore;
|
||||
console.log("store.searchText=", store.searchText);
|
||||
const promise: Promise<void> = 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));
|
||||
|
||||
setStore('searchInProgress', false);
|
||||
onSuccess();
|
||||
}, searchTextDelayMs).then(() => {
|
||||
setStore('searchPromise', undefined);
|
||||
});
|
||||
setStore('searchPromise', promise);
|
||||
}
|
||||
|
||||
const isSearchInProgress = (): boolean => {
|
||||
return store.searchInProgress;
|
||||
}
|
||||
|
||||
const getFoundStops = (): Stop[] => {
|
||||
@@ -161,7 +171,7 @@ function SearchProvider(props: { children: JSX.Element }) {
|
||||
|
||||
return (
|
||||
<SearchContext.Provider value={{
|
||||
getSearchText, setSearchText, isSearchInProgress,
|
||||
getSearchText, setSearchText,
|
||||
getFoundStops, setFoundStops,
|
||||
getDisplayedPanelId, setDisplayedPanelId,
|
||||
getPanels, setPanels,
|
||||
@@ -182,13 +192,12 @@ const Header: VoidComponent<{ title: string, minCharsNb: number }> = (props) =>
|
||||
if (businessDataStore === undefined || searchStore === undefined)
|
||||
return <div />;
|
||||
|
||||
const { isSearchInProgress, setSearchText } = searchStore;
|
||||
const { setSearchText } = searchStore;
|
||||
|
||||
const onStopNameInput: JSX.EventHandler<HTMLInputElement, InputEvent> = async (event): Promise<void> => {
|
||||
/* 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) =>
|
||||
<div class="inputGroup">
|
||||
<InputGroup >
|
||||
<InputLeftAddon>🚉 🚏</InputLeftAddon>
|
||||
<Input onInput={onStopNameInput} readOnly={isSearchInProgress()} placeholder="Stop name..." />
|
||||
<Input onInput={onStopNameInput} placeholder="Stop name..." />
|
||||
</InputGroup>
|
||||
</div>
|
||||
</div >
|
||||
|
Reference in New Issue
Block a user