Drei Sachen, die beim Benutzen aufgefallen sind. ANGEBOTENE WAEHRUNGEN. In den Einstellungen steht jetzt, welche Waehrungen in den Auswahlfeldern erscheinen (Vorgabe EUR, CHF, USD). Dass dreissig unterstuetzt werden, ist gut; dreissig Zeilen in einem Feld zu sehen, wenn man drei davon braucht, ist es nicht. Die Einstellung beschraenkt nur die ANZEIGE. Gueltig bleibt alles mit EZB-Kurs, und die gerade gesetzte Waehrung steht IMMER im Feld – sonst stuende ein Konto in Dollar vor einem Feld ohne Dollar und wechselte beim naechsten Speichern stillschweigend die Waehrung. Der Saldo waere danach still falsch. Die Hauptwaehrung laesst sich nicht abwaehlen. ZEICHEN STATT KUERZEL, wo es hilft: "€ EUR", "$ USD", "£ GBP". CHF steht bewusst ohne: "Fr." ist weniger gelaeufig als CHF selbst. Mehrfach belegte Zeichen bleiben ebenfalls draussen – "US$" von "CA$" zu unterscheiden ist Raetselraten. AUF DEM TELEFON. Die Vertragszeile quetschte vier Spalten in 375 Pixel; vom Namen blieb "Sal..." uebrig und von der Kategorie ein Punkt. Sie ist jetzt ein Gitter: Unter 620 Pixel rutscht der Betrag unter den Namen, die Knoepfe bleiben rechts. Der Name bekommt die volle Breite – auf dem Telefon ist er das Einzige, woran man die Zeile erkennt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
82 lines
2.4 KiB
React
82 lines
2.4 KiB
React
import { createContext, useCallback, useContext, useEffect, useState } from "react";
|
||
import i18n from "./i18n";
|
||
import { api } from "./api";
|
||
import { useAuth } from "./auth";
|
||
import { applyTheme } from "./theme";
|
||
import { formatMoney as fmtMoney, formatDate as fmtDate } from "./format";
|
||
import { ausEinstellung, STANDARD_AKTIV } from "./waehrungen";
|
||
|
||
const DEFAULTS = {
|
||
base_currency: "EUR",
|
||
locale: "de",
|
||
theme: "system",
|
||
date_format: "de",
|
||
budget_start_day: "1",
|
||
// Welche Währungen in Auswahlfeldern erscheinen. Der Rest bleibt erlaubt,
|
||
// steht aber nicht im Weg: Dreissig Zeilen sind kein Gewinn, wenn man drei
|
||
// davon braucht.
|
||
active_currencies: STANDARD_AKTIV.join(","),
|
||
};
|
||
|
||
const SettingsContext = createContext({
|
||
...DEFAULTS,
|
||
formatMoney: (cents, currency) => fmtMoney(cents, currency),
|
||
formatDate: (iso) => fmtDate(iso, "de"),
|
||
update: async () => {},
|
||
reload: async () => {},
|
||
});
|
||
|
||
export function SettingsProvider({ children }) {
|
||
const { user } = useAuth();
|
||
const [values, setValues] = useState(DEFAULTS);
|
||
|
||
// Sprache und Thema anwenden, sobald sich die Werte ändern.
|
||
useEffect(() => {
|
||
if (i18n.language !== values.locale) i18n.changeLanguage(values.locale);
|
||
}, [values.locale]);
|
||
|
||
useEffect(() => {
|
||
applyTheme(values.theme);
|
||
}, [values.theme]);
|
||
|
||
const reload = useCallback(async () => {
|
||
try {
|
||
const rows = await api.listSettings();
|
||
const map = { ...DEFAULTS };
|
||
for (const r of rows) {
|
||
if (r.value != null) map[r.key] = r.value;
|
||
}
|
||
setValues(map);
|
||
} catch {
|
||
/* Einstellungen sind optional – Standardwerte bleiben bestehen. */
|
||
}
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
if (user) reload();
|
||
else setValues(DEFAULTS); // nach Logout auf Standard zurück
|
||
}, [user, reload]);
|
||
|
||
// Eine Einstellung setzen: erst lokal (sofort sichtbar), dann speichern.
|
||
const update = useCallback(async (key, value) => {
|
||
setValues((prev) => ({ ...prev, [key]: value }));
|
||
await api.setSetting(key, value);
|
||
}, []);
|
||
|
||
const value = {
|
||
...values,
|
||
baseCurrency: values.base_currency,
|
||
activeCurrencies: ausEinstellung(values.active_currencies),
|
||
formatMoney: (cents, currency) => fmtMoney(cents, currency ?? values.base_currency),
|
||
formatDate: (iso) => fmtDate(iso, values.locale),
|
||
update,
|
||
reload,
|
||
};
|
||
|
||
return <SettingsContext.Provider value={value}>{children}</SettingsContext.Provider>;
|
||
}
|
||
|
||
export function useSettings() {
|
||
return useContext(SettingsContext);
|
||
}
|