https://github.com/code-spirit-369/weather-app-shadcn-charts
A Weather application that allows users to easily view real-time weather data for various locations, featuring detailed visualizations of temperature, humidity, and precipitation using ShadCN UI charts.
https://github.com/code-spirit-369/weather-app-shadcn-charts
nextjs open-meteo reactjs recharts shadcn-ui tailwindcss typescript
Last synced: 3 months ago
JSON representation
A Weather application that allows users to easily view real-time weather data for various locations, featuring detailed visualizations of temperature, humidity, and precipitation using ShadCN UI charts.
- Host: GitHub
- URL: https://github.com/code-spirit-369/weather-app-shadcn-charts
- Owner: code-spirit-369
- Created: 2024-07-16T09:31:53.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-07-18T03:23:20.000Z (over 1 year ago)
- Last Synced: 2025-03-05T05:17:03.192Z (8 months ago)
- Topics: nextjs, open-meteo, reactjs, recharts, shadcn-ui, tailwindcss, typescript
- Language: TypeScript
- Homepage:
- Size: 250 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
## π Table of Contents
1. π€ [Introduction](#introduction)
2. βοΈ [Tech Stack](#tech-stack)
3. π [Features](#features)
4. π€Έ [Quick Start](#quick-start)
5. πΈοΈ [Snippets (Code to Copy)](#snippets)
## π¨ Tutorial
This repository contains the code corresponding to an in-depth tutorial available on our YouTube channel, Code Spirit.
- React.js
- Next.js
- Typescript
- TailwindCSS
- ShadCN
A Weather application that allows users to easily view real-time weather data for various locations, featuring detailed visualizations of temperature, humidity, and precipitation using ShadCN UI charts. The app is built using Next.js and TypeScript and integrates the openmeteo weather forecast API for accurate weather information. Additional features include a city picker for location selection and skeleton loading for a smooth user experience.
π Real-time weather data for multiple locations
π Detailed visualizations of temperature, humidity, and precipitation
π City picker for easy location selection
π Skeleton loading for a smooth user experience
Follow these steps to set up the project locally on your machine.
**Prerequisites**
Make sure you have the following installed on your machine:
- [Git](https://git-scm.com/)
- [Node.js](https://nodejs.org/en)
- [npm](https://www.npmjs.com/) (Node Package Manager)
**Cloning the Repository**
```bash
git clone https://github.com/code-spirit-369/weather-app-shadcn-charts.git
cd weather-app-shadcn-charts
```
**Installation**
Install the project dependencies using npm:
```bash
npm install
```
**Running the Project**
```bash
npm run dev
```
Open [http://localhost:3000](http://localhost:3000) in your browser to view the project.
hooks/useWeatherData.ts
```typescript
import { useEffect, useState } from "react";
import { fetchWeatherData } from "@/lib/fetchWeatherData";
export function useWeatherData(lat: string, long: string) {
const [temperatureChartData, setTemperatureChartData] = useState(null);
const [humidityChartData, setHumidityChartData] = useState(null);
const [precipitationSumChartData, setPrecipitationSumChartData] =
useState(null);
const [
precipitationProbabilityChartData,
setPrecipitationProbabilityChartData,
] = useState(null);
const [weatherCode, setWeatherCode] = useState(0);
const [currentTemp, setCurrentTemp] = useState(0);
const [currentApparentTemp, setCurrentApparentTemp] = useState(0);
const [currentHumidity, setCurrentHumidity] = useState(0);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
try {
const data = await fetchWeatherData(lat, long);
console.log(data);
const now = new Date();
// Next 6 hours
const next6Hours = data.hourly.time
.map((t) => new Date(t))
.filter(
(t: Date) =>
t > now && t <= new Date(now.getTime() + 6 * 60 * 60 * 1000)
);
// Next 24 hours
const next24Hours = data.hourly.time
.map((t) => new Date(t))
.filter(
(t: Date) =>
t > now && t <= new Date(now.getTime() + 24 * 60 * 60 * 1000)
);
// Temperature
const currentTemp = data.current.temperature2m;
const currentApparentTemp = data.current.apparentTemperature;
const weatherCode = data.current.weatherCode;
const temperatureData = data.hourly.temperature2m.slice(
0,
next24Hours.length
);
const apparentTemperatureData = data.hourly.apparentTemperature.slice(
0,
next24Hours.length
);
const temperatureChartData = next24Hours.map((t, index) => {
const temperature = temperatureData[index].toFixed(1);
const apparentTemperature = apparentTemperatureData[index].toFixed(1);
return {
date: t.toString(),
temperature: temperature,
apparent_temperature: apparentTemperature,
};
});
setCurrentTemp(currentTemp);
setWeatherCode(weatherCode);
setCurrentApparentTemp(currentApparentTemp);
setTemperatureChartData(temperatureChartData);
// Humidity
const currentHumidity = data.current.relativeHumidity2m;
const humidityData = Object.values(
data.hourly.relativeHumidity2m
).slice(0, next24Hours.length);
const humidityChartData = next24Hours.map((t, index) => {
const humidity = Math.round(humidityData[index]);
return {
date: t.toString(),
humidity: humidity,
};
});
setHumidityChartData(humidityChartData);
setCurrentHumidity(currentHumidity);
// Precipitation Probability
const precipitationData = Object.values(
data.hourly.precipitationProbability
).slice(0, next6Hours.length);
const precipitationProbabilityChartData = next6Hours.map((t, index) => {
const precipitationProbability = Math.round(precipitationData[index]);
return {
date: t.toString(),
precipitationProbability: precipitationProbability,
};
});
setPrecipitationProbabilityChartData(precipitationProbabilityChartData);
// Precipitation Sum
const precipitationSumData = Object.values(
data.hourly.precipitation
).slice(0, next24Hours.length);
const precipitationSumChartData = next24Hours.map((t, index) => {
const precipitationSum = precipitationSumData[index].toFixed(2);
return {
date: t.toString(),
precipitation: precipitationSum,
};
});
setPrecipitationSumChartData(precipitationSumChartData);
} catch (error: any) {
setError(error.message);
} finally {
setLoading(false);
}
};
fetchData();
}, [lat, long]);
return {
temperatureChartData,
humidityChartData,
precipitationSumChartData,
precipitationProbabilityChartData,
weatherCode,
currentTemp,
currentApparentTemp,
currentHumidity,
error,
loading,
};
}
```
constants/index.ts
```typescript
export const weatherCodes: {
[key: number]: {
icon: string;
label: string;
};
} = {
0: {
icon: "c01d",
label: "Clear sky",
},
1: {
icon: "c02d",
label: "Mainly clear",
},
2: {
icon: "c03d",
label: "Partly cloudy",
},
3: {
icon: "c04d",
label: "Overcast",
},
45: {
icon: "s05d",
label: "Fog",
},
48: {
icon: "s05d",
label: "Deposite rime fog",
},
51: {
icon: "d01d",
label: "Drizzle",
},
53: {
icon: "d01d",
label: "Drizzle",
},
55: {
icon: "d01d",
label: "Drizzle",
},
56: {
icon: "d01d",
label: "Freezing Drizzle",
},
57: {
icon: "d01d",
label: "Freezing Drizzle",
},
61: {
icon: "r01d",
label: "Rain",
},
63: {
icon: "r01d",
label: "Rain",
},
65: {
icon: "r01d",
label: "Rain",
},
66: {
icon: "f01d",
label: "Freezing Rain",
},
67: {
icon: "f01d",
label: "Freezing Rain",
},
71: {
icon: "s02d",
label: "Snow",
},
73: {
icon: "s02d",
label: "Snow",
},
75: {
icon: "s02d",
label: "Snow",
},
77: {
icon: "s02d",
label: "Snow Grains",
},
80: {
icon: "r02d",
label: "Rain Showers",
},
81: {
icon: "r02d",
label: "Rain Showers",
},
82: {
icon: "r02d",
label: "Rain Showers",
},
85: {
icon: "s01d",
label: "Snow Showers",
},
86: {
icon: "s01d",
label: "Snow Showers",
},
95: {
icon: "t04d",
label: "Thunderstorm",
},
96: {
icon: "t04d",
label: "Thunderstorm",
},
99: {
icon: "t04d",
label: "Thunderstorm",
},
};
export const humidityLevels = [
{
max: 20,
message:
"ποΈ The air is quite dry today with very low humidity. You might experience dry skin and irritation.",
},
{
max: 40,
message:
"π΅ The humidity level is low. It's a relatively dry day, but comfortable for most activities.",
},
{
max: 60,
message:
"π€οΈ The humidity level is moderate. The air feels comfortable and pleasant.",
},
{
max: 80,
message:
"π§οΈ The humidity level is high. It might feel a bit muggy and sticky outside.",
color: "#87CEEB",
},
{
max: 100,
message:
"π§ The air is very humid today. Expect a heavy, damp feeling, and possible discomfort due to high moisture levels.",
},
];
```
lib/fetchWeatherData.ts
```typescript
import { fetchWeatherApi } from "openmeteo";
const url = "https://api.open-meteo.com/v1/forecast";
const range = (start: number, stop: number, step: number) =>
Array.from({ length: (stop - start) / step }, (_, i) => start + i * step);
export const fetchWeatherData = async (lat: string, long: string) => {
const params = {
latitude: parseFloat(lat),
longitude: parseFloat(long),
current: [
"temperature_2m",
"relative_humidity_2m",
"apparent_temperature",
"weather_code",
],
hourly: [
"temperature_2m",
"relative_humidity_2m",
"apparent_temperature",
"precipitation_probability",
"precipitation",
],
};
const responses = await fetchWeatherApi(url, params);
const response = responses[0];
const utcOffsetSeconds = response.utcOffsetSeconds();
const timezone = response.timezone();
const timezoneAbbreviation = response.timezoneAbbreviation();
const latitude = response.latitude();
const longitude = response.longitude();
const current = response.current()!;
const hourly = response.hourly()!;
const weatherData = {
current: {
time: new Date((Number(current.time()) + utcOffsetSeconds) * 1000),
temperature2m: current.variables(0)!.value(),
relativeHumidity2m: current.variables(1)!.value(),
apparentTemperature: current.variables(2)!.value(),
weatherCode: current.variables(3)!.value(),
},
hourly: {
time: range(
Number(hourly.time()),
Number(hourly.timeEnd()),
hourly.interval()
).map((t) => new Date((t + utcOffsetSeconds) * 1000)),
temperature2m: hourly.variables(0)!.valuesArray()!,
relativeHumidity2m: hourly.variables(1)!.valuesArray()!,
apparentTemperature: hourly.variables(2)!.valuesArray()!,
precipitationProbability: hourly.variables(3)!.valuesArray()!,
precipitation: hourly.variables(4)!.valuesArray()!,
},
};
return weatherData;
};
```