diff --git a/index.html b/index.html index 68b320b9a..7eb96cb63 100644 --- a/index.html +++ b/index.html @@ -4,9 +4,41 @@ + Weather Report + + + + - - - \ No newline at end of file +
+

Weather for

+
+ + + +
+ +

Temperature is º F

+
+ + +
+
+ +
+

Landscape is

+ +

Sky is

+
+ +
+
+ + diff --git a/package.json b/package.json index 9cf5ca65b..1cfcba810 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "axios": "^0.27.2" + "axios": "^1.2.1" } } diff --git a/src/index.js b/src/index.js index e69de29bb..626fd743d 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,175 @@ +//application states +const state = { + sky: 'sunny', + temperature: 0, + city: '', +}; +const temperatureChangeStep = 1; + +//references to all elements on the page +const elTemperature = document.querySelector('#temperature'); +const elIncreaseTemp = document.querySelector('#increaseTemp'); +const elDecreaseTemp = document.querySelector('#decreaseTemp'); +const elLandscape = document.querySelector('#landscape'); +const elCity = document.querySelector('#city'); +const elCityInput = document.querySelector('#cityInput'); +const elCityReset = document.querySelector('#cityReset'); +const elCitySearch = document.querySelector('#citySearch'); +const elSky = document.querySelector('#sky'); +const elSkyInput = document.querySelector('#skyInput'); + +//event handlers to intercept user interactions +elSkyInput.addEventListener('change', (event) => { + setSky(event.target.value); +}); + +elCityInput.addEventListener('input', (event) => { + setCity(event.target.value); +}); + +elCityReset.addEventListener('click', (event) => { + setCity(''); + elCityInput.focus(); +}); + +elCitySearch.addEventListener('click', (event) => { + searchCityWeather(state.city); +}); + +elIncreaseTemp.addEventListener('click', (event) => { + increaseTemp(event.target.value); +}); + +elDecreaseTemp.addEventListener('click', (event) => { + decreaseTemp(event.target.value); +}); + +//functions to render state to the screen +const renderSky = () => { + const sky = state.sky; + let skyScape = 'unknown'; + + if (sky === 'sunny') skyScape = '☀️'; + else if (sky === 'cloudy') skyScape = '☁️'; + else if (sky === 'rainy') skyScape = '🌧'; + else if (sky === 'snowy') skyScape = '🌨'; + + elSky.innerText = skyScape; +}; + +const renderTemperature = () => { + elTemperature.innerText = state.temperature; + + const temp = state.temperature; + let color = 'teal'; + let landscape = '❄️❄️❄️❄️❄️'; + + if (temp >= 80) { + color = 'red'; + landscape = '🔥🔥🔥🔥🔥'; + } else if (temp >= 70) { + color = 'orange'; + landscape = '😊😊😊😊😊'; + } else if (temp >= 60) { + color = 'yellow'; + landscape = '🌷🌷🌷🌷🌷'; + } else if (temp >= 50) { + color = 'green'; + landscape = '🐿🐿🐿🐿🐿'; + } + + elTemperature.style.color = color; + elLandscape.innerText = landscape; +}; + +const renderCity = () => { + elCity.innerText = state.city; + elCityInput.value = state.city; +}; + +//setters for changing state and calling respective render functions +const setSky = (value) => { + state.sky = value; + renderSky(); +}; + +const setTemperature = (value) => { + state.temperature = value; + renderTemperature(); +}; + +const setCity = (value) => { + state.city = value; + renderCity(); +}; + +//functions to run user actions +const increaseTemp = () => { + setTemperature(state.temperature + temperatureChangeStep); +}; + +const decreaseTemp = () => { + setTemperature(state.temperature - temperatureChangeStep); +}; + +const kelvinToFarenheit = (k) => 1.8 * (k - 273) + 32; + +const searchCityWeather = (city) => { + console.log('searchCityWeather()', city); + + //disable buttons to prevent multiple requests + elCitySearch.disabled = true; + elCityReset.disabled = true; + + return fetchCityLatLong(city) + .then(fetchLatLongTemperature) + .then((temperature) => setTemperature(temperature)) + .catch(console.error) + .finally(() => { + elCitySearch.disabled = false; + elCityReset.disabled = false; + }); +}; + +//use the city to get lat/long +const fetchCityLatLong = (city) => { + console.log('fetchCityLatLong()', city); + const url = `http://127.0.0.1:5000/location?q=${city}`; + + return axios.get(url).then((response) => { + const { data } = response; + const firstResult = data[0]; + return { + lat: firstResult.lat, + lon: firstResult.lon, + }; + }); +}; + +// use lat/lon coordinates to get temperature +const fetchLatLongTemperature = (latLong) => { + const { lat, lon } = latLong; + console.log('fetchLatLongTemperature()', lat, lon); + + const url = `http://127.0.0.1:5000/weather?lat=${lat}&lon=${lon}`; + return axios.get(url).then((response) => { + const { data } = response; + const tempK = data.main.temp; + const tempF = kelvinToFarenheit(tempK); + const tempRounded = Math.round(tempF); + console.log({ tempRounded, tempK, tempF }); + + return tempRounded; + }); +}; + +//initialization - render all state first +renderCity(); +renderTemperature(); +renderSky(); + +//run initial search and show a temperature +setCity('Denver'); +searchCityWeather('Denver'); + +// setTemperature(60) diff --git a/styles/index.css b/styles/index.css index e69de29bb..d7c7b9495 100644 --- a/styles/index.css +++ b/styles/index.css @@ -0,0 +1,123 @@ + +body { + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 30px; + background-color: rgb(136, 55, 211); + font-size: 120%; + flex-direction: column; +} + +.card { + background-color: gray; + padding: 2em; + border-radius: 30px; + width: 100%; + height: 80%; + max-width: 420px; + margin: .5em; + font-family: 'Roboto Mono', monospace; + margin-top: 4em; + border: 1px solid purple; +} + +button { + border-radius: 50%; + margin: .5em 1em; + height: 56px; + width: 55px; + border: 1px solid purple; + transition: 0.2s ease-in-out; + cursor: pointer; + font-size: 12px; + font-weight: 800; +} + +button:hover { + background:rgb(214, 208, 202); +} + +#cityInput { + border: 1px solid purple; + border-radius: 24px; + background-color: rgb(214, 208, 202); + color: black; + font-size: 105%; + font-family: inherit; + padding: 0.4em 1em; + width: 180px; + height: 24px; +} + +#skyInput { + margin: 0; + width: calc(100% - 200px); + font-size: 105%; + border: 1px solid purple; + background-color: antiquewhite; + color: black; + font-family: inherit; + padding: 1.5em 1em; + float: left; + + } + +#decreaseTemp{ + font-size: 36px; + font-weight: 600; +} +#increaseTemp { + font-size: 28px; + font-weight: 600; +} + + +.landscapeSky{ + background-color: gray; + padding: 2em; + border-radius: 30px; + width: 100%; + max-width: 420px; + margin: .5em; + margin-bottom: 4em; + font-family: 'Roboto Mono', monospace; + font-size: 24px; + border: 1px solid purple; + +} + +h4 { + font-size: 30px; + font-family: 'Roboto Mono', monospace; +} + +h1 { + font-size: 48px; + font-family: 'Roboto Mono', monospace; +} + + .red { + color: red; + } + + .orange { + color: orange; + } + + .yellow { + color: gold; + } + + .yellow-green { + color: yellowgreen; + } + + .green { + color: green; + } + + .teal { + color: teal; + } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 37fbaed29..26630f422 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,13 +7,14 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -axios@^0.27.2: - version "0.27.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" - integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== +axios@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.1.tgz#44cf04a3c9f0c2252ebd85975361c026cb9f864a" + integrity sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A== dependencies: - follow-redirects "^1.14.9" + follow-redirects "^1.15.0" form-data "^4.0.0" + proxy-from-env "^1.1.0" combined-stream@^1.0.8: version "1.0.8" @@ -27,10 +28,10 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -follow-redirects@^1.14.9: - version "1.15.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.0.tgz#06441868281c86d0dda4ad8bdaead2d02dca89d4" - integrity sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ== +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== form-data@^4.0.0: version "4.0.0" @@ -52,3 +53,8 @@ mime-types@^2.1.12: integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==