From 6dcd873b6c20b15a56d175c706478ebfa4abc828 Mon Sep 17 00:00:00 2001 From: JoeCarnahan42 Date: Tue, 26 Nov 2024 15:49:47 -0600 Subject: [PATCH 1/8] Initial Commit, Blank Canvas --- index.html | 0 main.js | 0 style.css | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 index.html create mode 100644 main.js create mode 100644 style.css diff --git a/index.html b/index.html new file mode 100644 index 00000000..e69de29b diff --git a/main.js b/main.js new file mode 100644 index 00000000..e69de29b diff --git a/style.css b/style.css new file mode 100644 index 00000000..e69de29b From 166085affd7decca5622bd40d6215007f9a73851 Mon Sep 17 00:00:00 2001 From: Joe Date: Wed, 27 Nov 2024 17:14:01 -0600 Subject: [PATCH 2/8] Add starter HTML --- index.html | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/index.html b/index.html index e69de29b..fdd0cc71 100644 --- a/index.html +++ b/index.html @@ -0,0 +1,23 @@ + + + + + + + + + Weather App + + + + + From 1e1211932f67c7cd9487e3ea4ab23c5b8d147055 Mon Sep 17 00:00:00 2001 From: Joe Date: Thu, 28 Nov 2024 08:40:08 -0600 Subject: [PATCH 3/8] Add text file for openweather api key. Add to git-ignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..4dcd5a69 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +key.txt From 331fbe4cc51e472ac26e7de5760e8e4e4bbbcffc Mon Sep 17 00:00:00 2001 From: Joe Date: Thu, 28 Nov 2024 09:05:33 -0600 Subject: [PATCH 4/8] Add HTML framework/style --- index.html | 10 ++++++++++ style.css | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/index.html b/index.html index fdd0cc71..5eacc04f 100644 --- a/index.html +++ b/index.html @@ -18,6 +18,16 @@ Weather App +
+

Weather App

+
+
+
+ + +
+
+
diff --git a/style.css b/style.css index e69de29b..7ac92f99 100644 --- a/style.css +++ b/style.css @@ -0,0 +1,7 @@ +.app-header { + margin-top: 50px; +} + +hr { + border-top-width: 3px; +} From 46ed91af2df9c0b3f9a22e0b88b102000e84f2bb Mon Sep 17 00:00:00 2001 From: Joe Date: Thu, 28 Nov 2024 13:59:05 -0600 Subject: [PATCH 5/8] Add full functionality of current weather function. Add comments in main.js listing known bugs and works in progress. --- index.html | 9 +++--- main.js | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ style.css | 4 +++ 3 files changed, 98 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 5eacc04f..d498aa4e 100644 --- a/index.html +++ b/index.html @@ -23,11 +23,12 @@

Weather App


- - + +
-
-
+
+
+
diff --git a/main.js b/main.js index e69de29b..6c316d1d 100644 --- a/main.js +++ b/main.js @@ -0,0 +1,89 @@ +let fiveDayForecast = []; + +// City Submission // +document.querySelector('#submit').addEventListener('click', function () { + const cityInput = document.querySelector('#city-input'); + getLocation(cityInput.value); + cityInput.value = ''; +}); +// Gets city latitude and longitude // +function getLocation(cityInput) { + const url = `http://api.openweathermap.org/geo/1.0/direct?q=${cityInput}&limit=5&appid=c09e162aa897c3130ce9f6bfd5698b9b`; + fetch(url, { + method: 'GET', + dataType: 'json', + }) + .then(data => data.json()) + .then(data => getWeather(data, cityInput)); +}; +// Gets one day weather data // +function getWeather(data, cityInput) { + // turn cityInput into an array and always capitalize the start of words // + const dataIndex = data.findIndex(data => data.name === cityInput); + const dataLat = data[dataIndex].lat; + const dataLon = data[dataIndex].lon; + const url = `https://api.openweathermap.org/data/2.5/weather?lat=${dataLat}&lon=${dataLon}&appid=c09e162aa897c3130ce9f6bfd5698b9b&units=imperial`; + + if (dataIndex === -1) { + alert('Error: Error finding City information'); + return; + } else { + fetch(url, { + method: 'GET', + dataType: 'json' + }) + .then(singleWeatherdata => singleWeatherdata.json()) + .then(singleWeatherdata => oneDayWeather(singleWeatherdata)); + }; +}; +// Adds current day weather to currWeather array // +function oneDayWeather(singleWeatherdata) { + console.log(singleWeatherdata); + const weatherData = singleWeatherdata; + const data = { + name: weatherData.name, + temp: Math.floor(weatherData.main.temp), + condition: weatherData.weather[0].description, + imageURL: `https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@2x.png` + }; + + renderWeather(data); +}; + +function renderWeather(data) { + const currWeatherDiv = document.querySelector('#current-weather'); + currWeatherDiv.replaceChildren(); + const currWeatherInfo = document.createElement('div'); + currWeatherInfo.className = 'col-lg-4 weather-info'; + const currWeatherImage = document.createElement('div'); + currWeatherImage.className = 'col-lg-4 weather-info'; + + const infoTemplate = ` +

