Skip to content
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

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
51 changes: 46 additions & 5 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,60 @@
import "./App.scss";
import React, { useState } from "react";
import Header from "./components/Header/Header";
import Footer from "./components/Footer/Footer";
import Icon from './components/Icon/Icon';
import WeatherIcon from "./components/Picture/WeatherIcon";
import CurrentWeather from "./components/CurrentWeather/CurrentWeather";
import FutureWeather from "./components/FutureWeather";


//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">
<Icon name="clear"/>

<section>
<WeatherIcon weatherId={weatherData?.list?.[0]?.weather?.[0]?.id} />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this WeatherIcon component not part of CurrentWeather? It displays information about the current weather so it should appear in the same component that displays the temp, pressure etc.

Move it down one level inside the CurrentWeather component

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved it down inside the CurrentWeather component.
I ended with the design like that. I know it should not be like that and this is not how I wanted. I couldn't do the exact design due to my poor CSS skill.

Thank you so much Lucy all along the way for teaching and guiding me!! I have learned a lot from you. I started final project on last Saturday therefore, I will focus on final project now. :)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good luck with it all @zkhing 😊

<CurrentWeather
description={weatherData?.list?.[0]?.weather?.[0]?.description}
temp_min={Math.floor(weatherData?.list?.[0]?.main?.temp_min)}
temp_max={Math.ceil(weatherData?.list?.[0]?.main?.temp_max)}
humidity={weatherData?.list?.[0]?.main?.humidity}
pressure={weatherData?.list?.[0]?.main?.pressure}
/>
</section>

<section>
{weatherData?.list?.splice(0, 7)?.map((future) => (
<FutureWeather
time={future.dt_txt}
iconId={future.weather[0].id}
temp={future.main.temp.toFixed()}
/>
))}
</section>

{/* <FutureWeather /> */}
</main>

<Footer />
</div>
);
Expand Down
81 changes: 81 additions & 0 deletions src/App.scss
Original file line number Diff line number Diff line change
@@ -1,2 +1,83 @@
@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;
}


// -----------future weather------

.container{
display: flex;
width: 100%;
padding: 0px 2em 0px 2em;
}

.items{
display: flex;
background-color: #023047;
justify-content: center;
align-items: center;
width: 100%;
border: 1px solid #fb8500;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you added this border to help you in your development that's fine, but don't commit it 😉

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.It's deleted now.

}

.time,.temperature{
color: white;
}
30 changes: 30 additions & 0 deletions src/components/CurrentWeather/CurrentWeather.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react'


function CurrentWeather({ description, temp_min, temp_max, humidity, pressure }) {
return (
<>
<div className="description">
<h2>{description}</h2>
</div>

<div className="temp">
<h3>
Temperature : {temp_min}° to {temp_max}°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>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to wrap each heading inside a div? What is the intention here? Could you not put the CSS class (description, temp, sub-box etc) on the heading element itself?
Remember we only want the minimum amount of markup to make a cohesive, semantic structure for our content.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I deleted some divs :) thank you

</>
);
}

export default CurrentWeather
36 changes: 36 additions & 0 deletions src/components/FutureWeather.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from "react";
import WeatherIcon from "./Picture/WeatherIcon";


function FutureWeather({ time, iconId, temp }) {
const formattedTime = time.split(" ")[1].slice(0,5)

return (
<div className="container">
<div className="items time">{formattedTime}</div>
<div className="items">
<WeatherIcon weatherId={iconId} />
</div>
<div className="items temperature">{temp}°C</div>
</div>
);
}
export default FutureWeather;


// function FutureWeather({ getNewWeather, weatherData }) {

// return (
// <div>
// {weatherData?.list?.map((future) => (
// <div>
// <p>{future?.dt_txt?.split(" ")[1].slice(0, 5)}</p>
// <WeatherIcon>{future.weather[0].id}</WeatherIcon>
// <p>{future.main.temp.toFixed()}</p>
// </div>
// ))}
// </div>
// );
// }

// export default FutureWeather;
30 changes: 23 additions & 7 deletions src/components/Header/Header.jsx
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 React, { useState } from "react";

const Header = ({title}) =>
const Header = ({ title, getNewWeather }) => {
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;
57 changes: 57 additions & 0 deletions src/components/Picture/WeatherIcon.jsx
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;
Loading