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..8e1d0ba9 100644
--- a/src/app/(dashboard)/app/_components/weather.tsx
+++ b/src/app/(dashboard)/app/_components/weather.tsx
@@ -40,10 +40,10 @@ 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)} for today's
+ weather.
);
};
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..39642867 100644
--- a/src/utils/getFormattedWeatherDescription.ts
+++ b/src/utils/getFormattedWeatherDescription.ts
@@ -1,48 +1,52 @@
+const weatherCodeToEnglish: Record = {
+ clearsky: "π a clear sky",
+ cloudy: "βοΈ clouds",
+ fair: "β
fair",
+ fair_day: "π€οΈ fair day",
+ 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;
+ const weatherDescription = weatherCodeToEnglish[condition];
+ return `with ${weatherDescription}`;
};