Web: Kassenzettel-Trefferschwelle in den Einstellungen
Prozent-Feld fuer receipt_match_threshold (Default 45) analog zur Ablaufwarnung; speichert ueber den generischen Settings-Endpunkt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -10,11 +10,13 @@ import { DATE_FORMATS, formatDate } from "../units";
|
|||||||
import { applyFavicon } from "../branding";
|
import { applyFavicon } from "../branding";
|
||||||
|
|
||||||
const EXPIRY_KEY = "expiry_warning_days";
|
const EXPIRY_KEY = "expiry_warning_days";
|
||||||
|
const RECEIPT_KEY = "receipt_match_threshold";
|
||||||
|
|
||||||
export default function Settings() {
|
export default function Settings() {
|
||||||
const { reload } = useSettings();
|
const { reload } = useSettings();
|
||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
const [days, setDays] = useState("");
|
const [days, setDays] = useState("");
|
||||||
|
const [threshold, setThreshold] = useState("");
|
||||||
const [dateFormat, setDateFormat] = useState("de");
|
const [dateFormat, setDateFormat] = useState("de");
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
@@ -23,6 +25,7 @@ export default function Settings() {
|
|||||||
try {
|
try {
|
||||||
const settings = await api.listSettings();
|
const settings = await api.listSettings();
|
||||||
setDays(settings.find((s) => s.key === EXPIRY_KEY)?.value ?? "7");
|
setDays(settings.find((s) => s.key === EXPIRY_KEY)?.value ?? "7");
|
||||||
|
setThreshold(settings.find((s) => s.key === RECEIPT_KEY)?.value ?? "45");
|
||||||
setDateFormat(settings.find((s) => s.key === DATE_FORMAT_KEY)?.value ?? "de");
|
setDateFormat(settings.find((s) => s.key === DATE_FORMAT_KEY)?.value ?? "de");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err.message);
|
setError(err.message);
|
||||||
@@ -36,6 +39,7 @@ export default function Settings() {
|
|||||||
setError(null); setBusy(true);
|
setError(null); setBusy(true);
|
||||||
try {
|
try {
|
||||||
await api.setSetting(EXPIRY_KEY, String(parseInt(days, 10)));
|
await api.setSetting(EXPIRY_KEY, String(parseInt(days, 10)));
|
||||||
|
await api.setSetting(RECEIPT_KEY, String(Math.max(0, Math.min(100, parseInt(threshold, 10) || 0))));
|
||||||
await api.setSetting(DATE_FORMAT_KEY, dateFormat);
|
await api.setSetting(DATE_FORMAT_KEY, dateFormat);
|
||||||
await reload();
|
await reload();
|
||||||
toast("Gespeichert.");
|
toast("Gespeichert.");
|
||||||
@@ -71,6 +75,20 @@ export default function Settings() {
|
|||||||
bereits überschritten ist), erscheinen auf der Übersicht unter „Bald ablaufend“.
|
bereits überschritten ist), erscheinen auf der Übersicht unter „Bald ablaufend“.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div className="card-head" style={{ marginTop: "var(--sp-5)" }}>
|
||||||
|
<Icon name="cart" /><h2>Kassenzettel-Scan</h2>
|
||||||
|
</div>
|
||||||
|
<label>
|
||||||
|
Trefferschwelle (%)
|
||||||
|
<input type="number" min="0" max="100" step="1" value={threshold}
|
||||||
|
onChange={(e) => setThreshold(e.target.value)} style={{ maxWidth: 160 }} />
|
||||||
|
</label>
|
||||||
|
<p className="muted small mt-0">
|
||||||
|
Beim Scannen eines Kassenzettels (iOS) werden je Zeile nur Artikel vorgeschlagen,
|
||||||
|
deren Übereinstimmung mindestens so hoch ist. Höher = strenger (weniger, dafür
|
||||||
|
sicherere Vorschläge), niedriger = mehr Vorschläge.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div className="card-head" style={{ marginTop: "var(--sp-5)" }}>
|
<div className="card-head" style={{ marginTop: "var(--sp-5)" }}>
|
||||||
<Icon name="settings" /><h2>Darstellung</h2>
|
<Icon name="settings" /><h2>Darstellung</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user