diff --git a/src/components/location-picker.tsx b/src/components/location-picker.tsx index f257cde..056322e 100644 --- a/src/components/location-picker.tsx +++ b/src/components/location-picker.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useRef, useState } from "react"; import classnames from "classnames"; -import { autoComplete, geoLocSearch } from "../utils/geonameSearch"; +import { autoComplete, geoLocSearch, geoNameSearch } from "../utils/geonameSearch"; import { geonamesUser, kOffsetMap, timezoneServiceURL } from "../constants"; import { useStateContext } from "../hooks/use-state"; import { IPlace, IStation, IWeatherStation, IStatus } from "../types"; @@ -55,9 +55,9 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { if (locationInputEl.current && !locationInputEl.current.contains(event.target as Node) && !locationSelectionListElRef.current?.contains(event.target as Node) && !locationDivRef.current?.contains(event.target as Node)) { setIsEditing(false); setShowSelectionList(false); - setShowMapButton(false); + setShowMapButton(locationInputEl.current.value !== ""); setState((draft) => { - draft.location = undefined; + draft.location = locationInputEl.current?.value === "" ? undefined : location; draft.zoomMap = false; }); } @@ -71,7 +71,7 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { document.removeEventListener("mousedown", handleClickOutside); }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [location]); useEffect(() => { if (locationInputEl.current?.value === "") { @@ -88,7 +88,7 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { useEffect(() => { if (location) { - setShowMapButton(true); + setShowMapButton(location !== undefined); } }, [location]); @@ -107,7 +107,6 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { if (stationList) { setActiveStations(stationList); setStationPossibilities(stationList.slice(0, 5)); - (isEditing && stationList.length > 0) && setShowSelectionList(true); } if (stationList.length > 0 && !didUserSelectStationFromMap) { setState((draft) => { @@ -123,7 +122,7 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { }); } // eslint-disable-next-line react-hooks/exhaustive-deps - },[endDate, isEditing, location, startDate, didUserSelectStationFromMap]); + },[endDate, location, startDate]); useEffect(() => { if (showStationSelectionList) { @@ -156,9 +155,10 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { } }; - const getLocationList = () => { - if (locationInputEl.current) { - autoComplete(locationInputEl.current) + const getLocationList = (newLoc?: string) => { + const locationToUse = newLoc || locationInputEl.current?.value; + if (locationToUse) { + autoComplete(locationToUse) .then ((placeList: IPlace[] | undefined) => { if (placeList) { setLocationPossibilities(placeList); @@ -168,10 +168,12 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { }; useEffect(() => { - if (isEditing) { - getLocationList(); + if (isEditing || location) { //if location changes from map selection + const newLocation = location ? location.name : ""; + setCandidateLocation(newLocation); + getLocationList(newLocation); } - }, [isEditing]); + }, [isEditing, location]); const placeNameSelected = (place: IPlace | undefined) => { setState(draft => { @@ -182,13 +184,27 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { setCandidateLocation(place?.name || ""); setShowSelectionList(false); setIsEditing(false); - setShowMapButton(true); + setShowMapButton(place?.name !== undefined || (location !== undefined && locationInputEl.current?.value !== "")); setLocationPossibilities([]); setHoveredIndex(null); setArrowedIndex(-1); }; - const handleInputKeyDown = (e: React.KeyboardEvent) => { + const handleInputKeyDown = async(e: React.KeyboardEvent) => { + if (e.key === "Enter") { + if (e.currentTarget.value === "") { + setShowMapButton(false); + setState(draft => { + draft.location = undefined; + draft.weatherStation = undefined; + }); + } else { + const locale = await geoNameSearch(e.currentTarget.value); + placeNameSelected(locale?.[0]); + } + setIsEditing(false); + locationInputEl.current?.blur(); + } else if (e.key === "ArrowDown" && locationPossibilities.length > 0) { setHoveredIndex(0); setArrowedIndex(0); @@ -234,6 +250,7 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { if (target.value !== "") { getLocationList(); setCandidateLocation(target.value); + setState(draft => {draft.location = location;}); } else { setIsEditing(false); setCandidateLocation(location?.name || ""); @@ -280,6 +297,17 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { }; // Station selection functions + const stationSelected = (station: IWeatherStation | undefined, distance: number) => { + setState(draft => { + draft.weatherStation = station; + draft.weatherStationDistance = distance; + draft.didUserSelectStationFromMap = false; + draft.zoomMap = false; + }); + setShowStationSelectionList(false); + setStationHoveredIndex(null); + setArrowedIndex(-1); + }; const handleStationSelection = (ev: React.MouseEvent) => { const target = ev.currentTarget; @@ -287,45 +315,18 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { const selectedLocIdx = parseInt(target.dataset.ix, 10); if (selectedLocIdx >= 0) { const selectedStation = stationPossibilities[selectedLocIdx].station; - stationSelected(selectedStation); - setState(draft => { - draft.didUserSelectStationFromMap = false; - draft.weatherStation = selectedStation; - draft.weatherStationDistance = stationPossibilities[selectedLocIdx].distance; - }); + stationSelected(selectedStation, stationPossibilities[selectedLocIdx].distance); } - setShowStationSelectionList(false); - setState(draft => { - draft.zoomMap = false; - }); } }; const handleStationSelectionKeyDown = (e: React.KeyboardEvent, index: number) => { if (e.key === "Enter") { const selectedStation = stationPossibilities[index].station; - stationSelected(selectedStation); - setState(draft => { - draft.weatherStation = selectedStation; - draft.weatherStationDistance = stationPossibilities[index].distance; - }); - setShowStationSelectionList(false); - setState(draft => { - draft.zoomMap = false; - }); + stationSelected(selectedStation, stationPossibilities[index].distance); } }; - const stationSelected = (station: IWeatherStation | undefined) => { - setState(draft => { - draft.weatherStation = station; - draft.didUserSelectStationFromMap = false; - }); - setShowStationSelectionList(false); - setStationHoveredIndex(null); - setArrowedIndex(-1); - }; - const handleStationHover = (index: number | null) => { setStationHoveredIndex(index); }; diff --git a/src/utils/geonameSearch.ts b/src/utils/geonameSearch.ts index 009427f..5a0467a 100644 --- a/src/utils/geonameSearch.ts +++ b/src/utils/geonameSearch.ts @@ -36,8 +36,7 @@ export const geoNameSearch = async (searchString: string, maxRows?: number): Pro } }; -export const autoComplete = async(inputEl: HTMLInputElement) => { - let thisQuery = inputEl.value; +export const autoComplete = async(thisQuery: string) => { try { let placeList = await geoNameSearch(thisQuery); placeList = placeList || [];