-
Notifications
You must be signed in to change notification settings - Fork 221
Audrey Clark's Weather App Eval #209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
1c264c1
9aeece9
0ca9ec7
21a9457
e3ee946
20d9e31
b23eae5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| ## Weather Project | ||
| ## Weather Project using Open Weather Map's API | ||
|
|
||
| This project has been created by a student at Parsity, an online software engineering course. The work in this repository is wholly of the student based on a sample starter project that can be accessed by looking at the repository that this project forks. | ||
|
|
||
| If you have any questions about this project or the program in general, visit [parsity.io](https://parsity.io/) or email hello@parsity.io. | ||
|
|
||
|  |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <link | ||
| href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" | ||
| rel="stylesheet" | ||
| integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" | ||
| crossorigin="anonymous" | ||
| /> | ||
| <link rel="stylesheet" href="style.css" /> | ||
| <title>Weather App Eval</title> | ||
| </head> | ||
| <body> | ||
| <div class="container-fluid justify-content-center align-items-center"> | ||
| <div class="row"> | ||
| <div class="d-grid col-xxl-6 mx-auto"> | ||
| <div class="page-header text-center mt-5"> | ||
| <h1>Weather App Project</h1> | ||
| <hr /> | ||
| </div> | ||
|
|
||
| <!-- form input field and search button --> | ||
| <div id="form-group"> | ||
| <form class="search-form"> | ||
| <div class="input-group mb-4 mt-4"> | ||
| <input | ||
| type="text" | ||
| class="form-control" | ||
| id="city-input" | ||
| placeholder="Enter City Here" | ||
| /> | ||
| <button type="submit" class="btn btn-primary search"> | ||
| Get Weather | ||
| </button> | ||
| </div> | ||
| </form> | ||
| </div> | ||
|
|
||
| <hr /> | ||
|
|
||
| <!-- row for current weather --> | ||
| <div | ||
| class="current-weather row d-flex align-items-center justify-content-center" | ||
| ></div> | ||
|
|
||
| <!-- 5 day forecast container and row --> | ||
| <div class="container-fluid"> | ||
| <div class="forecast row"></div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <script src="main.js"></script> | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,170 @@ | ||
| const cityInput = document.querySelector('#city-input'); | ||
| const currentWeatherContainer = document.querySelector('.current-weather'); | ||
| const forecastContainer = document.querySelector('.forecast'); | ||
|
|
||
| // click event listener for city input and the search button | ||
| document.querySelector('.search').addEventListener('click', function(event) { | ||
| event.preventDefault(); | ||
|
|
||
| const city = cityInput.value; | ||
| if (city !== '') { | ||
| getWeather(city); | ||
|
|
||
| cityInput.value = ''; | ||
|
|
||
| } else { | ||
| alert(('Please enter a city.')); | ||
| }; | ||
| }); | ||
|
|
||
| /** | ||
| * Fetches data from the specified URL using the GET method and returns the response as JSON. | ||
| * If the response is not OK, throws an error with a message from the response or a default message. | ||
| * If an error occurs during the fetch, displays an error message and returns an empty object. | ||
| * | ||
| * @param {string} url - The URL to fetch data from. | ||
| * @return {Promise<Object>} A promise that resolves to the JSON response data. | ||
| * @throws {Error} If the response is not OK. | ||
| */ | ||
| async function fetchApiData(url){ | ||
| try { | ||
| const response = await fetch(url, { method: 'GET', dataType: 'json' }); | ||
| const data = await response.json(); | ||
|
|
||
| if (response.ok) { | ||
| return data; | ||
| } else { | ||
| throw new Error(data.message || 'Error fetching data'); | ||
| } | ||
| } | ||
| catch(error) { | ||
| alert('Not a valid city. Please try again.'); | ||
| console.error('Error fetching weather data:', error); | ||
| return {}; | ||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * Fetches weather data for a given city using the OpenWeatherMap API. | ||
| * | ||
| * @param {string} city - The name of the city to fetch weather data for. | ||
| * @return {Promise<void>} A promise that resolves when the weather data has been fetched and displayed. | ||
| * Rejects with an error if there was an issue fetching the data. | ||
| */ | ||
| async function getWeather(city) { | ||
| const apiKey = '3a16b1625fdf1f83be7f01c3a15bd5f0'; | ||
| const apiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=imperial`; | ||
|
|
||
| try { | ||
| const weatherData = await fetchApiData(apiUrl); | ||
|
|
||
| // Get coordinates for the forecast API | ||
| const { lon, lat } = weatherData.coord; | ||
| const forecastUrl = `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&appid=${apiKey}&units=imperial`; | ||
| const forecastData = await fetchApiData(forecastUrl); | ||
|
|
||
| displayCurrentWeather(weatherData); | ||
| displayForecast(processForecastData(forecastData.list)); | ||
| } | ||
| catch(error) { | ||
| console.error('Error fetching weather data:', error); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would also display the error to the user. |
||
| } | ||
| }; | ||
|
|
||
| /** | ||
| * Displays the current weather information on the page. | ||
| * | ||
| * @param {Object} data - The weather data object containing the current weather information. | ||
| * @return {void} This function does not return anything. | ||
| */ | ||
| function displayCurrentWeather(data) { | ||
| currentWeatherContainer.replaceChildren(); | ||
| forecastContainer.replaceChildren(); | ||
|
|
||
| // Destructure the necessary data | ||
| const { name: city, main: {temp}, weather: [{description, icon}] } = data; | ||
|
|
||
| // Create a template string for the current weather | ||
| const currentWeatherTemplate = ` | ||
| <div class="col-3 mt-3"> | ||
| <p class="fs-3 fw-bold">${city}</p> | ||
| <p class="fs-3 fw-bold">${Math.round(temp)}°F</p> | ||
| <p class="fs-4 fst-italic text-capitalize">${description}</p> | ||
|
Comment on lines
+90
to
+92
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. great use of concatenation |
||
| </div> | ||
| <div class="col-3"> | ||
| <img | ||
| src="https://openweathermap.org/img/wn/${icon}@2x.png" | ||
| alt="weather icon" | ||
| /> | ||
| </div> | ||
| ` | ||
| // Insert the template into the DOM | ||
| currentWeatherContainer.insertAdjacentHTML('beforeend', currentWeatherTemplate); | ||
| }; | ||
|
|
||
| /** | ||
| * Processes the forecast data to calculate the average temperature and other information for each day. | ||
| * | ||
| * @param {Array} data - An array of objects containing the forecast data. | ||
| * @return {Array} An array of objects containing the processed forecast data for the next 5 days. | ||
| */ | ||
| function processForecastData(data) { | ||
| const dailyData = {}; | ||
|
|
||
| data.forEach(item => { | ||
| const date = new Date(item.dt * 1000); | ||
| const day = date.toLocaleDateString('en-US', { weekday: 'long' }); | ||
| const temp = item.main.temp; | ||
| const icon = item.weather[0].icon; | ||
| const description = item.weather[0].description; | ||
|
|
||
| if (!dailyData[day]) { | ||
| dailyData[day] = { | ||
| temps: [], | ||
| icons: [], | ||
| descriptions: [] | ||
| }; | ||
| } | ||
|
|
||
| dailyData[day].temps.push(temp); | ||
| dailyData[day].icons.push(icon); | ||
| dailyData[day].descriptions.push(description); | ||
| }); | ||
|
|
||
| const result = []; | ||
| for (const day in dailyData) { | ||
| const temps = dailyData[day].temps; | ||
| const avgTemp = temps.reduce((sum, t) => sum + t, 0) / temps.length; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. extract to a new function for readability |
||
| const icon = dailyData[day].icons[0]; | ||
| const description = dailyData[day].descriptions[0]; | ||
|
|
||
| result.push({ | ||
| day, | ||
| avgTemp: avgTemp.toFixed(1), | ||
| icon, | ||
| description | ||
| }); | ||
| } | ||
|
|
||
| return result.slice(0, 5); // Return only the next 5 days | ||
| }; | ||
|
|
||
|
|
||
| /** | ||
| * Displays the forecast information for the next 5 days. | ||
| * @param {Object} data - The forecast data containing the list of forecast items. | ||
| * @return {void} This function does not return anything. | ||
| */ | ||
| function displayForecast(data) { | ||
| data.forEach(dayData => { | ||
| const forecastTemplate = ` | ||
| <div class="d-grid col mt-5 mb-5 bg-transparent border border-secondary shadow-sm"> | ||
| <p class="fs-5 fw-bold">${dayData.day}</p> | ||
| <img src="https://openweathermap.org/img/wn/${dayData.icon}@2x.png" alt="weather icon" /> | ||
| <p class="fs-5 fw-bold">${Math.round(dayData.avgTemp)}°F</p> | ||
| <p class="fs-5 fst-italic text-capitalize">${dayData.description}</p> | ||
| </div> | ||
| `; | ||
| forecastContainer.insertAdjacentHTML('beforeend', forecastTemplate); | ||
| }) | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| body { | ||
| width: 100%; | ||
| min-height: 100vh; | ||
| text-align: center; | ||
| background-color: #bfdfec; | ||
| } | ||
|
|
||
| @media (max-width: 576px) { | ||
|
|
||
| .page-header h1 { | ||
| font-size: 1.5rem; | ||
| } | ||
|
|
||
| .input-group { | ||
| flex-direction: column; | ||
| } | ||
|
|
||
| .input-group .form-control, | ||
| .input-group .btn { | ||
| width: 100%; | ||
| margin-bottom: 10px; | ||
| } | ||
|
|
||
| .forecast { | ||
| width: 100%; | ||
| margin-bottom: 10px; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great, this is the only error you may have? I think there can be more