From 18368e6e93a9dbaae12bb15f7cb22d87809fb3de Mon Sep 17 00:00:00 2001 From: Guido Date: Fri, 21 Aug 2026 20:59:51 +0200 Subject: [PATCH] feat: Buchungstexte in der Offen-Liste kopierbar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit body hat user-select:none mit einer Ausnahmeliste; die Buchungsliste steht als Tabelle darin, die Offen-Seite mit ihren Listenzeilen aber nicht. Damit liess sich der Empfaengertext nicht markieren – ausgerechnet dort, wo man ihn nachschlagen will, um zu erkennen, welches Franchise dahintersteckt. .named-text ist jetzt markierbar, und je Zeile steht ein Kopierknopf. Ausserdem wird der Verwendungszweck mit angezeigt, wenn er vom Empfaenger abweicht – oft steht die eigentliche Kennung dort. Co-Authored-By: Claude Opus 5 --- web/src/locales/de.json | 5 ++++- web/src/locales/en.json | 5 ++++- web/src/pages/Offen.jsx | 22 +++++++++++++++++++++- web/src/styles.css | 2 +- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/web/src/locales/de.json b/web/src/locales/de.json index 7c1d311..92ad666 100644 --- a/web/src/locales/de.json +++ b/web/src/locales/de.json @@ -450,6 +450,9 @@ "allDone": "Alles zugeordnet.", "choose": "Kategorie wählen …", "noText": "Ohne Text", - "rememberKeyword": "Zweck als Schlagwort merken, damit die nächste gleiche Buchung beim Import gleich zugeordnet wird" + "rememberKeyword": "Zweck als Schlagwort merken, damit die nächste gleiche Buchung beim Import gleich zugeordnet wird", + "copy": "Text kopieren", + "copied": "Kopiert", + "copyFailed": "Kopieren nicht möglich – Text lässt sich jetzt aber markieren." } } diff --git a/web/src/locales/en.json b/web/src/locales/en.json index 49cabbe..64c5ec1 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -450,6 +450,9 @@ "allDone": "Everything sorted.", "choose": "Pick a category …", "noText": "No text", - "rememberKeyword": "Remember the text as a keyword so the next matching booking is categorised on import" + "rememberKeyword": "Remember the text as a keyword so the next matching booking is categorised on import", + "copy": "Copy text", + "copied": "Copied", + "copyFailed": "Copying failed – but the text can be selected now." } } diff --git a/web/src/pages/Offen.jsx b/web/src/pages/Offen.jsx index 5d948d4..bc2db4f 100644 --- a/web/src/pages/Offen.jsx +++ b/web/src/pages/Offen.jsx @@ -44,6 +44,17 @@ export default function Offen() { } useEffect(() => { laden(); }, []); + // Der Empfaengertext ist oft genau das, was man nachschlagen will („welches + // Franchise steckt hinter diesem Namen?"). Abtippen faellt damit weg. + async function kopieren(text) { + try { + await navigator.clipboard.writeText(text); + toast(t("open.copied")); + } catch { + toast(t("open.copyFailed"), "error"); + } + } + async function zuordnen(tx, categoryId) { if (categoryId == null) return; try { @@ -90,9 +101,18 @@ export default function Offen() {
-
{tx.payee || tx.description || t("open.noText")}
+
+ {tx.payee || tx.description || t("open.noText")} + {(tx.payee || tx.description) && ( + + )} +
{formatDate(tx.date)} · {accountById[tx.account_id]?.name || "—"} + {tx.description && tx.payee && tx.description !== tx.payee && ` · ${tx.description}`}