From d1a1046969fdf8c98cd9c20ca4571cc1059c3646 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 6 Oct 2026 10:19:18 +0000 Subject: [PATCH] Finanzen: Einstellungen, Bankzugang, Fixkosten und Bankrueckkehr ohne Karten Co-Authored-By: Claude Sonnet 5.5 --- src/components/finance/BankAccessCard.jsx | 43 +++++++----------- src/components/finance/FixedCostsCard.jsx | 55 +++++++++++------------ src/components/finance/FormField.jsx | 9 ++-- src/components/finance/SettingsCard.jsx | 35 +++++++-------- src/pages/BankCallbackPage.jsx | 15 +++---- src/pages/FinanceSettingsPage.jsx | 7 ++- src/styles/global.css | 53 +++++++++------------- 7 files changed, 91 insertions(+), 126 deletions(-) diff --git a/src/components/finance/BankAccessCard.jsx b/src/components/finance/BankAccessCard.jsx index 0e794e4..6265145 100644 --- a/src/components/finance/BankAccessCard.jsx +++ b/src/components/finance/BankAccessCard.jsx @@ -1,7 +1,7 @@ -import { useEffect, useRef, useState } from 'react' -import { FaRotate, FaSpinner } from 'react-icons/fa6' +import { Fragment, useEffect, useRef, useState } from 'react' import { Badge, Button, Card } from '../ui' import { useFinanceResource } from '../../hooks/useFinanceResource' +import { noticeProps } from '../../lib/financeUi' import { getBank, refreshBank, startBankAuth } from '../../lib/financeApi' import { bankCardModel, refreshResultMessage } from '../../lib/financeSettings' import { safeUrl } from '../../lib/financeView' @@ -67,14 +67,11 @@ export default function BankAccessCard() { return ( {res.loading ? ( -
-
+
Bankzugang wird geladen …
) : ( -
-

{res.error || LOAD_ERROR}

- +
+

{res.error || LOAD_ERROR}

+
)} @@ -85,36 +82,28 @@ export default function BankAccessCard() { return ( {model.statusLabel}}> {res.error && ( -

- Der Stand konnte nicht neu geladen werden: {res.error} -

+

Der Stand konnte nicht neu geladen werden: {res.error}

)} {model.rows.length > 0 && ( -
+
{model.rows.map((row) => ( -
+
{row.label}
-
{row.text}
-
+
{row.text}
+ ))}
)} - {model.error && ( -

Fehler: {model.error}

- )} - {model.hint &&

{model.hint}

} - {message && ( -

- {message.text} -

- )} + {model.error &&

Fehler: {model.error}

} + {model.hint &&

{model.hint}

} + {message &&

{message.text}

}
{model.canRefresh && ( )} -
diff --git a/src/components/finance/FixedCostsCard.jsx b/src/components/finance/FixedCostsCard.jsx index ded7b7d..155f0ac 100644 --- a/src/components/finance/FixedCostsCard.jsx +++ b/src/components/finance/FixedCostsCard.jsx @@ -1,8 +1,8 @@ import { useEffect, useMemo, useRef, useState } from 'react' -import { FaPlus, FaSpinner } from 'react-icons/fa6' import { Badge, Button, Card, EmptyState } from '../ui' import FormField from './FormField' import { useFinanceResource } from '../../hooks/useFinanceResource' +import { noticeProps } from '../../lib/financeUi' import { createFixedCost, deleteFixedCost, getFixedCosts, updateFixedCost } from '../../lib/financeApi' import { FIXED_COST_DELETE_CONFIRM, @@ -146,45 +146,44 @@ export default function FixedCostsCard() { let body if (!res.data) { body = res.loading ? ( -
-
+
Fixkosten werden geladen …
) : ( -
-

{res.error || LOAD_ERROR}

- +
+

{res.error || LOAD_ERROR}

+
) } else { body = ( <> {res.error && ( -

+

Die Liste konnte nicht neu geladen werden: {res.error}{' '} - +

)} {editing && (
-

{editing.id ? 'Position bearbeiten' : 'Neue Position'}

+

{editing.id ? 'Position bearbeiten' : 'Neue Position'}

-
+
- + - + +
+
- {INTERVAL_OPTIONS.map((o) => ( ))} - +
- +
- +
)} - {message && ( -

- {message.text} -

- )} + {message &&

{message.text}

} {rows.length === 0 ? ( ) : ( @@ -222,13 +217,13 @@ export default function FixedCostsCard() {
{row.amountText}
{row.metaText}
- - + - +
@@ -245,8 +240,8 @@ export default function FixedCostsCard() { title="Fixkosten" actions={ res.data && ( - ) } diff --git a/src/components/finance/FormField.jsx b/src/components/finance/FormField.jsx index 7ce10ef..8aecaf8 100644 --- a/src/components/finance/FormField.jsx +++ b/src/components/finance/FormField.jsx @@ -1,8 +1,9 @@ import { cloneElement } from 'react' /** - * Formularfeld mit Beschriftung, Hinweis und Fehlermeldung. `children` ist genau ein Eingabeelement; es bekommt - * `id`, `aria-invalid` und `aria-describedby` (Hinweis und Fehler). Die Fehlermeldung wird vorgelesen (role="alert"). + * Formularfeld mit Beschriftung, Hinweis und Fehlermeldung (Klassen des Bausteins `Field`: `.field`, `.hint`, `.msg.err`). + * `children` ist genau ein Eingabeelement; es bekommt `id`, `aria-invalid` und `aria-describedby` (Hinweis und Fehler). + * Den roten Ring am Feld liefert allein `aria-invalid`. Die Fehlermeldung wird vorgelesen (role="alert"). */ export default function FormField({ id, label, hint, error, children }) { const hintId = hint ? `${id}-hint` : undefined @@ -13,12 +14,12 @@ export default function FormField({ id, label, hint, error, children }) { {cloneElement(children, { id, 'aria-invalid': error ? 'true' : undefined, 'aria-describedby': describedBy })} {hint && ( -
+
{hint}
)} {error && ( -