${data.temp}

+

${data.name}

+

${data.condition}

`; + + const imageTemplate = ``; + + currWeatherDiv.appendChild(currWeatherInfo) + currWeatherDiv.appendChild(currWeatherImage) + currWeatherInfo.insertAdjacentHTML('beforeend', infoTemplate) + currWeatherImage.insertAdjacentHTML('beforeend', imageTemplate) +} + + +// BUGS // +// 1. City name must be spelled perfectly or there is an error. Need to handle the errors without breaking the whole app. +// 2. Need to capitalize city names, even if they are not typed as such. This may not be needed if issue #1 is addressed in a way that makes this a non-issue + +// TO-DO // +// 1. Write fetch request for 5 day forecast. +// 2. Make sure to only grab the info in the middle of the array, regardless of the length. I.E : + +// today = ['afternoon', 'early evening', 'evening', 'night] +// Tomorrow = ['early morning', 'morning', 'early afternoon', 'afternoon', 'early evening', 'evening', 'night'] + +// Todays weather will add all entries in the array and return the middle most one. In this case, 'early evening', or 'evening'. +// Tomorrows weather will return 'afternoon'. + +// also, make sure each forecasted day has its own dive and is surrounded by a box to clearly identify it from the others. \ No newline at end of file diff --git a/style.css b/style.css index 7ac92f99..8dd2baff 100644 --- a/style.css +++ b/style.css @@ -5,3 +5,7 @@ hr { border-top-width: 3px; } + +.weather-info { + text-align: center; +} From 257f92b91abb7dbbf1c1f1917a527a34ca3f78c0 Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 29 Nov 2024 10:25:57 -0600 Subject: [PATCH 6/8] Change classes for bootstrap --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index d498aa4e..b1b52c75 100644 --- a/index.html +++ b/index.html @@ -28,7 +28,7 @@

Weather App


-
+
From 7b8ce994fb7993605e41c1ddd2e22c1978d7071a Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 29 Nov 2024 10:26:56 -0600 Subject: [PATCH 7/8] Complete app functionality --- main.js | 118 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 32 deletions(-) diff --git a/main.js b/main.js index 6c316d1d..45f464cc 100644 --- a/main.js +++ b/main.js @@ -1,14 +1,20 @@ let fiveDayForecast = []; +const key = 'c09e162aa897c3130ce9f6bfd5698b9b' // City Submission // document.querySelector('#submit').addEventListener('click', function () { const cityInput = document.querySelector('#city-input'); - getLocation(cityInput.value); - cityInput.value = ''; + if (!cityInput.value) { + alert('Error: You must enter a city name to seach.') + } else { + getLocation(cityInput.value); + cityInput.value = ''; + } }); + // Gets city latitude and longitude // function getLocation(cityInput) { - const url = `http://api.openweathermap.org/geo/1.0/direct?q=${cityInput}&limit=5&appid=c09e162aa897c3130ce9f6bfd5698b9b`; + const url = `http://api.openweathermap.org/geo/1.0/direct?q=${cityInput}&limit=5&appid=${key}&units=imperial`; fetch(url, { method: 'GET', dataType: 'json', @@ -16,30 +22,48 @@ function getLocation(cityInput) { .then(data => data.json()) .then(data => getWeather(data, cityInput)); }; -// Gets one day weather data // -function getWeather(data, cityInput) { - // turn cityInput into an array and always capitalize the start of words // - const dataIndex = data.findIndex(data => data.name === cityInput); + +// Gets five day forecast // +function getForecast(data, cityInput) { + const dataIndex = data.findIndex(data => data.name.toLowerCase() === cityInput.toLowerCase()); const dataLat = data[dataIndex].lat; const dataLon = data[dataIndex].lon; - const url = `https://api.openweathermap.org/data/2.5/weather?lat=${dataLat}&lon=${dataLon}&appid=c09e162aa897c3130ce9f6bfd5698b9b&units=imperial`; + const url = `http://api.openweathermap.org/data/2.5/forecast?lat=${dataLat}&lon=${dataLon}&appid=${key}&units=imperial`; + fetch(url, { + method: 'GET', + dataType: 'json' + }) + .then(forecastData => forecastData.json()) + .then(forecastData => renderForecast(forecastData)) +} +// Gets one day weather data // +function getWeather(data, cityInput) { + if (cityInput.split('.')[0].toLowerCase() == 'st') { + cityInput = 'saint ' + cityInput.split('.')[1] + } + const dataIndex = data.findIndex(data => data.name.toLowerCase() === cityInput.toLowerCase()); if (dataIndex === -1) { alert('Error: Error finding City information'); return; } else { + const dataLat = data[dataIndex].lat; + const dataLon = data[dataIndex].lon; + const url = `https://api.openweathermap.org/data/2.5/weather?lat=${dataLat}&lon=${dataLon}&appid=${key}&units=imperial`; fetch(url, { method: 'GET', dataType: 'json' }) - .then(singleWeatherdata => singleWeatherdata.json()) - .then(singleWeatherdata => oneDayWeather(singleWeatherdata)); + .then(singleWeatherData => singleWeatherData.json()) + .then(singleWeatherData => oneDayWeather(singleWeatherData)); }; + + getForecast(data, cityInput) }; + // Adds current day weather to currWeather array // -function oneDayWeather(singleWeatherdata) { - console.log(singleWeatherdata); - const weatherData = singleWeatherdata; +function oneDayWeather(singleWeatherData) { + const weatherData = singleWeatherData; const data = { name: weatherData.name, temp: Math.floor(weatherData.main.temp), @@ -47,43 +71,73 @@ function oneDayWeather(singleWeatherdata) { imageURL: `https://openweathermap.org/img/wn/${weatherData.weather[0].icon}@2x.png` }; - renderWeather(data); + renderCurrWeather(data); }; -function renderWeather(data) { +// Renders Current Weather Data to Page // +function renderCurrWeather(data) { const currWeatherDiv = document.querySelector('#current-weather'); currWeatherDiv.replaceChildren(); const currWeatherInfo = document.createElement('div'); - currWeatherInfo.className = 'col-lg-4 weather-info'; + currWeatherInfo.className = 'col-md-2 weather-info'; + currWeatherInfo.id = 'currInfo' const currWeatherImage = document.createElement('div'); - currWeatherImage.className = 'col-lg-4 weather-info'; + currWeatherImage.className = 'col-md-2 weather-info'; + const currWeatherHeading = document.createElement('h1') + currWeatherHeading.className = 'lead weather-info' + currWeatherHeading.textContent = 'Currently:' + const seperator = document.createElement('hr') const infoTemplate = `

