@@ -57,6 +66,20 @@ export default function Settings() {
Chargen, deren Mindesthaltbarkeitsdatum innerhalb dieser Frist liegt (oder
bereits überschritten ist), erscheinen auf der Übersicht unter „Bald ablaufend".
+
+
+
Darstellung
+
+
+
Beispiel: {preview}
+
diff --git a/web/src/settings.jsx b/web/src/settings.jsx
new file mode 100644
index 0000000..b884c5d
--- /dev/null
+++ b/web/src/settings.jsx
@@ -0,0 +1,45 @@
+import { createContext, useCallback, useContext, useEffect, useState } from "react";
+import { api } from "./api";
+import { useAuth } from "./auth";
+import { formatDate } from "./units";
+
+export const DATE_FORMAT_KEY = "date_format";
+const DEFAULT_FORMAT = "de";
+
+const SettingsContext = createContext({
+ dateFormat: DEFAULT_FORMAT,
+ formatDate: (iso) => formatDate(iso, DEFAULT_FORMAT),
+ reload: () => {},
+});
+
+/** Lädt die anzeigerelevanten Einstellungen einmal nach dem Login. */
+export function SettingsProvider({ children }) {
+ const { user } = useAuth();
+ const [dateFormat, setDateFormat] = useState(DEFAULT_FORMAT);
+
+ const reload = useCallback(async () => {
+ try {
+ const rows = await api.listSettings();
+ const row = rows.find((r) => r.key === DATE_FORMAT_KEY);
+ setDateFormat(row?.value || DEFAULT_FORMAT);
+ } catch {
+ /* Einstellungen sind optional – Standard bleibt bestehen. */
+ }
+ }, []);
+
+ useEffect(() => {
+ if (user) reload();
+ }, [user, reload]);
+
+ const value = {
+ dateFormat,
+ formatDate: (iso) => formatDate(iso, dateFormat),
+ reload,
+ };
+
+ return {children};
+}
+
+export function useSettings() {
+ return useContext(SettingsContext);
+}
diff --git a/web/src/units.js b/web/src/units.js
index a3cbce8..b601c04 100644
--- a/web/src/units.js
+++ b/web/src/units.js
@@ -53,6 +53,34 @@ export function isExpired(dateStr) {
return d != null && d < 0;
}
+// Auswählbare Datumsformate (Einstellungen -> Darstellung).
+export const DATE_FORMATS = [
+ { value: "de", label: "23.12.2026" },
+ { value: "de-short", label: "23.12.26" },
+ { value: "long", label: "23. Dezember 2026" },
+ { value: "iso", label: "2026-12-23" },
+ { value: "us", label: "12/23/2026" },
+];
+
+// Formatiert ein ISO-Datum (YYYY-MM-DD) nach dem gewählten Format.
+export function formatDate(iso, format = "de") {
+ if (!iso) return "–";
+ const date = new Date(`${iso}T00:00:00`);
+ if (Number.isNaN(date.getTime())) return iso;
+ switch (format) {
+ case "iso":
+ return iso;
+ case "de-short":
+ return date.toLocaleDateString("de-DE", { day: "2-digit", month: "2-digit", year: "2-digit" });
+ case "long":
+ return date.toLocaleDateString("de-DE", { day: "numeric", month: "long", year: "numeric" });
+ case "us":
+ return date.toLocaleDateString("en-US");
+ default:
+ return date.toLocaleDateString("de-DE");
+ }
+}
+
// MHD lesbar als Zeitspanne: "in 3 Tagen", "in 1 Woche", "vor 2 Wochen".
// Deutsch nach "in"/"vor" steht im Dativ: 1 Tag / 3 Tagen, 1 Woche / 2 Wochen.
export function relativeExpiry(daysLeft) {