Hourlycard with temp and icon utilizing props

This commit is contained in:
ChrQR 2024-05-10 14:50:01 +02:00
parent 0a0481d63f
commit 65091eecf7
10 changed files with 150 additions and 51 deletions

View File

@ -5,8 +5,8 @@ import "./globals.css";
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Create Next App", title: "Get the weather anywhere!",
description: "Generated by create next app", description: "Get todays weather hour-by-hour or a 7 day forecast!",
}; };
export default function RootLayout({ export default function RootLayout({

View File

@ -4,7 +4,6 @@ import WeatherNow from '../components/WeatherNow'
import { createContext, useState } from 'react'; import { createContext, useState } from 'react';
import { defaultGeoLocation } from './defaultState'; import { defaultGeoLocation } from './defaultState';
import { LocationContextType, coordType } from '@/types/types'; import { LocationContextType, coordType } from '@/types/types';
import WeatherIcon from '@/components/WeatherIcon';
export const LocationContext = createContext<LocationContextType>({ export const LocationContext = createContext<LocationContextType>({
@ -22,8 +21,8 @@ export default function Home() {
}; };
return ( return (
<main> <main className='flex'>
<div className='block mx-auto max-w-4xl'> <div className='mx-auto'>
<LocationContext.Provider value={contextValue}> <LocationContext.Provider value={contextValue}>
<LocationSearch /> <LocationSearch />
<WeatherNow /> <WeatherNow />

View File

@ -1,11 +0,0 @@
import { LocationContext } from "@/app/page"
import { useContext } from "react"
export default function HourlyCard() {
const { geoLocation } = useContext(LocationContext)
return (
<h1>Hejsa</h1>
)
};

View File

@ -0,0 +1,14 @@
import { HourlyCardPropType } from "@/types/types"
import WeatherIcon from "./WeatherIcon"
import HourlyTemp from "./HourlyTemp"
export default function HourlyCard(props: HourlyCardPropType) {
const weatherCode = props.weather.weather_code[props.timeIndex]
const temperature = props.weather.apparent_temperature[props.timeIndex]
return (
<>
<WeatherIcon weatherCode={weatherCode}/>
<HourlyTemp temperature={temperature} />
</>
)
};

View File

@ -0,0 +1,7 @@
export default function HourlyTemp(props: {temperature: number;}) {
const feels = props.temperature;
return (
<p>{feels}°C</p>
)
}

View File

@ -11,8 +11,6 @@ import cloud from '../public/cloud.svg'
import moon from '../public/moon.svg' import moon from '../public/moon.svg'
import sun from '../public/sun.svg' import sun from '../public/sun.svg'
import { useContext } from "react";
import { WeatherContext } from "./WeatherNow";
@ -79,13 +77,12 @@ function getCurrentWeatherIcon(weatherCode: number) {
} }
}; };
// this component takes WeatherIconPropType as props and shows the weather icon for the hour index it is given in timeIndex prop.
export default function WeatherIcon() { export default function WeatherIcon(props: {weatherCode: number}) {
const { weather } = useContext(WeatherContext) const weatherCode = props.weatherCode
return( return (
<> <>
<Image src={getCurrentWeatherIcon(weather.current.weather_code)} alt="Weather icon"/> <Image className="h-1/3 mx-auto" src={getCurrentWeatherIcon(weatherCode)} alt="Weather icon"/>
{JSON.stringify(weather.current.weather_code)}
</> </>
) )
}; };

View File

@ -27,6 +27,7 @@ export default function LocationSearch() {
return ( return (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<input <input
className="my-4 w-full rounded h-8 px-2 box-border border-2 hover:shadow-md"
id="location" id="location"
name="locationSearch" name="locationSearch"
type="text" type="text"
@ -34,13 +35,8 @@ export default function LocationSearch() {
value={searchLocation} value={searchLocation}
onChange={handleChange} onChange={handleChange}
disabled={pending} disabled={pending}
aria-label="Enter location to query the weather"
/> />
<button type="submit" disabled={pending}>
{pending ? "Searching..." : "Search"}
</button>
<label htmlFor="location" className="hidden">
Enter location to get the weather!
</label>
</form> </form>
); );
} }

View File

@ -0,0 +1,91 @@
import Image from "next/image";
import cloudAndLightening from '../public/cloud-and-lightening.svg'
import cloudAndMoon from '../public/cloud-and-moon.svg'
import cloudAndRain from '../public/cloud-and-rain.svg'
import cloudAndSnow from '../public/cloud-and-snow.svg'
import cloudAndWind from '../public/cloud-and-wind.svg'
import cloudSnowRain from '../public/cloud-snow-rain.svg'
import cloudAndSun from '../public/cloud-and-sun.svg'
import cloudWindRain from '../public/cloud-wind-rain.svg'
import cloud from '../public/cloud.svg'
import moon from '../public/moon.svg'
import sun from '../public/sun.svg'
import { useContext } from "react";
import { WeatherContext } from "./WeatherNow";
function getCurrentWeatherIcon(weatherCode: number) {
switch (weatherCode) {
default:
return sun;
case 0: // clear sky
return sun;
case 1: // clear mainly
return cloudAndSun;
case 2: // partly cloudy
return cloud;
case 3: // overcast
return cloud;
case 45: // fog
return cloud;
case 48: // fog rime
return cloud;
case 51: // drizzle light
return cloudAndRain;
case 53: // drizzle moderate
return cloudAndRain;
case 55: // drizzle dense
return cloudAndRain;
case 56: // drizzle light freezing
return cloudSnowRain;
case 57: // drizzle dense freezing
return cloudSnowRain;
case 61: // rain slight
return cloudAndRain;
case 63: // rain moderate
return cloudAndRain;
case 65: // rain heavy
return cloudAndRain;
case 66: // rain light freezing
return cloudWindRain;
case 67: // rain dense freezing
return cloudWindRain;
case 71: // snow slight
return cloudAndSnow;
case 73: // snow moderate
return cloudAndSnow;
case 75: // snow heavy
return cloudAndSnow;
case 77: // snow grains
return cloudAndSnow;
case 80: // rain showers slight
return cloudAndRain;
case 81: // rain showers moderate
return cloudAndRain;
case 82: // rain showers violent
return cloudAndRain;
case 85: // snow showers slight
return cloudAndSnow;
case 86: // snow showers heavy
return cloudAndSnow;
case 95: // thunderstorm
return cloudAndLightening;
case 96: //thunderstorm hail slight
return cloudAndLightening;
case 99: //thunderstorm hail heavy
return cloudAndLightening;
}
};
export default function WeatherHero() {
const { weather } = useContext(WeatherContext);
const weatherCode = weather.current.weather_code;
return(
<>
<Image className="h-1/3 mx-auto" src={getCurrentWeatherIcon(weatherCode)} alt="Weather icon"/>
</>
)
};

View File

@ -2,24 +2,23 @@
import { getHourlyForecast } from "@/app/actions"; import { getHourlyForecast } from "@/app/actions";
import Temperature from "./Temperature"; import Temperature from "./Temperature";
import { HourlyForecast, WeatherContextType} from "@/types/types"; import { HourlyForecast, WeatherContextType } from "@/types/types";
import { createContext, useContext, useEffect, useState } from "react"; import { createContext, useContext, useEffect, useState } from "react";
import { defaultHourlyForecast } from "@/app/defaultState"; import { defaultHourlyForecast } from "@/app/defaultState";
import { LocationContext } from "@/app/page"; import { LocationContext } from "@/app/page";
import WeatherIcon from "./WeatherIcon"; import WeatherHero from "./WeatherHero";
export const WeatherContext = createContext<WeatherContextType>({ export const WeatherContext = createContext<WeatherContextType>({
weather: defaultHourlyForecast, weather: defaultHourlyForecast,
setWeather: () => {} // Default function, does nothing setWeather: () => {}, // Default function, does nothing
}); });
export default function WeatherNow() { export default function WeatherNow() {
const { geoLocation } = useContext(LocationContext) const { geoLocation } = useContext(LocationContext);
const [weather, setWeather] = useState<HourlyForecast>(defaultHourlyForecast); const [weather, setWeather] = useState<HourlyForecast>(defaultHourlyForecast);
const contextValue: WeatherContextType = { const contextValue: WeatherContextType = {
weather, weather,
setWeather setWeather,
}; };
useEffect(() => { useEffect(() => {
let mounted = true; let mounted = true;
@ -34,9 +33,11 @@ export default function WeatherNow() {
}, [geoLocation]); }, [geoLocation]);
return ( return (
<> <>
<h1>Here is the current weather in {geoLocation.name}</h1> <h1 className="my-4 text-2xl">
Here is the current weather in {geoLocation.name}
</h1>
<WeatherContext.Provider value={contextValue}> <WeatherContext.Provider value={contextValue}>
<WeatherIcon /> <WeatherHero />
<Temperature /> <Temperature />
</WeatherContext.Provider> </WeatherContext.Provider>
</> </>

View File

@ -99,7 +99,7 @@ interface HourlyUnits {
is_day: string; is_day: string;
} }
interface HourlyWeather { export interface HourlyWeather {
time: string[]; time: string[];
temperature_2m: number[]; temperature_2m: number[];
apparent_temperature: number[]; apparent_temperature: number[];
@ -213,3 +213,8 @@ export interface WeatherContextType {
weather: HourlyForecast; weather: HourlyForecast;
setWeather: React.Dispatch<React.SetStateAction<HourlyForecast>>; setWeather: React.Dispatch<React.SetStateAction<HourlyForecast>>;
} }
export interface HourlyCardPropType {
weather: HourlyWeather;
timeIndex: number;
}