diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d4ebdd00..a138ed34 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -26,9 +26,6 @@ env:
UPSTASH_REDIS_REST_URL: ${{secrets.UPSTASH_REDIS_REST_URL}}
UPSTASH_REDIS_REST_TOKEN: ${{secrets.UPSTASH_REDIS_REST_TOKEN}}
- # Openweather
- OPENWEATHER_API_KEY: ${{secrets.OPENWEATHER_API_KEY}}
-
jobs:
main:
name: CI
diff --git a/src/app/(dashboard)/app/_components/weather.tsx b/src/app/(dashboard)/app/_components/weather.tsx
index a0a1a280..68080ed9 100644
--- a/src/app/(dashboard)/app/_components/weather.tsx
+++ b/src/app/(dashboard)/app/_components/weather.tsx
@@ -40,10 +40,9 @@ export const WeatherData: FC = () => {
return (
- You can expect a π high of {weatherData.main.temp_max.toFixed()}ΒΊ and a
- π low of {weatherData.main.temp_min.toFixed()}ΒΊ with{" "}
- {getFormattedWeatherDescription(weatherData.weather[0]?.description)}{" "}
- today.
+ You can expect a high of {weatherData.temp_max.toFixed()}ΒΊ π and a
+ low of {weatherData.temp_min.toFixed()}ΒΊ π
+ {getFormattedWeatherDescription(weatherData.summary)} today.
);
};
diff --git a/src/env.mjs b/src/env.mjs
index fe0e9517..cf284977 100644
--- a/src/env.mjs
+++ b/src/env.mjs
@@ -12,7 +12,6 @@ export const env = createEnv({
UPSTASH_REDIS_REST_URL: z.string().optional(),
UPSTASH_REDIS_REST_TOKEN: z.string().optional(),
CLERK_SECRET_KEY: z.string().min(1),
- OPENWEATHER_API_KEY: z.string().min(1),
},
client: {
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: z.string().min(1),
@@ -26,7 +25,6 @@ export const env = createEnv({
process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
UPSTASH_REDIS_REST_TOKEN: process.env.UPSTASH_REDIS_REST_TOKEN,
UPSTASH_REDIS_REST_URL: process.env.UPSTASH_REDIS_REST_URL,
- OPENWEATHER_API_KEY: process.env.OPENWEATHER_API_KEY,
},
skipValidation: !!process.env.SKIP_ENV_VALIDATION,
});
diff --git a/src/server/api/routers/weather.ts b/src/server/api/routers/weather.ts
index 4580836c..d5c5c318 100644
--- a/src/server/api/routers/weather.ts
+++ b/src/server/api/routers/weather.ts
@@ -1,19 +1,31 @@
import { TRPCError } from "@trpc/server";
import fetch from "node-fetch";
import { z } from "zod";
-
-import { env } from "@/env.mjs";
-
import { createTRPCRouter, protectedProcedure } from "../trpc";
+type RawWeatherData = {
+ properties: {
+ timeseries: {
+ data: {
+ next_12_hours: {
+ summary: {
+ symbol_code: string;
+ }
+ },
+ instant: {
+ details: {
+ air_temperature: number;
+ }
+ }
+ }
+ }[]
+ }
+}
+
type WeatherData = {
- main: {
- temp_max: number;
- temp_min: number;
- };
- weather: {
- description: string;
- }[];
+ temp_max: number;
+ temp_min: number;
+ summary: string;
};
export const weatherRouter = createTRPCRouter({
@@ -28,7 +40,12 @@ export const weatherRouter = createTRPCRouter({
const { latitude, longitude } = input;
const response = await fetch(
- `https://api.openweathermap.org/data/2.5/weather?lat=${latitude}&lon=${longitude}&appid=${env.OPENWEATHER_API_KEY}&units=metric`,
+ `https://api.met.no/weatherapi/locationforecast/2.0/compact?lat=${latitude}&lon=${longitude}`,
+ {
+ headers: {
+ "User-Agent": `noodle.run (https://github.com/noodle-run/noodle)`
+ }
+ }
);
if (!response.ok) {
@@ -38,6 +55,27 @@ export const weatherRouter = createTRPCRouter({
});
}
- return response.json() as Promise;
+ const rawWeatherData: RawWeatherData = await response.json() as RawWeatherData;
+
+ if (rawWeatherData.properties.timeseries.length < 12) {
+ throw new TRPCError({
+ code: "INTERNAL_SERVER_ERROR",
+ message: "Partial weather data"
+ })
+ }
+
+ const temperatures = [];
+
+ for (const timeseries of rawWeatherData.properties.timeseries) {
+ temperatures.push(timeseries.data.instant.details.air_temperature);
+ }
+
+ const weatherData: WeatherData = {
+ summary: rawWeatherData.properties.timeseries[0]!.data.next_12_hours.summary.symbol_code,
+ temp_max: Math.max(...temperatures),
+ temp_min: Math.min(...temperatures)
+ }
+
+ return weatherData;
}),
});
diff --git a/src/utils/getFormattedWeatherDescription.ts b/src/utils/getFormattedWeatherDescription.ts
index 2fa4cdc7..d159aaac 100644
--- a/src/utils/getFormattedWeatherDescription.ts
+++ b/src/utils/getFormattedWeatherDescription.ts
@@ -1,48 +1,50 @@
+const weatherCodeToEnglish: Record = {
+ "clearsky": "a clear sky",
+ "cloudy": "clouds",
+ "fair": "fair",
+ "fog": "fog",
+ "heavyrain": "heavy rain",
+ "heavyrainandthunder": "heavy rain and thunder",
+ "heavyrainshowers": "heavy rain showers",
+ "heavyrainshowersandthunder": "heavy rain showers and thunder",
+ "heavysleet": "heavy sleet",
+ "heavysleetandthunder": "heavy sleet and thunder",
+ "heavysleetshowers": "heavy sleet showers",
+ "heavysleetshowersandthunder": "heavy sleet showers and thunder",
+ "heavysnow": "heavy snow",
+ "heavysnowandthunder": "heavy snow and thunder",
+ "heavysnowshowers": "heavy snow showers",
+ "heavysnowshowersandthunder": "heavy snow showers and thunder",
+ "lightrain": "light rain",
+ "lightrainandthunder": "light rain and thunder",
+ "lightrainshowers": "light rain showers",
+ "lightrainshowersandthunder": "light rain showers and thunder",
+ "lightsleet": "light sleet",
+ "lightsleetandthunder": "light sleet and thunder",
+ "lightsleetshowers": "light sleet showers",
+ "lightsnow": "light snow",
+ "lightsnowandthunder": "light snow and thunder",
+ "lightsnowshowers": "light snow showers",
+ "lightssleetshowersandthunder": "light sleet showers and thunder",
+ "lightssnowshowersandthunder": "light snow showers and thunder",
+ "partlycloudy": "some clouds",
+ "rain": "rain",
+ "rainandthunder": "rain and thunder",
+ "rainshowers": "rain showers",
+ "rainshowersandthunder": "rain showers and thunder",
+ "sleet": "sleet",
+ "sleetandthunder": "sleet and thunder",
+ "sleetshowers": "sleet showers",
+ "sleetshowersandthunder": "sleet showers and thunder",
+ "snow": "snow",
+ "snowandthunder": "snow and thunder",
+ "snowshowers": "snow showers",
+ "snowshowersandthunder": "snow showers and thunder",
+};
+
export const getFormattedWeatherDescription = (
condition: string | undefined,
) => {
- if (!condition) return;
-
- const weatherToEmoji: Record = {
- "clear sky": "βοΈ",
- "few clouds": "π€οΈ",
- "scattered clouds": "β
",
- "broken clouds": "βοΈ",
- "overcast clouds": "βοΈ",
- rain: "π§οΈ",
- "light rain": "π§οΈ",
- "moderate rain": "π§οΈ",
- "heavy intensity rain": "π§οΈ",
- "very heavy rain": "π§οΈ",
- "extreme rain": "π§οΈ",
- "freezing rain": "π¨οΈ",
- "light intensity shower rain": "π¦οΈ",
- "shower rain": "π§οΈ",
- "heavy intensity shower rain": "π§οΈ",
- "ragged shower rain": "π§οΈ",
- "light snow": "βοΈ",
- snow: "βοΈ",
- "heavy snow": "βοΈ",
- sleet: "π¨οΈ",
- "shower sleet": "π¨οΈ",
- "light rain and snow": "π¨οΈ",
- "rain and snow": "π¨οΈ",
- "light shower snow": "π¨οΈ",
- "shower snow": "π¨οΈ",
- "heavy shower snow": "π¨οΈ",
- mist: "π«οΈ",
- smoke: "π«οΈ",
- haze: "π«οΈ",
- "sand/ dust whirls": "πͺοΈ",
- fog: "π«οΈ",
- sand: "π«οΈ",
- dust: "π«οΈ",
- "volcanic ash": "π«οΈ",
- squalls: "π¬οΈ",
- tornado: "πͺοΈ",
- clear: "βοΈ",
- clouds: "βοΈ",
- };
-
- return `${weatherToEmoji[condition.toLowerCase()] ?? ""} ${condition}`;
+ if (!condition || !weatherCodeToEnglish[condition]) return;
+ return `with ${weatherCodeToEnglish[condition]}`;
};