feat(LocationSearch): add LocationSearch component for improved location input

This commit is contained in:
alexsparkes
2026-01-28 13:43:29 +00:00
parent 6e852eb252
commit 50aae0f8ec
7 changed files with 830 additions and 66 deletions

View File

@@ -13,7 +13,21 @@ import { getWeather } from './api/getWeather.js';
import './weather.scss';
const WeatherWidget = memo(() => {
const [location, setLocation] = useState(localStorage.getItem('location') || 'London');
const [location, setLocation] = useState(() => {
const stored = localStorage.getItem('location');
if (!stored) return 'London';
// Try parsing as new JSON format
try {
const parsed = JSON.parse(stored);
if (parsed && typeof parsed === 'object') {
return parsed;
}
} catch {
// Legacy string format
}
return stored;
});
const [done, setDone] = useState(false);
const [weatherData, setWeatherData] = useState({});
@@ -57,10 +71,14 @@ const WeatherWidget = memo(() => {
return <WeatherSkeleton weatherType={weatherType} />;
}
// Get display name from location (handles both object and string formats)
const locationDisplay =
typeof location === 'object' ? location.displayName || location.name : location;
if (!weatherData.weather) {
return (
<div className="weather">
<span className="loc">{location}</span>
<span className="loc">{locationDisplay}</span>
</div>
);
}
@@ -87,7 +105,7 @@ const WeatherWidget = memo(() => {
amount: `${formatNumber(weatherData.weather.feels_like)}${weatherData.temp_text}`,
})}
</span>
<span className="loc">{location}</span>
<span className="loc">{locationDisplay}</span>
</div>
)}
</div>

View File

@@ -49,7 +49,19 @@ export const getWeather = async (location) => {
}
try {
const response = await fetch(variables.constants.API_URL + `/weather?city=${location}`);
// Build URL based on location type
let url;
if (typeof location === 'object' && location.lat && location.lon) {
// New format: use coordinates (preferred)
url = `${variables.constants.API_URL}/weather?lat=${location.lat}&lon=${location.lon}`;
} else {
// Legacy format: use city name string
const cityName =
typeof location === 'object' ? location.displayName || location.name : location;
url = `${variables.constants.API_URL}/weather?city=${encodeURIComponent(cityName)}`;
}
const response = await fetch(url);
if (!response.ok) {
console.error('Weather API response not ok:', response.status, response.statusText);

View File

@@ -1,59 +1,19 @@
import { useCallback } from 'react';
import { MdAutoAwesome } from 'react-icons/md';
import { Header, Row, Content, Action, PreferencesWrapper } from 'components/Layout/Settings';
import { useLocalStorageState } from 'utils/useLocalStorageState';
import { Radio, Dropdown, Checkbox } from 'components/Form/Settings';
import { Radio, Dropdown, Checkbox, LocationSearch } from 'components/Form/Settings';
import variables from 'config/variables';
const useWeatherSettings = () => {
const [location, setLocation] = useLocalStorageState('location', '');
const [windSpeed, setWindSpeed] = useLocalStorageState('windspeed', 'true');
const showReminder = useCallback(() => {
document.querySelector('.reminder-info').style.display = 'flex';
localStorage.setItem('showReminder', true);
}, []);
const changeLocation = (e) => {
localStorage.removeItem('currentWeather');
setLocation(e.target.value);
showReminder();
};
const getAutoLocation = useCallback(() => {
setLocation(variables.getMessage('modals.main.loading'));
navigator.geolocation.getCurrentPosition(
async (position) => {
const data = await (
await fetch(
`${variables.constants.API_URL}/gps?latitude=${position.coords.latitude}&longitude=${position.coords.longitude}`,
)
).json();
setLocation(data[0].name);
showReminder();
},
(error) => {
console.error(error);
},
{
enableHighAccuracy: true,
},
);
}, [setLocation, showReminder]);
return {
location,
windSpeed: windSpeed !== 'true',
setWindSpeed,
changeLocation,
getAutoLocation,
};
};
const WeatherOptions = () => {
const { location, windSpeed, setWindSpeed, changeLocation, getAutoLocation } =
useWeatherSettings();
const { windSpeed, setWindSpeed } = useWeatherSettings();
const weatherType = localStorage.getItem('weatherType');
const WEATHER_SECTION = 'modals.main.settings.sections.weather';
@@ -81,26 +41,12 @@ const WeatherOptions = () => {
<Row>
<Content title={variables.getMessage(`${WEATHER_SECTION}.location`)} />
<Action>
<div className="text-field-container">
<div className="text-field">
<div className="text-field-header">
<label className="text-field-label">
{variables.getMessage(`${WEATHER_SECTION}.location`)}
</label>
<span className="text-field-reset" onClick={getAutoLocation}>
<MdAutoAwesome />
{variables.getMessage(`${WEATHER_SECTION}.auto`)}
</span>
</div>
<input
type="text"
className="text-field-input"
value={location}
onChange={changeLocation}
placeholder="London"
/>
</div>
</div>
<LocationSearch
label={variables.getMessage(`${WEATHER_SECTION}.location`)}
name="location"
category="weather"
placeholder="London"
/>
</Action>
</Row>
);