feat: Bank ueber alle Laender suchen
Unter "Deutschland" liessen sich N26 und Revolut nicht finden – und bei Revolut kann das gar nicht klappen: Die Bank vergibt deutsche IBANs, ist aber die Revolut Bank UAB in Litauen. Das Sitzland einer Bank steht nicht in der IBAN, also ist die Laenderauswahl der falsche Einstieg. Jetzt ein Suchfeld, das ohne Land ueber alle sucht; das Land ist nur noch ein optionaler Filter. Der Treffer zeigt sein Land mit an, und verbunden wird mit dem Land der BANK statt dem des Filters – sonst schluege die Autorisierung fehl, sobald ohne Land gesucht wurde. Ohne Land UND ohne Begriff wird abgelehnt: Sonst kaemen alle Banken Europas ins Formular. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+6
-1
@@ -194,7 +194,12 @@ export const api = {
|
||||
getBankApp: () => request("/bank/app"),
|
||||
saveBankApp: (body) => request("/bank/app", { method: "PUT", body }),
|
||||
deleteBankApp: () => request("/bank/app", { method: "DELETE" }),
|
||||
listBanks: (country) => request(`/bank/banks?country=${encodeURIComponent(country)}`),
|
||||
listBanks: (country, search) => {
|
||||
const p = new URLSearchParams();
|
||||
if (country) p.set("country", country);
|
||||
if (search) p.set("search", search);
|
||||
return request(`/bank/banks?${p.toString()}`);
|
||||
},
|
||||
connectBank: (body) => request("/bank/connect", { method: "POST", body }),
|
||||
bankCallback: (state, code) =>
|
||||
request(`/bank/callback?state=${encodeURIComponent(state)}&code=${encodeURIComponent(code)}`,
|
||||
|
||||
@@ -582,8 +582,8 @@
|
||||
"baseUrlHint": "Muss mit https:// beginnen und von aussen erreichbar sein – Banken leiten nicht auf eine unverschlüsselte Adresse zurück. Genau diese Adresse plus /bank/rueckkehr trägst du bei Enable Banking ein.",
|
||||
"country": "Land der Bank",
|
||||
"findBanks": "Banken suchen",
|
||||
"noBanks": "Für dieses Land wurde nichts gefunden.",
|
||||
"pickBank": "{{n}} Banken gefunden – wähle deine aus:",
|
||||
"noBanks": "Keine Treffer. Versuch einen kürzeren Suchbegriff, oder lass das Land leer.",
|
||||
"pickBank": "{{n}} Treffer – wähle deine Bank:",
|
||||
"connect": "Verbinden",
|
||||
"notMapped": "noch keinem Konto zugeordnet",
|
||||
"mapHint": "Ohne Zuordnung wird von diesem Konto nichts abgerufen.",
|
||||
@@ -597,7 +597,11 @@
|
||||
"validUntil": "Zustimmung gültig bis {{datum}}",
|
||||
"expiresSoon": "Zustimmung läuft am {{datum}} ab – danach musst du neu autorisieren.",
|
||||
"disconnect": "Verbindung trennen",
|
||||
"disconnectConfirm": "Verbindung zu „{{name}}“ trennen? Bereits abgerufene Buchungen bleiben."
|
||||
"disconnectConfirm": "Verbindung zu „{{name}}“ trennen? Bereits abgerufene Buchungen bleiben.",
|
||||
"search": "Bank suchen",
|
||||
"searchPlaceholder": "z. B. revolut oder n26",
|
||||
"searchHint": "Ohne Land wird überall gesucht. Das ist meist richtig: Das Sitzland einer Bank steht nicht in der IBAN – Revolut vergibt deutsche IBANs, sitzt aber in Litauen.",
|
||||
"allCountries": "alle Länder"
|
||||
},
|
||||
"bankReturn": {
|
||||
"title": "Rückkehr von der Bank",
|
||||
|
||||
@@ -582,8 +582,8 @@
|
||||
"baseUrlHint": "Must start with https:// and be reachable from outside – banks do not redirect to an unencrypted address. This address plus /bank/rueckkehr is what you register with Enable Banking.",
|
||||
"country": "Country of the bank",
|
||||
"findBanks": "Find banks",
|
||||
"noBanks": "Nothing found for this country.",
|
||||
"pickBank": "{{n}} banks found – pick yours:",
|
||||
"noBanks": "No matches. Try a shorter term, or leave the country empty.",
|
||||
"pickBank": "{{n}} matches – pick your bank:",
|
||||
"connect": "Connect",
|
||||
"notMapped": "not mapped to an account yet",
|
||||
"mapHint": "Without a mapping nothing is fetched from this account.",
|
||||
@@ -597,7 +597,11 @@
|
||||
"validUntil": "Consent valid until {{datum}}",
|
||||
"expiresSoon": "Consent expires on {{datum}} – you will need to authorise again.",
|
||||
"disconnect": "Disconnect",
|
||||
"disconnectConfirm": "Disconnect from “{{name}}”? Transactions already fetched stay."
|
||||
"disconnectConfirm": "Disconnect from “{{name}}”? Transactions already fetched stay.",
|
||||
"search": "Search for a bank",
|
||||
"searchPlaceholder": "e.g. revolut or n26",
|
||||
"searchHint": "Without a country it searches everywhere, which is usually right: a bank's home country is not in the IBAN – Revolut issues German IBANs but is based in Lithuania.",
|
||||
"allCountries": "all countries"
|
||||
},
|
||||
"bankReturn": {
|
||||
"title": "Back from your bank",
|
||||
|
||||
@@ -31,7 +31,8 @@ export default function Bankanbindung() {
|
||||
const [konten, setKonten] = useState([]);
|
||||
const [verbindungen, setVerbindungen] = useState([]);
|
||||
const [links, setLinks] = useState([]);
|
||||
const [land, setLand] = useState("DE");
|
||||
const [land, setLand] = useState("");
|
||||
const [suche, setSuche] = useState("");
|
||||
const [banken, setBanken] = useState(null);
|
||||
const [busy, setBusy] = useState(false);
|
||||
|
||||
@@ -72,10 +73,11 @@ export default function Bankanbindung() {
|
||||
}
|
||||
}
|
||||
|
||||
async function bankenLaden() {
|
||||
async function bankenLaden(e) {
|
||||
e?.preventDefault();
|
||||
setBusy(true);
|
||||
try {
|
||||
setBanken(await api.listBanks(land));
|
||||
setBanken(await api.listBanks(land, suche));
|
||||
} catch (e) {
|
||||
toast(e.message, "error");
|
||||
setBanken(null);
|
||||
@@ -87,7 +89,9 @@ export default function Bankanbindung() {
|
||||
async function verbinden(bank) {
|
||||
setBusy(true);
|
||||
try {
|
||||
const r = await api.connectBank({ aspsp_name: bank.name, country: land });
|
||||
// Das Land der BANK, nicht das des Filters – bei einer Suche über alle
|
||||
// Länder ist das Filterfeld leer.
|
||||
const r = await api.connectBank({ aspsp_name: bank.name, country: bank.country });
|
||||
// Weiter zur Bank. Von dort kommt der Nutzer auf /bank/rueckkehr zurück.
|
||||
window.location.href = r.url;
|
||||
} catch (e) {
|
||||
@@ -237,15 +241,24 @@ export default function Bankanbindung() {
|
||||
{/* Schritt 3: neue Bank verbinden */}
|
||||
{app && (
|
||||
<div style={{ marginTop: "var(--sp-3)" }}>
|
||||
<label className="field">
|
||||
<span>{t("bank.country")}</span>
|
||||
<select value={land} onChange={(e) => { setLand(e.target.value); setBanken(null); }}>
|
||||
{LAENDER.map((l) => <option key={l} value={l}>{l}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
<button className="btn" disabled={busy} onClick={bankenLaden}>
|
||||
<Icon name="search" size={15} /> {t("bank.findBanks")}
|
||||
</button>
|
||||
<form onSubmit={bankenLaden}>
|
||||
<label className="field">
|
||||
<span>{t("bank.search")}</span>
|
||||
<input value={suche} placeholder={t("bank.searchPlaceholder")}
|
||||
onChange={(e) => setSuche(e.target.value)} />
|
||||
</label>
|
||||
<p className="muted small">{t("bank.searchHint")}</p>
|
||||
<label className="field">
|
||||
<span>{t("bank.country")}</span>
|
||||
<select value={land} onChange={(e) => setLand(e.target.value)}>
|
||||
<option value="">{t("bank.allCountries")}</option>
|
||||
{LAENDER.map((l) => <option key={l} value={l}>{l}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
<button className="btn" disabled={busy || (!suche.trim() && !land)}>
|
||||
<Icon name="search" size={15} /> {t("bank.findBanks")}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{banken && (
|
||||
<div style={{ marginTop: "var(--sp-2)" }}>
|
||||
@@ -257,7 +270,9 @@ export default function Bankanbindung() {
|
||||
<div className="account-list">
|
||||
{banken.map((b) => (
|
||||
<div className="account-row" key={`${b.name}-${b.country}`}>
|
||||
<span className="grow ellipsis">{b.name}</span>
|
||||
<span className="grow ellipsis">
|
||||
{b.name} <span className="muted small">{b.country}</span>
|
||||
</span>
|
||||
<button className="btn sm primary" disabled={busy}
|
||||
onClick={() => verbinden(b)}>
|
||||
{t("bank.connect")}
|
||||
|
||||
Reference in New Issue
Block a user