···
12
12
try {
13
13
const { searchParams } = new URL(req.url);
14
14
const stationId = searchParams.get("stationId");
15
15
-
const daysParam = Number(searchParams.get("days") || "30");
16
16
-
const days = Number.isFinite(daysParam) && daysParam > 0 ? Math.min(Math.floor(daysParam), 3650) : 30;
15
15
+
const daysRaw = searchParams.get("days") || "30";
16
16
+
const allDays = daysRaw === "all";
17
17
+
const daysParam = Number(daysRaw);
18
18
+
const days = allDays ? null : Number.isFinite(daysParam) && daysParam > 0 ? Math.min(Math.floor(daysParam), 3650) : 30;
17
19
18
20
if (!stationId) {
19
21
return NextResponse.json({ error: "stationId parameter is required" }, { status: 400 });
···
55
57
forecast_wind_speed
56
58
FROM forecast_analysis
57
59
WHERE station_id = ${sqlLiteral(stationId)}
58
58
-
AND analysis_date >= CURRENT_DATE - INTERVAL '${days}' DAYS
60
60
+
${days === null ? "" : `AND analysis_date >= CURRENT_DATE - INTERVAL '${days}' DAYS`}
59
61
ORDER BY analysis_date DESC, forecast_date DESC, source
60
62
`;
61
63
···
124
126
125
127
const payload = {
126
128
stationId,
127
127
-
days,
129
129
+
days: days === null ? "all" : days,
128
130
dailyAnalysis: Object.values(byDate),
129
131
accuracyStats,
130
132
generated: new Date().toISOString(),
···
6
6
7
7
interface ForecastAccuracyData {
8
8
stationId: string;
9
9
-
days: number;
9
9
+
days: number | "all";
10
10
data: {
11
11
dailyComparisons: DailyComparison[];
12
12
accuracyStats: AccuracyStats;
···
50
50
const { t, i18n } = useTranslation();
51
51
const locale = i18n.language === "en" ? "en-GB" : "de-DE";
52
52
const [stationId, setStationId] = useState("");
53
53
-
const [days, setDays] = useState(30);
53
53
+
const [days, setDays] = useState<number | "all">(30);
54
54
const [data, setData] = useState<ForecastAccuracyData | null>(null);
55
55
const [loading, setLoading] = useState(true); // Start with loading true
56
56
const [error, setError] = useState<string | null>(null);
···
193
193
<div>
194
194
<label className="block text-sm font-medium mb-1">{t("analysis.daysLabel")}</label>
195
195
<select
196
196
-
value={days}
197
197
-
onChange={(e) => setDays(parseInt(e.target.value))}
196
196
+
value={String(days)}
197
197
+
onChange={(e) => setDays(e.target.value === "all" ? "all" : parseInt(e.target.value))}
198
198
className="border rounded px-3 py-2"
199
199
>
200
200
<option value={7}>{t("analysis.days7")}</option>
201
201
<option value={14}>{t("analysis.days14")}</option>
202
202
<option value={30}>{t("analysis.days30")}</option>
203
203
<option value={60}>{t("analysis.days60")}</option>
204
204
+
<option value={90}>{t("analysis.days90")}</option>
205
205
+
<option value="all">{t("analysis.daysAll")}</option>
204
206
</select>
205
207
</div>
206
208
···
194
194
"days14": "14 Tage",
195
195
"days30": "30 Tage",
196
196
"days60": "60 Tage",
197
197
+
"days90": "90 Tage",
198
198
+
"daysAll": "Alles",
197
199
"sourceGeosphere": "Geosphere 🇦🇹",
198
200
"sourceOpenweather": "OpenWeatherMap 🌍",
199
201
"sourceMeteoblue": "Meteoblue 🇨🇭",
···
193
193
"days7": "7 days",
194
194
"days14": "14 days",
195
195
"days30": "30 days",
196
196
-
"days60": "60 days"
196
196
+
"days60": "60 days",
197
197
+
"days90": "90 days",
198
198
+
"daysAll": "All"
197
199
},
198
200
"weather": {
199
201
"clear": "Clear",