-
Notifications
You must be signed in to change notification settings - Fork 12
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
Connect to Weather API #28
base: main
Are you sure you want to change the base?
Changes from 11 commits
08fa292
dac08f8
87d8e92
a18dd57
be36012
85d523f
ebb724f
accfe59
544ee29
2cbd25e
8b2d947
fa398df
dc4e844
f47a206
925f7de
7c3b35c
050e635
4a6f098
b458d4b
42f58a9
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 |
---|---|---|
@@ -0,0 +1 @@ | ||
{} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,71 @@ | ||
import "./App.scss"; | ||
import React, { useState } from "react"; | ||
import Header from "./components/Header/Header"; | ||
import Footer from "./components/Footer/Footer"; | ||
|
||
import WeatherIcon from "./components/Picture/WeatherIcon"; | ||
import CurrentWeather from "./components/CurrentWeather/CurrentWeather"; | ||
import FutureWeather from "./components/FutureForecast"; | ||
|
||
|
||
import Icon from './components/Icon/Icon'; | ||
|
||
//configs | ||
const siteTitle = process.env.REACT_APP_SITE_TITLE ?? "CYF Weather"; | ||
|
||
function App() { | ||
const [weatherData, setWeatherData] = useState([]); | ||
|
||
function getNewWeather(city) { | ||
fetch( | ||
`https://api.openweathermap.org/data/2.5/forecast?q=${city}&units=metric&appid=3b86046cce0de3be7cfa8369f4540b37` | ||
) | ||
.then((res) => res.json()) | ||
.then((data) => { | ||
setWeatherData(data); | ||
}); | ||
} | ||
|
||
return ( | ||
<div className="App"> | ||
<Header title={siteTitle} /> | ||
<Header | ||
title={siteTitle} | ||
getNewWeather={getNewWeather} | ||
weatherData={weatherData} | ||
/> | ||
|
||
<main className="c-site-main" tabIndex="0"> | ||
|
||
<section> | ||
{/* <WeatherIcon weatherId={weatherData?.weather?.[0]?.id} /> */} | ||
{weatherData?.list?.map((icon) => ( | ||
<WeatherIcon weatherId={icon.weather[0].id} /> | ||
))} | ||
|
||
{weatherData?.list?.map((current) => ( | ||
<CurrentWeather | ||
description={current.weather.description} | ||
temp={current.main.temp.toFixed()} | ||
humidity={current.main.humidity} | ||
pressure={current.main.pressure} | ||
/> | ||
))} | ||
</section> | ||
|
||
<section> | ||
{weatherData?.list?.map((future) => ( | ||
<FutureWeather | ||
time={future.dt_txt} | ||
iconId={future.weather[0].id} | ||
temp={future.main.temp.toFixed()} | ||
/> | ||
))} | ||
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. Here we do want more than one item, however:
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.
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.
Hope this makes sense! Give it a go and I'll have a look when you're ready. |
||
</section> | ||
|
||
|
||
<Icon name="clear"/> | ||
|
||
</main> | ||
|
||
<Footer /> | ||
</div> | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,61 @@ | ||
@use "theme/utilities.scss"; | ||
@use "theme/global.scss"; | ||
|
||
|
||
.App{ | ||
background-color: #8ecae6; | ||
} | ||
|
||
.c-site-header{ | ||
padding: 20px; | ||
} | ||
|
||
.heading{ | ||
background-color: #219ebc; | ||
padding: 10px; | ||
} | ||
|
||
.c-site-header__title{ | ||
color: #023047; | ||
padding: 20px; | ||
} | ||
|
||
.city{ | ||
margin: 15px; | ||
padding: 15px; | ||
} | ||
|
||
.search-btn{ | ||
background-color: #023047; | ||
color: white; | ||
margin-left: 15px; | ||
padding: 15px; | ||
} | ||
|
||
.weather-img{ | ||
margin: auto; | ||
width: 200px; | ||
height: 200px; | ||
object-fit: cover; | ||
} | ||
|
||
.description{ | ||
display: flex; | ||
justify-content: center; | ||
color: white; | ||
} | ||
|
||
.temp { | ||
display: flex; | ||
justify-content: center; | ||
margin: 20px; | ||
} | ||
|
||
.box{ | ||
display: flex; | ||
justify-content: center; | ||
} | ||
|
||
.sub-box{ | ||
padding: 30px; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import React from 'react' | ||
|
||
function CurrentWeather({ description, temp, humidity, pressure }) { | ||
return ( | ||
<> | ||
<div className="description"> | ||
<h2>{description}</h2> | ||
</div> | ||
|
||
<div className="temp"> | ||
<h3>Temperature : {temp}°C</h3> | ||
</div> | ||
|
||
<div className="box"> | ||
<div className="sub-box"> | ||
<h4>Humidity : {humidity}%</h4> | ||
</div> | ||
|
||
<div className="sub-box"> | ||
<h4>Pressure : {pressure}</h4> | ||
</div> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
export default CurrentWeather |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import React from "react"; | ||
import WeatherIcon from "./Picture/WeatherIcon"; | ||
|
||
|
||
export default function FutureWeather({ time, iconId, temp }) { | ||
|
||
const formattedTime = time.split(" ")[1].slice(0,5) | ||
|
||
return ( | ||
<div> | ||
<p>{formattedTime}</p> | ||
<WeatherIcon weatherId={iconId} /> | ||
<p>{temp}</p> | ||
</div> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,27 @@ | ||
import React from "react"; | ||
import './Header.scss' | ||
import "./Header.scss"; | ||
// import WeatherIcon from "../Picture/WeatherIcon"; | ||
import React, { useState } from "react"; | ||
|
||
const Header = ({title}) => | ||
const Header = ({ title, getNewWeather, weatherData }) => { | ||
const [city, setCity] = useState(""); | ||
|
||
return ( | ||
<header className="c-site-header"> | ||
<h1 className="c-site-header__title o-type__invisible">{title}</h1> | ||
{/* look up component */} | ||
<div className="heading"> | ||
<h1 className="c-site-header__title">{title}</h1> | ||
<input | ||
className="city" | ||
type="text" | ||
placeholder="Type in a city name" | ||
value={city} | ||
onChange={(event) => setCity(event.target.value)} | ||
/> | ||
<button className="search-btn" onClick={() => getNewWeather(city)}> | ||
FIND WEATHER | ||
</button> | ||
</div> | ||
</header> | ||
); | ||
}; | ||
|
||
|
||
export default Header; | ||
export default Header; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import React from "react"; | ||
import storm from "../../img/weather-icons/storm.svg"; | ||
import drizzle from "../../img/weather-icons/drizzle.svg"; | ||
import rain from "../../img/weather-icons/rain.svg"; | ||
import snow from "../../img/weather-icons/snow.svg"; | ||
import fog from "../../img/weather-icons/fog.svg"; | ||
import clear from "../../img/weather-icons/clear.svg"; | ||
import partlyCloudy from "../../img/weather-icons/partlycloudy.svg"; | ||
import mostlyCloudy from "../../img/weather-icons/mostlycloudy.svg"; | ||
import unknown from "../../img/weather-icons/unknown.svg" | ||
|
||
const images = { | ||
storm: { src: storm, alt: "storm" }, | ||
drizzle: { src: drizzle, alt: "drizzle" }, | ||
rain: { src: rain, alt: "rain" }, | ||
snow: { src: snow, alt: "snow" }, | ||
fog: { src: fog, alt: "fog" }, | ||
clear: { src: clear, alt: "clear" }, | ||
partlyCloudy: { src: partlyCloudy, alt: "partly cloudy" }, | ||
mostlyCloudy: { src: mostlyCloudy, alt: "mostly cloudy" }, | ||
unknown: { src: unknown, alt: "unknown" }, | ||
}; | ||
|
||
|
||
function selectImage(weatherId){ | ||
if (weatherId < 300) { | ||
return images.storm; | ||
} else if (weatherId < 499) { | ||
return images.drizzle; | ||
} else if (weatherId < 599) { | ||
return images.rain; | ||
} else if (weatherId < 699) { | ||
return images.snow; | ||
} else if (weatherId < 799) { | ||
return images.fog; | ||
} else if (weatherId === 800) { | ||
return images.clear; | ||
} else if (weatherId === 801) { | ||
return images.partlyCloudy; | ||
} else if (weatherId < 805 && weatherId > 801) { | ||
return images.mostlyCloudy; | ||
} | ||
return images.unknown; | ||
} | ||
|
||
const WeatherIcon = ({weatherId}) =>{ | ||
|
||
const image = selectImage(weatherId) | ||
|
||
return ( | ||
<div className="weather-img"> | ||
<img src={image.src} alt={image.alt} /> | ||
</div> | ||
); | ||
} | ||
|
||
export default WeatherIcon; |
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.
Let's think about this @zkhing
<CurrentWeather />
is just one item of weather. The weather at a specific time.Unlike FutureWeather which is a list of several items of weather.
So does it makes sense to
.map()
over the data here? When all we want is one item?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.
Hi Lucy, it makes sense not to use .map( ) but I couldn't fetch current weather from API for somehow.