♻️ Refactor StopsSearchMenu + load Map lazily + placeholder
This commit is contained in:
165
frontend/src/stopsSearchMenu/searchStore.tsx
Normal file
165
frontend/src/stopsSearchMenu/searchStore.tsx
Normal file
@@ -0,0 +1,165 @@
|
||||
import { createContext, JSX } from 'solid-js';
|
||||
import { createStore } from "solid-js/store";
|
||||
import OlFeature from 'ol/Feature';
|
||||
import { BusinessDataStore } from "../businessData";
|
||||
|
||||
import { Stop } from '../types';
|
||||
import { PositionedPanel } from '../utils';
|
||||
|
||||
type ByStopIdMapFeatures = Record<number, OlFeature>;
|
||||
|
||||
export interface SearchStore {
|
||||
|
||||
getSearchText: () => string;
|
||||
setSearchText: (text: string, businessDataStore: BusinessDataStore) => Promise<void>;
|
||||
|
||||
getFoundStops: () => Stop[];
|
||||
setFoundStops: (stops: Stop[]) => void;
|
||||
|
||||
getDisplayedPanelId: () => number;
|
||||
setDisplayedPanelId: (panelId: number) => void;
|
||||
|
||||
getPanels: () => PositionedPanel[];
|
||||
setPanels: (panels: PositionedPanel[]) => void;
|
||||
|
||||
getHighlightedStop: () => Stop | undefined;
|
||||
setHighlightedStop: (stop: Stop) => void;
|
||||
resetHighlightedStop: () => void;
|
||||
|
||||
enableMap: (enable: boolean) => void;
|
||||
isMapEnabled: () => boolean;
|
||||
getMapFeature: (stopId: number) => OlFeature | undefined;
|
||||
getAllMapFeatures: () => ByStopIdMapFeatures;
|
||||
setMapFeature: (stopId: number, feature: OlFeature) => void;
|
||||
};
|
||||
|
||||
export const SearchContext = createContext<SearchStore>();
|
||||
|
||||
|
||||
export function SearchProvider(props: { children: JSX.Element }) {
|
||||
|
||||
const searchTextDelayMs = 1500;
|
||||
|
||||
type Store = {
|
||||
searchText: string;
|
||||
searchPromise: Promise<void> | undefined;
|
||||
foundStops: Stop[];
|
||||
displayedPanelId: number;
|
||||
panels: PositionedPanel[];
|
||||
highlightedStop: Stop | undefined;
|
||||
mapEnabled: boolean;
|
||||
mapFeatures: ByStopIdMapFeatures;
|
||||
};
|
||||
|
||||
const [store, setStore] = createStore<Store>({
|
||||
searchText: "",
|
||||
searchPromise: undefined,
|
||||
foundStops: [],
|
||||
displayedPanelId: 0,
|
||||
panels: [],
|
||||
highlightedStop: undefined,
|
||||
// mapEnabled: false,
|
||||
mapFeatures: {},
|
||||
});
|
||||
|
||||
const getSearchText = (): string => {
|
||||
return store.searchText;
|
||||
}
|
||||
|
||||
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;
|
||||
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));
|
||||
onSuccess();
|
||||
}, searchTextDelayMs).then(() => {
|
||||
setStore('searchPromise', undefined);
|
||||
});
|
||||
setStore('searchPromise', promise);
|
||||
}
|
||||
}
|
||||
|
||||
const getFoundStops = (): Stop[] => {
|
||||
return store.foundStops;
|
||||
}
|
||||
|
||||
const setFoundStops = (stops: Stop[]): void => {
|
||||
setStore('foundStops', stops);
|
||||
}
|
||||
|
||||
const getDisplayedPanelId = (): number => {
|
||||
return store.displayedPanelId;
|
||||
}
|
||||
|
||||
const setDisplayedPanelId = (panelId: number): void => {
|
||||
setStore('displayedPanelId', panelId);
|
||||
}
|
||||
|
||||
const getPanels = (): PositionedPanel[] => {
|
||||
return store.panels;
|
||||
}
|
||||
|
||||
const setPanels = (panels: PositionedPanel[]): void => {
|
||||
setStore('panels', panels);
|
||||
}
|
||||
|
||||
const getHighlightedStop = (): Stop | undefined => {
|
||||
return store.highlightedStop;
|
||||
}
|
||||
|
||||
const setHighlightedStop = (stop: Stop): void => {
|
||||
setStore('highlightedStop', stop);
|
||||
}
|
||||
|
||||
const resetHighlightedStop = (): void => {
|
||||
setStore('highlightedStop', undefined);
|
||||
}
|
||||
|
||||
|
||||
const enableMap = (enable: boolean): void => {
|
||||
setStore("mapEnabled", enable);
|
||||
}
|
||||
|
||||
const isMapEnabled = (): boolean => {
|
||||
return store.mapEnabled;
|
||||
}
|
||||
|
||||
const getAllMapFeatures = (): ByStopIdMapFeatures => {
|
||||
return store.mapFeatures;
|
||||
}
|
||||
|
||||
const getMapFeature = (stopId: number): OlFeature | undefined => {
|
||||
return store.mapFeatures[stopId];
|
||||
}
|
||||
|
||||
const setMapFeature = (stopId: number, feature: OlFeature): void => {
|
||||
setStore('mapFeatures', stopId, feature);
|
||||
};
|
||||
|
||||
return (
|
||||
<SearchContext.Provider value={{
|
||||
getSearchText, setSearchText,
|
||||
getFoundStops, setFoundStops,
|
||||
getDisplayedPanelId, setDisplayedPanelId,
|
||||
getPanels, setPanels,
|
||||
getHighlightedStop, setHighlightedStop, resetHighlightedStop,
|
||||
enableMap, isMapEnabled,
|
||||
getMapFeature, getAllMapFeatures, setMapFeature,
|
||||
}}>
|
||||
{props.children}
|
||||
</SearchContext.Provider>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user