rxjs/operators#debounceTime JavaScript Examples

The following examples show how to use rxjs/operators#debounceTime. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.js    From sampo-ui with MIT License 6 votes vote down vote up
fullTextSearchEpic = (action$, state$) => action$.pipe(
  ofType(FETCH_FULL_TEXT_RESULTS),
  withLatestFrom(state$),
  debounceTime(500),
  switchMap(([action, state]) => {
    const requestUrl = `${apiUrl}/full-text-search?q=${action.query}`
    return ajax.getJSON(requestUrl).pipe(
      map(response => updateResults({
        resultClass: 'fullTextSearch',
        data: response.data,
        sparqlQuery: response.sparqlQuery,
        query: action.query,
        jenaIndex: action.jenaIndex
      })),
      catchError(error => of({
        type: FETCH_RESULTS_FAILED,
        resultClass: 'fullTextSearch',
        error: error,
        message: {
          text: backendErrorText,
          title: 'Error'
        }
      }))
    )
  })
)
Example #2
Source File: index.js    From sampo-ui with MIT License 6 votes vote down vote up
clientFSFetchResultsEpic = (action$, state$) => action$.pipe(
  ofType(CLIENT_FS_FETCH_RESULTS),
  withLatestFrom(state$),
  debounceTime(500),
  switchMap(([action, state]) => {
    const { perspectiveID, jenaIndex } = action
    const federatedSearchState = state[perspectiveID]
    const selectedDatasets = pickSelectedDatasets(federatedSearchState.datasets)
    const dsParams = selectedDatasets.map(ds => `dataset=${ds}`).join('&')
    let requestUrl
    if (action.jenaIndex === 'text') {
      requestUrl = `${apiUrl}/federated-search?q=${action.query}&${dsParams}&perspectiveID=${perspectiveID}`
    } else if (action.jenaIndex === 'spatial') {
      const { latMin, longMin, latMax, longMax } = federatedSearchState.maps.boundingboxSearch
      requestUrl = `${apiUrl}/federated-search?latMin=${latMin}&longMin=${longMin}&latMax=${latMax}&longMax=${longMax}&${dsParams}&perspectiveID=${perspectiveID}`
    }
    return ajax.getJSON(requestUrl).pipe(
      map(response => clientFSUpdateResults({
        results: response,
        jenaIndex
      })),
      catchError(error => of({
        type: CLIENT_FS_FETCH_RESULTS_FAILED,
        error: error,
        message: {
          text: backendErrorText,
          title: 'Error'
        }
      }))
    )
  })
)
Example #3
Source File: SearchPage.js    From app with MIT License 4 votes vote down vote up
function SearchPage() {
  const classes = useStyles();
  const { showError } = useNotifications();

  // State
  const [showAddressPicker, setShowAddressPicker] = useState(false);
  const [nearbyRequests, setNearbyRequests] = useState(null);
  const [currentLatLong, setCurrentLatLong] = useState({
    latitude: DEFAULT_LATITUDE,
    longitude: DEFAULT_LONGITUDE,
  });
  const [currentPlaceLabel, setCurrentPlaceLabel] = React.useState(
    `Using default location: ${DEFAULT_LOCATION_NAME}`,
  );
  const [distance, setDistance] = useState(defaultDistance);
  const [searching, setSearching] = useState(false);

  const [onSearch$] = useState(() => new Subject());

  // Data
  const user = useUser();
  const firestore = useFirestore();
  const analytics = useAnalytics();
  const { GeoPoint } = useFirestore;

  async function searchForNearbyRequests({ searchLocation, searchDistance }) {
    if (!searchLocation) return;
    // Use lat/long set to state (either from profile or default)
    const { latitude, longitude } = searchLocation;
    setSearching(true);
    analytics.logEvent('search', {
      search_term: `latitude=${latitude}&longitude=${longitude}`,
    });
    try {
      // Query for nearby requests
      const geofirestore = new GeoFirestore(firestore);
      const nearbyRequestsSnap = await geofirestore
        .collection(REQUESTS_PUBLIC_COLLECTION)
        .near({
          center: new GeoPoint(latitude, longitude),
          radius: KM_TO_MILES * searchDistance,
        })
        .where('status', '==', 1)
        .limit(30)
        .get();
      const sortedByDistance = nearbyRequestsSnap.docs.sort(
        (a, b) => a.distance - b.distance,
      );
      setNearbyRequests(
        sortedByDistance.map((docSnap) => ({
          ...docSnap.data(),
          id: docSnap.id,
          distance: kmToMiles(docSnap.distance).toFixed(2),
        })),
      );
      setSearching(false);
    } catch (err) {
      showError('Error searching for nearby requests');
      // eslint-disable-next-line no-console
      console.log(err);
      setSearching(false);
    }
  }

  // Setup an observable for debouncing the search requests.
  useEffect(() => {
    const subscription = onSearch$
      .pipe(debounceTime(500))
      .subscribe(searchForNearbyRequests);

    return () => subscription.unsubscribe();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // This pushes new empty values to the observable when the distance or location changes.
  useEffect(() => {
    onSearch$.next({
      searchLocation: currentLatLong,
      searchDistance: distance,
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [currentLatLong, distance]);

  useEffect(() => {
    async function loadLatLongFromProfile() {
      // TODO: Search is triggered twice when the user is logged in. Once with the first render,
      //       and then again when the user is assigned.  Need to fix this behavior.
      // Set lat/long from profile or fallback to defaults
      if (user && user.uid) {
        const profileRef = firestore.doc(`${USERS_COLLECTION}/${user.uid}`);
        const profileSnap = await profileRef.get();
        const geopoint = profileSnap.get('preciseLocation');
        if (geopoint) {
          const userLocation = {
            latitude: geopoint.latitude,
            longitude: geopoint.longitude,
          };
          setCurrentLatLong(userLocation);
          setCurrentPlaceLabel(
            `Near ${profileSnap.get('generalLocationName')}`,
          );
          onSearch$.next({
            searchLocation: userLocation,
            searchDistance: defaultDistance,
          });
        } else {
          onSearch$.next({
            searchLocation: currentLatLong,
            searchDistance: defaultDistance,
          });
        }
      } else {
        onSearch$.next({
          searchLocation: currentLatLong,
          searchDistance: defaultDistance,
        });
      }
    }
    // NOTE: useEffect is used to load data so it can be done conditionally based
    // on whether current user is logged in
    loadLatLongFromProfile();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [user]);

  function handleCopyNeedLink(id) {
    const el = document.createElement('textarea');
    document.body.appendChild(el);
    el.value = `${window.location.origin}${generatePath(REQUEST_PATH, {
      requestId: id,
    })}`;
    el.select();
    document.execCommand('copy');
    document.body.removeChild(el);
  }

  // Gets the lat/lng for the selected address.
  function handlePlaceSelect(_event, selection) {
    if (!selection) return;
    geocodeByAddress(selection.description)
      .then((results) => getLatLng(results[0]))
      .then((latLng) => {
        setCurrentLatLong({ latitude: latLng.lat, longitude: latLng.lng });
      })
      .catch((error) => {
        showError('Failed to get the location from address.');
        // eslint-disable-next-line no-console
        console.error('Error', error);
      });
  }

  function handlePlaceChange(address) {
    setCurrentPlaceLabel(address);
  }

  return (
    <Container maxWidth="md">
      <Helmet>
        <title>Find Opportunities</title>
      </Helmet>
      <Typography variant="h6">Search Criteria</Typography>
      <Paper className={classes.filterPaper}>
        {!showAddressPicker && (
          <div className={classes.searchLocation}>
            <Typography id="continuous-slider">{currentPlaceLabel}</Typography>
            <Button
              data-test="new-location-button"
              onClick={() => setShowAddressPicker(true)}
              className={classes.enterAddressButton}>
              Select new location
            </Button>
          </div>
        )}
        {showAddressPicker && (
          <>
            <LoadScript
              id="script-loader"
              libraries={USED_GOOGLE_MAPS_LIBRARIES}
              googleMapsApiKey={process.env.REACT_APP_FIREBASE_API_KEY}>
              <PlacesAutocomplete
                value={currentPlaceLabel}
                onChange={handlePlaceChange}>
                {({ getInputProps, suggestions, loading }) => (
                  <>
                    {/* {console.log(suggestions)} */}
                    <Autocomplete
                      data-test="places-autocomplete"
                      onChange={handlePlaceSelect}
                      options={suggestions}
                      loading={loading}
                      getOptionLabel={(sug) => sug.description}
                      noOptionsText="No matches"
                      renderInput={(params) => (
                        <TextField
                          margin="none"
                          data-test="address-entry"
                          {...getInputProps({
                            ...params,
                            label: 'Address',
                            className: classes.searchInput,
                          })}
                          InputProps={{
                            ...params.InputProps,
                            endAdornment: (
                              <>
                                {loading && (
                                  <CircularProgress color="inherit" size={20} />
                                )}
                              </>
                            ),
                          }}
                        />
                      )}
                    />
                  </>
                )}
              </PlacesAutocomplete>
            </LoadScript>
            <Typography align="right" variant="caption" display="block">
              Powered by Google Maps
            </Typography>
          </>
        )}

        <Divider className={classes.divider} />

        <Typography id="continuous-slider" gutterBottom>
          Distance (in miles)
        </Typography>
        <div className={classes.distance}>
          <Slider
            defaultValue={defaultDistance}
            valueLabelDisplay="on"
            // valueLabelFormat={x => `${x} mi`}
            marks={markValues}
            onChange={(_event, value) => setDistance(value)}
            min={1}
            max={markValues[markValues.length - 1].value}
          />
        </div>
      </Paper>
      {searching && (
        <Paper className={classes.simplePaper}>
          <LinearProgress />
        </Paper>
      )}
      {nearbyRequests && nearbyRequests.length === 0 && (
        <Paper className={classes.simplePaper}>
          <Typography data-test="no-requests-found">
            No requests found with {distance} miles. You can try expanding the
            search area or try entering a new location.
          </Typography>
        </Paper>
      )}
      {nearbyRequests &&
        nearbyRequests.map((result) => (
          <Paper className={classes.resultPaper} key={result.id}>
            <Grid container>
              <Hidden xsDown>
                <Grid item className={classes.distanceContainer} sm={2}>
                  {result.distance}
                  <br />
                  miles
                </Grid>
              </Hidden>
              <Grid item className={classes.requestSummary} xs={12} sm={10}>
                {parseInt(result.immediacy, 10) > 5 && (
                  <img
                    align="right"
                    src="/taskIcon.png"
                    width="50px"
                    height="50px"
                    alt="Urgent"
                    title="Urgent"
                  />
                )}

                <Typography variant="h6">
                  {result.name ? result.name : result.firstName} &ndash;{' '}
                  {result.generalLocationName}
                </Typography>

                <Typography variant="caption" gutterBottom>
                  Requested {format(result.createdAt.toDate(), 'p - PPPP')}
                </Typography>

                <Typography variant="h5" className={classes.needs} gutterBottom>
                  {result.needs.map((item) => (
                    <React.Fragment key={item}>
                      {allCategoryMap[item] ? (
                        <Chip
                          size="small"
                          variant="outlined"
                          icon={
                            item === 'grocery-pickup' ? <GroceryIcon /> : null
                          }
                          label={allCategoryMap[item].shortDescription}
                        />
                      ) : (
                        <Alert severity="error">
                          Could not find &apos;{item}&apos; in all category map.
                        </Alert>
                      )}
                    </React.Fragment>
                  ))}
                  {result.needFinancialAssistance && (
                    <Chip
                      variant="outlined"
                      size="small"
                      icon={<FinancialAssitanceIcon />}
                      label="Need financial assistance"
                    />
                  )}
                </Typography>

                <Hidden smUp>
                  <Typography
                    align="right"
                    variant="h5"
                    className={classes.TaskTitle}>
                    {result.distance} miles
                  </Typography>
                </Hidden>

                <Grid container justify="flex-end">
                  <Grid item>
                    {navigator.share ? (
                      <Button
                        size="small"
                        onClick={() => {
                          navigator.share({
                            title: 'CV19 Assist Need Link',
                            text: 'CV19 Assist Need Link',
                            url: `${window.location.origin}${generatePath(
                              REQUEST_PATH,
                              {
                                requestId: result.id,
                              },
                            )}`,
                          });
                        }}>
                        SHARE
                      </Button>
                    ) : (
                      <Button
                        size="small"
                        onClick={() => handleCopyNeedLink(result.id)}>
                        COPY LINK FOR SHARING
                      </Button>
                    )}{' '}
                    <Button
                      component={Link}
                      to={generatePath(REQUEST_PATH, {
                        requestId: result.id,
                      })}
                      size="small"
                      color="primary"
                      disableElevation>
                      DETAILS...
                    </Button>
                  </Grid>
                </Grid>
              </Grid>
            </Grid>
          </Paper>
        ))}
    </Container>
  );
}
Example #4
Source File: exception-search.js    From real-time-map with MIT License 4 votes vote down vote up
exceptionSearch = {
	exceptionResultsCache: {},
	displayList: {},

	get searchInput() {
		return document.getElementById("RTM-exception-search-bar");
	},

	init(mapPropsToComponent) {
		// Init rxjs debounce search.
		const searchInputObservable$ = fromEvent(exceptionSearch.searchInput, "input").pipe(map(i => i.currentTarget.value));
		const debouncedInput = searchInputObservable$.pipe(debounceTime(250));
		debouncedInput.subscribe((searchInput) => exceptionSearch.buildSearchList(searchInput, mapPropsToComponent));
	},

	loadSavedExceptionConfig(mapPropsToComponent) {

		return getBlobStorage().then(val => {

			if (val.length > 0 && !storage.setBlobStorageObj) { storage.setBlobStorageObj = val[0]; }
			else {
				return saveBlobStorage("Exception", {}).then(() => {
					return getBlobStorage().then(val => {
						storage.setBlobStorageObj = val[0];
					});
				});
			};

			exceptionSearch.searchInput.value = "";
			const cachedExceptions = JSON.parse(val[0].data);

			if (cachedExceptions.configData.Exception) {
				exceptionSearch.displayList = cachedExceptions.configData.Exception;
				storage.selectedExceptions = filterByVisibility(exceptionSearch.displayList);
				exceptionSearch.buildExceptionDisplayList(mapPropsToComponent);
			}
		}).catch(error =>
			console.warn("Server is unavailable, please try again later: ", error)
		);
	},

	buildSearchList(searchInput, mapPropsToComponent) {
		return getRulesByName(searchInput).then(ruleList => {

			ruleList.forEach(rule => {
				let {
					color,
					name,
					id,
					baseType
				} = rule;

				if (baseType === "Stock") { name += " (Default)"; };
				const visible = true;

				exceptionSearch.exceptionResultsCache[name] = { color, name, id, visible, baseType };
			});

			mapPropsToComponent(Object.values(exceptionSearch.exceptionResultsCache));
		});
	},

	handleItemSelected(event, mapPropsToComponent) {
		event.preventDefault();
		exceptionSearch.saveSelectedValue(mapPropsToComponent);
	},

	saveSelectedValue(mapPropsToComponent) {
		const { value } = exceptionSearch.searchInput;
		const exceptionData = exceptionSearch.exceptionResultsCache[value];

		if (exceptionData) {
			exceptionSearch.displayList[exceptionData.id] = exceptionData;
			exceptionSearch.saveConfig(mapPropsToComponent);
			exceptionSearch.searchInput.value = "";
		}
		return exceptionData;
	},

	buildExceptionDisplayList(mapPropsToComponent) {
		mapPropsToComponent(Object.values(exceptionSearch.displayList)
			.filter(ruleData => ruleData.id && ruleData.name));
	},

	deleteItemFromExceptionList(id, mapPropsToComponent) {
		delete exceptionSearch.displayList[id];
		exceptionSearch.saveConfig(mapPropsToComponent);
	},

	saveConfig(mapPropsToComponent) {
		storage.selectedExceptions = filterByVisibility(exceptionSearch.displayList);
		storage.setBlobStorageObj ? setBlobStorage("Exception", exceptionSearch.displayList) : saveBlobStorage("Exception", exceptionSearch.displayList);
		exceptionSearch.buildExceptionDisplayList(mapPropsToComponent);
		storage.dateKeeper$.update();
	},

	toggleExceptionVisibility(ruleID, mapPropsToComponent) {
		const selectedException = exceptionSearch.displayList[ruleID];
		selectedException.visible = !selectedException.visible;
		exceptionSearch.saveConfig(mapPropsToComponent);
	},
	deleteAllItems(mapPropsToComponent) {
		exceptionSearch.displayList = {};
		exceptionSearch.saveConfig(mapPropsToComponent);
	},
	setVisibilityForAllItems(visibility, mapPropsToComponent) {
		Object.values(exceptionSearch.displayList)
			.forEach(selectedItem =>
				selectedItem.visible = visibility
			);
		exceptionSearch.saveConfig(mapPropsToComponent);
	}
}
Example #5
Source File: status-search.js    From real-time-map with MIT License 4 votes vote down vote up
diagnosticSearch = {
	resultsCache: {},
	displayList: {},

	get searchInput() {
		return document.getElementById("RTM-status-search-bar");
	},

	init(mapPropsToComponent) {
		// Init rxjs debounce search.
		const searchInputObservable$ = fromEvent(diagnosticSearch.searchInput, "input").pipe(map(i => i.currentTarget.value));
		const debouncedInput = searchInputObservable$.pipe(debounceTime(250));
		debouncedInput.subscribe((searchInput) => diagnosticSearch.buildSearchList(searchInput, mapPropsToComponent));
	},

	loadSavedStatusConfig(mapPropsToComponent) {

		return getBlobStorage().then(val => {
			if (val.length === 0) { return; }
			const cachedDiagnostics = JSON.parse(val[0].data);

			if (cachedDiagnostics.configData.Status) {
				diagnosticSearch.displayList = cachedDiagnostics.configData.Status;
				storage.selectedStatuses = filterByVisibility(diagnosticSearch.displayList);
				diagnosticSearch.buildStatusDisplayList(mapPropsToComponent);
			}
		});
	},

	buildSearchList(searchInput, mapPropstoComponent) {

		return getDiagnosticByName(searchInput).then(diagnosticResults => {

			diagnosticResults.forEach(diagnostic => {
				const {
					id,
					name,
					unitOfMeasure
				} = diagnostic;

				const visible = true;

				diagnosticSearch.resultsCache[name] = { name, id, visible, unitOfMeasure };
			});
			mapPropstoComponent(Object.values(diagnosticSearch.resultsCache));
		});
	},

	handleItemSelected(event, mapPropsToComponent) {
		event.preventDefault();
		diagnosticSearch.saveSelectedValue(mapPropsToComponent);
	},

	saveSelectedValue(mapPropsToComponent) {

		const { value } = diagnosticSearch.searchInput;
		const diagnosticData = diagnosticSearch.resultsCache[value];

		if (diagnosticData) {
			diagnosticSearch.displayList[diagnosticData.id] = diagnosticData;
			diagnosticSearch.searchInput.value = "";
			diagnosticSearch.saveConfig(mapPropsToComponent);
		}

		return diagnosticData;
	},

	buildStatusDisplayList(mapPropsToComponent) {
		mapPropsToComponent(Object.values(diagnosticSearch.displayList)
			.filter(diagnostic => diagnostic.id && diagnostic.name));
	},

	deleteItemFromStatusList(id, mapPropsToComponent) {
		delete diagnosticSearch.displayList[id];
		diagnosticSearch.saveConfig(mapPropsToComponent);
	},

	saveConfig(mapPropsToComponent) {
		storage.selectedStatuses = filterByVisibility(diagnosticSearch.displayList);
		storage.setBlobStorageObj ? setBlobStorage("Status", diagnosticSearch.displayList) : saveBlobStorage("Status", diagnosticSearch.displayList);
		storage.dateKeeper$.update();
		diagnosticSearch.buildStatusDisplayList(mapPropsToComponent);
	},

	toggleStatusVisibility(id, mapPropsToComponent) {
		const selectedDiagnostic = diagnosticSearch.displayList[id];
		selectedDiagnostic.visible = !selectedDiagnostic.visible;
		diagnosticSearch.saveConfig(mapPropsToComponent);
	},

	deleteAllItems(mapPropsToComponent) {
		diagnosticSearch.displayList = {};
		diagnosticSearch.saveConfig(mapPropsToComponent);
	},

	showAllItems(mapPropsToComponent) {
		Object.values(diagnosticSearch.displayList)
			.forEach(selectedDiagnostic =>
				selectedDiagnostic.visible = true
			);
		diagnosticSearch.saveConfig(mapPropsToComponent);
	},

	hideAllItems(mapPropsToComponent) {
		Object.values(diagnosticSearch.displayList)
			.forEach(selectedDiagnostic =>
				selectedDiagnostic.visible = false
			);
		diagnosticSearch.saveConfig(mapPropsToComponent);
	}
}
Example #6
Source File: vehicle-search.js    From real-time-map with MIT License 4 votes vote down vote up
deviceSearch = {
	shown: true,
	deviceResultsCache: {},
	selectedIDS: {},

	get searchInput() {
		return document.getElementById("RTM-vehicle-search-bar");
	},

	init(mapPropsToComponent) {
		// Init rxjs debounce search.
		const searchInputObservable = fromEvent(deviceSearch.searchInput, "input").pipe(map(i => i.currentTarget.value));
		const debouncedInput = searchInputObservable.pipe(debounceTime(250));
		debouncedInput.subscribe((searchInput) => deviceSearch.buildSearchList(searchInput, mapPropsToComponent));
	},

	loadSavedDeviceConfig(mapPropsToComponent) {

		return getBlobStorage().then(val => {
			if (val.length === 0) { return; }
			const cachedDevices = JSON.parse(val[0].data);

			if (cachedDevices.configData.Vehicle) {
				deviceSearch.selectedIDS = cachedDevices.configData.Vehicle;
				deviceSearch.applyFilter();
				deviceSearch.buildDeviceDisplayList(mapPropsToComponent);
			}
		});
	},

	buildSearchList(searchInput, mapPropsToComponent) {

		const nameSearchMultiCall = [
			createDeviceByNameCall(searchInput),
			createGroupsByNameCall(searchInput)
		];

		return makeAPIMultiCall(nameSearchMultiCall).then(results => {
			// deviceList = results[0];
			results[0]
				.map(deviceSearch.saveDeviceDataToCache);
			// groupList = results[1];
			results[1]
				.map(deviceSearch.saveGroupDataToCache);
			mapPropsToComponent(Object.values(deviceSearch.deviceResultsCache));
		});

	},

	saveDeviceDataToCache(deviceData) {
		const data = {};
		["id", "name", "groups"].forEach(prop => data[prop] = deviceData[prop]);
		data.visible = true;
		deviceSearch.deviceResultsCache[data.name] = data;
		return data;
	},

	saveGroupDataToCache(deviceData) {
		const data = {};
		["id", "name", "color"].forEach(prop => data[prop] = deviceData[prop]);
		data.visible = true;
		data.name += " (Group)";

		deviceSearch.deviceResultsCache[data.name] = data;
		return data;
	},

	buildDeviceDisplayList(mapPropsToComponent) {
		deviceSearch.mapPropsToComponent = mapPropsToComponent;
		mapPropsToComponent(Object.values(deviceSearch.selectedIDS)
			.filter(device => device.id && device.name));
	},

	handleItemSelected(event, mapPropsToComponent) {
		event.preventDefault();
		deviceSearch.saveSelectedValue(mapPropsToComponent);
	},

	saveSelectedValue(mapPropsToComponent) {

		const { value } = deviceSearch.searchInput;
		if (!deviceSearch.deviceResultsCache.hasOwnProperty(value)) {
			return;
		}

		const deviceData = deviceSearch.deviceResultsCache[value];
		deviceData.visible = true;
		const {
			id,
			name,
			groups,
			color,
			visible
		} = deviceData;

		if (color) { //It's a group
			deviceSearch.selectedIDS[id] = { id, name, color, visible };
		}
		else {
			deviceSearch.selectedIDS[id] = { id, name, groups, visible };
		}

		deviceSearch.searchInput.value = "";
		deviceSearch.saveConfig(mapPropsToComponent);
		return deviceData;
	},

	deleteItemFromdeviceList(id, mapPropsToComponent) {
		delete deviceSearch.selectedIDS[id];
		deviceSearch.saveConfig(mapPropsToComponent);
	},

	deleteAllItems(mapPropsToComponent) {
		deviceSearch.selectedIDS = {};
		deviceSearch.saveConfig(mapPropsToComponent);
	},

	saveConfig(mapPropsToComponent) {
		storage.setBlobStorageObj ? setBlobStorage("Vehicle", deviceSearch.selectedIDS) : saveBlobStorage("Vehicle", deviceSearch.selectedIDS);

		deviceSearch.applyFilter();
		deviceSearch.buildDeviceDisplayList(mapPropsToComponent);
	},

	applyFilter() {
		_getDeviceList(deviceSearch.selectedIDS).then(() => {
			_applyDeviceFilter(Object.keys(storage.selectedDevices));
		});
	},
	showAll(mapPropsToComponent) {
		Object.values(deviceSearch.selectedIDS)
			.forEach(selectedDevice =>
				selectedDevice.visible = true
			);
		deviceSearch.saveConfig(mapPropsToComponent);
	},
	hideAll(mapPropsToComponent) {
		Object.values(deviceSearch.selectedIDS)
			.forEach(selectedDevice =>
				selectedDevice.visible = false
			);
		deviceSearch.saveConfig(mapPropsToComponent);
	},
	toggleDeviceVisibility(id, mapPropsToComponent) {
		const selectedDevice = deviceSearch.selectedIDS[id];
		selectedDevice.visible = !selectedDevice.visible;
		deviceSearch.saveConfig(mapPropsToComponent);
	},
	zoomIntoDevice(id) {
		const deviceMarker = markerList[id];
		if (deviceMarker) {
			const newZoomLevel = Math.max(Math.min(storage.map.getZoom() + 1, 18), 15);
			storage.map.flyTo(deviceMarker.currentlatLng, newZoomLevel);
		} else {
			alert("Sorry, no current day data for selected vehicle.");
		}
	}
}