From bb20461cc2dd6095e96d81c6d69b7656253b30b4 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 3 Mar 2026 20:24:44 +0100 Subject: [PATCH] Kalender-Warnschwelle konfigurierbar + Saison-Datepicker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - kalender_warnung_prozent Setting: Admin kann Grün→Orange-Schwelle einstellen - Verfügbarkeits-API liefert Warnschwelle mit, BookingCalendar nutzt dynamischen Wert - Saison-Start/Ende als Date-Picker statt Textfeld im Admin-Dashboard Co-Authored-By: Claude Opus 4.6 --- src/app/admin/dashboard/page.tsx | 39 +++++++++++++----------- src/app/api/pool/verfuegbarkeit/route.ts | 18 +++++++---- src/components/BookingCalendar.tsx | 6 +++- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/app/admin/dashboard/page.tsx b/src/app/admin/dashboard/page.tsx index 4fdc4ff..c806cd5 100644 --- a/src/app/admin/dashboard/page.tsx +++ b/src/app/admin/dashboard/page.tsx @@ -564,25 +564,28 @@ export default function AdminDashboardPage() {

Einstellungen

- {settings.map((s) => ( -
-
-
{s.beschreibung || s.key}
-
{s.key}
+ {settings.map((s) => { + const isDate = s.key === 'saison_start' || s.key === 'saison_ende'; + return ( +
+
+
{s.beschreibung || s.key}
+
{s.key}
+
+ { + if (e.target.value !== s.value) { + updateSetting(s.key, e.target.value); + } + }} + className="border border-border rounded-xl px-3 py-2.5 text-sm w-48 text-right" + aria-label={s.beschreibung || s.key} + />
- { - if (e.target.value !== s.value) { - updateSetting(s.key, e.target.value); - } - }} - className="border border-border rounded-xl px-3 py-2.5 text-sm w-48 text-right" - aria-label={s.beschreibung || s.key} - /> -
- ))} + ); + })}

Änderungen werden beim Verlassen des Feldes gespeichert. diff --git a/src/app/api/pool/verfuegbarkeit/route.ts b/src/app/api/pool/verfuegbarkeit/route.ts index 0cc5b93..e19ae4b 100644 --- a/src/app/api/pool/verfuegbarkeit/route.ts +++ b/src/app/api/pool/verfuegbarkeit/route.ts @@ -37,18 +37,24 @@ export async function GET(request: NextRequest) { summe_m3: info.summe_m3, })); - // Max m³ pro Tag laden - const { data: setting } = await supabase + // Settings laden (max_m3_per_day + kalender_warnung_prozent) + const { data: settingsData } = await supabase .from('settings') - .select('value') - .eq('key', 'max_m3_per_day') - .single(); + .select('key, value') + .in('key', ['max_m3_per_day', 'kalender_warnung_prozent']); - const maxM3PerDay = setting ? parseInt(setting.value) : 150; + const settingsMap: Record = {}; + settingsData?.forEach((s: { key: string; value: string }) => { + settingsMap[s.key] = s.value; + }); + + const maxM3PerDay = settingsMap['max_m3_per_day'] ? parseInt(settingsMap['max_m3_per_day']) : 150; + const kalenderWarnungProzent = settingsMap['kalender_warnung_prozent'] ? parseInt(settingsMap['kalender_warnung_prozent']) : 30; return NextResponse.json({ verfuegbarkeit, max_m3_per_day: maxM3PerDay, + kalender_warnung_prozent: kalenderWarnungProzent, }); } catch (err) { console.error('Verfügbarkeit Error:', err); diff --git a/src/components/BookingCalendar.tsx b/src/components/BookingCalendar.tsx index f0b6c19..7fb30a2 100644 --- a/src/components/BookingCalendar.tsx +++ b/src/components/BookingCalendar.tsx @@ -37,6 +37,7 @@ export default function BookingCalendar({ onDateSelect, selectedDate, requestedM const [viewYear] = useState(currentYear); const [auslastungM3, setAuslastungM3] = useState>({}); const [maxM3PerDay, setMaxM3PerDay] = useState(150); + const [warnungProzent, setWarnungProzent] = useState(30); const [loading, setLoading] = useState(true); const isBrunnen = wasserquelle === 'brunnen'; @@ -55,6 +56,9 @@ export default function BookingCalendar({ onDateSelect, selectedDate, requestedM if (data.max_m3_per_day) { setMaxM3PerDay(data.max_m3_per_day); } + if (data.kalender_warnung_prozent != null) { + setWarnungProzent(data.kalender_warnung_prozent); + } } catch { // silent } finally { @@ -97,7 +101,7 @@ export default function BookingCalendar({ onDateSelect, selectedDate, requestedM const freeM3 = maxM3PerDay - usedM3; if (requestedM3 && freeM3 < requestedM3) return 'full'; - if (freeM3 <= maxM3PerDay * 0.3) return 'partial'; + if (freeM3 <= maxM3PerDay * (warnungProzent / 100)) return 'partial'; return 'available'; }