From acf6a968bd7c5ce5cd2a2159e226f4a29d065511 Mon Sep 17 00:00:00 2001 From: eireland Date: Wed, 7 Feb 2024 17:16:50 -0800 Subject: [PATCH 1/4] Better handling of changes in location in the input, and from CODAP map --- src/components/location-picker.tsx | 33 ++++++++++++++++++++---------- src/utils/geonameSearch.ts | 3 +-- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/components/location-picker.tsx b/src/components/location-picker.tsx index f257cde..3477d8e 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"; @@ -57,7 +57,7 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { setShowSelectionList(false); setShowMapButton(false); 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 === "") { @@ -156,9 +156,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 +169,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 +185,20 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { setCandidateLocation(place?.name || ""); setShowSelectionList(false); setIsEditing(false); - setShowMapButton(true); + setShowMapButton(place?.name !== undefined); setLocationPossibilities([]); setHoveredIndex(null); setArrowedIndex(-1); }; - const handleInputKeyDown = (e: React.KeyboardEvent) => { + const handleInputKeyDown = async(e: React.KeyboardEvent) => { + if (e.key === "Enter") { + if (e.currentTarget.value) { + const locale = await geoNameSearch(e.currentTarget.value); + placeNameSelected(locale?.[0]); + } + setIsEditing(false); + } else if (e.key === "ArrowDown" && locationPossibilities.length > 0) { setHoveredIndex(0); setArrowedIndex(0); @@ -234,6 +244,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 || ""); 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 || []; From 672704049c71e9ddc5d0bf6cdaf02f8d355550d7 Mon Sep 17 00:00:00 2001 From: eireland Date: Thu, 8 Feb 2024 11:45:56 -0800 Subject: [PATCH 2/4] Consolidates station selection to one function. Experiment not using didUserSelectStationFromMap as a dependency for findNearestActiveStations --- src/components/location-picker.tsx | 46 ++++++++++-------------------- 1 file changed, 15 insertions(+), 31 deletions(-) diff --git a/src/components/location-picker.tsx b/src/components/location-picker.tsx index f257cde..da6da06 100644 --- a/src/components/location-picker.tsx +++ b/src/components/location-picker.tsx @@ -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,8 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { }); } // eslint-disable-next-line react-hooks/exhaustive-deps - },[endDate, isEditing, location, startDate, didUserSelectStationFromMap]); + },[endDate, location, startDate]); + // },[endDate, location, startDate, didUserSelectStationFromMap]); useEffect(() => { if (showStationSelectionList) { @@ -280,6 +280,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 +298,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); }; From 37fe9c41599f6c054493f5e720931993a30f9951 Mon Sep 17 00:00:00 2001 From: eireland Date: Thu, 8 Feb 2024 12:05:55 -0800 Subject: [PATCH 3/4] Removes unused code --- src/components/location-picker.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/location-picker.tsx b/src/components/location-picker.tsx index 38640a5..c4fc234 100644 --- a/src/components/location-picker.tsx +++ b/src/components/location-picker.tsx @@ -123,7 +123,6 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { } // eslint-disable-next-line react-hooks/exhaustive-deps },[endDate, location, startDate]); - // },[endDate, location, startDate, didUserSelectStationFromMap]); useEffect(() => { if (showStationSelectionList) { From 5de9c118d924e0c5d247013e9b046dc7c77126cd Mon Sep 17 00:00:00 2001 From: eireland Date: Thu, 8 Feb 2024 17:02:01 -0800 Subject: [PATCH 4/4] Fixes bug with map button not showing or showing inappropriately. Also fixes bluring location input field when user types Enter --- src/components/location-picker.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/components/location-picker.tsx b/src/components/location-picker.tsx index c4fc234..056322e 100644 --- a/src/components/location-picker.tsx +++ b/src/components/location-picker.tsx @@ -55,7 +55,7 @@ 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 = locationInputEl.current?.value === "" ? undefined : location; draft.zoomMap = false; @@ -88,7 +88,7 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { useEffect(() => { if (location) { - setShowMapButton(true); + setShowMapButton(location !== undefined); } }, [location]); @@ -184,7 +184,7 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { setCandidateLocation(place?.name || ""); setShowSelectionList(false); setIsEditing(false); - setShowMapButton(place?.name !== undefined); + setShowMapButton(place?.name !== undefined || (location !== undefined && locationInputEl.current?.value !== "")); setLocationPossibilities([]); setHoveredIndex(null); setArrowedIndex(-1); @@ -192,11 +192,18 @@ export const LocationPicker = ({setActiveStations, setStatus}: IProps) => { const handleInputKeyDown = async(e: React.KeyboardEvent) => { if (e.key === "Enter") { - if (e.currentTarget.value) { + 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);