import { useEffect, useState } from "react"; import { api } from "../api"; import { useConfirm } from "../confirm"; import Icon from "../components/Icon"; import { useToast } from "../toast"; import BrandingUpload from "../components/BrandingUpload"; import DangerAction from "../components/DangerAction"; import { DATE_FORMAT_KEY, useSettings } from "../settings"; import { DATE_FORMATS, formatDate } from "../units"; import { applyFavicon } from "../branding"; const EXPIRY_KEY = "expiry_warning_days"; export default function Settings() { const { reload } = useSettings(); const toast = useToast(); const [days, setDays] = useState(""); const [dateFormat, setDateFormat] = useState("de"); const [error, setError] = useState(null); const [busy, setBusy] = useState(false); async function load() { try { const settings = await api.listSettings(); setDays(settings.find((s) => s.key === EXPIRY_KEY)?.value ?? "7"); setDateFormat(settings.find((s) => s.key === DATE_FORMAT_KEY)?.value ?? "de"); } catch (err) { setError(err.message); } } useEffect(() => { load(); }, []); async function save(e) { e.preventDefault(); setError(null); setBusy(true); try { await api.setSetting(EXPIRY_KEY, String(parseInt(days, 10))); await api.setSetting(DATE_FORMAT_KEY, dateFormat); await reload(); toast("Gespeichert."); } catch (err) { setError(err.message); } finally { setBusy(false); } } // Beispiel mit einem festen Datum, damit man die Wirkung sofort sieht. const preview = formatDate("2026-12-23", dateFormat); return (

Einstellungen

Allgemeine Konfiguration der Anwendung
{error &&
{error}
}

Ablaufwarnung

Chargen, deren Mindesthaltbarkeitsdatum innerhalb dieser Frist liegt (oder bereits überschritten ist), erscheinen auf der Übersicht unter „Bald ablaufend“.

Darstellung

Beispiel: {preview}

); } /** Langlebige Tokens für externe Zugriffe (Home Assistant, Skripte). */ function ApiTokensCard() { const confirm = useConfirm(); const [tokens, setTokens] = useState([]); const [name, setName] = useState(""); const [fresh, setFresh] = useState(null); const [error, setError] = useState(null); async function load() { try { setTokens(await api.listApiTokens()); } catch (err) { setError(err.message); } } useEffect(() => { load(); }, []); async function create(e) { e.preventDefault(); setError(null); try { const created = await api.createApiToken({ name }); setFresh(created.token); setName(""); load(); } catch (err) { setError(err.message); } } async function remove(token) { const ok = await confirm({ title: `Token „${token.name}“ widerrufen?`, message: "Zugriffe mit diesem Token funktionieren sofort nicht mehr.", confirmLabel: "Widerrufen", danger: true, }); if (!ok) return; try { await api.deleteApiToken(token.id); load(); } catch (err) { setError(err.message); } } return (

API-Zugriff (z.B. Home Assistant)

{error &&
{error}
}

Mit einem Token lässt sich die Einkaufsliste dauerhaft abfragen, ohne dass eine Anmeldung abläuft. Der Token wird nur einmal angezeigt – danach ist nur noch sein Fingerabdruck gespeichert.

{fresh && (
Neuer Token – bitte jetzt kopieren:
{fresh}
)}
setName(e.target.value)} required />
Beispiel für Home Assistant
{`# configuration.yaml
rest:
  - resource: http://DEIN-SERVER:8080/api/shopping-list
    scan_interval: 900
    headers:
      Authorization: "Bearer DEIN_TOKEN"
    sensor:
      - name: "Einkaufsliste Anzahl"
        value_template: "{{ value_json | length }}"
        json_attributes_path: "$"
      - name: "Einkaufsliste"
        value_template: "{{ value_json | map(attribute='name') | join(', ') }}"`}
); } /** * Gefahrenbereich: Daten in großem Stil löschen. * * Drei Stufen, damit man nicht mehr wegwirft als nötig. Benutzer, API-Tokens, * Einstellungen und das eigene Logo bleiben in allen Stufen erhalten. */ function DangerZoneCard() { const toast = useToast(); const [zahlen, setZahlen] = useState(null); const [error, setError] = useState(null); async function load() { try { setZahlen(await api.maintenanceSummary()); } catch (err) { setError(err.message); } } useEffect(() => { load(); }, []); function run(aktion, meldung) { return async () => { setError(null); try { setZahlen(await aktion()); toast(meldung); } catch (err) { setError(err.message); } }; } if (!zahlen) return null; const n = (wert, eins, mehr) => `${wert} ${wert === 1 ? eins : mehr}`; return (

Gefahrenbereich

Diese Aktionen lassen sich nicht rückgängig machen. Lege vorher ein Backup an (Import / Export → Backup als JSON). Benutzer, API-Tokens, Einstellungen und dein Logo bleiben in allen Fällen erhalten.

{error &&
{error}
}
); }