-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bring over front end from weather repo for separation of concerns and…
… easier deployment
- Loading branch information
0 parents
commit b11cafc
Showing
51 changed files
with
941 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
<title>Wilsons Weather</title> | ||
<link rel="stylesheet" href="styles.css"> | ||
<link href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap" rel="stylesheet"> | ||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"> | ||
<script type="module" src="scripts/script.js" defer></script> | ||
</head> | ||
<body> | ||
<div class="grid-main"> | ||
<!-- Navbar --> | ||
<div class="navbar glass-effect"></div> | ||
<div class="navbar-content"> | ||
<div class="logo"> | ||
<img src="public/weather-day/partly-sunny-day.png" alt=""> | ||
<h1 class="title-text">Wilson's Weather</h1> | ||
</div> | ||
<form id="search-form"> | ||
<input type="text" id="location-search" placeholder="Search location"> | ||
</form> | ||
</div> | ||
<!-- Current Weather --> | ||
<div class="current glass-effect"> | ||
<div class="current-header header"> | ||
Current Weather | ||
<div id="currentTime"></div> | ||
</div> | ||
<div class="current-body"> | ||
<!-- Current weather goes here --> | ||
</div> | ||
</div> | ||
<!-- Hourly Weather --> | ||
<div class="hourly glass-effect"> | ||
<div class="blur-effect"> | ||
<div class="header"> | ||
Hourly Forecast | ||
<div id="currentDate"></div> | ||
</div> | ||
<div class="hourly-body"> | ||
<!-- Hourly forecast goes here --> | ||
</div> | ||
</div> | ||
</div> | ||
<!-- Weekly Forecast --> | ||
<div class="weekly glass-effect"> | ||
<div class="header"> | ||
Weekly Forecast | ||
<div id="currentWeek"></div> | ||
</div> | ||
<div class="weekly-body body-text"> | ||
<!-- Weekly forecast goes here --> | ||
</div> | ||
</div> | ||
</div> | ||
<script src="/client/scripts/mobile.js"></script> | ||
</body> | ||
</html> |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export async function getIp() { | ||
return await fetch('https://api.ipify.org?format=json') | ||
.then(response => response.json()) | ||
.then(data => console.log(data.ip)) | ||
.catch(error => console.log('Unable to get IP address', error)); | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import { updateWeather } from './weather.js'; | ||
import { getIp } from './getIp.js'; | ||
import { updateTime } from './timeDate.js'; | ||
import { updateCurrent } from './updateCurrent.js'; | ||
|
||
// This is unsecure fix at some point!!! | ||
const API_BASE_URL = 'https://weather-app-server-d5459d7e5648.herokuapp.com' | ||
|
||
async function startWeather(latitude, longitude) { | ||
const response = await fetch(`${API_BASE_URL}/?coords=${latitude},${longitude}`); | ||
const weatherData = await response.json() | ||
console.log(weatherData); | ||
return weatherData; | ||
} | ||
|
||
// Create get ip function | ||
async function getIP() { | ||
return await fetch(`${API_BASE_URL}/get-ip`); | ||
} | ||
|
||
async function ipWeather(ip) { | ||
const response = await fetch(`${API_BASE_URL}/ip-weather-data?ip=${ip}`); | ||
const weatherData = await response.json(); | ||
return weatherData; | ||
} | ||
|
||
// Ask for location, if not get ip | ||
if (navigator.geolocation) { | ||
navigator.geolocation.getCurrentPosition( | ||
async function(position) { | ||
const latitude = position.coords.latitude; | ||
const longitude = position.coords.longitude; | ||
const weatherData = await startWeather(latitude, longitude); | ||
updateWeather(weatherData, 'Your Location'); | ||
updateTime(weatherData); | ||
}, | ||
async function(error) { | ||
// This function is called when an error occurs, such as when the user denies the location permission | ||
console.log("Geolocation permission denied."); | ||
try { | ||
const ip = await getIp(); | ||
const weatherData = await ipWeather(ip); | ||
updateWeather(weatherData, 'Your Location'); | ||
updateTime(weatherData); | ||
} catch (error) { | ||
console.error('Error:', error); | ||
} | ||
} | ||
); | ||
} else { | ||
console.log("Geolocation is not supported by this browser."); | ||
(async () => { | ||
try { | ||
const ip = await getIp(); | ||
const weatherData = await ipWeather(ip); | ||
updateWeather(weatherData, 'Your Location'); | ||
updateTime(weatherData); | ||
} catch (error) { | ||
console.error('Error:', error); | ||
} | ||
})(); | ||
} | ||
|
||
// Get the form | ||
const searchForm = document.getElementById('search-form'); | ||
|
||
// Get the search bar | ||
const searchBar = document.getElementById('location-search'); | ||
|
||
// Create a dropdown for suggestions | ||
const dropdown = document.createElement('div'); | ||
dropdown.setAttribute('id', 'dropdown'); | ||
searchBar.parentNode.appendChild(dropdown); | ||
|
||
// Stop user from enter invalid address in search bar | ||
searchBar.addEventListener('keydown', function(event) { | ||
if (event.key === 'Enter') { | ||
event.preventDefault(); | ||
} | ||
}); | ||
|
||
// Add event listener | ||
searchBar.addEventListener('input', async function(event) { | ||
const userInput = event.target.value; | ||
|
||
if (userInput.length > 2) { // Trigger autocomplete after 2 char | ||
try { | ||
const response = await fetch(`${API_BASE_URL}/search-locations?input=${encodeURIComponent(userInput)}`); | ||
const data = await response.json(); | ||
dropdown.innerHTML = ''; // Clear previous suggestions | ||
|
||
data.predictions.forEach(item => { | ||
const div = document.createElement('div'); | ||
div.innerHTML = item.description; | ||
div.onclick = function() { | ||
searchBar.value = item.description; | ||
dropdown.innerHTML = ''; // Clear suggestions after selection | ||
|
||
// Trigger form submission event manually | ||
const event = new Event('submit'); | ||
searchForm.dispatchEvent(event); | ||
}; | ||
dropdown.appendChild(div); | ||
}); | ||
} catch (error) { | ||
console.error('Error:', error); | ||
} | ||
} | ||
}); | ||
|
||
searchForm.addEventListener('submit', async function(event) { | ||
event.preventDefault(); | ||
// Get the user input from the search bar | ||
const userSubmission = searchBar.value; | ||
console.log('Form was submitted') | ||
try { | ||
// Clear the search bar | ||
searchBar.value = ''; | ||
|
||
// Send a request to the server with the user input | ||
const response = await fetch(`${API_BASE_URL}/weather-data?input=${encodeURIComponent(userSubmission)}`); | ||
const weatherData = await response.json(); | ||
|
||
// Handle the response data here | ||
updateWeather(weatherData, userSubmission); | ||
updateTime(weatherData); | ||
} catch (error) { | ||
console.error('Error:', error); | ||
} | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
export function updateTime(weatherData) { | ||
// Extract timezone and timestamp from weatherData | ||
const timezone = weatherData.timezone; | ||
const time = weatherData.current.dt; | ||
|
||
// Get first day of the week | ||
const firstDay = weatherData.daily[0].dt; | ||
const lastDay = weatherData.daily[weatherData.daily.length - 1].dt; | ||
|
||
const weekDateOptions = { | ||
month: 'numeric', | ||
day: 'numeric', | ||
timeZone: timezone, | ||
} | ||
|
||
const firstDayDate = new Date(firstDay * 1000).toLocaleDateString('en-US', weekDateOptions); | ||
const lastDayDate = new Date(lastDay * 1000).toLocaleDateString('en-US', weekDateOptions); | ||
|
||
// Convert Unix timestamp to Date object | ||
const currentDateTime = new Date(time * 1000); | ||
|
||
|
||
// Date formatting options | ||
const dateOptions = { | ||
weekday: 'long', | ||
month: 'long', | ||
day: 'numeric', | ||
timeZone: timezone // Set the timezone for formatting | ||
}; | ||
// Format date | ||
const formattedDate = currentDateTime.toLocaleDateString('en-US', dateOptions); | ||
|
||
// Time formatting options | ||
const timeOptions = { | ||
hour: 'numeric', | ||
minute: '2-digit', | ||
timeZone: timezone // Set the timezone for formatting | ||
}; | ||
// Format time | ||
const formattedTime = currentDateTime.toLocaleTimeString('en-US', timeOptions); | ||
|
||
// Example: Update date and time in HTML | ||
document.getElementById('currentTime').textContent = formattedTime; | ||
document.getElementById('currentDate').textContent = formattedDate; | ||
document.getElementById('currentWeek').textContent = `${firstDayDate} - ${lastDayDate}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
export function kelvinToFahrenheit(kelvin) { | ||
const fahrenheit = Math.round((kelvin - 273.15) * 9/5 + 32); | ||
return fahrenheit; | ||
} | ||
|
||
export function kelvinToCelsius(kelvin) { | ||
const celsius = Math.round(kelvin - 273.15); | ||
return celsius; | ||
} | ||
|
||
export function capitalizeFirstLetterOfEachWord(str) { | ||
// Split the string into words | ||
const words = str.split(' '); | ||
|
||
// Capitalize the first letter of each word | ||
const capitalizedWords = words.map(word => { | ||
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); | ||
}); | ||
|
||
// Join the words back into a single string | ||
const capitalizedStr = capitalizedWords.join(' '); | ||
|
||
return capitalizedStr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { kelvinToFahrenheit, kelvinToCelsius, capitalizeFirstLetterOfEachWord } from './unitConversions.js'; | ||
|
||
export function updateCurrent(weatherData, weatherCodeToImageMap, userInput) { | ||
const current = weatherData.current; | ||
const temperature = kelvinToFahrenheit(current.temp); | ||
const description = capitalizeFirstLetterOfEachWord(current.weather[0].description); | ||
const time = current.dt; | ||
const sunrise = current.sunrise; | ||
const sunset = current.sunset; | ||
const id = current.weather[0].id; | ||
let image = weatherCodeToImageMap[id]; | ||
if (typeof image !== 'string' && time > sunrise && time < sunset) { | ||
image = image[0]; | ||
} else { | ||
image = image[1]; | ||
} | ||
const location = userInput.split(','); | ||
|
||
// Get the town from userInput | ||
// There's two possible scenarios for the userInput | ||
// 1. A string from a verified google address | ||
// 2. Your location | ||
// For your location set userInput to false | ||
let currentHTML = ` | ||
<div class="current-left body-text"> | ||
<div class="current-place">${location[0]}</div> | ||
<div class="current-temp">${temperature}°</div> | ||
<div class="current-description">${description}</div> | ||
</div> | ||
`; | ||
|
||
const currentForecastDiv = document.querySelector('.current-body'); | ||
currentForecastDiv.innerHTML = currentHTML | ||
} |
Oops, something went wrong.