${data.temp}

-

${data.name}

-

${data.condition}

`; +

${data.name}

`; - const imageTemplate = ``; + const imageTemplate = ` +

${data.condition}

+ `; + currWeatherDiv.appendChild(currWeatherHeading) currWeatherDiv.appendChild(currWeatherInfo) currWeatherDiv.appendChild(currWeatherImage) + currWeatherDiv.appendChild(seperator) currWeatherInfo.insertAdjacentHTML('beforeend', infoTemplate) currWeatherImage.insertAdjacentHTML('beforeend', imageTemplate) } +// Renders five day forecast // +function renderForecast(forecastData) { + const days = ['Sunday','Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] + const forecastArr = forecastData.list; -// BUGS // -// 1. City name must be spelled perfectly or there is an error. Need to handle the errors without breaking the whole app. -// 2. Need to capitalize city names, even if they are not typed as such. This may not be needed if issue #1 is addressed in a way that makes this a non-issue + const dayOne = forecastArr[0]; + const dayTwo = forecastArr[8]; + const dayThree = forecastArr[16] + const dayFour = forecastArr[24] + const dayFive = forecastArr[32] + fiveDayForecast = []; + fiveDayForecast.push(dayOne, dayTwo, dayThree, dayFour, dayFive) + const forecastDiv = document.querySelector('#five-day-forecast'); + const forecastHeading = document.createElement('h1') + forecastHeading.className = 'lead weather-info' + forecastHeading.textContent = 'Five Day Forecast:' + forecastDiv.replaceChildren(); + forecastDiv.appendChild(forecastHeading) + + fiveDayForecast.forEach(day => { + const dailyWeatherInfo = document.createElement('div'); + dailyWeatherInfo.className = 'col weather-info forecast border'; + const temp = Math.floor(day.main.temp); + const dayIndex = new Date(day.dt_txt) + const dayOfWeek = dayIndex.getDay(days) -// TO-DO // -// 1. Write fetch request for 5 day forecast. -// 2. Make sure to only grab the info in the middle of the array, regardless of the length. I.E : + const template = ` +

${temp}

+

${days[dayOfWeek]}

+

${day.weather[0].description}

+ `; -// today = ['afternoon', 'early evening', 'evening', 'night] -// Tomorrow = ['early morning', 'morning', 'early afternoon', 'afternoon', 'early evening', 'evening', 'night'] + forecastDiv.appendChild(dailyWeatherInfo); + dailyWeatherInfo.insertAdjacentHTML('beforeend', template) + }) -// Todays weather will add all entries in the array and return the middle most one. In this case, 'early evening', or 'evening'. -// Tomorrows weather will return 'afternoon'. - -// also, make sure each forecasted day has its own dive and is surrounded by a box to clearly identify it from the others. \ No newline at end of file +} \ No newline at end of file From ecd3503d03787bed34344614a9464c61ff32f7b7 Mon Sep 17 00:00:00 2001 From: Joe Date: Fri, 29 Nov 2024 10:27:19 -0600 Subject: [PATCH 8/8] Add custom styling --- style.css | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/style.css b/style.css index 8dd2baff..19f81c45 100644 --- a/style.css +++ b/style.css @@ -9,3 +9,17 @@ hr { .weather-info { text-align: center; } + +#five-day-forecast { + max-width: fit-content; + margin-left: auto; + margin-right: auto; +} + +#currDesc { + margin-bottom: 0; +} + +#currInfo { + margin-top: 15px; +}