diff --git a/index.html b/index.html new file mode 100644 index 00000000..711546aa --- /dev/null +++ b/index.html @@ -0,0 +1,36 @@ + + + + + + Weather App + + + +
+

Weather Forecast

+
+
+ + + +
+
+
+

+
+
+ + + \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 00000000..77aab4f4 --- /dev/null +++ b/main.js @@ -0,0 +1,121 @@ +const app = { + apiKey: '35545a9a120d7f1193670e2f13d3c4bb', + units: 'imperial', + lang: 'en', + init: () => { + document + .getElementById('btnSearch') + .addEventListener('click', () => app.fetchWeather()); + document + .getElementById('btnLocation') + .addEventListener('click', app.getLocation); + }, + getLocation: () => { + if (navigator.geolocation) { + navigator.geolocation.getCurrentPosition( + (position) => { + const { latitude: lat, longitude: lon } = position.coords; + app.fetchWeather({ lat, lon }); + }, + (error) => { + console.error(error); + alert('Unable to get location. Please allow location access.'); + } + ); + } else { + alert('Geolocation is not supported by your browser.'); + } + }, + fetchWeather: (coords) => { + let params = coords + ? `lat=${coords.lat}&lon=${coords.lon}` + : `q=${document.getElementById('city').value.trim()}`; + + if (!params) { + alert('Please enter a city name.'); + return; + } + + const baseUrl = `https://api.openweathermap.org/data/2.5/`; + const currentUrl = `${baseUrl}weather?${params}&appid=${app.apiKey}&units=${app.units}&lang=${app.lang}`; + const forecastUrl = `${baseUrl}forecast?${params}&appid=${app.apiKey}&units=${app.units}&lang=${app.lang}`; + + Promise.all([fetch(currentUrl), fetch(forecastUrl)]) + .then((responses) => Promise.all(responses.map((resp) => resp.json()))) + .then(([current, forecast]) => { + if (current.cod !== 200) throw new Error(current.message); + if (forecast.cod !== '200') throw new Error(forecast.message); + + app.showWeather(current); + app.showForecast(forecast); + if (coords) { + document.getElementById('city').value = current.name; + } + }) + .catch((err) => { + console.error(err); + alert(`Error getting weather: ${err.message}`); + }); + }, + showWeather: (resp) => { + if (!resp || !resp.weather || !resp.weather[0]) { + alert('Invalid weather data'); + return; + } + + let currentWeather = document.querySelector('.current-weather'); + currentWeather.innerHTML = ` +
+

${resp.name} - Current Weather

+
+ ${resp.weather[0].description} +
+

${Math.round(resp.main.temp)}°F

+

${resp.weather[0].main} - ${resp.weather[0].description}

+
+
+

Feels like: ${Math.round(resp.main.feels_like)}°F

+

Humidity: ${resp.main.humidity}%

+

Wind: ${Math.round(resp.wind.speed)} mph

+
+
+
`; + }, + showForecast: (resp) => { + if (!resp || !resp.list || resp.list.length === 0) { + alert('Invalid forecast data'); + return; + } + + const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; + let dailyData = resp.list.filter((item, index) => index % 8 === 0).slice(0, 5); + + let forecast = document.querySelector('.forecast'); + forecast.innerHTML = dailyData + .map( + (day) => ` +
+
+
+
${days[new Date(day.dt * 1000).getDay()]}
+ ${day.weather[0].description} +

${Math.round(day.main.temp)}°F

+

${day.weather[0].main}

+
+
+
` + ) + .join(''); + }, + }; + + app.init(); + \ No newline at end of file