moved passed down states and setters to context

This commit is contained in:
ChrQR 2024-05-09 23:40:14 +02:00
parent 1772c0b543
commit 55b425c03a
8 changed files with 190 additions and 84 deletions

View File

@ -1,5 +1,5 @@
'use server'
import { Forecast, LocationType, coordType } from "@/types/types";
import { Forecast, HourlyForecast, LocationType, coordType } from "@/types/types";
//takes address and returns coords in obj as {lat: number, lng: number}
export async function getLocation(searchLocation: string): Promise<coordType>{
@ -26,3 +26,16 @@ export async function getForecast(geoLocation: coordType): Promise<Forecast> {
const data: Forecast = await res.json();
return data;
}
export async function getHourlyForecast(geoLocation: coordType): Promise<HourlyForecast> {
const { lat, lng } = geoLocation;
const appId = process.env.WEATHER_API;
const res = await fetch(
`https://pro.openweathermap.org/data/2.5/forecast/hourly?lat=${lat}&lon=${lng}&appid=${appId}&mode=json&`
);
if (!res.ok) {
throw new Error(`Failed to fetch the weather data`);
}
const data: HourlyForecast = await res.json();
return data;
}

View File

@ -1,3 +1,5 @@
import { coordType } from "@/types/types";
export const defaultState = {
results: [
{
@ -93,3 +95,8 @@ export const defaultForecast = {
name: "Copenhagen municipality",
cod: 200,
};
export const defaultGeoLocation: coordType = {
lat: 55.647229603577124,
lng: 12.54995987788925
}

View File

@ -1,27 +1,34 @@
'use client'
import LocationSearch from '@/components/LocationSearch';
import WeatherNow from '../components/WeatherNow'
import { useState } from 'react';
import { defaultState } from './defaultState';
import { coordType } from '@/types/types';
import { createContext, useState } from 'react';
import { defaultGeoLocation } from './defaultState';
import { LocationContextType, coordType } from '@/types/types';
import WeatherIcon from '@/components/WeatherIcon';
const defaultGeoLocation: coordType = {
lat: 55.647229603577124,
lng: 12.54995987788925
}
export const LocationContext = createContext<LocationContextType>({
geoLocation: defaultGeoLocation,
setGeoLocation: () => {} // Default function, does nothing
});
export default function Home() {
const [geoLocation, setGeoLocation] = useState({
lat: 55.647229603577124,
lng: 12.54995987788925
});
const [geoLocation, setGeoLocation] = useState<coordType>(defaultGeoLocation);
// Create an object that will be passed to the context provider
const contextValue: LocationContextType = {
geoLocation,
setGeoLocation
};
return (
<main>
<div className='block mx-auto max-w-4xl'>
<LocationSearch setGeoLocation={setGeoLocation}/>
<WeatherIcon />
<WeatherNow geoLocation={geoLocation}/>
<LocationContext.Provider value={contextValue}>
<LocationSearch />
<WeatherIcon />
<WeatherNow />
</LocationContext.Provider>
</div>
</main>
);

11
components/HourlyCard.tsx Normal file
View File

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

View File

@ -1,43 +1,47 @@
"use client";
import React, { useContext, useState } from "react";
import { getLocation } from "@/app/actions";
import { useState } from "react";
import { useFormStatus } from "react-dom";
import { LocationContext } from "@/app/page";
export default function LocationSearch(props: any) {
export default function LocationSearch() {
const [searchLocation, setSearchLocation] = useState("");
const setGeoLocation = props.setGeoLocation;
const { pending } = useFormStatus();
const { geoLocation, setGeoLocation } = useContext(LocationContext);
const [pending, setPending] = useState(false);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchLocation(e.target.value);
};
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setPending(true);
try {
const coordinates = await getLocation(searchLocation);
setGeoLocation(coordinates);
} catch (error) {
console.error("Error fetching location:", error);
}
setPending(false);
};
return (
<>
<form onSubmit={handleSubmit}>
<input
id="location"
name="locationSearch"
type="text"
placeholder="enter a location to get the weather"
value={searchLocation}
onChange={handleChange}
/>
<button type="submit" disabled={pending}>
{pending ? "Searching..." : "Search"}
</button>
<label htmlFor="location" className="hidden">
Enter location to get the weather!
</label>
</form>
</>
<form onSubmit={handleSubmit}>
<input
id="location"
name="locationSearch"
type="text"
placeholder="Enter a location to get the weather"
value={searchLocation}
onChange={handleChange}
disabled={pending}
/>
<button type="submit" disabled={pending}>
{pending ? "Searching..." : "Search"}
</button>
<label htmlFor="location" className="hidden">
Enter location to get the weather!
</label>
</form>
);
}

View File

@ -1,5 +1,6 @@
import Image from "next/image";
import sunnyColor from '../public/sunny.svg'
import { useContext } from "react";
export default function WeatherIcon() {
return(

View File

@ -3,15 +3,18 @@
import { getForecast } from "@/app/actions";
import Temperature from "./Temperature";
import { Forecast, coordType } from "@/types/types";
import { useEffect, useState } from "react";
import { useContext, useEffect, useState } from "react";
import { defaultForecast } from "@/app/defaultState";
import { LocationContext } from "@/app/page";
export default function WeatherNow(props: { geoLocation: coordType }) {
// const weather = getForecast(props.geoLocation);
export default function WeatherNow() {
const { geoLocation } = useContext(LocationContext)
const [weather, setWeather] = useState<Forecast>(defaultForecast);
useEffect(() => {
let mounted = true;
getForecast(props.geoLocation).then((data) => {
getForecast(geoLocation).then((data) => {
if (mounted) {
setWeather(data);
}
@ -19,12 +22,11 @@ export default function WeatherNow(props: { geoLocation: coordType }) {
return () => {
mounted = false;
};
}, [props.geoLocation]);
}, [geoLocation]);
return (
<>
<h1>Here is the current weather in {weather.name}</h1>
<Temperature tempInfo={weather?.main} />
<p></p>
</>
);
}

View File

@ -40,53 +40,108 @@ export interface Forecast {
cod: number;
}
export interface HourlyForecast {
cod: string;
message: number;
cnt: number;
list: Array<{
dt: number;
main: {
temp: number;
feels_like: number;
temp_min: number;
temp_max: number;
pressure: number;
sea_level: number;
grnd_level: number;
humidity: number;
temp_kf: number;
};
weather: Array<{
id: number;
main: string;
description: string;
icon: string;
}>;
clouds: {
all: number;
};
wind: {
speed: number;
deg: number;
gust: number;
};
visibility: number;
pop: number;
rain?: {
"1h": number;
};
sys: {
pod: string;
};
dt_txt: string;
}>;
city: {
id: number;
name: string;
coord: {
lat: number;
lon: number;
};
country: string;
population: number;
timezone: number;
sunrise: number;
sunset: number;
};
}
export interface LocationType {
results: {
address_components: {
long_name: string;
short_name: string;
types: string[];
}[];
formatted_address: string;
geometry: {
bounds: {
northeast: {
lat: number;
lng: number;
};
southwest: {
lat: number;
lng: number;
};
};
location: {
lat: number;
lng: number;
};
location_type: string;
viewport: {
northeast: {
lat: number;
lng: number;
};
southwest: {
lat: number;
lng: number;
};
};
};
place_id: string;
address_components: {
long_name: string;
short_name: string;
types: string[];
}[];
formatted_address: string;
geometry: {
bounds: {
northeast: {
lat: number;
lng: number;
};
southwest: {
lat: number;
lng: number;
};
};
location: {
lat: number;
lng: number;
};
location_type: string;
viewport: {
northeast: {
lat: number;
lng: number;
};
southwest: {
lat: number;
lng: number;
};
};
};
place_id: string;
types: string[];
}[];
status: string;
}
export interface coordType {
lat: number;
lng: number;
}
export type EffectCallback = () => (void | (() => void | undefined));
lat: number;
lng: number;
}
export type EffectCallback = () => void | (() => void | undefined);
export interface TempInfo {
temp: number;
@ -96,3 +151,9 @@ export interface TempInfo {
pressure: number;
humidity: number;
}
export interface LocationContextType {
geoLocation: coordType;
setGeoLocation: React.Dispatch<React.SetStateAction<coordType>>;
}