aboutsummaryrefslogtreecommitdiff
path: root/packages/demobank-ui
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-03-08 14:09:31 -0300
committerSebastian <sebasjm@gmail.com>2024-03-08 14:09:31 -0300
commitddd32a690bd13b1eb1aef1356a1d59fd64e254bf (patch)
tree44126872f6e8195a3617e2002c696c0afa13fb0d /packages/demobank-ui
parente0e82cdf07930d766081e42203c5a4e66d43191f (diff)
demobank => bank
Diffstat (limited to 'packages/demobank-ui')
-rw-r--r--packages/demobank-ui/.eslintrc.cjs28
-rw-r--r--packages/demobank-ui/.gitignore4
-rw-r--r--packages/demobank-ui/Makefile37
-rw-r--r--packages/demobank-ui/README.md24
-rw-r--r--packages/demobank-ui/TODO49
-rwxr-xr-xpackages/demobank-ui/build.mjs28
-rwxr-xr-xpackages/demobank-ui/contrib/po2ts42
-rw-r--r--packages/demobank-ui/copyleft-header.js15
-rwxr-xr-xpackages/demobank-ui/dev.mjs41
-rw-r--r--packages/demobank-ui/package.json52
-rw-r--r--packages/demobank-ui/postcss.config.js6
-rw-r--r--packages/demobank-ui/src/Routing.tsx604
-rw-r--r--packages/demobank-ui/src/app.tsx137
-rw-r--r--packages/demobank-ui/src/assets/empty.pngbin2785 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/example/id1.jpgbin103558 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/favicon.icobin15086 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/icons/android-chrome-192x192.pngbin14058 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/icons/android-chrome-512x512.pngbin51484 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/icons/apple-touch-icon.pngbin12746 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/icons/favicon-16x16.pngbin626 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/icons/favicon-32x32.pngbin1487 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/icons/languageicon.svg48
-rw-r--r--packages/demobank-ui/src/assets/icons/mstile-150x150.pngbin9050 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/assets/logo-2021.svg9
-rw-r--r--packages/demobank-ui/src/assets/logo-white.svg45
-rw-r--r--packages/demobank-ui/src/assets/logo.jpegbin39336 -> 0 bytes
-rw-r--r--packages/demobank-ui/src/components/Cashouts/index.ts86
-rw-r--r--packages/demobank-ui/src/components/Cashouts/state.ts51
-rw-r--r--packages/demobank-ui/src/components/Cashouts/stories.tsx29
-rw-r--r--packages/demobank-ui/src/components/Cashouts/test.ts68
-rw-r--r--packages/demobank-ui/src/components/Cashouts/views.tsx217
-rw-r--r--packages/demobank-ui/src/components/EmptyComponentExample/index.ts56
-rw-r--r--packages/demobank-ui/src/components/EmptyComponentExample/state.ts25
-rw-r--r--packages/demobank-ui/src/components/EmptyComponentExample/stories.tsx29
-rw-r--r--packages/demobank-ui/src/components/EmptyComponentExample/test.ts28
-rw-r--r--packages/demobank-ui/src/components/EmptyComponentExample/views.tsx25
-rw-r--r--packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx24
-rw-r--r--packages/demobank-ui/src/components/QR.tsx51
-rw-r--r--packages/demobank-ui/src/components/Time.tsx71
-rw-r--r--packages/demobank-ui/src/components/Transactions/index.ts80
-rw-r--r--packages/demobank-ui/src/components/Transactions/state.ts80
-rw-r--r--packages/demobank-ui/src/components/Transactions/stories.tsx44
-rw-r--r--packages/demobank-ui/src/components/Transactions/test.ts202
-rw-r--r--packages/demobank-ui/src/components/Transactions/views.tsx243
-rw-r--r--packages/demobank-ui/src/components/index.examples.ts17
-rw-r--r--packages/demobank-ui/src/context/config.ts263
-rw-r--r--packages/demobank-ui/src/context/navigation.ts92
-rw-r--r--packages/demobank-ui/src/context/settings.ts44
-rw-r--r--packages/demobank-ui/src/context/wallet-integration.ts83
-rw-r--r--packages/demobank-ui/src/declaration.d.ts35
-rw-r--r--packages/demobank-ui/src/hooks/account.ts294
-rw-r--r--packages/demobank-ui/src/hooks/bank-state.ts188
-rw-r--r--packages/demobank-ui/src/hooks/form.ts100
-rw-r--r--packages/demobank-ui/src/hooks/preferences.ts112
-rw-r--r--packages/demobank-ui/src/hooks/regional.ts484
-rw-r--r--packages/demobank-ui/src/hooks/session.ts131
-rw-r--r--packages/demobank-ui/src/i18n/bank.pot1740
-rw-r--r--packages/demobank-ui/src/i18n/de.po1778
-rw-r--r--packages/demobank-ui/src/i18n/en.po1784
-rw-r--r--packages/demobank-ui/src/i18n/es.po2063
-rw-r--r--packages/demobank-ui/src/i18n/fr.po1752
-rw-r--r--packages/demobank-ui/src/i18n/it.po1843
-rw-r--r--packages/demobank-ui/src/i18n/poheader26
-rw-r--r--packages/demobank-ui/src/i18n/strings.ts2295
-rw-r--r--packages/demobank-ui/src/i18n/uk.po1743
-rw-r--r--packages/demobank-ui/src/index.html41
-rw-r--r--packages/demobank-ui/src/index.tsx27
-rw-r--r--packages/demobank-ui/src/manifest.json21
-rw-r--r--packages/demobank-ui/src/pages/AccountPage/index.ts134
-rw-r--r--packages/demobank-ui/src/pages/AccountPage/state.ts117
-rw-r--r--packages/demobank-ui/src/pages/AccountPage/stories.tsx29
-rw-r--r--packages/demobank-ui/src/pages/AccountPage/test.ts31
-rw-r--r--packages/demobank-ui/src/pages/AccountPage/views.tsx144
-rw-r--r--packages/demobank-ui/src/pages/BankFrame.stories.tsx29
-rw-r--r--packages/demobank-ui/src/pages/BankFrame.tsx237
-rw-r--r--packages/demobank-ui/src/pages/LoginForm.tsx226
-rw-r--r--packages/demobank-ui/src/pages/OperationState/index.ts157
-rw-r--r--packages/demobank-ui/src/pages/OperationState/state.ts232
-rw-r--r--packages/demobank-ui/src/pages/OperationState/stories.tsx29
-rw-r--r--packages/demobank-ui/src/pages/OperationState/test.ts31
-rw-r--r--packages/demobank-ui/src/pages/OperationState/views.tsx440
-rw-r--r--packages/demobank-ui/src/pages/PaymentOptions.stories.tsx35
-rw-r--r--packages/demobank-ui/src/pages/PaymentOptions.tsx237
-rw-r--r--packages/demobank-ui/src/pages/PaytoWireTransferForm.stories.tsx35
-rw-r--r--packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx792
-rw-r--r--packages/demobank-ui/src/pages/ProfileNavigation.tsx202
-rw-r--r--packages/demobank-ui/src/pages/PublicHistoriesPage.tsx95
-rw-r--r--packages/demobank-ui/src/pages/QrCodeSection.stories.tsx32
-rw-r--r--packages/demobank-ui/src/pages/QrCodeSection.tsx150
-rw-r--r--packages/demobank-ui/src/pages/RegistrationPage.tsx415
-rw-r--r--packages/demobank-ui/src/pages/SolveChallengePage.tsx716
-rw-r--r--packages/demobank-ui/src/pages/WalletWithdrawForm.tsx366
-rw-r--r--packages/demobank-ui/src/pages/WireTransfer.tsx103
-rw-r--r--packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx355
-rw-r--r--packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx71
-rw-r--r--packages/demobank-ui/src/pages/WithdrawalQRCode.tsx310
-rw-r--r--packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx85
-rw-r--r--packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx244
-rw-r--r--packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx301
-rw-r--r--packages/demobank-ui/src/pages/admin/AccountForm.tsx901
-rw-r--r--packages/demobank-ui/src/pages/admin/AccountList.tsx244
-rw-r--r--packages/demobank-ui/src/pages/admin/AdminHome.tsx541
-rw-r--r--packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx204
-rw-r--r--packages/demobank-ui/src/pages/admin/DownloadStats.tsx585
-rw-r--r--packages/demobank-ui/src/pages/admin/RemoveAccount.tsx267
-rw-r--r--packages/demobank-ui/src/pages/index.stories.tsx20
-rw-r--r--packages/demobank-ui/src/pages/regional/ConversionConfig.tsx978
-rw-r--r--packages/demobank-ui/src/pages/regional/CreateCashout.tsx809
-rw-r--r--packages/demobank-ui/src/pages/regional/ShowCashoutDetails.tsx192
-rw-r--r--packages/demobank-ui/src/pages/rnd.ts2907
-rw-r--r--packages/demobank-ui/src/route.ts130
-rw-r--r--packages/demobank-ui/src/scss/main.css3
-rw-r--r--packages/demobank-ui/src/settings.json11
-rw-r--r--packages/demobank-ui/src/settings.ts112
-rw-r--r--packages/demobank-ui/src/stories.test.ts84
-rw-r--r--packages/demobank-ui/src/stories.tsx41
-rw-r--r--packages/demobank-ui/src/utils.ts447
-rw-r--r--packages/demobank-ui/tailwind.config.js14
-rwxr-xr-xpackages/demobank-ui/test.mjs32
-rw-r--r--packages/demobank-ui/tsconfig.json46
120 files changed, 0 insertions, 34482 deletions
diff --git a/packages/demobank-ui/.eslintrc.cjs b/packages/demobank-ui/.eslintrc.cjs
deleted file mode 100644
index 05618b499..000000000
--- a/packages/demobank-ui/.eslintrc.cjs
+++ /dev/null
@@ -1,28 +0,0 @@
-module.exports = {
- extends: [
- 'eslint:recommended',
- 'plugin:@typescript-eslint/recommended',
- 'plugin:react/recommended',
- ],
- parser: '@typescript-eslint/parser',
- plugins: ['@typescript-eslint', 'header'],
- root: true,
- rules: {
- "react/no-unknown-property": 0,
- "react/no-unescaped-entities": 0,
- "@typescript-eslint/no-namespace": 0,
- "@typescript-eslint/no-unused-vars": [2,{argsIgnorePattern:"^_"}],
- "header/header": [2,"copyleft-header.js"]
- },
- parserOptions: {
- ecmaVersion: 6,
- sourceType: 'module',
- jsx: true,
- },
- settings: {
- react: {
- version: "18",
- pragma: "h",
- }
- },
-};
diff --git a/packages/demobank-ui/.gitignore b/packages/demobank-ui/.gitignore
deleted file mode 100644
index 30cb2774c..000000000
--- a/packages/demobank-ui/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-/build
-/*.log
-/demobank-ui-settings.js
diff --git a/packages/demobank-ui/Makefile b/packages/demobank-ui/Makefile
deleted file mode 100644
index 2399cc427..000000000
--- a/packages/demobank-ui/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-# This Makefile has been placed in the public domain
-
-ifeq ($(TOPLEVEL), yes)
- $(info top-level build)
- -include ../../.config.mk
- override DESTDIR := $(TOP_DESTDIR)
-else
- $(info package-level build)
- -include ../../.config.mk
- -include .config.mk
-endif
-
-$(info prefix is $(prefix))
-
-.PHONY: all
-all:
- @echo run \'make install\' to install
-
-spa_dir=$(DESTDIR)$(prefix)/share/taler/demobank-ui
-
-.PHONY: deps
-deps:
- pnpm install --frozen-lockfile --filter @gnu-taler/demobank-ui...
- pnpm run --filter @gnu-taler/demobank-ui... compile
- pnpm run check
- pnpm run build
-
-.PHONY: install-nodeps
-install-nodeps:
- install -d $(spa_dir)
- install ./dist/prod/* $(spa_dir)
-
-.PHONY: install
-install:
- $(MAKE) deps
- $(MAKE) install-nodeps
-
diff --git a/packages/demobank-ui/README.md b/packages/demobank-ui/README.md
deleted file mode 100644
index a49dc7bb0..000000000
--- a/packages/demobank-ui/README.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Taler Demobank UI
-
-Web-based user interface for the libeufin demobank.
-
-## CLI Commands
-
-- `./dev.mjs` development setup. Will listen in :8080 and reload every time a file is save.
-- `./build.mjs` build for production.
-- `./test.mjs` build and run unit test
-
-## Testing
-
-By default, the demobank-ui will expect the backend to be in `window.origin` but that can be overridden using the `settings.json` file or by session in the localStorage.
-
-```
-localStorage.setItem("bank-base-url", OTHER_URL);
-```
-
-## Customizing Per-Deployment Settings
-
-To customize per-deployment settings, make sure that the
-`settings.json` file is served alongside the UI.
-
-For more information about the values check the file `settings.ts` in the src folder.
diff --git a/packages/demobank-ui/TODO b/packages/demobank-ui/TODO
deleted file mode 100644
index cc578cce0..000000000
--- a/packages/demobank-ui/TODO
+++ /dev/null
@@ -1,49 +0,0 @@
-Urgent TODOs:
-
-- General:
-
- - not only Nora dark-theme, but default light! (CSS)
- - DONE: auto-focus on input fields is not working well
- - DONE: buttons should be visibly insensitive
- as long as required input fields are not
- working
- - DONE: next required invalid/missing input field is
- not properly highlighted in red
- - Logout button needs more padding to the right (CSS)
-
-- Error bar:
- - DONE: hows JSON, should only show good error message
- and numeric code, not JSON syntax
- - should auto-hide after next action, no need for
- "clear"!
- - need variant "status bar" in green (or blue)
- which shows status of last operation
-
-* H1-Titles:
- - Center more (currently way on the left) (CSS)
-
-- Assets:
-
- - Numeric amount needs to be shown MUCH bigger (CSS)
- - Center more? (CSS)
-
-- Payments:
-
- - Amount to withdraw currently shown in white-on-white (CSS)
- - Big frame drawn around notebook-tabs is not nice (CSS)
- - Center more? (CSS)
- - "Wire to bank account"
- - maybe split two types (payto and IBAN) into
- two tabs?
- - currently cannot switch back from payto to IBAN
-
-- Withdraw:
-
- - Should use new 'status' bar at the end, instead
- of extra dialog with "close" button
- - ditto for bank-wire-transfer final stage
-
-- Footer:
- - overlaps with transaction history or other
- content, needs to consistently show at the
- end! => change rendering logic!? (CSS?)
diff --git a/packages/demobank-ui/build.mjs b/packages/demobank-ui/build.mjs
deleted file mode 100755
index 04a6f646b..000000000
--- a/packages/demobank-ui/build.mjs
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/bin/env node
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { build } from "@gnu-taler/web-util/build";
-
-await build({
- type: "production",
- source: {
- js: ["src/index.tsx"],
- assets: [{ base: "src", files: ["src/index.html"] }],
- },
- destination: "./dist/prod",
- css: "postcss",
-});
diff --git a/packages/demobank-ui/contrib/po2ts b/packages/demobank-ui/contrib/po2ts
deleted file mode 100755
index a135da61b..000000000
--- a/packages/demobank-ui/contrib/po2ts
+++ /dev/null
@@ -1,42 +0,0 @@
-#!/usr/bin/env node
-/*
- This file is part of GNU Taler
- (C) 2020 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- * Convert a <lang>.po file into a JavaScript / TypeScript expression.
- */
-
-const po2json = require("po2json");
-
-const filename = process.argv[2];
-
-if (!filename) {
- console.error("error: missing filename");
- process.exit(1);
-}
-
-const m = filename.match(/([a-zA-Z0-9-_]+).po/);
-
-if (!m) {
- console.error("error: unexpected filename (expected <lang>.po)");
- process.exit(1);
-}
-
-const lang = m[1];
-const pojson = po2json.parseFileSync(filename, { format: "jed1.x", fuzzy: true });
-const s =
- "strings['" + lang + "'] = " + JSON.stringify(pojson, null, " ") + ";\n";
-console.log(s);
diff --git a/packages/demobank-ui/copyleft-header.js b/packages/demobank-ui/copyleft-header.js
deleted file mode 100644
index 7fa276bea..000000000
--- a/packages/demobank-ui/copyleft-header.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
diff --git a/packages/demobank-ui/dev.mjs b/packages/demobank-ui/dev.mjs
deleted file mode 100755
index 7b4f719ae..000000000
--- a/packages/demobank-ui/dev.mjs
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env node
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { serve } from "@gnu-taler/web-util/node";
-import { initializeDev } from "@gnu-taler/web-util/build";
-
-const devEntryPoints = ["src/stories.tsx", "src/index.tsx"];
-
-const build = initializeDev({
- type: "development",
- source: {
- js: devEntryPoints,
- assets: [{ base: "src", files: ["src/index.html", "src/settings.json"] }],
- },
- destination: "./dist/dev",
- public: "/app",
- css: "postcss",
-});
-
-await build();
-
-serve({
- folder: "./dist/dev",
- port: 8080,
- source: "./src",
- onSourceUpdate: build,
-});
diff --git a/packages/demobank-ui/package.json b/packages/demobank-ui/package.json
deleted file mode 100644
index 14fb28081..000000000
--- a/packages/demobank-ui/package.json
+++ /dev/null
@@ -1,52 +0,0 @@
-{
- "private": true,
- "name": "@gnu-taler/demobank-ui",
- "version": "0.9.3-dev.29",
- "license": "AGPL-3.0-OR-LATER",
- "type": "module",
- "scripts": {
- "build": "./build.mjs",
- "check": "tsc",
- "clean": "rm -rf dist lib tsconfig.tsbuildinfo",
- "compile": "tsc && ./build.mjs",
- "test": "./test.mjs && mocha --require source-map-support/register 'dist/test/**/*.test.js' 'dist/test/**/test.js'",
- "lint": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
- "typedoc": "typedoc --out dist/typedoc ./src/",
- "i18n:strings": "pogen extract && pogen merge",
- "i18n:translations": "pogen emit",
- "pretty": "prettier --write src"
- },
- "dependencies": {
- "@gnu-taler/taler-util": "workspace:*",
- "@gnu-taler/web-util": "workspace:*",
- "date-fns": "2.29.3",
- "jed": "1.1.1",
- "preact": "10.11.3",
- "qrcode-generator": "^1.4.4",
- "swr": "2.0.3"
- },
- "devDependencies": {
- "eslint": "^8.56.0",
- "@gnu-taler/pogen": "^0.0.5",
- "@tailwindcss/forms": "^0.5.3",
- "@tailwindcss/typography": "^0.5.9",
- "@types/chai": "^4.3.0",
- "@types/history": "^4.7.8",
- "@types/mocha": "^10.0.1",
- "@types/node": "^18.11.17",
- "@typescript-eslint/eslint-plugin": "^6.19.0",
- "@typescript-eslint/parser": "^6.19.0",
- "autoprefixer": "^10.4.14",
- "chai": "^4.3.6",
- "esbuild": "^0.19.9",
- "eslint-config-prettier": "^9.1.0",
- "eslint-plugin-react": "^7.33.2",
- "mocha": "9.2.0",
- "po2json": "^0.4.5",
- "tailwindcss": "^3.3.2",
- "typescript": "5.3.3"
- },
- "pogen": {
- "domain": "bank"
- }
-}
diff --git a/packages/demobank-ui/postcss.config.js b/packages/demobank-ui/postcss.config.js
deleted file mode 100644
index 2e7af2b7f..000000000
--- a/packages/demobank-ui/postcss.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
-}
diff --git a/packages/demobank-ui/src/Routing.tsx b/packages/demobank-ui/src/Routing.tsx
deleted file mode 100644
index f9b388ed1..000000000
--- a/packages/demobank-ui/src/Routing.tsx
+++ /dev/null
@@ -1,604 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- LocalNotificationBanner,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-
-import {
- AccessToken,
- HttpStatusCode,
- TranslatedString,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import { useEffect } from "preact/hooks";
-import { useBankCoreApiContext } from "./context/config.js";
-import { useNavigationContext } from "./context/navigation.js";
-import { useSettingsContext } from "./context/settings.js";
-import { useSessionState } from "./hooks/session.js";
-import { AccountPage } from "./pages/AccountPage/index.js";
-import { BankFrame } from "./pages/BankFrame.js";
-import { LoginForm } from "./pages/LoginForm.js";
-import { PublicHistoriesPage } from "./pages/PublicHistoriesPage.js";
-import { RegistrationPage } from "./pages/RegistrationPage.js";
-import { SolveChallengePage } from "./pages/SolveChallengePage.js";
-import { WireTransfer } from "./pages/WireTransfer.js";
-import { WithdrawalOperationPage } from "./pages/WithdrawalOperationPage.js";
-import { CashoutListForAccount } from "./pages/account/CashoutListForAccount.js";
-import { ShowAccountDetails } from "./pages/account/ShowAccountDetails.js";
-import { UpdateAccountPassword } from "./pages/account/UpdateAccountPassword.js";
-import { AdminHome } from "./pages/admin/AdminHome.js";
-import { CreateNewAccount } from "./pages/admin/CreateNewAccount.js";
-import { DownloadStats } from "./pages/admin/DownloadStats.js";
-import { RemoveAccount } from "./pages/admin/RemoveAccount.js";
-import { ConversionConfig } from "./pages/regional/ConversionConfig.js";
-import { CreateCashout } from "./pages/regional/CreateCashout.js";
-import { ShowCashoutDetails } from "./pages/regional/ShowCashoutDetails.js";
-import { urlPattern, useCurrentLocation } from "./route.js";
-
-export function Routing(): VNode {
- const session = useSessionState();
-
- if (session.state.status === "loggedIn") {
- const { isUserAdministrator, username } = session.state;
- return (
- <BankFrame account={username} routeAccountDetails={privatePages.myAccountDetails}>
- <PrivateRouting username={username} isAdmin={isUserAdministrator} />
- </BankFrame>
- );
- }
- return (
- <BankFrame>
- <PublicRounting
- onLoggedUser={(username, token) => {
- session.logIn({ username, token: token });
- }}
- />
- </BankFrame>
- );
-}
-
-const publicPages = {
- login: urlPattern(/\/login/, () => "#/login"),
- register: urlPattern(/\/register/, () => "#/register"),
- publicAccounts: urlPattern(/\/public-accounts/, () => "#/public-accounts"),
- operationDetails: urlPattern<{ wopid: string }>(
- /\/operation\/(?<wopid>[a-zA-Z0-9]+)/,
- ({ wopid }) => `#/operation/${wopid}`,
- ),
- solveSecondFactor: urlPattern(/\/2fa/, () => "#/2fa"),
-};
-
-function PublicRounting({
- onLoggedUser,
-}: {
- onLoggedUser: (username: string, token: AccessToken) => void;
-}): VNode {
- const settings = useSettingsContext();
- const { i18n } = useTranslationContext();
- const location = useCurrentLocation(publicPages);
- const { navigateTo } = useNavigationContext();
- const { bank, authenticator } = useBankCoreApiContext();
- const [notification, notify, handleError] = useLocalNotification();
-
- useEffect(() => {
- if (location === undefined) {
- navigateTo(publicPages.login.url({}));
- }
- }, [location]);
-
- if (location === undefined) {
- return <Fragment />;
- }
-
- async function doAutomaticLogin(username: string, password: string) {
- await handleError(async () => {
- const resp = await authenticator(username)
- .createAccessToken(password, {
- scope: "readwrite",
- duration: { d_us: "forever" },
- refreshable: true,
- });
- if (resp.type === "ok") {
- onLoggedUser(username, resp.body.access_token);
- } else {
- switch (resp.case) {
- case HttpStatusCode.Unauthorized:
- return notify({
- type: "error",
- title: i18n.str`Wrong credentials for "${username}"`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`Account not found`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- default:
- assertUnreachable(resp);
- }
- }
- });
- }
-
- switch (location.name) {
- case "login": {
- return (
- <Fragment>
- <div class="sm:mx-auto sm:w-full sm:max-w-sm">
- <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Welcome to ${settings.bankName}!`}</h2>
- </div>
- <LoginForm routeRegister={publicPages.register} />
- </Fragment>
- );
- }
- case "publicAccounts": {
- return <PublicHistoriesPage />;
- }
- case "operationDetails": {
- return (
- <WithdrawalOperationPage
- operationId={location.values.wopid}
- routeWithdrawalDetails={publicPages.operationDetails}
- purpose="after-confirmation"
- onOperationAborted={() => navigateTo(publicPages.login.url({}))}
- routeClose={publicPages.login}
- onAuthorizationRequired={() =>
- navigateTo(publicPages.solveSecondFactor.url({}))
- }
- />
- );
- }
- case "register": {
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} />
- <RegistrationPage
- onRegistrationSuccesful={doAutomaticLogin}
- routeCancel={publicPages.login}
- />
- </Fragment>
- );
- }
- case "solveSecondFactor": {
- return (
- <SolveChallengePage
- onChallengeCompleted={() => navigateTo(publicPages.login.url({}))}
- routeClose={publicPages.login}
- />
- );
- }
- default:
- assertUnreachable(location);
- }
-}
-
-export const privatePages = {
- homeChargeWallet: urlPattern(
- /\/account\/charge-wallet/,
- () => "#/account/charge-wallet",
- ),
- homeWireTransfer: urlPattern<{
- account?: string,
- subject?: string,
- amount?: string,
- }>(
- /\/account\/wire-transfer/,
- () => "#/account/wire-transfer",
- ),
- home: urlPattern(/\/account/, () => "#/account"),
- solveSecondFactor: urlPattern(/\/2fa/, () => "#/2fa"),
- cashoutCreate: urlPattern(/\/new-cashout/, () => "#/new-cashout"),
- cashoutDetails: urlPattern<{ cid: string }>(
- /\/cashout\/(?<cid>[a-zA-Z0-9]+)/,
- ({ cid }) => `#/cashout/${cid}`,
- ),
- wireTranserCreate: urlPattern<{
- account?: string,
- subject?: string,
- amount?: string,
- }>(
- /\/wire-transfer\/(?<account>[a-zA-Z0-9]+)/,
- ({ account }) => `#/wire-transfer/${account}`,
- ),
- publicAccountList: urlPattern(/\/public-accounts/, () => "#/public-accounts"),
- statsDownload: urlPattern(/\/download-stats/, () => "#/download-stats"),
- accountCreate: urlPattern(/\/new-account/, () => "#/new-account"),
- myAccountDelete: urlPattern(
- /\/delete-my-account/,
- () => "#/delete-my-account",
- ),
- myAccountDetails: urlPattern(/\/my-profile/, () => "#/my-profile"),
- myAccountPassword: urlPattern(/\/my-password/, () => "#/my-password"),
- myAccountCashouts: urlPattern(/\/my-cashouts/, () => "#/my-cashouts"),
- conversionConfig: urlPattern(/\/conversion/, () => "#/conversion"),
- accountDetails: urlPattern<{ account: string }>(
- /\/profile\/(?<account>[a-zA-Z0-9_-]+)\/details/,
- ({ account }) => `#/profile/${account}/details`,
- ),
- accountChangePassword: urlPattern<{ account: string }>(
- /\/profile\/(?<account>[a-zA-Z0-9_-]+)\/change-password/,
- ({ account }) => `#/profile/${account}/change-password`,
- ),
- accountDelete: urlPattern<{ account: string }>(
- /\/profile\/(?<account>[a-zA-Z0-9_-]+)\/delete/,
- ({ account }) => `#/profile/${account}/delete`,
- ),
- accountCashouts: urlPattern<{ account: string }>(
- /\/profile\/(?<account>[a-zA-Z0-9_-]+)\/cashouts/,
- ({ account }) => `#/profile/${account}/cashouts`,
- ),
- startOperation: urlPattern<{ wopid: string }>(
- /\/start-operation\/(?<wopid>[a-zA-Z0-9-]+)/,
- ({ wopid }) => `#/start-operation/${wopid}`,
- ),
- operationDetails: urlPattern<{ wopid: string }>(
- /\/operation\/(?<wopid>[a-zA-Z0-9-]+)/,
- ({ wopid }) => `#/operation/${wopid}`,
- ),
-};
-
-function PrivateRouting({
- username,
- isAdmin,
-}: {
- username: string;
- isAdmin: boolean;
-}): VNode {
- const { navigateTo } = useNavigationContext();
- const location = useCurrentLocation(privatePages);
- useEffect(() => {
- if (location === undefined) {
- navigateTo(privatePages.home.url({}));
- }
- }, [location]);
-
- if (location === undefined) {
- return <Fragment />;
- }
-
- switch (location.name) {
- case "operationDetails": {
-
- return (
- <WithdrawalOperationPage
- operationId={location.values.wopid}
- routeWithdrawalDetails={privatePages.operationDetails}
- purpose="after-confirmation"
- onOperationAborted={() => navigateTo(privatePages.home.url({}))}
- routeClose={privatePages.home}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- />
- );
- }
- case "startOperation": {
-
- return (
- <WithdrawalOperationPage
- operationId={location.values.wopid}
- routeWithdrawalDetails={privatePages.operationDetails}
- purpose="after-creation"
- onOperationAborted={() => navigateTo(privatePages.home.url({}))}
- routeClose={privatePages.home}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- />
- );
- }
- case "solveSecondFactor": {
- return (
- <SolveChallengePage
- onChallengeCompleted={() => navigateTo(privatePages.home.url({}))}
- routeClose={privatePages.home}
- />
- );
- }
- case "publicAccountList": {
- return <PublicHistoriesPage />;
- }
- case "statsDownload": {
- return <DownloadStats routeCancel={privatePages.home} />;
- }
- case "accountCreate": {
- return (
- <CreateNewAccount
- routeCancel={privatePages.home}
- onCreateSuccess={() => navigateTo(privatePages.home.url({}))}
- />
- );
- }
- case "accountDetails": {
- return (
- <ShowAccountDetails
- account={location.values.account}
- onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
- routeHere={privatePages.accountDetails}
- routeMyAccountCashout={privatePages.myAccountCashouts}
- routeMyAccountDelete={privatePages.myAccountDelete}
- routeMyAccountDetails={privatePages.myAccountDetails}
- routeMyAccountPassword={privatePages.myAccountPassword}
- routeConversionConfig={privatePages.conversionConfig}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeClose={privatePages.home}
- />
- );
- }
- case "accountChangePassword": {
- return (
- <UpdateAccountPassword
- focus
- account={location.values.account}
- routeHere={privatePages.accountChangePassword}
- onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
- routeMyAccountCashout={privatePages.myAccountCashouts}
- routeMyAccountDelete={privatePages.myAccountDelete}
- routeMyAccountDetails={privatePages.myAccountDetails}
- routeMyAccountPassword={privatePages.myAccountPassword}
- routeConversionConfig={privatePages.conversionConfig}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeClose={privatePages.home}
- />
- );
- }
- case "accountDelete": {
- return (
- <RemoveAccount
- account={location.values.account}
- routeHere={privatePages.accountDelete}
- onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeCancel={privatePages.home}
- />
- );
- }
- case "accountCashouts": {
- return (
- <CashoutListForAccount
- account={location.values.account}
- routeCreateCashout={privatePages.cashoutCreate}
- routeCashoutDetails={privatePages.cashoutDetails}
- routeClose={privatePages.home}
- routeMyAccountCashout={privatePages.myAccountCashouts}
- routeMyAccountDelete={privatePages.myAccountDelete}
- routeMyAccountDetails={privatePages.myAccountDetails}
- routeMyAccountPassword={privatePages.myAccountPassword}
- routeConversionConfig={privatePages.conversionConfig}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- />
- );
- }
- case "myAccountDelete": {
- return (
- <RemoveAccount
- account={username}
- routeHere={privatePages.accountDelete}
- onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeCancel={privatePages.home}
- />
- );
- }
- case "myAccountDetails": {
- return (
- <ShowAccountDetails
- account={username}
- routeHere={privatePages.accountDetails}
- onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
- routeMyAccountCashout={privatePages.myAccountCashouts}
- routeConversionConfig={privatePages.conversionConfig}
- routeMyAccountDelete={privatePages.myAccountDelete}
- routeMyAccountDetails={privatePages.myAccountDetails}
- routeMyAccountPassword={privatePages.myAccountPassword}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeClose={privatePages.home}
- />
- );
- }
- case "myAccountPassword": {
- return (
- <UpdateAccountPassword
- focus
- account={username}
- routeHere={privatePages.accountChangePassword}
- onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
- routeMyAccountCashout={privatePages.myAccountCashouts}
- routeMyAccountDelete={privatePages.myAccountDelete}
- routeMyAccountDetails={privatePages.myAccountDetails}
- routeMyAccountPassword={privatePages.myAccountPassword}
- routeConversionConfig={privatePages.conversionConfig}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeClose={privatePages.home}
- />
- );
- }
- case "myAccountCashouts": {
- return (
- <CashoutListForAccount
- account={username}
- routeCashoutDetails={privatePages.cashoutDetails}
- routeCreateCashout={privatePages.cashoutCreate}
- routeMyAccountCashout={privatePages.myAccountCashouts}
- routeMyAccountDelete={privatePages.myAccountDelete}
- routeMyAccountDetails={privatePages.myAccountDetails}
- routeMyAccountPassword={privatePages.myAccountPassword}
- routeConversionConfig={privatePages.conversionConfig}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeClose={privatePages.home}
- />
- );
- }
- case "home": {
- if (isAdmin) {
- return (
- <AdminHome
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeCreate={privatePages.accountCreate}
- routeRemoveAccount={privatePages.accountDelete}
- routeShowAccount={privatePages.accountDetails}
- routeShowCashoutsAccount={privatePages.accountCashouts}
- routeUpdatePasswordAccount={privatePages.accountChangePassword}
- routeCreateWireTransfer={privatePages.wireTranserCreate}
- routeDownloadStats={privatePages.statsDownload}
- />
- );
- }
- return (
- <AccountPage
- account={username}
- tab={undefined}
- routeCreateWireTransfer={privatePages.wireTranserCreate}
- routePublicAccounts={privatePages.publicAccountList}
- routeOperationDetails={privatePages.startOperation}
- routeChargeWallet={privatePages.homeChargeWallet}
- routeWireTransfer={privatePages.homeWireTransfer}
- routeSolveSecondFactor={privatePages.solveSecondFactor}
- routeCashout={privatePages.myAccountCashouts}
- routeClose={privatePages.home}
- onClose={() => navigateTo(privatePages.home.url({}))}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- onOperationCreated={(wopid) =>
- navigateTo(privatePages.startOperation.url({ wopid }))
- }
- />
- );
- }
- case "cashoutCreate": {
- return (
- <CreateCashout
- account={username}
- routeHere={privatePages.cashoutCreate}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeClose={privatePages.home}
- />
- );
- }
- case "cashoutDetails": {
- return (
- <ShowCashoutDetails
- id={location.values.cid}
- routeClose={privatePages.myAccountCashouts}
- />
- );
- }
- case "wireTranserCreate": {
- return (
- <WireTransfer
- toAccount={location.values.account}
- withAmount={location.values.amount}
- withSubject={location.values.subject}
- routeHere={privatePages.wireTranserCreate}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- routeCancel={privatePages.home}
- onSuccess={() => navigateTo(privatePages.home.url({}))}
- />
- );
- }
- case "homeChargeWallet": {
- return (
- <AccountPage
- account={username}
- tab="charge-wallet"
- routeChargeWallet={privatePages.homeChargeWallet}
- routeWireTransfer={privatePages.homeWireTransfer}
- routeCreateWireTransfer={privatePages.wireTranserCreate}
- routePublicAccounts={privatePages.publicAccountList}
- routeOperationDetails={privatePages.startOperation}
- routeCashout={privatePages.myAccountCashouts}
- routeSolveSecondFactor={privatePages.solveSecondFactor}
- routeClose={privatePages.home}
- onClose={() => navigateTo(privatePages.home.url({}))}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- onOperationCreated={(wopid) =>
- navigateTo(privatePages.startOperation.url({ wopid }))
- }
- />
- );
- }
- case "conversionConfig": {
- return <ConversionConfig
- routeMyAccountCashout={privatePages.myAccountCashouts}
- routeMyAccountDelete={privatePages.myAccountDelete}
- routeMyAccountDetails={privatePages.myAccountDetails}
- routeMyAccountPassword={privatePages.myAccountPassword}
- routeConversionConfig={privatePages.conversionConfig}
- routeCancel={privatePages.home}
- onUpdateSuccess={() => {
- navigateTo(privatePages.home.url({}))
- }}
- />;
- }
- case "homeWireTransfer": {
- return (
- <AccountPage
- account={username}
- tab="wire-transfer"
- routeChargeWallet={privatePages.homeChargeWallet}
- routeWireTransfer={privatePages.homeWireTransfer}
- routeCreateWireTransfer={privatePages.wireTranserCreate}
- routePublicAccounts={privatePages.publicAccountList}
- routeOperationDetails={privatePages.startOperation}
- routeSolveSecondFactor={privatePages.solveSecondFactor}
- routeCashout={privatePages.myAccountCashouts}
- routeClose={privatePages.home}
- onClose={() => navigateTo(privatePages.home.url({}))}
- onAuthorizationRequired={() =>
- navigateTo(privatePages.solveSecondFactor.url({}))
- }
- onOperationCreated={(wopid) =>
- navigateTo(privatePages.startOperation.url({ wopid }))
- }
- />
- );
- }
- default:
- assertUnreachable(location);
- }
-}
diff --git a/packages/demobank-ui/src/app.tsx b/packages/demobank-ui/src/app.tsx
deleted file mode 100644
index 3a7fafccf..000000000
--- a/packages/demobank-ui/src/app.tsx
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- canonicalizeBaseUrl,
- getGlobalLogLevel,
- setGlobalLogLevelFromString,
-} from "@gnu-taler/taler-util";
-import { Loading, TranslationProvider } from "@gnu-taler/web-util/browser";
-import { h } from "preact";
-import { useEffect, useState } from "preact/hooks";
-import { SWRConfig } from "swr";
-import { Routing } from "./Routing.js";
-import { BankCoreApiProvider } from "./context/config.js";
-import { BrowserHashNavigationProvider } from "./context/navigation.js";
-import { SettingsProvider } from "./context/settings.js";
-import { TalerWalletIntegrationBrowserProvider } from "./context/wallet-integration.js";
-import { strings } from "./i18n/strings.js";
-import { BankFrame } from "./pages/BankFrame.js";
-import { BankUiSettings, fetchSettings } from "./settings.js";
-const WITH_LOCAL_STORAGE_CACHE = false;
-
-export function App() {
- const [settings, setSettings] = useState<BankUiSettings>();
- useEffect(() => {
- fetchSettings(setSettings);
- }, []);
- if (!settings) return <Loading />;
-
- const baseUrl = getInitialBackendBaseURL(settings.backendBaseURL);
- return (
- <SettingsProvider value={settings}>
- <TranslationProvider
- source={strings}
- completeness={{
- es: strings["es"].completeness,
- de: strings["de"].completeness,
- }}
- >
- <BankCoreApiProvider baseUrl={baseUrl} frameOnError={BankFrame}>
- <SWRConfig
- value={{
- provider: WITH_LOCAL_STORAGE_CACHE
- ? localStorageProvider
- : undefined,
- // normally, do not revalidate
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- revalidateIfStale: false,
- revalidateOnMount: undefined,
- focusThrottleInterval: undefined,
-
- // normally, do not refresh
- refreshInterval: undefined,
- dedupingInterval: 2000,
- refreshWhenHidden: false,
- refreshWhenOffline: false,
-
- // ignore errors
- shouldRetryOnError: false,
- errorRetryCount: 0,
- errorRetryInterval: undefined,
-
- // do not go to loading again if already has data
- keepPreviousData: true,
- }}
- >
- <TalerWalletIntegrationBrowserProvider>
- <BrowserHashNavigationProvider>
- <Routing />
- </BrowserHashNavigationProvider>
- </TalerWalletIntegrationBrowserProvider>
- </SWRConfig>
- </BankCoreApiProvider>
- </TranslationProvider>
- </SettingsProvider>
- );
-};
-
-// @ts-expect-error creating a new property for window object
-window.setGlobalLogLevelFromString = setGlobalLogLevelFromString;
-// @ts-expect-error creating a new property for window object
-window.getGlobalLevel = getGlobalLogLevel;
-
-function localStorageProvider(): Map<unknown, unknown> {
- const map = new Map(JSON.parse(localStorage.getItem("app-cache") || "[]"));
-
- window.addEventListener("beforeunload", () => {
- const appCache = JSON.stringify(Array.from(map.entries()));
- localStorage.setItem("app-cache", appCache);
- });
- return map;
-}
-
-function getInitialBackendBaseURL(
- backendFromSettings: string | undefined,
-): string {
- const overrideUrl =
- typeof localStorage !== "undefined"
- ? localStorage.getItem("corebank-api-base-url")
- : undefined;
- let result: string;
-
- if (!overrideUrl) {
- // normal path
- if (!backendFromSettings) {
- console.error(
- "ERROR: backendBaseURL was overridden by a setting file and missing. Setting value to 'window.origin'",
- );
- result = window.origin;
- } else {
- result = backendFromSettings;
- }
- } else {
- // testing/development path
- result = overrideUrl;
- }
- try {
- return canonicalizeBaseUrl(result);
- } catch (e) {
- // fall back
- return canonicalizeBaseUrl(window.origin);
- }
-}
diff --git a/packages/demobank-ui/src/assets/empty.png b/packages/demobank-ui/src/assets/empty.png
deleted file mode 100644
index 5120d3138..000000000
--- a/packages/demobank-ui/src/assets/empty.png
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/example/id1.jpg b/packages/demobank-ui/src/assets/example/id1.jpg
deleted file mode 100644
index 5d022a379..000000000
--- a/packages/demobank-ui/src/assets/example/id1.jpg
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/favicon.ico b/packages/demobank-ui/src/assets/favicon.ico
deleted file mode 100644
index 07419145b..000000000
--- a/packages/demobank-ui/src/assets/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/icons/android-chrome-192x192.png b/packages/demobank-ui/src/assets/icons/android-chrome-192x192.png
deleted file mode 100644
index 93ebe2e2c..000000000
--- a/packages/demobank-ui/src/assets/icons/android-chrome-192x192.png
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/icons/android-chrome-512x512.png b/packages/demobank-ui/src/assets/icons/android-chrome-512x512.png
deleted file mode 100644
index 52d1623ea..000000000
--- a/packages/demobank-ui/src/assets/icons/android-chrome-512x512.png
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/icons/apple-touch-icon.png b/packages/demobank-ui/src/assets/icons/apple-touch-icon.png
deleted file mode 100644
index 254e4bb4d..000000000
--- a/packages/demobank-ui/src/assets/icons/apple-touch-icon.png
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/icons/favicon-16x16.png b/packages/demobank-ui/src/assets/icons/favicon-16x16.png
deleted file mode 100644
index e81177dcb..000000000
--- a/packages/demobank-ui/src/assets/icons/favicon-16x16.png
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/icons/favicon-32x32.png b/packages/demobank-ui/src/assets/icons/favicon-32x32.png
deleted file mode 100644
index 40e9b5b47..000000000
--- a/packages/demobank-ui/src/assets/icons/favicon-32x32.png
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/icons/languageicon.svg b/packages/demobank-ui/src/assets/icons/languageicon.svg
deleted file mode 100644
index 22d58da65..000000000
--- a/packages/demobank-ui/src/assets/icons/languageicon.svg
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 2411.2 2794" style="enable-background:new 0 0 2411.2 2794;" xml:space="preserve">
-<style type="text/css">
- .st0{fill:#FFFFFF;}
- .st1{fill-rule:evenodd;clip-rule:evenodd;}
- .st2{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
-</style>
-<g id="Layer_2">
-</g>
-<g id="Layer_x5F_1_x5F_1">
- <g>
- <polygon points="1204.6,359.2 271.8,30 271.8,2060.1 1204.6,1758.3 "/>
- <polygon class="st0" points="1182.2,358.1 2150.6,29 2150.6,2059 1182.2,1757.3 "/>
- <polygon class="st0" points="30,2415.4 1182.2,2031.4 1182.2,357.9 30,742 "/>
- <polygon points="1707.2,2440.7 1870.5,2709.4 1956.6,2459.8 "/>
- <g>
- <path d="M421.7,934.8c-6.1-6,8,49.1,27.6,68.9c34.8,35.1,61.9,39.6,76.4,40.2c32,1.3,71.5-8,94.9-17.8
- c22.7-9.7,62.4-30,77.5-59.6c3.2-6.3,11.9-17,6.4-43.2c-4.2-20.2-17-27.3-32.7-26.2c-15.7,1.1-63.2,13.7-86.1,20.8
- c-23,7-70.3,21.4-90.9,25.8C474.3,948.2,429,941.7,421.7,934.8z"/>
- <path d="M1003.1,1593.7c-9.1-3.3-196.9-81.1-223.6-93.9c-21.8-10.5-75.2-33.1-100.4-43.3c70.8-109.2,115.5-191.6,121.5-204.1
- c11-23,86-169.6,87.7-178.7c1.7-9.1,3.8-42.9,2.2-51c-1.7-8.2-29.1,7.6-66.4,20.2c-37.4,12.6-108.4,58.8-135.8,64.6
- c-27.5,5.7-115.5,39.1-160.5,54c-45,14.9-130.2,40.9-165.2,50.4c-35.1,9.5-65.7,10.2-85.3,16.2c0,0,2.6,27.5,7.8,35.7
- c5.2,8.2,23.7,28.4,45.3,34.1c21.6,5.7,57.3,3.4,73.6-0.3c16.3-3.8,44.4-17.5,48.2-23.6c3.8-6.1-2-24.9,4.5-30.6
- c6.5-5.6,92.2-25.7,124.6-35.4c32.4-10,156.3-52.6,173.1-50.5c-5.3,17.7-105,215.1-137.1,274c-32.1,58.9-218.6,318-258.3,363.6
- c-30.1,34.7-103.2,123.5-128.5,143.6c6.4,1.8,51.6-2.1,59.9-7.2c51.3-31.6,136.9-138.1,164.4-170.5
- c81.9-96,153.8-196.8,210.8-283.4h0.1c11.1,4.6,100.9,77.8,124.4,94c23.4,16.2,115.9,67.8,136,76.4c20,8.7,97.1,44.2,100.3,32.2
- C1029.4,1668,1012.2,1597.1,1003.1,1593.7z"/>
- </g>
- <path class="st1" d="M569,2572c18,11,35,20,54,29c38,19,81,39,122,54c56,21,112,38,168,51c31,7,65,13,98,18c3,0,92,11,110,11h90
- c35-3,68-5,103-10c28-4,59-9,89-16c22-5,45-10,67-17c21-6,45-14,68-22c15-5,31-12,47-18c13-6,29-13,44-19c18-8,39-19,59-29
- c16-8,34-18,51-28c13-7,43-30,59-30c18,0,30,16,30,30c0,29-39,38-57,51c-19,13-42,23-62,34c-40,21-81,39-120,54
- c-51,19-107,37-157,49c-19,4-38,9-57,12c-10,2-114,18-143,18h-132c-35-3-72-7-107-12c-31-5-64-11-95-18c-24-5-50-12-73-19
- c-40-11-79-25-117-40c-69-26-141-60-209-105c-12-8-13-16-13-25c0-15,11-29,29-29C531,2546,563,2569,569,2572z"/>
- <path class="st1" d="M1151,2009L61,2372V764l1090-363V2009z M1212,354v1680c-1,5-3,10-7,15c-2,3-6,7-9,8c-25,10-1151,388-1166,388
- c-12,0-23-8-29-21c0-1-1-2-1-4V739c2-5,3-12,7-16c8-11,22-13,31-16c17-6,1126-378,1142-378C1190,329,1212,336,1212,354z"/>
- <path class="st1" d="M2120,2017l-907-282V380l907-308V2017z M2181,32v2023c-1,23-17,33-32,33c-13,0-107-32-123-37
- c-126-39-253-78-378-117c-28-9-57-18-84-27c-24-7-50-15-74-23c-107-33-216-66-323-102c-4-1-14-15-14-18V351c2-5,4-11,9-15
- c8-9,351-123,486-168c36-13,487-168,501-168C2167,0,2181,13,2181,32z"/>
- <polygon points="2411.2,2440.7 1199.5,2054.5 1204.6,373.2 2411.2,757.2 "/>
- <g>
- <path class="st2" d="M1800.3,1124.6L1681.4,1412l218.6,66.3L1800.3,1124.6z M1729,853.2l156.1,47.3l284.4,1025l-160.3-48.7
- l-57.6-210.4L1620.2,1566l-71.3,171.4l-160.4-48.7L1729,853.2z"/>
- </g>
- </g>
-</g>
-</svg>
diff --git a/packages/demobank-ui/src/assets/icons/mstile-150x150.png b/packages/demobank-ui/src/assets/icons/mstile-150x150.png
deleted file mode 100644
index 9cfb889be..000000000
--- a/packages/demobank-ui/src/assets/icons/mstile-150x150.png
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/assets/logo-2021.svg b/packages/demobank-ui/src/assets/logo-2021.svg
deleted file mode 100644
index 8c5ff3e5b..000000000
--- a/packages/demobank-ui/src/assets/logo-2021.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 201 90">
- <g fill="#0042b3" fill-rule="evenodd" stroke-width=".3">
- <path d="M86.7 1.1c15.6 0 29 9.4 36 23.2h-5.9A35.1 35.1 0 0086.7 6.5C67 6.5 51 23.6 51 44.7c0 10.4 3.8 19.7 10 26.6a31.4 31.4 0 01-4.2 3A45.2 45.2 0 0146 44.7c0-24 18.2-43.6 40.7-43.6zm35.8 64.3a40.4 40.4 0 01-39 22.8c3-1.5 6-3.5 8.6-5.7a35.6 35.6 0 0024.6-17.1z" />
- <path d="M64.2 1.1l3.1.1c-3 1.6-5.9 3.5-8.5 5.8a37.5 37.5 0 00-30.2 37.7c0 14.3 7.3 26.7 18 33.3a29.6 29.6 0 01-8.5.2c-9-8-14.6-20-14.6-33.5 0-24 18.2-43.6 40.7-43.6zm5.4 81.4a35.6 35.6 0 0024.6-17.1h5.9a40.4 40.4 0 01-39 22.8c3-1.5 5.9-3.5 8.5-5.7zm24.8-58.2a37 37 0 00-12.6-12.8 29.6 29.6 0 018.5-.2c4 3.6 7.4 8 9.9 13z" />
- <path d="M41.8 1.1c1 0 2 0 3.1.2-3 1.5-5.9 3.4-8.5 5.6A37.5 37.5 0 006.1 44.7c0 21.1 16 38.3 35.7 38.3 12.6 0 23.6-7 30-17.6h5.8a40.4 40.4 0 01-35.8 23C19.3 88.4 1 68.8 1 44.7c0-24 18.2-43.6 40.7-43.6zm30.1 23.2a38.1 38.1 0 00-4.5-6.1c1.3-1.2 2.7-2.2 4.3-3 2.3 2.7 4.4 5.8 6 9.1z" />
- </g>
- <path d="M76.1 34.4h9.2v-5H61.9v5H71v26h5.1zM92.6 52.9h13.7l3 7.4h5.3l-12.7-31.2h-4.7L84.5 60.3h5.2zm11.8-4.9h-9.9l5-12.4zM123.8 29.4h-4.6v31h20.6v-5h-16zM166.5 29.4H145v31h21.6v-5H150v-8.3h14.5v-4.9h-14.5v-8h16.4zM191.2 39.5c0 1.6-.5 2.8-1.6 3.8s-2.6 1.4-4.4 1.4h-7.4V34.3h7.4c1.9 0 3.4.4 4.4 1.3 1 .9 1.6 2.2 1.6 3.9zm6 20.8l-7.7-11.7c1-.3 1.9-.7 2.7-1.3a8.8 8.8 0 003.6-4.6c.4-1 .5-2.2.5-3.5 0-1.5-.2-2.9-.7-4.1a8.4 8.4 0 00-2.1-3.1c-1-.8-2-1.5-3.4-2-1.3-.4-2.8-.6-4.5-.6h-12.9v31h5V49.4h6.5l7 10.8z" />
-</svg> \ No newline at end of file
diff --git a/packages/demobank-ui/src/assets/logo-white.svg b/packages/demobank-ui/src/assets/logo-white.svg
deleted file mode 100644
index cb1f023c5..000000000
--- a/packages/demobank-ui/src/assets/logo-white.svg
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- width="670"
- height="300"
- viewBox="0 0 201 90"
- version="1.1"
- id="svg8">
- <g
- id="logo">
- <g
- id="circles"
- style="fill:#FFF;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.327943">
- <path
- d="m 86.662153,1.1211936 c 15.589697,0 29.129227,9.4011664 35.961027,23.2018054 h -5.81736 C 110.4866,13.623304 99.349002,6.5180852 86.662153,6.5180852 c -19.690571,0 -35.652876,17.1120008 -35.652876,38.2205688 0,10.331797 3.825597,19.704678 10.03957,26.582945 -1.342357,1.120912 -2.771532,2.127905 -4.275488,3.006754 C 50.071485,66.553412 45.974857,56.15992 45.974857,44.738654 c 0,-24.089211 18.216325,-43.6174604 40.687296,-43.6174604 z M 122.51416,65.375898 c -6.86645,13.680134 -20.34561,22.980218 -35.852007,22.980218 -1.052702,0 -2.096093,-0.04291 -3.128683,-0.127026 3.052192,-1.561167 5.913582,-3.480387 8.538307,-5.707305 10.320963,-1.684389 19.185983,-8.113638 24.601813,-17.145887 z"
- id="path2350" />
- <path
- d="m 64.212372,1.1211936 c 1.052607,0 2.095998,0.042919 3.128684,0.1270583 C 64.288864,2.8094199 61.427378,4.728606 58.802653,6.9555572 41.679542,9.7498571 28.559494,25.601563 28.559494,44.738654 c 0,14.264563 7.29059,26.702023 18.093843,33.268925 -1.593656,0.26719 -3.226966,0.406948 -4.890748,0.406948 -1.239545,0 -2.46151,-0.07952 -3.663522,-0.229364 C 29.191129,70.184015 23.525076,58.171633 23.525076,44.738654 23.525076,20.649443 41.7414,1.1211936 64.212372,1.1211936 Z M 69.62209,82.521785 C 79.943207,80.837396 88.808164,74.407841 94.224059,65.375422 h 5.840511 c -6.866354,13.680305 -20.345548,22.980694 -35.852198,22.980694 -1.052703,0 -2.095999,-0.04291 -3.128684,-0.127026 3.052002,-1.561371 5.913836,-3.480218 8.538402,-5.707305 z M 94.355885,24.322999 c -3.13939,-5.314721 -7.467551,-9.74275 -12.584511,-12.853269 1.593656,-0.26719 3.226904,-0.406948 4.890779,-0.406948 1.239451,0 2.461512,0.07952 3.663524,0.229364 4.016018,3.607242 7.373195,8.030111 9.849053,13.030853 z"
- id="path2352" />
- <path
- d="m 41.762589,1.1211936 c 1.064296,0 2.118804,0.044379 3.162607,0.1302161 -3.046523,1.558961 -5.903162,3.4745139 -8.52358,5.6968133 C 19.254624,9.7205882 6.1097128,25.583465 6.1097128,44.738654 c 0,21.108568 15.9624012,38.22057 35.6528762,38.22057 12.599746,0 23.672446,-7.007056 30.013748,-17.583802 h 5.838515 C 70.748498,79.055727 57.26924,88.356116 41.762589,88.356116 c -22.470907,0 -40.6871998,-19.52825 -40.6871998,-43.617462 0,-24.089211 18.2162928,-43.6174604 40.6871998,-43.6174604 z M 71.905375,24.322999 c -1.31192,-2.220567 -2.830984,-4.287049 -4.528877,-6.166508 1.342452,-1.120945 2.771374,-2.128381 4.275139,-3.00723 2.372984,2.753011 4.418875,5.834636 6.072489,9.173738 z"
- id="path2354" />
- </g>
- <g
- id="letters"
- style="fill:#FFF">
- <path
- d="m 76.135411,34.409066 h 9.161042 V 29.36588 H 61.857537 v 5.043186 h 9.161137 v 25.92317 h 5.116737 z"
- id="path2346" />
- <path
- d="m 92.647571,52.856334 h 13.659009 l 2.93009,7.476072 h 5.36461 L 101.89122,29.144903 H 97.187186 L 84.477089,60.332406 h 5.199533 z m 11.802109,-4.822276 h -9.944771 l 4.951718,-12.386462 z"
- id="path2362" />
- <path
- d="m 123.80641,29.366084 h -4.58038 v 30.966322 h 20.54728 v -4.910253 c -5.32227,0 -10.64463,0 -15.9669,0 z"
- id="path2356" />
- <path
- d="m 166.4722,29.366084 h -21.37564 v 30.966322 h 21.58203 v -4.910253 h -16.54771 v -8.27275 h 14.48439 V 42.23925 h -14.48439 v -7.962811 h 16.34132 z"
- id="path2360" />
- <path
- d="m 191.19035,39.474593 c 0,1.59947 -0.53646,2.87535 -1.61628,3.818883 -1.07281,0.95124 -2.52409,1.422837 -4.34678,1.422837 h -7.44851 V 34.276439 h 7.4073 c 1.9051,0 3.38376,0.435027 4.42939,1.312178 1.05226,0.870258 1.57488,2.167734 1.57488,3.885976 z m 6.06602,20.857813 -7.79911,-11.723191 c 1.01771,-0.294794 1.94631,-0.714813 2.78553,-1.260566 0.83885,-0.545619 1.56122,-1.209263 2.16629,-1.990627 0.60541,-0.781738 1.07981,-1.681096 1.42369,-2.698345 0.34378,-1.017553 0.51561,-2.175238 0.51561,-3.472883 0,-1.50409 -0.24743,-2.867948 -0.74267,-4.092048 -0.49515,-1.223794 -1.20344,-2.256186 -2.12499,-3.096734 -0.92173,-0.840446 -2.04957,-1.489252 -3.38375,-1.946452 -1.33447,-0.457267 -2.82692,-0.685476 -4.4774,-0.685476 h -12.87512 v 30.966322 h 5.03433 V 49.538522 h 6.37569 l 7.11829,10.793884 z"
- id="path2358" />
- </g>
- </g>
-</svg>
diff --git a/packages/demobank-ui/src/assets/logo.jpeg b/packages/demobank-ui/src/assets/logo.jpeg
deleted file mode 100644
index 489832f7c..000000000
--- a/packages/demobank-ui/src/assets/logo.jpeg
+++ /dev/null
Binary files differ
diff --git a/packages/demobank-ui/src/components/Cashouts/index.ts b/packages/demobank-ui/src/components/Cashouts/index.ts
deleted file mode 100644
index 2c6bf681c..000000000
--- a/packages/demobank-ui/src/components/Cashouts/index.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { Loading, utils } from "@gnu-taler/web-util/browser";
-import {
- AbsoluteTime,
- AmountJson,
- TalerCoreBankErrorsByMethod,
- TalerCorebankApi,
- TalerError,
-} from "@gnu-taler/taler-util";
-import { ErrorLoadingWithDebug } from "../ErrorLoadingWithDebug.js";
-import { useComponentState } from "./state.js";
-import { FailedView, ReadyView } from "./views.js";
-import { RouteDefinition } from "../../route.js";
-
-export interface Props {
- account: string;
- routeCashoutDetails: RouteDefinition<{ cid: string }>;
-}
-
-export type State =
- | State.Loading
- | State.Failed
- | State.LoadingUriError
- | State.Ready;
-
-export namespace State {
- export interface Loading {
- status: "loading";
- error: undefined;
- }
-
- export interface LoadingUriError {
- status: "loading-error";
- error: TalerError;
- }
-
- export interface Failed {
- status: "failed";
- error: TalerCoreBankErrorsByMethod<"getAccountCashouts">;
- }
-
- export interface BaseInfo {
- error: undefined;
- }
- export interface Ready extends BaseInfo {
- status: "ready";
- error: undefined;
- cashouts: (TalerCorebankApi.CashoutStatusResponse & { id: number })[];
- routeCashoutDetails: RouteDefinition<{ cid: string }>;
- }
-}
-
-export interface Transaction {
- negative: boolean;
- counterpart: string;
- when: AbsoluteTime;
- amount: AmountJson | undefined;
- subject: string;
-}
-
-const viewMapping: utils.StateViewMap<State> = {
- loading: Loading,
- "loading-error": ErrorLoadingWithDebug,
- failed: FailedView,
- ready: ReadyView,
-};
-
-export const Cashouts = utils.compose(
- (p: Props) => useComponentState(p),
- viewMapping,
-);
diff --git a/packages/demobank-ui/src/components/Cashouts/state.ts b/packages/demobank-ui/src/components/Cashouts/state.ts
deleted file mode 100644
index 8616faa1b..000000000
--- a/packages/demobank-ui/src/components/Cashouts/state.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { TalerError } from "@gnu-taler/taler-util";
-import { useCashouts } from "../../hooks/regional.js";
-import { Props, State } from "./index.js";
-
-export function useComponentState({
- account,
- routeCashoutDetails,
-}: Props): State {
- const result = useCashouts(account);
- if (!result) {
- return {
- status: "loading",
- error: undefined,
- };
- }
- if (result instanceof TalerError) {
- return {
- status: "loading-error",
- error: result,
- };
- }
- if (result.type === "fail") {
- return {
- status: "failed",
- error: result,
- };
- }
-
- return {
- status: "ready",
- error: undefined,
- cashouts: result.body.cashouts,
- routeCashoutDetails,
- };
-}
diff --git a/packages/demobank-ui/src/components/Cashouts/stories.tsx b/packages/demobank-ui/src/components/Cashouts/stories.tsx
deleted file mode 100644
index 37ab64108..000000000
--- a/packages/demobank-ui/src/components/Cashouts/stories.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { ReadyView } from "./views.js";
-
-export default {
- title: "transaction list",
-};
-
-export const Ready = tests.createExample(ReadyView, {});
diff --git a/packages/demobank-ui/src/components/Cashouts/test.ts b/packages/demobank-ui/src/components/Cashouts/test.ts
deleted file mode 100644
index 4bd6b5eac..000000000
--- a/packages/demobank-ui/src/components/Cashouts/test.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { SwrMockEnvironment } from "@gnu-taler/web-util/testing";
-import { expect } from "chai";
-import { Props } from "./index.js";
-import { useComponentState } from "./state.js";
-import { buildNullRoutDefinition } from "../../route.js";
-
-describe("Cashout states", () => {
- it.skip("should query backend and render transactions", async () => {
- const env = new SwrMockEnvironment();
-
- const props: Props = {
- account: "123",
- routeCashoutDetails: buildNullRoutDefinition(),
- };
-
- // env.addRequestExpectation(CASHOUT_API_EXAMPLE.LIST_FIRST_PAGE, {
- // response: {
- // cashouts: [],
- // },
- // });
-
- // env.addRequestExpectation(CASHOUT_API_EXAMPLE.MULTI_GET_EMPTY_FIRST_PAGE, {
- // response: [],
- // });
-
- const hookBehavior = await tests.hookBehaveLikeThis(
- useComponentState,
- props,
- [
- ({ status, error }) => {
- expect(status).equals("loading");
- expect(error).undefined;
- },
- ({ status, error }) => {
- expect(status).equals("ready");
- expect(error).undefined;
- },
- ],
- env.buildTestingContext(),
- );
-
- expect(hookBehavior).deep.eq({ result: "ok" });
-
- expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
- });
-});
diff --git a/packages/demobank-ui/src/components/Cashouts/views.tsx b/packages/demobank-ui/src/components/Cashouts/views.tsx
deleted file mode 100644
index 7f16d5840..000000000
--- a/packages/demobank-ui/src/components/Cashouts/views.tsx
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- Amounts,
- Duration,
- HttpStatusCode,
- TalerError,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- Loading,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
-import { Fragment, VNode, h } from "preact";
-import { useConversionInfo } from "../../hooks/regional.js";
-import { RenderAmount } from "../../pages/PaytoWireTransferForm.js";
-import { ErrorLoadingWithDebug } from "../ErrorLoadingWithDebug.js";
-import { State } from "./index.js";
-import { Time } from "../Time.js";
-
-export function FailedView({ error }: State.Failed) {
- const { i18n } = useTranslationContext();
- switch (error.case) {
- case HttpStatusCode.NotImplemented: {
- return (
- <Attention
- type="danger"
- title={i18n.str`Cashout are disabled`}
- >
- <i18n.Translate>Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.</i18n.Translate>
- </Attention>
- );
- }
- default:
- assertUnreachable(error.case);
- }
-}
-
-export function ReadyView({
- cashouts,
- routeCashoutDetails,
-}: State.Ready): VNode {
- const { i18n, dateLocale } = useTranslationContext();
- const resp = useConversionInfo();
- if (!resp) {
- return <Loading />;
- }
- if (resp instanceof TalerError) {
- return <ErrorLoadingWithDebug error={resp} />;
- }
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.NotImplemented: {
- return (
- <Attention
- type="danger"
- title={i18n.str`Cashout are disabled`}
- >
- <i18n.Translate>Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.</i18n.Translate>
- </Attention>
- );
- }
- default:
- assertUnreachable(resp.case);
- }
- }
-
- if (!cashouts.length) return <div />;
- const txByDate = cashouts.reduce(
- (prev, cur) => {
- const d =
- cur.creation_time.t_s === "never"
- ? ""
- : format(cur.creation_time.t_s * 1000, "dd/MM/yyyy", {
- locale: dateLocale,
- });
- if (!prev[d]) {
- prev[d] = [];
- }
- prev[d].push(cur);
- return prev;
- },
- {} as Record<string, typeof cashouts>,
- );
- return (
- <div class="px-4 mt-4">
- <div class="sm:flex sm:items-center">
- <div class="sm:flex-auto">
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Latest cashouts</i18n.Translate>
- </h1>
- </div>
- </div>
- <div class="-mx-4 mt-5 ring-1 ring-gray-300 sm:mx-0 rounded-lg min-w-fit bg-white">
- <table class="min-w-full divide-y divide-gray-300">
- <thead>
- <tr>
- <th
- scope="col"
- class=" pl-2 py-3.5 text-left text-sm font-semibold text-gray-900"
- >{i18n.str`Created`}</th>
- <th
- scope="col"
- class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900"
- >{i18n.str`Total debit`}</th>
- <th
- scope="col"
- class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900"
- >{i18n.str`Total credit`}</th>
- <th
- scope="col"
- class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900"
- >{i18n.str`Subject`}</th>
- </tr>
- </thead>
- <tbody>
- {Object.entries(txByDate).map(([date, txs], idx) => {
- return (
- <Fragment key={idx}>
- <tr class="border-t border-gray-200">
- <th
- colSpan={6}
- scope="colgroup"
- class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3"
- >
- {date}
- </th>
- </tr>
- {txs.map((item) => {
- return (
- <a
- name="cashout details"
- key={idx}
- class="table-row border-b border-gray-200 hover:bg-gray-200 last:border-none"
- // class="table-row"
- href={routeCashoutDetails.url({
- cid: String(item.id),
- })}
- >
- <td class="relative py-2 pl-2 pr-2 text-sm ">
- <div class="font-medium text-gray-900">
- <Time format="HH:mm:ss"
- timestamp={AbsoluteTime.fromProtocolTimestamp(item.creation_time)}
- // relative={Duration.fromSpec({ days: 1 })}
- />
- </div>
- {
- //FIXME: implement responsive view
- }
- {/* <dl class="font-normal sm:hidden">
- <dt class="sr-only sm:hidden"><i18n.Translate>Amount</i18n.Translate></dt>
- <dd class="mt-1 truncate text-gray-700">
- {item.negative ? i18n.str`sent` : i18n.str`received`} {item.amount ? (
- <span data-negative={item.negative ? "true" : "false"} class="data-[negative=false]:text-green-600 data-[negative=true]:text-red-600">
- <RenderAmount value={item.amount} />
- </span>
- ) : (
- <span style={{ color: "grey" }}>&lt;{i18n.str`invalid value`}&gt;</span>
- )}</dd>
-
- <dt class="sr-only sm:hidden"><i18n.Translate>Counterpart</i18n.Translate></dt>
- <dd class="mt-1 truncate text-gray-500 sm:hidden">
- {item.negative ? i18n.str`to` : i18n.str`from`} {item.counterpart}
- </dd>
- <dd class="mt-1 text-gray-500 sm:hidden" >
- <pre class="break-words w-56 whitespace-break-spaces p-2 rounded-md mx-auto my-2 bg-gray-100">
- {item.subject}
- </pre>
- </dd>
- </dl> */}
- </td>
- <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-red-600 cursor-pointer">
- <RenderAmount
- value={Amounts.parseOrThrow(item.amount_debit)}
- spec={resp.body.regional_currency_specification}
- />
- </td>
- <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-green-600 cursor-pointer">
- <RenderAmount
- value={Amounts.parseOrThrow(item.amount_credit)}
- spec={resp.body.fiat_currency_specification}
- />
- </td>
-
- <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md">
-
- {item.subject}
- </td>
- </a>
- );
- })}
- </Fragment>
- );
- })}
- </tbody>
- </table>
- </div>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/components/EmptyComponentExample/index.ts b/packages/demobank-ui/src/components/EmptyComponentExample/index.ts
deleted file mode 100644
index da84f9921..000000000
--- a/packages/demobank-ui/src/components/EmptyComponentExample/index.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { HookError, Loading, utils } from "@gnu-taler/web-util/browser";
-import { useComponentState } from "./state.js";
-import { LoadingUriView, ReadyView } from "./views.js";
-
-export interface Props {
- p: string;
-}
-
-export type State = State.Loading | State.LoadingUriError | State.Ready;
-
-export namespace State {
- export interface Loading {
- status: "loading";
- error: undefined;
- }
-
- export interface LoadingUriError {
- status: "loading-error";
- error: HookError;
- }
-
- export interface BaseInfo {
- error: undefined;
- }
- export interface Ready extends BaseInfo {
- status: "ready";
- error: undefined;
- }
-}
-
-const viewMapping: utils.StateViewMap<State> = {
- loading: Loading,
- "loading-error": LoadingUriView,
- ready: ReadyView,
-};
-
-export const ComponentName = utils.compose(
- (p: Props) => useComponentState(p),
- viewMapping,
-);
diff --git a/packages/demobank-ui/src/components/EmptyComponentExample/state.ts b/packages/demobank-ui/src/components/EmptyComponentExample/state.ts
deleted file mode 100644
index 057664983..000000000
--- a/packages/demobank-ui/src/components/EmptyComponentExample/state.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-// import { wxApi } from "../../wxApi.js";
-import { Props, State } from "./index.js";
-
-export function useComponentState({ p: _p }: Props): State {
- return {
- status: "ready",
- error: undefined,
- };
-}
diff --git a/packages/demobank-ui/src/components/EmptyComponentExample/stories.tsx b/packages/demobank-ui/src/components/EmptyComponentExample/stories.tsx
deleted file mode 100644
index 160acdf79..000000000
--- a/packages/demobank-ui/src/components/EmptyComponentExample/stories.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { ReadyView } from "./views.js";
-
-export default {
- title: "example",
-};
-
-export const Ready = tests.createExample(ReadyView, {});
diff --git a/packages/demobank-ui/src/components/EmptyComponentExample/test.ts b/packages/demobank-ui/src/components/EmptyComponentExample/test.ts
deleted file mode 100644
index 629948d91..000000000
--- a/packages/demobank-ui/src/components/EmptyComponentExample/test.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { expect } from "chai";
-
-describe("test description", () => {
- it("should assert", () => {
- expect([]).deep.equals([]);
- });
-});
diff --git a/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx b/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx
deleted file mode 100644
index 457933a5f..000000000
--- a/packages/demobank-ui/src/components/EmptyComponentExample/views.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { h, VNode } from "preact";
-
-export function LoadingUriView(): VNode {
- return <div></div>;
-}
-
-export function ReadyView(): VNode {
- return <div />;
-}
diff --git a/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx b/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx
deleted file mode 100644
index 8679af050..000000000
--- a/packages/demobank-ui/src/components/ErrorLoadingWithDebug.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import { TalerError } from "@gnu-taler/taler-util";
-import { ErrorLoading } from "@gnu-taler/web-util/browser";
-import { VNode, h } from "preact";
-import { usePreferences } from "../hooks/preferences.js";
-
-export function ErrorLoadingWithDebug({ error }: { error: TalerError }): VNode {
- const [pref] = usePreferences();
- return <ErrorLoading error={error} showDetail={pref.showDebugInfo} />;
-}
diff --git a/packages/demobank-ui/src/components/QR.tsx b/packages/demobank-ui/src/components/QR.tsx
deleted file mode 100644
index b039bbd1e..000000000
--- a/packages/demobank-ui/src/components/QR.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { h, VNode } from "preact";
-import { useEffect, useRef } from "preact/hooks";
-import qrcode from "qrcode-generator";
-
-export function QR({ text }: { text: string }): VNode {
- const divRef = useRef<HTMLDivElement>(null);
- useEffect(() => {
- const qr = qrcode(0, "L");
- qr.addData(text);
- qr.make();
- if (divRef.current)
- divRef.current.innerHTML = qr.createSvgTag({
- scalable: true,
- });
- });
-
- return (
- <div
- style={{
- display: "flex",
- flexDirection: "column",
- alignItems: "left",
- }}
- >
- <div
- style={{
- width: "100%",
- marginRight: "auto",
- marginLeft: "auto",
- }}
- ref={divRef}
- />
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/components/Time.tsx b/packages/demobank-ui/src/components/Time.tsx
deleted file mode 100644
index 39ce33f60..000000000
--- a/packages/demobank-ui/src/components/Time.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { AbsoluteTime, Duration } from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { formatISO, format, formatDuration, intervalToDuration } from "date-fns";
-import { Fragment, h, VNode } from "preact";
-
-/**
- *
- * @param timestamp time to be formatted
- * @param relative duration threshold, if the difference is lower
- * the timestamp will be formatted as relative time from "now"
- *
- * @returns
- */
-export function Time({
- timestamp,
- relative,
- format: formatString,
-}: {
- timestamp: AbsoluteTime | undefined;
- relative?: Duration,
- format: string;
-}): VNode {
- const { i18n, dateLocale } = useTranslationContext()
- if (!timestamp) return <Fragment />
-
- if (timestamp.t_ms === "never") {
- return <time >{i18n.str`never`}</time>
- }
-
- const now = AbsoluteTime.now();
- const diff = AbsoluteTime.difference(now, timestamp)
- if (relative && now.t_ms !== "never" && Duration.cmp(diff, relative) === -1) {
- const d = intervalToDuration({
- start: now.t_ms,
- end: timestamp.t_ms
- })
- d.seconds = 0
- const duration = formatDuration(d, { locale: dateLocale })
- const isFuture = AbsoluteTime.cmp(now, timestamp) < 0
- if (isFuture) {
- return <time dateTime={formatISO(timestamp.t_ms)}>
- <i18n.Translate>in {duration}</i18n.Translate>
- </time>
- } else {
- return <time dateTime={formatISO(timestamp.t_ms)}>
- <i18n.Translate>{duration} ago</i18n.Translate>
- </time>
- }
- }
- return (
- <time dateTime={formatISO(timestamp.t_ms)}>
- {format(timestamp.t_ms, formatString, { locale: dateLocale })}
- </time>
- );
-}
diff --git a/packages/demobank-ui/src/components/Transactions/index.ts b/packages/demobank-ui/src/components/Transactions/index.ts
deleted file mode 100644
index c8bb1e108..000000000
--- a/packages/demobank-ui/src/components/Transactions/index.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { AbsoluteTime, AmountJson, TalerError } from "@gnu-taler/taler-util";
-import { Loading, utils } from "@gnu-taler/web-util/browser";
-import { ErrorLoadingWithDebug } from "../ErrorLoadingWithDebug.js";
-import { useComponentState } from "./state.js";
-import { ReadyView } from "./views.js";
-import { RouteDefinition } from "../../route.js";
-
-export interface Props {
- account: string;
- routeCreateWireTransfer: RouteDefinition<{
- account?: string,
- subject?: string,
- amount?: string,
- }> | undefined;
-}
-
-export type State = State.Loading | State.LoadingUriError | State.Ready;
-
-export namespace State {
- export interface Loading {
- status: "loading";
- error: undefined;
- }
-
- export interface LoadingUriError {
- status: "loading-error";
- error: TalerError;
- }
-
- export interface BaseInfo {
- error: undefined;
- }
- export interface Ready extends BaseInfo {
- status: "ready";
- error: undefined;
- routeCreateWireTransfer: RouteDefinition<{
- account?: string,
- subject?: string,
- amount?: string,
- }> | undefined;
- transactions: Transaction[];
- onGoStart?: () => void;
- onGoNext?: () => void;
- }
-}
-
-export interface Transaction {
- negative: boolean;
- counterpart: string;
- when: AbsoluteTime;
- amount: AmountJson | undefined;
- subject: string;
-}
-
-const viewMapping: utils.StateViewMap<State> = {
- loading: Loading,
- "loading-error": ErrorLoadingWithDebug,
- ready: ReadyView,
-};
-
-export const Transactions = utils.compose(
- (p: Props) => useComponentState(p),
- viewMapping,
-);
diff --git a/packages/demobank-ui/src/components/Transactions/state.ts b/packages/demobank-ui/src/components/Transactions/state.ts
deleted file mode 100644
index 3e9103b59..000000000
--- a/packages/demobank-ui/src/components/Transactions/state.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- Amounts,
- TalerError,
- parsePaytoUri,
-} from "@gnu-taler/taler-util";
-import { useTransactions } from "../../hooks/account.js";
-import { Props, State, Transaction } from "./index.js";
-
-export function useComponentState({ account, routeCreateWireTransfer }: Props): State {
- const txResult = useTransactions(account);
- if (!txResult) {
- return {
- status: "loading",
- error: undefined,
- };
- }
- if (txResult instanceof TalerError) {
- return {
- status: "loading-error",
- error: txResult,
- };
- }
-
- const transactions =
- txResult.result
- .map((tx) => {
- const negative = tx.direction === "debit";
- const cp = parsePaytoUri(
- negative ? tx.creditor_payto_uri : tx.debtor_payto_uri,
- );
- const counterpart =
- (cp === undefined || !cp.isKnown
- ? undefined
- : cp.targetType === "iban"
- ? cp.iban
- : cp.targetType === "x-taler-bank"
- ? cp.account
- : cp.targetType === "bitcoin"
- ? `${cp.targetPath.substring(0, 6)}...`
- : undefined) ?? "unknown";
-
- const when = AbsoluteTime.fromProtocolTimestamp(tx.date);
- const amount = Amounts.parse(tx.amount);
- const subject = tx.subject;
- return {
- negative,
- counterpart,
- when,
- amount,
- subject,
- };
- })
- .filter((x): x is Transaction => x !== undefined);
-
- return {
- status: "ready",
- error: undefined,
- routeCreateWireTransfer,
- transactions,
- onGoNext: txResult.isLastPage ? undefined : txResult.loadNext,
- onGoStart: txResult.isFirstPage ? undefined : txResult.loadFirst,
- };
-}
diff --git a/packages/demobank-ui/src/components/Transactions/stories.tsx b/packages/demobank-ui/src/components/Transactions/stories.tsx
deleted file mode 100644
index 95014574b..000000000
--- a/packages/demobank-ui/src/components/Transactions/stories.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { ReadyView } from "./views.js";
-import { AbsoluteTime } from "@gnu-taler/taler-util";
-
-export default {
- title: "transaction list",
-};
-
-export const Ready = tests.createExample(ReadyView, {
- transactions: [
- {
- amount: {
- currency: "USD",
- fraction: 0,
- value: 1,
- },
- counterpart: "ASD",
- negative: false,
- subject: "Some",
- when: AbsoluteTime.now(),
- },
- ],
-});
diff --git a/packages/demobank-ui/src/components/Transactions/test.ts b/packages/demobank-ui/src/components/Transactions/test.ts
deleted file mode 100644
index d9442c742..000000000
--- a/packages/demobank-ui/src/components/Transactions/test.ts
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import { TalerErrorCode } from "@gnu-taler/taler-util";
-import * as tests from "@gnu-taler/web-util/testing";
-import { SwrMockEnvironment } from "@gnu-taler/web-util/testing";
-import { expect } from "chai";
-import { Props } from "./index.js";
-import { useComponentState } from "./state.js";
-
-describe("Transaction states", () => {
- it.skip("should query backend and render transactions", async () => {
- const env = new SwrMockEnvironment();
-
- const props: Props = {
- account: "myAccount",
- routeCreateWireTransfer: undefined,
- };
-
- // env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_FIRST_PAGE, {
- // response: {
- // data: {
- // transactions: [
- // {
- // creditorIban: "DE159593",
- // creditorBic: "SANDBOXX",
- // creditorName: "exchange company",
- // debtorIban: "DE118695",
- // debtorBic: "SANDBOXX",
- // debtorName: "Name unknown",
- // amount: "1",
- // currency: "KUDOS",
- // subject:
- // "Taler Withdrawal N588V8XE9TR49HKAXFQ20P0EQ0EYW2AC9NNANV8ZP5P59N6N0410",
- // date: "2022-12-12Z",
- // uid: "8PPFR9EM",
- // direction: "DBIT",
- // pmtInfId: null,
- // msgId: null,
- // },
- // {
- // creditorIban: "DE159593",
- // creditorBic: "SANDBOXX",
- // creditorName: "exchange company",
- // debtorIban: "DE118695",
- // debtorBic: "SANDBOXX",
- // debtorName: "Name unknown",
- // amount: "5.00",
- // currency: "KUDOS",
- // subject: "HNEWWT679TQC5P1BVXJS48FX9NW18FWM6PTK2N80Z8GVT0ACGNK0",
- // date: "2022-12-07Z",
- // uid: "7FZJC3RJ",
- // direction: "DBIT",
- // pmtInfId: null,
- // msgId: null,
- // },
- // {
- // creditorIban: "DE118695",
- // creditorBic: "SANDBOXX",
- // creditorName: "Name unknown",
- // debtorIban: "DE579516",
- // debtorBic: "SANDBOXX",
- // debtorName: "The Bank",
- // amount: "100",
- // currency: "KUDOS",
- // subject: "Sign-up bonus",
- // date: "2022-12-07Z",
- // uid: "I31A06J8",
- // direction: "CRDT",
- // pmtInfId: null,
- // msgId: null,
- // },
- // ],
- // },
- // },
- // });
-
- const hookBehavior = await tests.hookBehaveLikeThis(
- useComponentState,
- props,
- [
- ({ status, error }) => {
- expect(status).equals("loading");
- expect(error).undefined;
- },
- ({ status, error }) => {
- expect(status).equals("ready");
- expect(error).undefined;
- },
- ],
- env.buildTestingContext(),
- );
-
- expect(hookBehavior).deep.eq({ result: "ok" });
-
- expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
- });
-
- // it("should show error message on not found", async () => {
- // const env = new SwrMockEnvironment();
-
- // const props: Props = {
- // account: "myAccount",
- // };
-
- // env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_NOT_FOUND, {
- // response: {
- // error: {
- // description: "Transaction page 0 could not be retrieved.",
- // },
- // },
- // });
-
- // const hookBehavior = await tests.hookBehaveLikeThis(
- // useComponentState,
- // props,
- // [
- // ({ status, error }) => {
- // expect(status).equals("loading");
- // expect(error).undefined;
- // },
- // ({ status, error }) => {
- // expect(status).equals("loading-error");
- // if (error === undefined || error.type !== ErrorType.CLIENT) {
- // throw Error("not the expected error");
- // }
- // expect(error.payload).deep.equal({
- // error: {
- // description: "Transaction page 0 could not be retrieved.",
- // },
- // });
- // },
- // ],
- // env.buildTestingContext(),
- // );
-
- // expect(hookBehavior).deep.eq({ result: "ok" });
- // expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
- // });
-
- it.skip("should show error message on server error", async () => {
- const env = new SwrMockEnvironment();
-
- const props: Props = {
- account: "myAccount",
- routeCreateWireTransfer: undefined,
- };
-
- // env.addRequestExpectation(TRANSACTION_API_EXAMPLE.LIST_ERROR, {
- // response: {
- // error: {
- // code: TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
- // },
- // },
- // });
-
- const hookBehavior = await tests.hookBehaveLikeThis(
- useComponentState,
- props,
- [
- ({ status, error }) => {
- expect(status).equals("loading");
- expect(error).undefined;
- },
- ({ status, error }) => {
- expect(status).equals("loading-error");
- if (
- error === undefined ||
- !error.hasErrorCode(TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED)
- ) {
- throw Error("not the expected error");
- }
- expect(error.errorDetail.code).deep.equal(
- TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED,
- );
- },
- ],
- env.buildTestingContext(),
- );
-
- expect(hookBehavior).deep.eq({ result: "ok" });
- expect(env.assertJustExpectedRequestWereMade()).deep.eq({ result: "ok" });
- });
-});
diff --git a/packages/demobank-ui/src/components/Transactions/views.tsx b/packages/demobank-ui/src/components/Transactions/views.tsx
deleted file mode 100644
index 7da9fc5a9..000000000
--- a/packages/demobank-ui/src/components/Transactions/views.tsx
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { Attention, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
-import { Fragment, VNode, h } from "preact";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { RenderAmount } from "../../pages/PaytoWireTransferForm.js";
-import { State } from "./index.js";
-import { Duration } from "@gnu-taler/taler-util";
-import { Time } from "../Time.js";
-
-export function ReadyView({
- transactions,
- routeCreateWireTransfer,
- onGoNext,
- onGoStart,
-}: State.Ready): VNode {
- const { i18n, dateLocale } = useTranslationContext();
- const { config } = useBankCoreApiContext()
-
- if (!transactions.length) {
- return <div class="px-4 mt-4">
- <div class="sm:flex sm:items-center">
- <div class="sm:flex-auto">
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Transactions history</i18n.Translate>
- </h1>
- </div>
- </div>
-
- <Attention type="low" title={i18n.str`No transactions yet.`}>
- <i18n.Translate>
- You can start sending a wire transfer or withdrawing to your wallet.
- </i18n.Translate>
- </Attention>
- </div>;
- }
-
- const txByDate = transactions.reduce(
- (prev, cur) => {
- const d =
- cur.when.t_ms === "never"
- ? ""
- : format(cur.when.t_ms, "dd/MM/yyyy", { locale: dateLocale });
- if (!prev[d]) {
- prev[d] = [];
- }
- prev[d].push(cur);
- return prev;
- },
- {} as Record<string, typeof transactions>,
- );
- return (
- <div class="px-4 mt-4">
- <div class="sm:flex sm:items-center">
- <div class="sm:flex-auto">
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Transactions history</i18n.Translate>
- </h1>
- </div>
- </div>
- <div class="-mx-4 mt-5 ring-1 ring-gray-300 sm:mx-0 rounded-lg min-w-fit bg-white">
- <table class="min-w-full divide-y divide-gray-300">
- <thead>
- <tr>
- <th
- scope="col"
- class="pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >{i18n.str`Date`}</th>
- <th
- scope="col"
- class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >{i18n.str`Amount`}</th>
- <th
- scope="col"
- class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >{i18n.str`Counterpart`}</th>
- <th
- scope="col"
- class="hidden sm:table-cell pl-2 py-3.5 text-left text-sm font-semibold text-gray-900 "
- >{i18n.str`Subject`}</th>
- </tr>
- </thead>
- <tbody>
- {Object.entries(txByDate).map(([date, txs], idx) => {
- return (
- <Fragment key={idx}>
- <tr class="border-t border-gray-200">
- <th
- colSpan={4}
- scope="colgroup"
- class="bg-gray-50 py-2 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-3"
- >
- {date}
- </th>
- </tr>
- {txs.map((item) => {
- return (
- <tr
- key={idx}
- class="border-b border-gray-200 last:border-none"
- >
- <td class="relative py-2 pl-2 pr-2 text-sm ">
- <div class="font-medium text-gray-900">
- <Time format="HH:mm:ss"
- timestamp={item.when}
- // relative={Duration.fromSpec({ days: 1 })}
- />
- </div>
- <dl class="font-normal sm:hidden">
- <dt class="sr-only sm:hidden">
- <i18n.Translate>Amount</i18n.Translate>
- </dt>
- <dd class="mt-1 truncate text-gray-700">
- {item.negative
- ? i18n.str`sent`
- : i18n.str`received`}{" "}
- {item.amount ? (
- <span
- data-negative={
- item.negative ? "true" : "false"
- }
- class="data-[negative=false]:text-green-600 data-[negative=true]:text-red-600"
- >
- <RenderAmount
- value={item.amount}
- spec={config.currency_specification}
- />
- </span>
- ) : (
- <span style={{ color: "grey" }}>
- &lt;{i18n.str`Invalid value`}&gt;
- </span>
- )}
- </dd>
-
- <dt class="sr-only sm:hidden">
- <i18n.Translate>Counterpart</i18n.Translate>
- </dt>
- <dd class="mt-1 truncate text-gray-500 sm:hidden">
- {item.negative ? i18n.str`to` : i18n.str`from`}{" "}
- {!routeCreateWireTransfer ? item.counterpart :
- <a
- name={`transfer to ${item.counterpart}`}
- href={routeCreateWireTransfer.url({
- account: item.counterpart,
- })}
- class="text-indigo-600 hover:text-indigo-900"
- >
- {item.counterpart}
- </a>
- }
- </dd>
- <dd class="mt-1 text-gray-500 sm:hidden">
- <pre class="break-words w-56 whitespace-break-spaces p-2 rounded-md mx-auto my-2 bg-gray-100">
- {item.subject}
- </pre>
- </dd>
- </dl>
- </td>
- <td
- data-negative={item.negative ? "true" : "false"}
- class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 "
- >
- {item.amount ? (
- <RenderAmount
- value={item.amount}
- negative={item.negative}
- withColor
- spec={config.currency_specification}
- />
- ) : (
- <span style={{ color: "grey" }}>
- &lt;{i18n.str`Invalid value`}&gt;
- </span>
- )}
- </td>
- <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500">
- {!routeCreateWireTransfer ? item.counterpart :
- <a
- name={`wire transfer to ${item.counterpart}`}
- href={routeCreateWireTransfer.url({
- account: item.counterpart,
- })}
- class="text-indigo-600 hover:text-indigo-900"
- >
- {item.counterpart}
- </a>
- }
- </td>
- <td class="hidden sm:table-cell px-3 py-3.5 text-sm text-gray-500 break-all min-w-md">
- {item.subject}
- </td>
- </tr>
- );
- })}
- </Fragment>
- );
- })}
- </tbody>
- </table>
-
- <nav
- class="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg"
- aria-label="Pagination"
- >
- <div class="flex flex-1 justify-between sm:justify-end">
- <button
- name="first page"
- class="relative disabled:bg-gray-100 disabled:text-gray-500 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
- disabled={!onGoStart}
- onClick={onGoStart}
- >
- <i18n.Translate>First page</i18n.Translate>
- </button>
- <button
- name="next page"
- class="relative disabled:bg-gray-100 disabled:text-gray-500 ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
- disabled={!onGoNext}
- onClick={onGoNext}
- >
- <i18n.Translate>Next</i18n.Translate>
- </button>
- </div>
- </nav>
- </div>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/components/index.examples.ts b/packages/demobank-ui/src/components/index.examples.ts
deleted file mode 100644
index 20e013070..000000000
--- a/packages/demobank-ui/src/components/index.examples.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-export * as tx from "./Transactions/stories.js";
diff --git a/packages/demobank-ui/src/context/config.ts b/packages/demobank-ui/src/context/config.ts
deleted file mode 100644
index 39d12be86..000000000
--- a/packages/demobank-ui/src/context/config.ts
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- assertUnreachable,
- LibtoolVersion,
- TalerBankConversionCacheEviction,
- TalerBankConversionHttpClient,
- TalerCorebankApi,
- TalerAuthenticationHttpClient,
- TalerCoreBankCacheEviction,
- TalerCoreBankHttpClient,
- TalerError
-} from "@gnu-taler/taler-util";
-import {
- BrowserHttpLib,
- ErrorLoading,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import {
- ComponentChildren,
- createContext,
- FunctionComponent,
- h,
- VNode,
-} from "preact";
-import { useContext, useEffect, useState } from "preact/hooks";
-import {
- revalidateAccountDetails,
- revalidatePublicAccounts,
- revalidateTransactions,
-} from "../hooks/account.js";
-import {
- revalidateBusinessAccounts,
- revalidateCashouts,
- revalidateConversionInfo,
-} from "../hooks/regional.js";
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-export type Type = {
- url: URL;
- config: TalerCorebankApi.Config;
- bank: TalerCoreBankHttpClient;
- conversion: TalerBankConversionHttpClient;
- authenticator: (user: string) => TalerAuthenticationHttpClient;
- hints: VersionHint[];
-};
-
-// FIXME: below
-// @ts-expect-error default value to undefined, should it be another thing?
-const Context = createContext<Type>(undefined);
-
-export const useBankCoreApiContext = (): Type => useContext(Context);
-
-export enum VersionHint {
- /**
- * when this flag is on, server is running an old version with cashout before implementing 2fa API
- */
- CASHOUT_BEFORE_2FA,
-}
-
-export type ConfigResult =
- | undefined
- | { type: "ok"; config: TalerCorebankApi.Config; hints: VersionHint[] }
- | { type: "incompatible"; result: TalerCorebankApi.Config; supported: string }
- | { type: "error"; error: TalerError };
-
-export const BankCoreApiProvider = ({
- baseUrl,
- children,
- frameOnError,
-}: {
- baseUrl: string;
- children: ComponentChildren;
- frameOnError: FunctionComponent<{ children: ComponentChildren }>;
-}): VNode => {
- const [checked, setChecked] = useState<ConfigResult>();
- const { i18n } = useTranslationContext();
-
- const { bankClient, conversionClient, authClient } = buildApiClient(new URL(baseUrl))
-
- useEffect(() => {
- bankClient
- .getConfig()
- .then((resp) => {
- if (bankClient.isCompatible(resp.body.version)) {
- setChecked({ type: "ok", config: resp.body, hints: [] });
- } else {
- // this API supports version 3.0.3
- const compare = LibtoolVersion.compare("3:0:3", resp.body.version);
- if (compare?.compatible ?? false) {
- setChecked({
- type: "ok",
- config: resp.body,
- hints: [VersionHint.CASHOUT_BEFORE_2FA],
- });
- } else {
- setChecked({
- type: "incompatible",
- result: resp.body,
- supported: bankClient.PROTOCOL_VERSION,
- });
- }
- }
- })
- .catch((error: unknown) => {
- if (error instanceof TalerError) {
- setChecked({ type: "error", error });
- }
- });
- }, []);
-
- if (checked === undefined) {
- return h(frameOnError, { children: h("div", {}, "loading...") });
- }
- if (checked.type === "error") {
- return h(frameOnError, {
- children: h(ErrorLoading, { error: checked.error, showDetail: true }),
- });
- }
- if (checked.type === "incompatible") {
- return h(frameOnError, {
- children: h(
- "div",
- {},
- i18n.str`The bank backend is not supported. Supported version "${checked.supported}", server version "${checked.result.version}"`,
- ),
- });
- }
- const value: Type = {
- url: new URL(bankClient.baseUrl),
- config: checked.config,
- bank: bankClient,
- conversion: conversionClient,
- authenticator: authClient,
- hints: checked.hints,
- };
- return h(Context.Provider, {
- value,
- children,
- });
-};
-
-/**
- * build http client with cache breaker due to SWR
- * @param url
- * @returns
- */
-function buildApiClient(url: URL) {
- const httpLib = new BrowserHttpLib();
-
- const bankClient = new TalerCoreBankHttpClient(url.href, httpLib, {
- async notifySuccess(op) {
- switch (op) {
- case TalerCoreBankCacheEviction.DELELE_ACCOUNT: {
- await Promise.all([
- revalidatePublicAccounts(),
- revalidateBusinessAccounts(),
- ]);
- return
- }
- case TalerCoreBankCacheEviction.CREATE_ACCOUNT: {
- // admin balance change on new account
- await Promise.all([
- revalidateAccountDetails(),
- revalidateTransactions(),
- revalidatePublicAccounts(),
- revalidateBusinessAccounts(),
- ])
- return;
- }
- case TalerCoreBankCacheEviction.UPDATE_ACCOUNT: {
- await Promise.all([
- revalidateAccountDetails(),
- ])
- return;
- }
- case TalerCoreBankCacheEviction.CREATE_TRANSACTION: {
- await Promise.all([
- revalidateAccountDetails(),
- revalidateTransactions(),
- ])
- return;
- }
- case TalerCoreBankCacheEviction.CONFIRM_WITHDRAWAL: {
- await Promise.all([
- revalidateAccountDetails(),
- revalidateTransactions(),
- ])
- return;
- }
- case TalerCoreBankCacheEviction.CREATE_CASHOUT: {
- await Promise.all([
- revalidateAccountDetails(),
- revalidateCashouts(),
- revalidateTransactions(),
- ])
- return;
- }
- case TalerCoreBankCacheEviction.UPDATE_PASSWORD:
- case TalerCoreBankCacheEviction.ABORT_WITHDRAWAL:
- case TalerCoreBankCacheEviction.CREATE_WITHDRAWAL:
- return;
- default:
- assertUnreachable(op)
- }
- }
- });
- const conversionClient = new TalerBankConversionHttpClient(bankClient.getConversionInfoAPI(), httpLib, {
- async notifySuccess(op) {
- switch (op) {
- case TalerBankConversionCacheEviction.UPDATE_RATE: {
- await revalidateConversionInfo();
- return
- }
- default:
- assertUnreachable(op)
- }
- }
- });
- const authClient = (user: string) => new TalerAuthenticationHttpClient(bankClient.getAuthenticationAPI(user), user, httpLib);
- return { bankClient, conversionClient, authClient }
-}
-
-export const BankCoreApiProviderTesting = ({
- children,
- state,
- url,
-}: {
- children: ComponentChildren;
- state: TalerCorebankApi.Config;
- url: string;
-}): VNode => {
- const value: Type = {
- url: new URL(url),
- config: state,
- // @ts-expect-error this API is not being used, not really needed
- bank: undefined,
- hints: [],
- };
-
- return h(Context.Provider, {
- value,
- children,
- });
-};
diff --git a/packages/demobank-ui/src/context/navigation.ts b/packages/demobank-ui/src/context/navigation.ts
deleted file mode 100644
index 9552bf899..000000000
--- a/packages/demobank-ui/src/context/navigation.ts
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { ComponentChildren, createContext, h, VNode } from "preact";
-import { useContext, useEffect, useState } from "preact/hooks";
-import { AppLocation } from "../route.js";
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-export type Type = {
- path: string;
- params: Record<string, string>;
- navigateTo: (path: AppLocation) => void;
- // addNavigationListener: (listener: (path: string, params: Record<string, string>) => void) => (() => void);
-};
-
-// @ts-expect-error should not be used without provider
-const Context = createContext<Type>(undefined);
-
-export const useNavigationContext = (): Type => useContext(Context);
-
-function getPathAndParamsFromWindow() {
- const path =
- typeof window !== "undefined" ? window.location.hash.substring(1) : "/";
- const params: Record<string, string> = {};
- if (typeof window !== "undefined") {
- for (const [key, value] of new URLSearchParams(window.location.search)) {
- params[key] = value;
- }
- }
- return { path, params };
-}
-
-const { path: initialPath, params: initialParams } =
- getPathAndParamsFromWindow();
-
-// there is a possibility that if the browser does a redirection
-// (which doesn't go through navigatTo function) and that executed
-// too early (before addEventListener runs) it won't be taking
-// into account
-const PopStateEventType = "popstate";
-
-export const BrowserHashNavigationProvider = ({
- children,
-}: {
- children: ComponentChildren;
-}): VNode => {
- const [{ path, params }, setState] = useState({
- path: initialPath,
- params: initialParams,
- });
- if (typeof window === "undefined") {
- throw Error(
- "Can't use BrowserHashNavigationProvider if there is no window object",
- );
- }
- function navigateTo(path: string) {
- const { params } = getPathAndParamsFromWindow();
- setState({ path, params });
- window.location.href = path;
- }
-
- useEffect(() => {
- function eventListener() {
- setState(getPathAndParamsFromWindow());
- }
- window.addEventListener(PopStateEventType, eventListener);
- return () => {
- window.removeEventListener(PopStateEventType, eventListener);
- };
- }, []);
- return h(Context.Provider, {
- value: { path, params, navigateTo },
- children,
- });
-};
diff --git a/packages/demobank-ui/src/context/settings.ts b/packages/demobank-ui/src/context/settings.ts
deleted file mode 100644
index 053fcbd12..000000000
--- a/packages/demobank-ui/src/context/settings.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { ComponentChildren, createContext, h, VNode } from "preact";
-import { useContext } from "preact/hooks";
-import { BankUiSettings } from "../settings.js";
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-export type Type = BankUiSettings;
-
-const initial: BankUiSettings = {};
-const Context = createContext<Type>(initial);
-
-export const useSettingsContext = (): Type => useContext(Context);
-
-export const SettingsProvider = ({
- children,
- value,
-}: {
- value: BankUiSettings;
- children: ComponentChildren;
-}): VNode => {
- return h(Context.Provider, {
- value,
- children,
- });
-};
diff --git a/packages/demobank-ui/src/context/wallet-integration.ts b/packages/demobank-ui/src/context/wallet-integration.ts
deleted file mode 100644
index e14988ed1..000000000
--- a/packages/demobank-ui/src/context/wallet-integration.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { stringifyTalerUri, TalerUri } from "@gnu-taler/taler-util";
-import { ComponentChildren, createContext, h, VNode } from "preact";
-import { useContext } from "preact/hooks";
-
-/**
- * https://docs.taler.net/design-documents/039-taler-browser-integration.html
- *
- * @param uri
- */
-function createHeadMetaTag(uri: TalerUri, onNotFound?: () => void) {
- const meta = document.createElement("meta");
- meta.setAttribute("name", "taler-uri");
- meta.setAttribute("content", stringifyTalerUri(uri));
-
- document.head.appendChild(meta);
-
- let walletFound = false;
- window.addEventListener("beforeunload", () => {
- walletFound = true;
- });
- setTimeout(() => {
- if (!walletFound && onNotFound) {
- onNotFound();
- }
- }, 10); //very short timeout
-}
-interface Type {
- /**
- * Tell the active wallet that an action is found
- *
- * @param uri
- * @returns
- */
- publishTalerAction: (uri: TalerUri, onNotFound?: () => void) => void;
-}
-
-// @ts-expect-error default value to undefined, should it be another thing?
-const Context = createContext<Type>(undefined);
-
-export const useTalerWalletIntegrationAPI = (): Type => useContext(Context);
-
-export const TalerWalletIntegrationBrowserProvider = ({
- children,
-}: {
- children: ComponentChildren;
-}): VNode => {
- const value: Type = {
- publishTalerAction: createHeadMetaTag,
- };
- return h(Context.Provider, {
- value,
- children,
- });
-};
-
-export const TalerWalletIntegrationTestingProvider = ({
- children,
- value,
-}: {
- children: ComponentChildren;
- value: Type;
-}): VNode => {
- return h(Context.Provider, {
- value,
- children,
- });
-};
diff --git a/packages/demobank-ui/src/declaration.d.ts b/packages/demobank-ui/src/declaration.d.ts
deleted file mode 100644
index 581cbcd07..000000000
--- a/packages/demobank-ui/src/declaration.d.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-declare module "*.css" {
- const mapping: Record<string, string>;
- export default mapping;
-}
-declare module "*.svg" {
- const content: string;
- export default content;
-}
-declare module "*.jpeg" {
- const content: string;
- export default content;
-}
-declare module "*.png" {
- const content: string;
- export default content;
-}
-
-declare const __VERSION__: string;
-declare const __GIT_HASH__: string;
diff --git a/packages/demobank-ui/src/hooks/account.ts b/packages/demobank-ui/src/hooks/account.ts
deleted file mode 100644
index aa0745253..000000000
--- a/packages/demobank-ui/src/hooks/account.ts
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AccessToken,
- TalerCoreBankResultByMethod,
- TalerHttpError,
- WithdrawalOperationStatus,
-} from "@gnu-taler/taler-util";
-import { useEffect, useState } from "preact/hooks";
-import { PAGE_SIZE } from "../utils.js";
-import { useSessionState } from "./session.js";
-
-// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-import _useSWR, { SWRHook, mutate } from "swr";
-import { useBankCoreApiContext } from "../context/config.js";
-const useSWR = _useSWR as unknown as SWRHook;
-
-export interface InstanceTemplateFilter {
- // FIXME: add filter to the template list
- position?: string;
-}
-
-export function revalidateAccountDetails() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getAccount",
- undefined,
- { revalidate: true },
- );
-}
-
-export function useAccountDetails(account: string) {
- const { state: credentials } = useSessionState();
- const { bank: api } = useBankCoreApiContext();
-
- async function fetcher([username, token]: [string, AccessToken]) {
- return await api.getAccount({ username, token });
- }
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
- const { data, error } = useSWR<
- TalerCoreBankResultByMethod<"getAccount">,
- TalerHttpError
- >([account, token, "getAccount"], fetcher, {});
-
- if (data) return data;
- if (error) return error;
- return undefined;
-}
-
-export function revalidateWithdrawalDetails() {
- return mutate((key) => Array.isArray(key) && key[key.length - 1] === "getWithdrawalById", undefined, { revalidate: true });
-}
-
-export function useWithdrawalDetails(wid: string) {
- const { bank: api } = useBankCoreApiContext();
- const [latestStatus, setLatestStatus] = useState<WithdrawalOperationStatus>();
-
- async function fetcher([wid, old_state]: [
- string,
- WithdrawalOperationStatus | undefined,
- ]) {
- return await api.getWithdrawalById(
- wid,
- old_state === undefined ? undefined : { old_state, timeoutMs: 15000 },
- );
- }
-
- const { data, error } = useSWR<
- TalerCoreBankResultByMethod<"getWithdrawalById">,
- TalerHttpError
- >([wid, latestStatus, "getWithdrawalById"], fetcher, {
- refreshInterval: 3000,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- });
-
- const currentStatus =
- data !== undefined && data.type === "ok" ? data.body.status : undefined;
-
- useEffect(() => {
- if (currentStatus !== undefined && currentStatus !== latestStatus) {
- setLatestStatus(currentStatus);
- }
- }, [currentStatus]);
-
- if (data) return data;
- if (error) return error;
- return undefined;
-}
-
-export function revalidateTransactionDetails() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getTransactionById", undefined, { revalidate: true }
- );
-}
-export function useTransactionDetails(account: string, tid: number) {
- const { state: credentials } = useSessionState();
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
- const { bank: api } = useBankCoreApiContext();
-
- async function fetcher([username, token, txid]: [
- string,
- AccessToken,
- number,
- ]) {
- return await api.getTransactionById({ username, token }, txid);
- }
-
- const { data, error } = useSWR<
- TalerCoreBankResultByMethod<"getTransactionById">,
- TalerHttpError
- >([account, token, tid, "getTransactionById"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- });
-
- if (data) return data;
- if (error) return error;
- return undefined;
-}
-
-export async function revalidatePublicAccounts() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getPublicAccounts", undefined, { revalidate: true }
- );
-}
-export function usePublicAccounts(
- filterAccount: string | undefined,
- initial?: number,
-) {
- const [offset, setOffset] = useState<number | undefined>(initial);
-
- const { bank: api } = useBankCoreApiContext();
-
- async function fetcher([account, txid]: [
- string | undefined,
- number | undefined,
- ]) {
- return await api.getPublicAccounts(
- { account },
- {
- limit: PAGE_SIZE,
- offset: txid ? String(txid) : undefined,
- order: "asc",
- },
- );
- }
-
- const { data, error } = useSWR<
- TalerCoreBankResultByMethod<"getPublicAccounts">,
- TalerHttpError
- >([filterAccount, offset, "getPublicAccounts"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- });
-
- const isLastPage =
- data && data.type === "ok" && data.body.public_accounts.length <= PAGE_SIZE;
- const isFirstPage = !offset;
-
- const result = data && data.type == "ok" ? structuredClone(data.body.public_accounts) : []
- if (result.length == PAGE_SIZE+1) {
- result.pop()
- }
- const pagination = {
- result,
- isLastPage,
- isFirstPage,
- loadNext: () => {
- if (!result.length) return;
- setOffset(result[result.length - 1].row_id);
- },
- loadFirst: () => {
- setOffset(0);
- },
- };
-
- // const public_accountslist = data?.type !== "ok" ? [] : data.body.public_accounts;
- if (data) {
- return { ok: true, data: data.body, ...pagination };
- }
- if (error) {
- return error;
- }
- return undefined;
-}
-
-export function revalidateTransactions() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getTransactions",
- undefined,
- { revalidate: true },
- );
-}
-export function useTransactions(account: string, initial?: number) {
- const { state: credentials } = useSessionState();
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
-
- const [offset, setOffset] = useState<number | undefined>(initial);
- const { bank: api } = useBankCoreApiContext();
-
- async function fetcher([username, token, txid]: [
- string,
- AccessToken,
- number | undefined,
- ]) {
- return await api.getTransactions(
- { username, token },
- {
- limit: PAGE_SIZE +1 ,
- offset: txid ? String(txid) : undefined,
- order: "dec",
- },
- );
- }
-
- const { data, error } = useSWR<
- TalerCoreBankResultByMethod<"getTransactions">,
- TalerHttpError
- >([account, token, offset, "getTransactions"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- refreshWhenOffline: false,
- // revalidateOnMount: false,
- revalidateIfStale: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- });
-
- const isLastPage =
- data && data.type === "ok" && data.body.transactions.length <= PAGE_SIZE;
- const isFirstPage = !offset;
-
- const result = data && data.type == "ok" ? structuredClone(data.body.transactions) : []
- if (result.length == PAGE_SIZE+1) {
- result.pop()
- }
- const pagination = {
- result,
- isLastPage,
- isFirstPage,
- loadNext: () => {
- if (!result.length) return;
- setOffset(result[result.length - 1].row_id);
- },
- loadFirst: () => {
- setOffset(0);
- },
- };
-
- if (data) {
- return { ok: true, data, ...pagination };
- }
- if (error) {
- return error;
- }
- return undefined;
-}
diff --git a/packages/demobank-ui/src/hooks/bank-state.ts b/packages/demobank-ui/src/hooks/bank-state.ts
deleted file mode 100644
index 83bb009cf..000000000
--- a/packages/demobank-ui/src/hooks/bank-state.ts
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- Codec,
- TalerCorebankApi,
- buildCodecForObject,
- buildCodecForUnion,
- codecForAbsoluteTime,
- codecForAny,
- codecForConstString,
- codecForString,
- codecForTanTransmission,
- codecOptional,
-} from "@gnu-taler/taler-util";
-import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
-import { AppLocation } from "../route.js";
-
-export type ChallengeInProgess =
- | DeleteAccountChallenge
- | UpdateAccountChallenge
- | UpdatePasswordChallenge
- | CreateTransactionChallenge
- | ConfirmWithdrawalChallenge
- | CashoutChallenge;
-
-type BaseChallenge<OpType extends string, ReqType> = {
- id: string;
- operation: OpType;
- sent: AbsoluteTime;
- location: AppLocation;
- info?: TalerCorebankApi.TanTransmission;
- request: ReqType;
-};
-
-type DeleteAccountChallenge = BaseChallenge<"delete-account", string>;
-type UpdateAccountChallenge = BaseChallenge<
- "update-account",
- TalerCorebankApi.AccountReconfiguration
->;
-type UpdatePasswordChallenge = BaseChallenge<
- "update-password",
- TalerCorebankApi.AccountPasswordChange
->;
-type CreateTransactionChallenge = BaseChallenge<
- "create-transaction",
- TalerCorebankApi.CreateTransactionRequest
->;
-type ConfirmWithdrawalChallenge = BaseChallenge<"confirm-withdrawal", string>;
-type CashoutChallenge = BaseChallenge<
- "create-cashout",
- TalerCorebankApi.CashoutRequest
->;
-
-const codecForChallengeUpdatePassword = (): Codec<UpdatePasswordChallenge> =>
- buildCodecForObject<UpdatePasswordChallenge>()
- .property("operation", codecForConstString("update-password"))
- .property("id", codecForString())
- .property("location", codecForAppLocation())
- .property("sent", codecForAbsoluteTime)
- .property("info", codecOptional(codecForTanTransmission()))
- .property("request", codecForAny())
- .build("UpdatePasswordChallenge");
-
-const codecForChallengeDeleteAccount = (): Codec<DeleteAccountChallenge> =>
- buildCodecForObject<DeleteAccountChallenge>()
- .property("operation", codecForConstString("delete-account"))
- .property("id", codecForString())
- .property("location", codecForAppLocation())
- .property("sent", codecForAbsoluteTime)
- .property("request", codecForString())
- .property("info", codecOptional(codecForTanTransmission()))
- .build("DeleteAccountChallenge");
-
-const codecForChallengeUpdateAccount = (): Codec<UpdateAccountChallenge> =>
- buildCodecForObject<UpdateAccountChallenge>()
- .property("operation", codecForConstString("update-account"))
- .property("id", codecForString())
- .property("location", codecForAppLocation())
- .property("sent", codecForAbsoluteTime)
- .property("info", codecOptional(codecForTanTransmission()))
- .property("request", codecForAny())
- .build("UpdateAccountChallenge");
-
-const codecForChallengeCreateTransaction =
- (): Codec<CreateTransactionChallenge> =>
- buildCodecForObject<CreateTransactionChallenge>()
- .property("operation", codecForConstString("create-transaction"))
- .property("id", codecForString())
- .property("location", codecForAppLocation())
- .property("sent", codecForAbsoluteTime)
- .property("info", codecOptional(codecForTanTransmission()))
- .property("request", codecForAny())
- .build("CreateTransactionChallenge");
-
-const codecForChallengeConfirmWithdrawal =
- (): Codec<ConfirmWithdrawalChallenge> =>
- buildCodecForObject<ConfirmWithdrawalChallenge>()
- .property("operation", codecForConstString("confirm-withdrawal"))
- .property("id", codecForString())
- .property("location", codecForAppLocation())
- .property("sent", codecForAbsoluteTime)
- .property("info", codecOptional(codecForTanTransmission()))
- .property("request", codecForString())
- .build("ConfirmWithdrawalChallenge");
-
-const codecForAppLocation = codecForString as () => Codec<AppLocation>
-
-const codecForChallengeCashout = (): Codec<CashoutChallenge> =>
- buildCodecForObject<CashoutChallenge>()
- .property("operation", codecForConstString("create-cashout"))
- .property("id", codecForString())
- .property("location", codecForAppLocation())
- .property("sent", codecForAbsoluteTime)
- .property("info", codecOptional(codecForTanTransmission()))
- .property("request", codecForAny())
- .build("CashoutChallenge");
-
-const codecForChallenge = (): Codec<ChallengeInProgess> =>
- buildCodecForUnion<ChallengeInProgess>()
- .discriminateOn("operation")
- .alternative("confirm-withdrawal", codecForChallengeConfirmWithdrawal())
- .alternative("create-cashout", codecForChallengeCashout())
- .alternative("create-transaction", codecForChallengeCreateTransaction())
- .alternative("delete-account", codecForChallengeDeleteAccount())
- .alternative("update-account", codecForChallengeUpdateAccount())
- .alternative("update-password", codecForChallengeUpdatePassword())
- .build("ChallengeInProgess");
-
-
-
-interface BankState {
- currentWithdrawalOperationId: string | undefined;
- currentChallenge: ChallengeInProgess | undefined;
-}
-
-export const codecForBankState = (): Codec<BankState> =>
- buildCodecForObject<BankState>()
- .property("currentWithdrawalOperationId", codecOptional(codecForString()))
- .property("currentChallenge", codecOptional(codecForChallenge()))
- .build("BankState");
-
-const defaultBankState: BankState = {
- currentWithdrawalOperationId: undefined,
- currentChallenge: undefined,
-};
-
-const BANK_STATE_KEY = buildStorageKey("bank-app-state", codecForBankState());
-
-/**
- * Client state saved in local storage.
- *
- * This information is saved in the client because
- * the backend server session API is not enough.
- *
- * @returns tuple of [state, update(), reset()]
- */
-export function useBankState(): [
- Readonly<BankState>,
- <T extends keyof BankState>(key: T, value: BankState[T]) => void,
- () => void,
-] {
- const { value, update } = useLocalStorage(BANK_STATE_KEY, defaultBankState);
-
- function updateField<T extends keyof BankState>(k: T, v: BankState[T]) {
- const newValue = { ...value, [k]: v };
- update(newValue);
- }
- function reset() {
- update(defaultBankState);
- }
- return [value, updateField, reset];
-}
-
diff --git a/packages/demobank-ui/src/hooks/form.ts b/packages/demobank-ui/src/hooks/form.ts
deleted file mode 100644
index 26354b108..000000000
--- a/packages/demobank-ui/src/hooks/form.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { AmountJson, TalerBankConversionApi, TranslatedString } from "@gnu-taler/taler-util";
-import { useState } from "preact/hooks";
-
-export type UIField = {
- value: string | undefined;
- onUpdate: (s: string) => void;
- error: TranslatedString | undefined;
-}
-
-type FormHandler<T> = {
- [k in keyof T]?:
- T[k] extends string ? UIField :
- T[k] extends AmountJson ? UIField :
- FormHandler<T[k]>;
-}
-
-export type FormValues<T> = {
- [k in keyof T]:
- T[k] extends string ? (string | undefined) :
- T[k] extends AmountJson ? (string | undefined) :
- FormValues<T[k]>;
-}
-
-export type RecursivePartial<T> = {
- [k in keyof T]?:
- T[k] extends string ? (string) :
- T[k] extends AmountJson ? (AmountJson) :
- RecursivePartial<T[k]>;
-}
-
-export type FormErrors<T> = {
- [k in keyof T]?:
- T[k] extends string ? (TranslatedString) :
- T[k] extends AmountJson ? (TranslatedString) :
- FormErrors<T[k]>;
-}
-
-export type FormStatus<T> = {
- status: "ok",
- result: T,
- errors: undefined,
-} | {
- status: "fail",
- result: RecursivePartial<T>,
- errors: FormErrors<T>,
-}
-
-
-function constructFormHandler<T>(form: FormValues<T>, updateForm: (d: FormValues<T>) => void, errors: FormErrors<T> | undefined): FormHandler<T> {
- const keys = (Object.keys(form) as Array<keyof T>)
-
- const handler = keys.reduce((prev, fieldName) => {
- const currentValue: any = form[fieldName];
- const currentError: any = errors ? errors[fieldName] : undefined;
- function updater(newValue: any) {
- updateForm({ ...form, [fieldName]: newValue })
- }
- if (typeof currentValue === "object") {
- const group = constructFormHandler(currentValue, updater, currentError)
- // @ts-expect-error asdasd
- prev[fieldName] = group
- return prev;
- }
- const field: UIField = {
- error: currentError,
- value: currentValue,
- onUpdate: updater
- }
- // @ts-expect-error asdasd
- prev[fieldName] = field
- return prev
- }, {} as FormHandler<T>)
-
- return handler;
-}
-
-export function useFormState<T>(defaultValue: FormValues<T>, check: (f: FormValues<T>) => FormStatus<T>): [FormHandler<T>, FormStatus<T>] {
- const [form, updateForm] = useState<FormValues<T>>(defaultValue)
-
- const status = check(form)
- const handler = constructFormHandler(form, updateForm, status.errors)
-
- return [handler, status]
-} \ No newline at end of file
diff --git a/packages/demobank-ui/src/hooks/preferences.ts b/packages/demobank-ui/src/hooks/preferences.ts
deleted file mode 100644
index 454dc8d80..000000000
--- a/packages/demobank-ui/src/hooks/preferences.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- Codec,
- TranslatedString,
- buildCodecForObject,
- codecForBoolean,
- codecForNumber,
-} from "@gnu-taler/taler-util";
-import {
- buildStorageKey,
- useLocalStorage,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-
-interface Preferences {
- showWithdrawalSuccess: boolean;
- showDemoDescription: boolean;
- showInstallWallet: boolean;
- maxWithdrawalAmount: number;
- fastWithdrawal: boolean;
- showDebugInfo: boolean;
-}
-
-export const codecForPreferences = (): Codec<Preferences> =>
- buildCodecForObject<Preferences>()
- .property("showWithdrawalSuccess", codecForBoolean())
- .property("showDemoDescription", codecForBoolean())
- .property("showInstallWallet", codecForBoolean())
- .property("fastWithdrawal", codecForBoolean())
- .property("showDebugInfo", codecForBoolean())
- .property("maxWithdrawalAmount", codecForNumber())
- .build("Settings");
-
-const defaultPreferences: Preferences = {
- showWithdrawalSuccess: true,
- showDemoDescription: true,
- showInstallWallet: true,
- maxWithdrawalAmount: 25,
- fastWithdrawal: false,
- showDebugInfo: false,
-};
-
-const BANK_PREFERENCES_KEY = buildStorageKey(
- "bank-preferences",
- codecForPreferences(),
-);
-/**
- * User preferences.
- *
- * @returns tuple of [state, update()]
- */
-export function usePreferences(): [
- Readonly<Preferences>,
- <T extends keyof Preferences>(key: T, value: Preferences[T]) => void,
-] {
- const { value, update } = useLocalStorage(
- BANK_PREFERENCES_KEY,
- defaultPreferences,
- );
-
- function updateField<T extends keyof Preferences>(k: T, v: Preferences[T]) {
- const newValue = { ...value, [k]: v };
- update(newValue);
- }
- return [value, updateField];
-}
-
-export function getAllBooleanPreferences(): Array<keyof Preferences> {
- return [
- "fastWithdrawal",
- "showDebugInfo",
- "showDemoDescription",
- "showInstallWallet",
- "showWithdrawalSuccess",
- ];
-}
-
-export function getLabelForPreferences(
- k: keyof Preferences,
- i18n: ReturnType<typeof useTranslationContext>["i18n"],
-): TranslatedString {
- switch (k) {
- case "maxWithdrawalAmount":
- return i18n.str`Max withdrawal amount`;
- case "showWithdrawalSuccess":
- return i18n.str`Show withdrawal confirmation`;
- case "showDemoDescription":
- return i18n.str`Show demo description`;
- case "showInstallWallet":
- return i18n.str`Show install wallet first`;
- case "fastWithdrawal":
- return i18n.str`Use fast withdrawal form`;
- case "showDebugInfo":
- return i18n.str`Show debug info`;
- }
-}
-
diff --git a/packages/demobank-ui/src/hooks/regional.ts b/packages/demobank-ui/src/hooks/regional.ts
deleted file mode 100644
index bf948d293..000000000
--- a/packages/demobank-ui/src/hooks/regional.ts
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { PAGE_SIZE } from "../utils.js";
-import { useSessionState } from "./session.js";
-
-import {
- AccessToken,
- AmountJson,
- Amounts,
- HttpStatusCode,
- OperationOk,
- TalerBankConversionResultByMethod,
- TalerCoreBankErrorsByMethod,
- TalerCoreBankResultByMethod,
- TalerCorebankApi,
- TalerError,
- TalerHttpError,
- opFixedSuccess,
-} from "@gnu-taler/taler-util";
-import _useSWR, { SWRHook, mutate } from "swr";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useState } from "preact/hooks";
-
-// FIX default import https://github.com/microsoft/TypeScript/issues/49189
-const useSWR = _useSWR as unknown as SWRHook;
-
-export type TransferCalculation = {
- debit: AmountJson;
- credit: AmountJson;
- beforeFee: AmountJson;
-} | "amount-is-too-small";
-type EstimatorFunction = (
- amount: AmountJson,
- fee: AmountJson,
-) => Promise<TransferCalculation>;
-
-type ConversionEstimators = {
- estimateByCredit: EstimatorFunction;
- estimateByDebit: EstimatorFunction;
-};
-
-export function revalidateConversionInfo() {
- return mutate(
- (key) =>
- Array.isArray(key) && key[key.length - 1] === "getConversionInfoAPI",
- );
-}
-export function useConversionInfo() {
- const { conversion, config } = useBankCoreApiContext();
-
- async function fetcher() {
- return await conversion.getConfig();
- }
- const { data, error } = useSWR<
- TalerBankConversionResultByMethod<"getConfig">,
- TalerHttpError
- >(!config.allow_conversion ? undefined : ["getConversionInfoAPI"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- });
-
- if (data) return data;
- if (error) return error;
- return undefined;
-}
-
-export function useCashinEstimator(): ConversionEstimators {
- const { conversion } = useBankCoreApiContext();
- return {
- estimateByCredit: async (fiatAmount, fee) => {
- const resp = await conversion.getCashinRate({
- credit: fiatAmount,
- });
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- return "amount-is-too-small"
- }
- // this below can't happen
- case HttpStatusCode.NotImplemented: //it should not be able to call this function
- case HttpStatusCode.BadRequest: //we are using just one parameter
- throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
- }
- }
- const credit = Amounts.parseOrThrow(resp.body.amount_credit);
- const debit = Amounts.parseOrThrow(resp.body.amount_debit);
- const beforeFee = Amounts.sub(credit, fee).amount;
-
- return {
- debit,
- beforeFee,
- credit,
- };
- },
- estimateByDebit: async (regionalAmount, fee) => {
- const resp = await conversion.getCashinRate({
- debit: regionalAmount,
- });
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- return "amount-is-too-small"
- }
- // this below can't happen
- case HttpStatusCode.NotImplemented: //it should not be able to call this function
- case HttpStatusCode.BadRequest: //we are using just one parameter
- throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
- }
- }
- const credit = Amounts.parseOrThrow(resp.body.amount_credit);
- const debit = Amounts.parseOrThrow(resp.body.amount_debit);
- const beforeFee = Amounts.add(credit, fee).amount;
-
- return {
- debit,
- beforeFee,
- credit,
- };
- },
- };
-}
-
-export function useCashoutEstimator(): ConversionEstimators {
- const { bank, conversion } = useBankCoreApiContext();
- return {
- estimateByCredit: async (fiatAmount, fee) => {
- const resp = await conversion.getCashoutRate({
- credit: fiatAmount,
- });
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- return "amount-is-too-small"
- }
- // this below can't happen
- case HttpStatusCode.NotImplemented: //it should not be able to call this function
- case HttpStatusCode.BadRequest: //we are using just one parameter
- throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
- }
- }
- const credit = Amounts.parseOrThrow(resp.body.amount_credit);
- const debit = Amounts.parseOrThrow(resp.body.amount_debit);
- const beforeFee = Amounts.sub(credit, fee).amount;
-
- return {
- debit,
- beforeFee,
- credit,
- };
- },
- estimateByDebit: async (regionalAmount, fee) => {
- const resp = await conversion.getCashoutRate({
- debit: regionalAmount,
- });
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- return "amount-is-too-small"
- }
- // this below can't happen
- case HttpStatusCode.NotImplemented: //it should not be able to call this function
- case HttpStatusCode.BadRequest: //we are using just one parameter
- throw TalerError.fromDetail(resp.detail.code, {}, resp.detail.hint);
- }
- }
- const credit = Amounts.parseOrThrow(resp.body.amount_credit);
- const debit = Amounts.parseOrThrow(resp.body.amount_debit);
- const beforeFee = Amounts.add(credit, fee).amount;
-
- return {
- debit,
- beforeFee,
- credit,
- };
- },
- };
-}
-
-/**
- * @deprecated use useCashoutEstimator
- */
-export function useEstimator(): ConversionEstimators {
- return useCashoutEstimator()
-}
-
-export async function revalidateBusinessAccounts() {
- return mutate((key) => Array.isArray(key) && key[key.length - 1] === "getAccounts", undefined, { revalidate: true });
-}
-export function useBusinessAccounts() {
- const { state: credentials } = useSessionState();
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
- const { bank: api } = useBankCoreApiContext();
-
- const [offset, setOffset] = useState<number | undefined>();
-
- function fetcher([token, offset]: [AccessToken, number]) {
- // FIXME: add account name filter
- return api.getAccounts(
- token,
- {},
- {
- limit: PAGE_SIZE + 1,
- offset: String(offset),
- order: "asc",
- },
- );
- }
-
- const { data, error } = useSWR<
- TalerCoreBankResultByMethod<"getAccounts">,
- TalerHttpError
- >([token, offset ?? 0, "getAccounts"], fetcher, {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- });
-
- const isLastPage =
- data && data.type === "ok" && data.body.accounts.length <= PAGE_SIZE;
- const isFirstPage = !offset;
-
- const result = data && data.type == "ok" ? structuredClone(data.body.accounts) : []
- if (result.length == PAGE_SIZE + 1) {
- result.pop()
- }
- const pagination = {
- result,
- isLastPage,
- isFirstPage,
- loadNext: () => {
- if (!result.length) return;
- setOffset(result[result.length - 1].row_id);
- },
- loadFirst: () => {
- setOffset(0);
- },
- };
-
- if (data) return { ok: true, data, ...pagination };
- if (error) return error;
- return undefined;
-}
-
-type CashoutWithId = TalerCorebankApi.CashoutStatusResponse & { id: number };
-function notUndefined(c: CashoutWithId | undefined): c is CashoutWithId {
- return c !== undefined;
-}
-export function revalidateOnePendingCashouts() {
- return mutate(
- (key) =>
- Array.isArray(key) && key[key.length - 1] === "useOnePendingCashouts", undefined, { revalidate: true }
- );
-}
-export function useOnePendingCashouts(account: string) {
- const { state: credentials } = useSessionState();
- const { bank: api, config } = useBankCoreApiContext();
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
-
- async function fetcher([username, token]: [string, AccessToken]) {
- const list = await api.getAccountCashouts({ username, token });
- if (list.type !== "ok") {
- return list;
- }
- const pendingCashout = list.body.cashouts.length > 0 ? list.body.cashouts[0] : undefined;
- if (!pendingCashout) return opFixedSuccess(undefined);
- const cashoutInfo = await api.getCashoutById(
- { username, token },
- pendingCashout.cashout_id,
- );
- if (cashoutInfo.type !== "ok") {
- return cashoutInfo;
- }
- return opFixedSuccess({
- ...cashoutInfo.body,
- id: pendingCashout.cashout_id,
- });
- }
-
- const { data, error } = useSWR<
- | OperationOk<CashoutWithId | undefined>
- | TalerCoreBankErrorsByMethod<"getAccountCashouts">
- | TalerCoreBankErrorsByMethod<"getCashoutById">,
- TalerHttpError
- >(
- !config.allow_conversion
- ? undefined
- : [account, token, "useOnePendingCashouts"],
- fetcher,
- {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- },
- );
-
- if (data) return data;
- if (error) return error;
- return undefined;
-}
-
-export function revalidateCashouts() {
- return mutate((key) => Array.isArray(key) && key[key.length - 1] === "useCashouts");
-}
-export function useCashouts(account: string) {
- const { state: credentials } = useSessionState();
- const { bank: api, config } = useBankCoreApiContext();
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
-
- async function fetcher([username, token]: [string, AccessToken]) {
- const list = await api.getAccountCashouts({ username, token });
- if (list.type !== "ok") {
- return list;
- }
- const all: Array<CashoutWithId | undefined> = await Promise.all(
- list.body.cashouts.map(async (c) => {
- const r = await api.getCashoutById({ username, token }, c.cashout_id);
- if (r.type === "fail") {
- return undefined;
- }
- return { ...r.body, id: c.cashout_id };
- }),
- );
- const cashouts = all.filter(notUndefined);
- return { type: "ok" as const, body: { cashouts }};
- }
- const { data, error } = useSWR<
- | OperationOk<{ cashouts: CashoutWithId[] }>
- | TalerCoreBankErrorsByMethod<"getAccountCashouts">,
- TalerHttpError
- >(
- !config.allow_conversion ? undefined : [account, token, "useCashouts"],
- fetcher,
- {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- },
- );
-
- if (data) return data;
- if (error) return error;
- return undefined;
-}
-
-export function revalidateCashoutDetails() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "getCashoutById", undefined, { revalidate: true }
- );
-}
-export function useCashoutDetails(cashoutId: number | undefined) {
- const { state: credentials } = useSessionState();
- const creds = credentials.status !== "loggedIn" ? undefined : credentials;
- const { bank: api } = useBankCoreApiContext();
-
- async function fetcher([username, token, id]: [string, AccessToken, number]) {
- return api.getCashoutById({ username, token }, id);
- }
-
- const { data, error } = useSWR<
- TalerCoreBankResultByMethod<"getCashoutById">,
- TalerHttpError
- >(
- cashoutId === undefined
- ? undefined
- : [creds?.username, creds?.token, cashoutId, "getCashoutById"],
- fetcher,
- {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- },
- );
-
- if (data) return data;
- if (error) return error;
- return undefined;
-}
-export type MonitorMetrics = {
- lastHour: TalerCoreBankResultByMethod<"getMonitor">;
- lastDay: TalerCoreBankResultByMethod<"getMonitor">;
- lastMonth: TalerCoreBankResultByMethod<"getMonitor">;
-};
-
-export type LastMonitor = {
- current: TalerCoreBankResultByMethod<"getMonitor">;
- previous: TalerCoreBankResultByMethod<"getMonitor">;
-};
-export function revalidateLastMonitorInfo() {
- return mutate(
- (key) => Array.isArray(key) && key[key.length - 1] === "useLastMonitorInfo", undefined, { revalidate: true }
- );
-}
-export function useLastMonitorInfo(
- currentMoment: number,
- previousMoment: number,
- timeframe: TalerCorebankApi.MonitorTimeframeParam,
-) {
- const { bank: api } = useBankCoreApiContext();
- const { state: credentials } = useSessionState();
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
-
- async function fetcher([token, timeframe]: [
- AccessToken,
- TalerCorebankApi.MonitorTimeframeParam,
- ]) {
- const [current, previous] = await Promise.all([
- api.getMonitor(token, { timeframe, which: currentMoment }),
- api.getMonitor(token, { timeframe, which: previousMoment }),
- ]);
- return {
- current,
- previous,
- };
- }
-
- const { data, error } = useSWR<LastMonitor, TalerHttpError>(
- !token ? undefined : [token, timeframe, "useLastMonitorInfo"],
- fetcher,
- {
- refreshInterval: 0,
- refreshWhenHidden: false,
- revalidateOnFocus: false,
- revalidateOnReconnect: false,
- refreshWhenOffline: false,
- errorRetryCount: 0,
- errorRetryInterval: 1,
- shouldRetryOnError: false,
- keepPreviousData: true,
- },
- );
-
- if (data) return data;
- if (error) return error;
- return undefined;
-}
diff --git a/packages/demobank-ui/src/hooks/session.ts b/packages/demobank-ui/src/hooks/session.ts
deleted file mode 100644
index 35f87e1be..000000000
--- a/packages/demobank-ui/src/hooks/session.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AccessToken,
- Codec,
- buildCodecForObject,
- buildCodecForUnion,
- codecForBoolean,
- codecForConstString,
- codecForString,
-} from "@gnu-taler/taler-util";
-import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
-import { mutate } from "swr";
-
-/**
- * Has the information to reach and
- * authenticate at the bank's backend.
- */
-export type SessionState = LoggedIn | LoggedOut | Expired;
-
-interface LoggedIn {
- status: "loggedIn";
- isUserAdministrator: boolean;
- username: string;
- token: AccessToken;
-}
-interface Expired {
- status: "expired";
- isUserAdministrator: boolean;
- username: string;
-}
-interface LoggedOut {
- status: "loggedOut";
-}
-
-export const codecForSessionStateLoggedIn = (): Codec<LoggedIn> =>
- buildCodecForObject<LoggedIn>()
- .property("status", codecForConstString("loggedIn"))
- .property("username", codecForString())
- .property("token", codecForString() as Codec<AccessToken>)
- .property("isUserAdministrator", codecForBoolean())
- .build("SessionState.LoggedIn");
-
-export const codecForSessionStateExpired = (): Codec<Expired> =>
- buildCodecForObject<Expired>()
- .property("status", codecForConstString("expired"))
- .property("username", codecForString())
- .property("isUserAdministrator", codecForBoolean())
- .build("SessionState.Expired");
-
-export const codecForSessionStateLoggedOut = (): Codec<LoggedOut> =>
- buildCodecForObject<LoggedOut>()
- .property("status", codecForConstString("loggedOut"))
- .build("SessionState.LoggedOut");
-
-export const codecForSessionState = (): Codec<SessionState> =>
- buildCodecForUnion<SessionState>()
- .discriminateOn("status")
- .alternative("loggedIn", codecForSessionStateLoggedIn())
- .alternative("loggedOut", codecForSessionStateLoggedOut())
- .alternative("expired", codecForSessionStateExpired())
- .build("SessionState");
-
-export const defaultState: SessionState = {
- status: "loggedOut",
-};
-
-export interface SessionStateHandler {
- state: SessionState;
- logOut(): void;
- expired(): void;
- logIn(info: { username: string; token: AccessToken }): void;
-}
-
-const SESSION_STATE_KEY = buildStorageKey("bank-state", codecForSessionState());
-
-/**
- * Return getters and setters for
- * login credentials and backend's
- * base URL.
- */
-export function useSessionState(): SessionStateHandler {
- const { value: state, update } = useLocalStorage(
- SESSION_STATE_KEY,
- defaultState,
- );
-
- return {
- state,
- logOut() {
- update(defaultState);
- },
- expired() {
- if (state.status === "loggedOut") return;
- const nextState: SessionState = {
- status: "expired",
- username: state.username,
- isUserAdministrator: state.username === "admin",
- };
- update(nextState);
- },
- logIn(info) {
- // admin is defined by the username
- const nextState: SessionState = {
- status: "loggedIn",
- ...info,
- isUserAdministrator: info.username === "admin",
- };
- update(nextState);
- cleanAllCache();
- },
- };
-}
-
-function cleanAllCache(): void {
- mutate(() => true, undefined, { revalidate: false });
-}
diff --git a/packages/demobank-ui/src/i18n/bank.pot b/packages/demobank-ui/src/i18n/bank.pot
deleted file mode 100644
index 1f11b8f10..000000000
--- a/packages/demobank-ui/src/i18n/bank.pot
+++ /dev/null
@@ -1,1740 +0,0 @@
-# This file is part of GNU Taler
-# (C) 2022-2024 Taler Systems S.A.
-#
-# GNU Taler is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-#
-# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: Taler Bank\n"
-"Report-Msgid-Bugs-To: taler@gnu.org\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-#: src/utils.ts:137
-#, c-format
-msgid "Operation failed, please report"
-msgstr ""
-
-#: src/utils.ts:156
-#, c-format
-msgid "Request timeout"
-msgstr ""
-
-#: src/utils.ts:165
-#, c-format
-msgid "Request throttled"
-msgstr ""
-
-#: src/utils.ts:174
-#, c-format
-msgid "Malformed response"
-msgstr ""
-
-#: src/utils.ts:183
-#, c-format
-msgid "Network error"
-msgstr ""
-
-#: src/utils.ts:192
-#, c-format
-msgid "Unexpected request error"
-msgstr ""
-
-#: src/utils.ts:201
-#, c-format
-msgid "Unexpected error"
-msgstr ""
-
-#: src/utils.ts:377
-#, c-format
-msgid "IBAN numbers usually have more that 4 digits"
-msgstr ""
-
-#: src/utils.ts:379
-#, c-format
-msgid "IBAN numbers usually have less that 34 digits"
-msgstr ""
-
-#: src/utils.ts:387
-#, c-format
-msgid "IBAN country code not found"
-msgstr ""
-
-#: src/utils.ts:401
-#, c-format
-msgid "IBAN number is not valid, checksum is wrong"
-msgstr ""
-
-#: src/context/config.ts:136
-#, c-format
-msgid ""
-"the bank backend is not supported. supported version \"%1$s\", server version "
-"\"%2$s\""
-msgstr ""
-
-#: src/hooks/preferences.ts:55
-#, c-format
-msgid "Max withdrawal amount"
-msgstr ""
-
-#: src/hooks/preferences.ts:57
-#, c-format
-msgid "Show withdrawal confirmation"
-msgstr ""
-
-#: src/hooks/preferences.ts:59
-#, c-format
-msgid "Show demo description"
-msgstr ""
-
-#: src/hooks/preferences.ts:61
-#, c-format
-msgid "Show install wallet first"
-msgstr ""
-
-#: src/hooks/preferences.ts:63
-#, c-format
-msgid "Use fast withdrawal form"
-msgstr ""
-
-#: src/hooks/preferences.ts:65
-#, c-format
-msgid "Show debug info"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:90
-#, c-format
-msgid "required"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:92
-#, c-format
-msgid "IBAN should have just uppercased letters and numbers"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:98
-#, c-format
-msgid "not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:100
-#, c-format
-msgid "should be greater than 0"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:102
-#, c-format
-msgid "balance is not enough"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:112
-#, c-format
-msgid "does not follow the pattern"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:114
-#, c-format
-msgid "only \"IBAN\" target are supported"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:116
-#, c-format
-msgid "use the \"amount\" parameter to specify the amount to be transferred"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:118
-#, c-format
-msgid "the amount is not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:120
-#, c-format
-msgid "use the \"message\" parameter to specify a reference text for the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:160
-#, c-format
-msgid "The request was invalid or the payto://-URI used unacceptable features."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:167
-#, c-format
-msgid "Not enough permission to complete the operation."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:174
-#, c-format
-msgid "The destination account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:181
-#, c-format
-msgid "The origin and the destination of the transfer can't be the same."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:188
-#, c-format
-msgid "Your balance is not enough."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:195
-#, c-format
-msgid "The origin account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:212
-#, c-format
-msgid "Wire transfer created!"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:270
-#, c-format
-msgid "Using a form"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:310
-#, c-format
-msgid "Import payto:// URI"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:335
-#, c-format
-msgid "Recipient"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:359
-#, c-format
-msgid "IBAN of the recipient's account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:369
-#, c-format
-msgid "Transfer subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:377
-#, c-format
-msgid "subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:390
-#, c-format
-msgid "some text to identify the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:400
-#, c-format
-msgid "Amount"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:415
-#, c-format
-msgid "amount to transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:425
-#, c-format
-msgid "payto URI:"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:436
-#, c-format
-msgid "uniform resource identifier of the target account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:437
-#, c-format
-msgid "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:457
-#, c-format
-msgid "Cancel"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:471
-#, c-format
-msgid "Send"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:71
-#, c-format
-msgid "Missing username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:75
-#, c-format
-msgid "Missing password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:104
-#, c-format
-msgid "Wrong credentials for \"%1$s\""
-msgstr ""
-
-#: src/pages/LoginForm.tsx:111
-#, c-format
-msgid "Account not found"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:142
-#, c-format
-msgid "Username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:156
-#, c-format
-msgid "username of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:175
-#, c-format
-msgid "Password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:188
-#, c-format
-msgid "password of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:223
-#, c-format
-msgid "Check"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:237
-#, c-format
-msgid "Log in"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:249
-#, c-format
-msgid "Register"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:52
-#, c-format
-msgid "Latest transactions"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:63
-#, c-format
-msgid "Date"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:71
-#, c-format
-msgid "Counterpart"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:75
-#, c-format
-msgid "Subject"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:111
-#, c-format
-msgid "sent"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:112
-#, c-format
-msgid "received"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:127
-#, c-format
-msgid "invalid value"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "to"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "from"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:202
-#, c-format
-msgid "First page"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:209
-#, c-format
-msgid "Next"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:86
-#, c-format
-msgid "Wire transfer completed!"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:93
-#, c-format
-msgid "The withdrawal has been aborted previously and can't be confirmed"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:100
-#, c-format
-msgid ""
-"The withdrawal operation can't be confirmed before a wallet accepted the "
-"transaction."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:107
-#, c-format
-msgid "The operation id is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:114
-#, c-format
-msgid "The operation was not found."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:121
-#, c-format
-msgid "Your balance is not enough for the operation."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:155
-#, c-format
-msgid "The reserve operation has been confirmed previously and can't be aborted"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:186
-#, c-format
-msgid "Confirm the withdrawal operation"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:203
-#, c-format
-msgid "Wire transfer details"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:217
-#, c-format
-msgid "Taler Exchange operator's account"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:228
-#, c-format
-msgid "Taler Exchange operator's name"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:317
-#, c-format
-msgid "Transfer"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:342
-#, c-format
-msgid "Authentication required"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:352
-#, c-format
-msgid "This operation was created with other username"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:209
-#, c-format
-msgid ""
-"Unauthorized to make the operation, maybe the session has expired or the "
-"password changed."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:218
-#, c-format
-msgid "The operation was rejected due to insufficient funds."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:268
-#, c-format
-msgid "Withdrawal confirmed"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:272
-#, c-format
-msgid ""
-"The wire transfer to the Taler operator has been initiated. You will soon "
-"receive the requested amount in your Taler wallet."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:287
-#, c-format
-msgid "Do not show this again"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:319
-#, c-format
-msgid "Close"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:399
-#, c-format
-msgid "On this device"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:404
-#, c-format
-msgid ""
-"If you are using a web browser on desktop you should access your wallet with the "
-"GNU Taler WebExtension now or click the link if your WebExtension have the "
-"\"Inject Taler support\" option enabled."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:417
-#, c-format
-msgid "Start"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:426
-#, c-format
-msgid "On a mobile phone"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:431
-#, c-format
-msgid "Scan the QR code with your mobile device."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:73
-#, c-format
-msgid "There is an operation already"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:75
-#, c-format
-msgid "Complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:84
-#, c-format
-msgid "this page"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:101
-#, c-format
-msgid "invalid"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:116
-#, c-format
-msgid "Server responded with an invalid withdraw URI"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:117
-#, c-format
-msgid "Withdraw URI: %1$s"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:132
-#, c-format
-msgid "The operation was rejected due to insufficient funds"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:253
-#, c-format
-msgid "Continue"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:282
-#, c-format
-msgid "Prepare your wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:285
-#, c-format
-msgid ""
-"After using your wallet you will need to confirm or cancel the operation on this "
-"site."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:295
-#, c-format
-msgid "You need a GNU Taler Wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:300
-#, c-format
-msgid "If you don't have one yet you can follow the instruction in"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:55
-#, c-format
-msgid "Send money"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:73
-#, c-format
-msgid "to a %1$s wallet"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:95
-#, c-format
-msgid "Withdraw digital money into your mobile wallet or browser extension"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:109
-#, c-format
-msgid "operation ready"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:129
-#, c-format
-msgid "to another bank account"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:149
-#, c-format
-msgid "Make a wire transfer to an account with known bank account number."
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:171
-#, c-format
-msgid "Transfer details"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:41
-#, c-format
-msgid "This is a demo bank"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:46
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would work. "
-"In addition to using your own bank account, you can also see the transaction "
-"history of some %1$s."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:53
-#, c-format
-msgid "This part of the demo shows how a bank that supports Taler directly would work."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:70
-#, c-format
-msgid "Pending account delete operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:72
-#, c-format
-msgid "Pending account update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:74
-#, c-format
-msgid "Pending password update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:76
-#, c-format
-msgid "Pending transaction operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:78
-#, c-format
-msgid "Pending withdrawal operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:80
-#, c-format
-msgid "Pending cashout operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:91
-#, c-format
-msgid "You can complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:64
-#, c-format
-msgid "Internal error, please report."
-msgstr ""
-
-#: src/pages/BankFrame.tsx:100
-#, c-format
-msgid "Preferences"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:184
-#, c-format
-msgid "Welcome, %1$s"
-msgstr ""
-
-#: src/pages/WireTransfer.tsx:79
-#, c-format
-msgid "Make a wire transfer"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:72
-#, c-format
-msgid "Accounts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:75
-#, c-format
-msgid "A list of all business account in the bank."
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:86
-#, c-format
-msgid "Create account"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:106
-#, c-format
-msgid "Name"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:110
-#, c-format
-msgid "Balance"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:112
-#, c-format
-msgid "Actions"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:151
-#, c-format
-msgid "unknown"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:170
-#, c-format
-msgid "change password"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:179
-#, c-format
-msgid "cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:189
-#, c-format
-msgid "remove"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:168
-#, c-format
-msgid "Cashout not implemented"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:184
-#, c-format
-msgid "Select a section"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:202
-#, c-format
-msgid "Last hour"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:208
-#, c-format
-msgid "Last day"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:216
-#, c-format
-msgid "Last month"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:222
-#, c-format
-msgid "Last year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:310
-#, c-format
-msgid "Last Year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:325
-#, c-format
-msgid "Trading volume on %1$s compared to %2$s"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:342
-#, c-format
-msgid "Cashin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:352
-#, c-format
-msgid "Cashout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:364
-#, c-format
-msgid "Payin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:374
-#, c-format
-msgid "Payout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:388
-#, c-format
-msgid "download stats as CSV"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:494
-#, c-format
-msgid "Decreased by"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:498
-#, c-format
-msgid "Increased by"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:89
-#, c-format
-msgid "Download bank stats"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:110
-#, c-format
-msgid "Include hour metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:143
-#, c-format
-msgid "Include day metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:173
-#, c-format
-msgid "Include month metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:206
-#, c-format
-msgid "Include year metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:239
-#, c-format
-msgid "Include table header"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:272
-#, c-format
-msgid "Add previous metric for compare"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:307
-#, c-format
-msgid "Fail on first error"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:364
-#, c-format
-msgid "Download"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:381
-#, c-format
-msgid "downloading... %1$s"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:399
-#, c-format
-msgid "Download completed"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:400
-#, c-format
-msgid "click here to save the file in your computer"
-msgstr ""
-
-#: src/pages/PublicHistoriesPage.tsx:78
-#, c-format
-msgid "History of public accounts"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:48
-#, c-format
-msgid "Currently, the bank is not accepting new registrations!"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:87
-#, c-format
-msgid "Missing name"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:91
-#, c-format
-msgid "Use letters and numbers only, and start with a lowercase letter"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:107
-#, c-format
-msgid "Passwords don't match"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:130
-#, c-format
-msgid "Server replied with invalid phone or email."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:137
-#, c-format
-msgid "Registration is disabled because the bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:144
-#, c-format
-msgid "No enough permission to create that account."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:151
-#, c-format
-msgid "That account id is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:158
-#, c-format
-msgid "That username is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:165
-#, c-format
-msgid "That username can't be used because is reserved."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:172
-#, c-format
-msgid "Only admin is allow to set debt limit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:179
-#, c-format
-msgid "No information for the selected authentication channel."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:186
-#, c-format
-msgid "Authentication channel is not supported."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:193
-#, c-format
-msgid "Only admin can create accounts with second factor authentication."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:233
-#, c-format
-msgid "Account registration"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:315
-#, c-format
-msgid "Repeat password"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:457
-#, c-format
-msgid "Create a random temporary user"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:110
-#, c-format
-msgid "If you have a Taler wallet installed in this device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:116
-#, c-format
-msgid ""
-"You will see the details of the operation in your wallet including the fees (if "
-"applies). If you still don't have one you can install it following instructions "
-"in"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:143
-#, c-format
-msgid "Withdraw"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:152
-#, c-format
-msgid "Or if you have the wallet in another device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:157
-#, c-format
-msgid "Scan the QR below to start the withdrawal."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:79
-#, c-format
-msgid "Operation aborted"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:82
-#, c-format
-msgid ""
-"The wire transfer to the Taler Exchange operator's account was aborted, your "
-"balance was not affected."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:88
-#, c-format
-msgid "You can close this page now or continue to the account page."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:147
-#, c-format
-msgid "Done"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:158
-#, c-format
-msgid "Operation canceled"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:173
-#, c-format
-msgid "The operation is marked as 'selected' but some step in the withdrawal failed"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:175
-#, c-format
-msgid "The account is selected but no withdrawal identification found."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:188
-#, c-format
-msgid ""
-"There is a withdrawal identification but no account has been selected or the "
-"selected account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:202
-#, c-format
-msgid ""
-"No withdrawal ID found and no account has been selected or the selected account "
-"is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:259
-#, c-format
-msgid "Operation not found"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:263
-#, c-format
-msgid ""
-"This operation is not known by the server. The operation id is wrong or the "
-"server deleted the operation information before reaching here."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:278
-#, c-format
-msgid "Cotinue to dashboard"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:98
-#, c-format
-msgid "Cashout not found. It may be also mean that it was already aborted."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:136
-#, c-format
-msgid "Challenge not found."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:143
-#, c-format
-msgid "This user is not authorized to complete this challenge."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:150
-#, c-format
-msgid "Too many attempts, try another code."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:157
-#, c-format
-msgid "The confirmation code is wrong, try again."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:164
-#, c-format
-msgid "The operation expired."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:197
-#, c-format
-msgid "The operation failed."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:212
-#, c-format
-msgid "The operation needs another confirmation to complete."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:224
-#, c-format
-msgid "Account delete"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:226
-#, c-format
-msgid "Account update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:228
-#, c-format
-msgid "Password update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:230
-#, c-format
-msgid "Wire transfer"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:232
-#, c-format
-msgid "Withdrawal"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:248
-#, c-format
-msgid "Confirm the operation"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:271
-#, c-format
-msgid "Enter the confirmation code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:313
-#, c-format
-msgid "Confirm"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:348
-#, c-format
-msgid "Send again"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:359
-#, c-format
-msgid "Send code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:369
-#, c-format
-msgid "Operation details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:529
-#, c-format
-msgid "Challenge details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:536
-#, c-format
-msgid "Sent at"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:551
-#, c-format
-msgid "To phone"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:553
-#, c-format
-msgid "To email"
-msgstr ""
-
-#: src/pages/WithdrawalOperationPage.tsx:49
-#, c-format
-msgid "The Withdrawal URI is not valid"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:100
-#, c-format
-msgid "Latest cashouts"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:111
-#, c-format
-msgid "Created"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:115
-#, c-format
-msgid "Total debit"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:119
-#, c-format
-msgid "Total credit"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:70
-#, c-format
-msgid "Details"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:74
-#, c-format
-msgid "Delete"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:78
-#, c-format
-msgid "Credentials"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:82
-#, c-format
-msgid "Cashouts"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:95
-#, c-format
-msgid "Unable to create a cashout"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:96
-#, c-format
-msgid "The bank configuration does not support cashout operations."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:223
-#, c-format
-msgid "need to be higher due to fees"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:225
-#, c-format
-msgid "the total transfer at destination will be zero"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:250
-#, c-format
-msgid "Cashout created"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:272
-#, c-format
-msgid "Duplicated request detected, check if the operation succeeded or try again."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:279
-#, c-format
-msgid "The conversion rate was incorrectly applied"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:286
-#, c-format
-msgid "The account does not have sufficient funds"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:293
-#, c-format
-msgid "Cashouts are not supported"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:300
-#, c-format
-msgid "Missing cashout URI in the profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:307
-#, c-format
-msgid ""
-"Sending the confirmation message failed, retry later or contact the "
-"administrator."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:339
-#, c-format
-msgid "Conversion rate"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:360
-#, c-format
-msgid "Fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:374
-#, c-format
-msgid "To account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:381
-#, c-format
-msgid "No cashout account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:382
-#, c-format
-msgid "Before doing a cashout you need to complete your profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:440
-#, c-format
-msgid "Amount to send"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:441
-#, c-format
-msgid "Amount to receive"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:490
-#, c-format
-msgid "Total cost"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:505
-#, c-format
-msgid "Balance left"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:520
-#, c-format
-msgid "Before fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:533
-#, c-format
-msgid "Total cashout transfer"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:553
-#, c-format
-msgid "No cashout channel available"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:555
-#, c-format
-msgid ""
-"Before doing a cashout the server need to provide an second channel to confirm "
-"the operation"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:567
-#, c-format
-msgid "Second factor authentication"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:598
-#, c-format
-msgid "Email"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:600
-#, c-format
-msgid "add a email in your profile to enable this option"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:646
-#, c-format
-msgid "SMS"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:648
-#, c-format
-msgid "add a phone number in your profile to enable this option"
-msgstr ""
-
-#: src/pages/account/CashoutListForAccount.tsx:52
-#, c-format
-msgid "Cashout for account %1$s"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:165
-#, c-format
-msgid "it doesn't have the pattern of an IBAN number"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:185
-#, c-format
-msgid "it doesn't have the pattern of an email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:190
-#, c-format
-msgid "should start with +"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:192
-#, c-format
-msgid "phone number can't have other than numbers"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:329
-#, c-format
-msgid "account identification in the bank"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:365
-#, c-format
-msgid "name of the person owner the account"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:374
-#, c-format
-msgid "Internal IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:377
-#, c-format
-msgid "if empty a random account number will be assigned"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:378
-#, c-format
-msgid "account identification for bank transfer"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:423
-#, c-format
-msgid "Phone"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:451
-#, c-format
-msgid "Cashout IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:452
-#, c-format
-msgid "account number where the money is going to be sent when doing cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:470
-#, c-format
-msgid "Max debt"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:494
-#, c-format
-msgid "how much is user able to transfer after zero balance"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:508
-#, c-format
-msgid "Is this a Taler Exchange?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:549
-#, c-format
-msgid "This server doesn't support second factor authentication."
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:560
-#, c-format
-msgid "Enable second factor authentication"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:596
-#, c-format
-msgid "Using email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:654
-#, c-format
-msgid "Using SMS"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:691
-#, c-format
-msgid "Is this account public?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:719
-#, c-format
-msgid "public accounts have their balance publicly accessible"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:100
-#, c-format
-msgid "Account updated"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:107
-#, c-format
-msgid "The rights to change the account are not sufficient"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:114
-#, c-format
-msgid "The username was not found"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:121
-#, c-format
-msgid "You can't change the legal name, please contact the your account administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:128
-#, c-format
-msgid "You can't change the debt limit, please contact the your account administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:135
-#, c-format
-msgid ""
-"You can't change the cashout address, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:177
-#, c-format
-msgid "Account \"%1$s\""
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:190
-#, c-format
-msgid "Change details"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:235
-#, c-format
-msgid "Update"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:78
-#, c-format
-msgid "password doesn't match"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:95
-#, c-format
-msgid "Password changed"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:102
-#, c-format
-msgid "Not authorized to change the password, maybe the session is invalid."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:112
-#, c-format
-msgid ""
-"You need to provide the old password. If you don't have it contact your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:117
-#, c-format
-msgid "Your current password doesn't match, can't change to a new password."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:149
-#, c-format
-msgid "Update password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:167
-#, c-format
-msgid "New password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:195
-#, c-format
-msgid "Type it again"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:217
-#, c-format
-msgid "repeat the same password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:227
-#, c-format
-msgid "Current password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:248
-#, c-format
-msgid "your current password, for security"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:272
-#, c-format
-msgid "Change"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:74
-#, c-format
-msgid ""
-"Account created with password \"%1$s\". The user must change the password on the "
-"next login."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:83
-#, c-format
-msgid "Server replied that phone or email is invalid"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:90
-#, c-format
-msgid "The rights to perform the operation are not sufficient"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:97
-#, c-format
-msgid "Account username is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:104
-#, c-format
-msgid "Account id is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:111
-#, c-format
-msgid "Bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:118
-#, c-format
-msgid "Account username can't be used because is reserved"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:160
-#, c-format
-msgid "Can't create accounts"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:161
-#, c-format
-msgid "Only system admin can create accounts."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:183
-#, c-format
-msgid "New business account"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:209
-#, c-format
-msgid "Create"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:94
-#, c-format
-msgid "Can't delete the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:95
-#, c-format
-msgid ""
-"The account can't be delete while still holding some balance. First make sure "
-"that the owner make a complete cashout."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:117
-#, c-format
-msgid "Account removed"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:124
-#, c-format
-msgid "No enough permission to delete the account."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:131
-#, c-format
-msgid "The username was not found."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:138
-#, c-format
-msgid "Can't delete a reserved username."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:145
-#, c-format
-msgid "Can't delete an account with balance different than zero."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:170
-#, c-format
-msgid "name doesn't match"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:180
-#, c-format
-msgid "You are going to remove the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:182
-#, c-format
-msgid "This step can't be undone."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:188
-#, c-format
-msgid "Deleting account \"%1$s\""
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:206
-#, c-format
-msgid "Verification"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:231
-#, c-format
-msgid "enter the account name that is going to be deleted"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:49
-#, c-format
-msgid "cashout id should be a number"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:65
-#, c-format
-msgid "This cashout not found. Maybe already aborted."
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:106
-#, c-format
-msgid "Cashout detail"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:139
-#, c-format
-msgid "Debited"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:154
-#, c-format
-msgid "Credited"
-msgstr ""
-
-#: src/Routing.tsx:140
-#, c-format
-msgid "Welcome to %1$s!"
-msgstr ""
-
diff --git a/packages/demobank-ui/src/i18n/de.po b/packages/demobank-ui/src/i18n/de.po
deleted file mode 100644
index b01edc57d..000000000
--- a/packages/demobank-ui/src/i18n/de.po
+++ /dev/null
@@ -1,1778 +0,0 @@
-# This file is part of GNU Taler
-# (C) 2021 Taler Systems S.A.
-# GNU Taler is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-# You should have received a copy of the GNU General Public License along with
-# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Taler Wallet\n"
-"Report-Msgid-Bugs-To: taler@gnu.org\n"
-"POT-Creation-Date: 2016-11-23 00:00+0100\n"
-"PO-Revision-Date: 2022-12-26 23:30+0000\n"
-"Last-Translator: Stefan Kügel <skuegel@web.de>\n"
-"Language-Team: German <https://weblate.taler.net/projects/gnu-taler/taler-"
-"bank-spa/de/>\n"
-"Language: de\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.13.1\n"
-
-#: src/utils.ts:137
-#, c-format
-msgid "Operation failed, please report"
-msgstr ""
-
-#: src/utils.ts:156
-#, c-format
-msgid "Request timeout"
-msgstr ""
-
-#: src/utils.ts:165
-#, c-format
-msgid "Request throttled"
-msgstr ""
-
-#: src/utils.ts:174
-#, c-format
-msgid "Malformed response"
-msgstr ""
-
-#: src/utils.ts:183
-#, c-format
-msgid "Network error"
-msgstr ""
-
-#: src/utils.ts:192
-#, c-format
-msgid "Unexpected request error"
-msgstr ""
-
-#: src/utils.ts:201
-#, c-format
-msgid "Unexpected error"
-msgstr ""
-
-#: src/utils.ts:377
-#, c-format
-msgid "IBAN numbers usually have more that 4 digits"
-msgstr ""
-
-#: src/utils.ts:379
-#, c-format
-msgid "IBAN numbers usually have less that 34 digits"
-msgstr ""
-
-#: src/utils.ts:387
-#, c-format
-msgid "IBAN country code not found"
-msgstr ""
-
-#: src/utils.ts:401
-#, c-format
-msgid "IBAN number is not valid, checksum is wrong"
-msgstr ""
-
-#: src/context/config.ts:136
-#, c-format
-msgid ""
-"the bank backend is not supported. supported version \"%1$s\", server "
-"version \"%2$s\""
-msgstr ""
-
-#: src/hooks/preferences.ts:55
-#, c-format
-msgid "Max withdrawal amount"
-msgstr ""
-
-#: src/hooks/preferences.ts:57
-#, c-format
-msgid "Show withdrawal confirmation"
-msgstr ""
-
-#: src/hooks/preferences.ts:59
-#, c-format
-msgid "Show demo description"
-msgstr ""
-
-#: src/hooks/preferences.ts:61
-#, c-format
-msgid "Show install wallet first"
-msgstr ""
-
-#: src/hooks/preferences.ts:63
-#, c-format
-msgid "Use fast withdrawal form"
-msgstr ""
-
-#: src/hooks/preferences.ts:65
-#, c-format
-msgid "Show debug info"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:90
-#, c-format
-msgid "required"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:92
-#, c-format
-msgid "IBAN should have just uppercased letters and numbers"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:98
-#, c-format
-msgid "not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:100
-#, c-format
-msgid "should be greater than 0"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:102
-#, c-format
-msgid "balance is not enough"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:112
-#, c-format
-msgid "does not follow the pattern"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:114
-#, c-format
-msgid "only \"IBAN\" target are supported"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:116
-#, c-format
-msgid "use the \"amount\" parameter to specify the amount to be transferred"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:118
-#, c-format
-msgid "the amount is not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:120
-#, c-format
-msgid ""
-"use the \"message\" parameter to specify a reference text for the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:160
-#, c-format
-msgid "The request was invalid or the payto://-URI used unacceptable features."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:167
-#, c-format
-msgid "Not enough permission to complete the operation."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:174
-#, c-format
-msgid "The destination account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:181
-#, c-format
-msgid "The origin and the destination of the transfer can't be the same."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:188
-#, c-format
-msgid "Your balance is not enough."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:195
-#, c-format
-msgid "The origin account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:212
-#, c-format
-msgid "Wire transfer created!"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:270
-#, c-format
-msgid "Using a form"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:310
-#, c-format
-msgid "Import payto:// URI"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:335
-#, c-format
-msgid "Recipient"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:359
-#, c-format
-msgid "IBAN of the recipient's account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:369
-#, c-format
-msgid "Transfer subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:377
-#, fuzzy, c-format
-msgid "subject"
-msgstr "Verwendungszweck"
-
-#: src/pages/PaytoWireTransferForm.tsx:390
-#, c-format
-msgid "some text to identify the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:400
-#, c-format
-msgid "Amount"
-msgstr "Betrag"
-
-#: src/pages/PaytoWireTransferForm.tsx:415
-#, fuzzy, c-format
-msgid "amount to transfer"
-msgstr "Betrag"
-
-#: src/pages/PaytoWireTransferForm.tsx:425
-#, c-format
-msgid "payto URI:"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:436
-#, c-format
-msgid "uniform resource identifier of the target account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:437
-#, c-format
-msgid "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:457
-#, c-format
-msgid "Cancel"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:471
-#, c-format
-msgid "Send"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:71
-#, c-format
-msgid "Missing username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:75
-#, c-format
-msgid "Missing password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:104
-#, c-format
-msgid "Wrong credentials for \"%1$s\""
-msgstr ""
-
-#: src/pages/LoginForm.tsx:111
-#, c-format
-msgid "Account not found"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:142
-#, c-format
-msgid "Username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:156
-#, c-format
-msgid "username of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:175
-#, c-format
-msgid "Password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:188
-#, fuzzy, c-format
-msgid "password of the account"
-msgstr "Buchungen auf öffentlich sichtbaren Konten"
-
-#: src/pages/LoginForm.tsx:223
-#, c-format
-msgid "Check"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:237
-#, c-format
-msgid "Log in"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:249
-#, c-format
-msgid "Register"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:52
-#, c-format
-msgid "Latest transactions"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:63
-#, c-format
-msgid "Date"
-msgstr "Datum"
-
-#: src/components/Transactions/views.tsx:71
-#, c-format
-msgid "Counterpart"
-msgstr "Empfänger"
-
-#: src/components/Transactions/views.tsx:75
-#, c-format
-msgid "Subject"
-msgstr "Verwendungszweck"
-
-#: src/components/Transactions/views.tsx:111
-#, c-format
-msgid "sent"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:112
-#, c-format
-msgid "received"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:127
-#, c-format
-msgid "invalid value"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "to"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "from"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:202
-#, c-format
-msgid "First page"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:209
-#, c-format
-msgid "Next"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:86
-#, c-format
-msgid "Wire transfer completed!"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:93
-#, c-format
-msgid "The withdrawal has been aborted previously and can't be confirmed"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:100
-#, c-format
-msgid ""
-"The withdrawal operation can't be confirmed before a wallet accepted the "
-"transaction."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:107
-#, c-format
-msgid "The operation id is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:114
-#, c-format
-msgid "The operation was not found."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:121
-#, c-format
-msgid "Your balance is not enough for the operation."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:155
-#, c-format
-msgid ""
-"The reserve operation has been confirmed previously and can't be aborted"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:186
-#, fuzzy, c-format
-msgid "Confirm the withdrawal operation"
-msgstr "Abhebung bestätigen"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:203
-#, c-format
-msgid "Wire transfer details"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:217
-#, c-format
-msgid "Taler Exchange operator's account"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:228
-#, c-format
-msgid "Taler Exchange operator's name"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:317
-#, c-format
-msgid "Transfer"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:342
-#, c-format
-msgid "Authentication required"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:352
-#, c-format
-msgid "This operation was created with other username"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:209
-#, c-format
-msgid ""
-"Unauthorized to make the operation, maybe the session has expired or the "
-"password changed."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:218
-#, c-format
-msgid "The operation was rejected due to insufficient funds."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:268
-#, c-format
-msgid "Withdrawal confirmed"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:272
-#, c-format
-msgid ""
-"The wire transfer to the Taler operator has been initiated. You will soon "
-"receive the requested amount in your Taler wallet."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:287
-#, c-format
-msgid "Do not show this again"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:319
-#, c-format
-msgid "Close"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:399
-#, c-format
-msgid "On this device"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:404
-#, c-format
-msgid ""
-"If you are using a web browser on desktop you should access your wallet with "
-"the GNU Taler WebExtension now or click the link if your WebExtension have "
-"the \"Inject Taler support\" option enabled."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:417
-#, c-format
-msgid "Start"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:426
-#, c-format
-msgid "On a mobile phone"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:431
-#, c-format
-msgid "Scan the QR code with your mobile device."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:73
-#, c-format
-msgid "There is an operation already"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:75
-#, fuzzy, c-format
-msgid "Complete or cancel the operation in"
-msgstr "Abhebung bestätigen"
-
-#: src/pages/WalletWithdrawForm.tsx:84
-#, c-format
-msgid "this page"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:101
-#, c-format
-msgid "invalid"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:116
-#, c-format
-msgid "Server responded with an invalid withdraw URI"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:117
-#, c-format
-msgid "Withdraw URI: %1$s"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:132
-#, c-format
-msgid "The operation was rejected due to insufficient funds"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:253
-#, c-format
-msgid "Continue"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:282
-#, c-format
-msgid "Prepare your wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:285
-#, c-format
-msgid ""
-"After using your wallet you will need to confirm or cancel the operation on "
-"this site."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:295
-#, c-format
-msgid "You need a GNU Taler Wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:300
-#, c-format
-msgid "If you don't have one yet you can follow the instruction in"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:55
-#, c-format
-msgid "Send money"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:73
-#, c-format
-msgid "to a %1$s wallet"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:95
-#, c-format
-msgid "Withdraw digital money into your mobile wallet or browser extension"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:109
-#, c-format
-msgid "operation ready"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:129
-#, c-format
-msgid "to another bank account"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:149
-#, c-format
-msgid "Make a wire transfer to an account with known bank account number."
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:171
-#, c-format
-msgid "Transfer details"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:41
-#, c-format
-msgid "This is a demo bank"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:46
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work. In addition to using your own bank account, you can also see the "
-"transaction history of some %1$s."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:53
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:70
-#, c-format
-msgid "Pending account delete operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:72
-#, c-format
-msgid "Pending account update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:74
-#, c-format
-msgid "Pending password update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:76
-#, c-format
-msgid "Pending transaction operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:78
-#, c-format
-msgid "Pending withdrawal operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:80
-#, c-format
-msgid "Pending cashout operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:91
-#, c-format
-msgid "You can complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:64
-#, c-format
-msgid "Internal error, please report."
-msgstr ""
-
-#: src/pages/BankFrame.tsx:100
-#, c-format
-msgid "Preferences"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:184
-#, c-format
-msgid "Welcome, %1$s"
-msgstr ""
-
-#: src/pages/WireTransfer.tsx:79
-#, c-format
-msgid "Make a wire transfer"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:72
-#, fuzzy, c-format
-msgid "Accounts"
-msgstr "Betrag"
-
-#: src/pages/admin/AccountList.tsx:75
-#, c-format
-msgid "A list of all business account in the bank."
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:86
-#, c-format
-msgid "Create account"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:106
-#, c-format
-msgid "Name"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:110
-#, c-format
-msgid "Balance"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:112
-#, c-format
-msgid "Actions"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:151
-#, c-format
-msgid "unknown"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:170
-#, c-format
-msgid "change password"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:179
-#, c-format
-msgid "cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:189
-#, c-format
-msgid "remove"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:168
-#, c-format
-msgid "Cashout not implemented"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:184
-#, c-format
-msgid "Select a section"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:202
-#, c-format
-msgid "Last hour"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:208
-#, c-format
-msgid "Last day"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:216
-#, c-format
-msgid "Last month"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:222
-#, c-format
-msgid "Last year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:310
-#, c-format
-msgid "Last Year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:325
-#, c-format
-msgid "Trading volume on %1$s compared to %2$s"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:342
-#, c-format
-msgid "Cashin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:352
-#, c-format
-msgid "Cashout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:364
-#, c-format
-msgid "Payin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:374
-#, c-format
-msgid "Payout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:388
-#, c-format
-msgid "download stats as CSV"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:494
-#, c-format
-msgid "Decreased by"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:498
-#, c-format
-msgid "Increased by"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:89
-#, c-format
-msgid "Download bank stats"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:110
-#, c-format
-msgid "Include hour metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:143
-#, c-format
-msgid "Include day metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:173
-#, c-format
-msgid "Include month metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:206
-#, c-format
-msgid "Include year metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:239
-#, c-format
-msgid "Include table header"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:272
-#, c-format
-msgid "Add previous metric for compare"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:307
-#, c-format
-msgid "Fail on first error"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:364
-#, c-format
-msgid "Download"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:381
-#, c-format
-msgid "downloading... %1$s"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:399
-#, c-format
-msgid "Download completed"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:400
-#, c-format
-msgid "click here to save the file in your computer"
-msgstr ""
-
-#: src/pages/PublicHistoriesPage.tsx:78
-#, c-format
-msgid "History of public accounts"
-msgstr "Buchungen auf öffentlich sichtbaren Konten"
-
-#: src/pages/RegistrationPage.tsx:48
-#, c-format
-msgid "Currently, the bank is not accepting new registrations!"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:87
-#, c-format
-msgid "Missing name"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:91
-#, c-format
-msgid "Use letters and numbers only, and start with a lowercase letter"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:107
-#, c-format
-msgid "Passwords don't match"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:130
-#, c-format
-msgid "Server replied with invalid phone or email."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:137
-#, c-format
-msgid "Registration is disabled because the bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:144
-#, c-format
-msgid "No enough permission to create that account."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:151
-#, c-format
-msgid "That account id is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:158
-#, c-format
-msgid "That username is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:165
-#, c-format
-msgid "That username can't be used because is reserved."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:172
-#, c-format
-msgid "Only admin is allow to set debt limit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:179
-#, c-format
-msgid "No information for the selected authentication channel."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:186
-#, c-format
-msgid "Authentication channel is not supported."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:193
-#, c-format
-msgid "Only admin can create accounts with second factor authentication."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:233
-#, c-format
-msgid "Account registration"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:315
-#, c-format
-msgid "Repeat password"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:457
-#, c-format
-msgid "Create a random temporary user"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:110
-#, c-format
-msgid "If you have a Taler wallet installed in this device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:116
-#, c-format
-msgid ""
-"You will see the details of the operation in your wallet including the fees "
-"(if applies). If you still don't have one you can install it following "
-"instructions in"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:143
-#, c-format
-msgid "Withdraw"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:152
-#, c-format
-msgid "Or if you have the wallet in another device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:157
-#, c-format
-msgid "Scan the QR below to start the withdrawal."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:79
-#, c-format
-msgid "Operation aborted"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:82
-#, c-format
-msgid ""
-"The wire transfer to the Taler Exchange operator's account was aborted, your "
-"balance was not affected."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:88
-#, c-format
-msgid "You can close this page now or continue to the account page."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:147
-#, c-format
-msgid "Done"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:158
-#, c-format
-msgid "Operation canceled"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:173
-#, c-format
-msgid ""
-"The operation is marked as 'selected' but some step in the withdrawal failed"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:175
-#, c-format
-msgid "The account is selected but no withdrawal identification found."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:188
-#, c-format
-msgid ""
-"There is a withdrawal identification but no account has been selected or the "
-"selected account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:202
-#, c-format
-msgid ""
-"No withdrawal ID found and no account has been selected or the selected "
-"account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:259
-#, c-format
-msgid "Operation not found"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:263
-#, c-format
-msgid ""
-"This operation is not known by the server. The operation id is wrong or the "
-"server deleted the operation information before reaching here."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:278
-#, c-format
-msgid "Cotinue to dashboard"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:98
-#, c-format
-msgid "Cashout not found. It may be also mean that it was already aborted."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:136
-#, c-format
-msgid "Challenge not found."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:143
-#, c-format
-msgid "This user is not authorized to complete this challenge."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:150
-#, c-format
-msgid "Too many attempts, try another code."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:157
-#, c-format
-msgid "The confirmation code is wrong, try again."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:164
-#, c-format
-msgid "The operation expired."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:197
-#, c-format
-msgid "The operation failed."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:212
-#, c-format
-msgid "The operation needs another confirmation to complete."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:224
-#, c-format
-msgid "Account delete"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:226
-#, c-format
-msgid "Account update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:228
-#, c-format
-msgid "Password update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:230
-#, c-format
-msgid "Wire transfer"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:232
-#, fuzzy, c-format
-msgid "Withdrawal"
-msgstr "Abhebung bestätigen"
-
-#: src/pages/SolveChallengePage.tsx:248
-#, fuzzy, c-format
-msgid "Confirm the operation"
-msgstr "Abhebung bestätigen"
-
-#: src/pages/SolveChallengePage.tsx:271
-#, c-format
-msgid "Enter the confirmation code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:313
-#, c-format
-msgid "Confirm"
-msgstr "Bestätigen"
-
-#: src/pages/SolveChallengePage.tsx:348
-#, c-format
-msgid "Send again"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:359
-#, c-format
-msgid "Send code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:369
-#, c-format
-msgid "Operation details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:529
-#, c-format
-msgid "Challenge details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:536
-#, c-format
-msgid "Sent at"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:551
-#, c-format
-msgid "To phone"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:553
-#, c-format
-msgid "To email"
-msgstr ""
-
-#: src/pages/WithdrawalOperationPage.tsx:49
-#, c-format
-msgid "The Withdrawal URI is not valid"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:100
-#, c-format
-msgid "Latest cashouts"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:111
-#, c-format
-msgid "Created"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:115
-#, c-format
-msgid "Total debit"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:119
-#, c-format
-msgid "Total credit"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:70
-#, c-format
-msgid "Details"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:74
-#, c-format
-msgid "Delete"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:78
-#, c-format
-msgid "Credentials"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:82
-#, c-format
-msgid "Cashouts"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:95
-#, c-format
-msgid "Unable to create a cashout"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:96
-#, c-format
-msgid "The bank configuration does not support cashout operations."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:223
-#, c-format
-msgid "need to be higher due to fees"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:225
-#, c-format
-msgid "the total transfer at destination will be zero"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:250
-#, c-format
-msgid "Cashout created"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:272
-#, c-format
-msgid ""
-"Duplicated request detected, check if the operation succeeded or try again."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:279
-#, c-format
-msgid "The conversion rate was incorrectly applied"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:286
-#, c-format
-msgid "The account does not have sufficient funds"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:293
-#, c-format
-msgid "Cashouts are not supported"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:300
-#, c-format
-msgid "Missing cashout URI in the profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:307
-#, c-format
-msgid ""
-"Sending the confirmation message failed, retry later or contact the "
-"administrator."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:339
-#, c-format
-msgid "Conversion rate"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:360
-#, c-format
-msgid "Fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:374
-#, c-format
-msgid "To account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:381
-#, c-format
-msgid "No cashout account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:382
-#, c-format
-msgid "Before doing a cashout you need to complete your profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:440
-#, fuzzy, c-format
-msgid "Amount to send"
-msgstr "Betrag"
-
-#: src/pages/business/CreateCashout.tsx:441
-#, c-format
-msgid "Amount to receive"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:490
-#, c-format
-msgid "Total cost"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:505
-#, c-format
-msgid "Balance left"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:520
-#, c-format
-msgid "Before fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:533
-#, c-format
-msgid "Total cashout transfer"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:553
-#, c-format
-msgid "No cashout channel available"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:555
-#, c-format
-msgid ""
-"Before doing a cashout the server need to provide an second channel to "
-"confirm the operation"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:567
-#, c-format
-msgid "Second factor authentication"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:598
-#, c-format
-msgid "Email"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:600
-#, c-format
-msgid "add a email in your profile to enable this option"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:646
-#, c-format
-msgid "SMS"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:648
-#, c-format
-msgid "add a phone number in your profile to enable this option"
-msgstr ""
-
-#: src/pages/account/CashoutListForAccount.tsx:52
-#, c-format
-msgid "Cashout for account %1$s"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:165
-#, c-format
-msgid "it doesn't have the pattern of an IBAN number"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:185
-#, c-format
-msgid "it doesn't have the pattern of an email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:190
-#, c-format
-msgid "should start with +"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:192
-#, c-format
-msgid "phone number can't have other than numbers"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:329
-#, c-format
-msgid "account identification in the bank"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:365
-#, c-format
-msgid "name of the person owner the account"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:374
-#, c-format
-msgid "Internal IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:377
-#, c-format
-msgid "if empty a random account number will be assigned"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:378
-#, c-format
-msgid "account identification for bank transfer"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:423
-#, c-format
-msgid "Phone"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:451
-#, c-format
-msgid "Cashout IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:452
-#, c-format
-msgid "account number where the money is going to be sent when doing cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:470
-#, c-format
-msgid "Max debt"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:494
-#, c-format
-msgid "how much is user able to transfer after zero balance"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:508
-#, c-format
-msgid "Is this a Taler Exchange?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:549
-#, c-format
-msgid "This server doesn't support second factor authentication."
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:560
-#, c-format
-msgid "Enable second factor authentication"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:596
-#, c-format
-msgid "Using email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:654
-#, c-format
-msgid "Using SMS"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:691
-#, c-format
-msgid "Is this account public?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:719
-#, c-format
-msgid "public accounts have their balance publicly accessible"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:100
-#, c-format
-msgid "Account updated"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:107
-#, c-format
-msgid "The rights to change the account are not sufficient"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:114
-#, c-format
-msgid "The username was not found"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:121
-#, c-format
-msgid ""
-"You can't change the legal name, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:128
-#, c-format
-msgid ""
-"You can't change the debt limit, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:135
-#, c-format
-msgid ""
-"You can't change the cashout address, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:177
-#, c-format
-msgid "Account \"%1$s\""
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:190
-#, c-format
-msgid "Change details"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:235
-#, c-format
-msgid "Update"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:78
-#, c-format
-msgid "password doesn't match"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:95
-#, c-format
-msgid "Password changed"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:102
-#, c-format
-msgid "Not authorized to change the password, maybe the session is invalid."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:112
-#, c-format
-msgid ""
-"You need to provide the old password. If you don't have it contact your "
-"account administrator."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:117
-#, c-format
-msgid "Your current password doesn't match, can't change to a new password."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:149
-#, c-format
-msgid "Update password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:167
-#, c-format
-msgid "New password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:195
-#, c-format
-msgid "Type it again"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:217
-#, c-format
-msgid "repeat the same password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:227
-#, c-format
-msgid "Current password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:248
-#, c-format
-msgid "your current password, for security"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:272
-#, c-format
-msgid "Change"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:74
-#, c-format
-msgid ""
-"Account created with password \"%1$s\". The user must change the password on "
-"the next login."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:83
-#, c-format
-msgid "Server replied that phone or email is invalid"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:90
-#, c-format
-msgid "The rights to perform the operation are not sufficient"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:97
-#, c-format
-msgid "Account username is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:104
-#, c-format
-msgid "Account id is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:111
-#, c-format
-msgid "Bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:118
-#, c-format
-msgid "Account username can't be used because is reserved"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:160
-#, c-format
-msgid "Can't create accounts"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:161
-#, c-format
-msgid "Only system admin can create accounts."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:183
-#, c-format
-msgid "New business account"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:209
-#, c-format
-msgid "Create"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:94
-#, c-format
-msgid "Can't delete the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:95
-#, c-format
-msgid ""
-"The account can't be delete while still holding some balance. First make "
-"sure that the owner make a complete cashout."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:117
-#, c-format
-msgid "Account removed"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:124
-#, c-format
-msgid "No enough permission to delete the account."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:131
-#, c-format
-msgid "The username was not found."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:138
-#, c-format
-msgid "Can't delete a reserved username."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:145
-#, c-format
-msgid "Can't delete an account with balance different than zero."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:170
-#, c-format
-msgid "name doesn't match"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:180
-#, c-format
-msgid "You are going to remove the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:182
-#, c-format
-msgid "This step can't be undone."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:188
-#, c-format
-msgid "Deleting account \"%1$s\""
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:206
-#, c-format
-msgid "Verification"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:231
-#, c-format
-msgid "enter the account name that is going to be deleted"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:49
-#, c-format
-msgid "cashout id should be a number"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:65
-#, c-format
-msgid "This cashout not found. Maybe already aborted."
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:106
-#, c-format
-msgid "Cashout detail"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:139
-#, c-format
-msgid "Debited"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:154
-#, c-format
-msgid "Credited"
-msgstr ""
-
-#: src/Routing.tsx:140
-#, c-format
-msgid "Welcome to %1$s!"
-msgstr ""
-
-#, fuzzy, c-format
-#~ msgid "Confirmed"
-#~ msgstr "Bestätigen"
-
-#, c-format
-#~ msgid "Logout"
-#~ msgstr "Abmelden"
-
-#, c-format
-#~ msgid "Skip to main content"
-#~ msgstr "Navigationsmenü überspringen"
-
-#, c-format
-#~ msgid "Taler logo"
-#~ msgstr "Taler-Logo"
-
-#, c-format
-#~ msgid "Please login!"
-#~ msgstr "Bitte melden Sie sich an!"
-
-#, c-format
-#~ msgid "payto address"
-#~ msgstr "payto-Adresse"
-
-#, c-format
-#~ msgid "Bank account balance"
-#~ msgstr "Kontostand"
diff --git a/packages/demobank-ui/src/i18n/en.po b/packages/demobank-ui/src/i18n/en.po
deleted file mode 100644
index a9657bd32..000000000
--- a/packages/demobank-ui/src/i18n/en.po
+++ /dev/null
@@ -1,1784 +0,0 @@
-# This file is part of GNU Taler
-# (C) 2021 Taler Systems S.A.
-# GNU Taler is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-# You should have received a copy of the GNU General Public License along with
-# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Taler Wallet\n"
-"Report-Msgid-Bugs-To: taler@gnu.org\n"
-"POT-Creation-Date: 2016-11-23 00:00+0100\n"
-"PO-Revision-Date: 2022-01-08 09:57+0100\n"
-"Last-Translator: <translate@taler.net>\n"
-"Language-Team: English\n"
-"Language: en\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: src/utils.ts:137
-#, c-format
-msgid "Operation failed, please report"
-msgstr ""
-
-#: src/utils.ts:156
-#, c-format
-msgid "Request timeout"
-msgstr ""
-
-#: src/utils.ts:165
-#, c-format
-msgid "Request throttled"
-msgstr ""
-
-#: src/utils.ts:174
-#, c-format
-msgid "Malformed response"
-msgstr ""
-
-#: src/utils.ts:183
-#, c-format
-msgid "Network error"
-msgstr ""
-
-#: src/utils.ts:192
-#, c-format
-msgid "Unexpected request error"
-msgstr ""
-
-#: src/utils.ts:201
-#, c-format
-msgid "Unexpected error"
-msgstr ""
-
-#: src/utils.ts:377
-#, c-format
-msgid "IBAN numbers usually have more that 4 digits"
-msgstr ""
-
-#: src/utils.ts:379
-#, c-format
-msgid "IBAN numbers usually have less that 34 digits"
-msgstr ""
-
-#: src/utils.ts:387
-#, c-format
-msgid "IBAN country code not found"
-msgstr ""
-
-#: src/utils.ts:401
-#, c-format
-msgid "IBAN number is not valid, checksum is wrong"
-msgstr ""
-
-#: src/context/config.ts:136
-#, c-format
-msgid ""
-"the bank backend is not supported. supported version \"%1$s\", server "
-"version \"%2$s\""
-msgstr ""
-
-#: src/hooks/preferences.ts:55
-#, fuzzy, c-format
-msgid "Max withdrawal amount"
-msgstr ""
-
-#: src/hooks/preferences.ts:57
-#, c-format
-msgid "Show withdrawal confirmation"
-msgstr ""
-
-#: src/hooks/preferences.ts:59
-#, c-format
-msgid "Show demo description"
-msgstr ""
-
-#: src/hooks/preferences.ts:61
-#, c-format
-msgid "Show install wallet first"
-msgstr ""
-
-#: src/hooks/preferences.ts:63
-#, fuzzy, c-format
-msgid "Use fast withdrawal form"
-msgstr ""
-
-#: src/hooks/preferences.ts:65
-#, c-format
-msgid "Show debug info"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:90
-#, c-format
-msgid "required"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:92
-#, c-format
-msgid "IBAN should have just uppercased letters and numbers"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:98
-#, c-format
-msgid "not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:100
-#, c-format
-msgid "should be greater than 0"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:102
-#, c-format
-msgid "balance is not enough"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:112
-#, c-format
-msgid "does not follow the pattern"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:114
-#, c-format
-msgid "only \"IBAN\" target are supported"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:116
-#, c-format
-msgid "use the \"amount\" parameter to specify the amount to be transferred"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:118
-#, c-format
-msgid "the amount is not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:120
-#, c-format
-msgid ""
-"use the \"message\" parameter to specify a reference text for the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:160
-#, c-format
-msgid "The request was invalid or the payto://-URI used unacceptable features."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:167
-#, c-format
-msgid "Not enough permission to complete the operation."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:174
-#, c-format
-msgid "The destination account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:181
-#, c-format
-msgid "The origin and the destination of the transfer can't be the same."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:188
-#, c-format
-msgid "Your balance is not enough."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:195
-#, c-format
-msgid "The origin account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:212
-#, c-format
-msgid "Wire transfer created!"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:270
-#, c-format
-msgid "Using a form"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:310
-#, c-format
-msgid "Import payto:// URI"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:335
-#, c-format
-msgid "Recipient"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:359
-#, c-format
-msgid "IBAN of the recipient's account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:369
-#, c-format
-msgid "Transfer subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:377
-#, c-format
-msgid "subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:390
-#, c-format
-msgid "some text to identify the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:400
-#, c-format
-msgid "Amount"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:415
-#, fuzzy, c-format
-msgid "amount to transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:425
-#, c-format
-msgid "payto URI:"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:436
-#, c-format
-msgid "uniform resource identifier of the target account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:437
-#, c-format
-msgid "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:457
-#, c-format
-msgid "Cancel"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:471
-#, c-format
-msgid "Send"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:71
-#, c-format
-msgid "Missing username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:75
-#, c-format
-msgid "Missing password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:104
-#, c-format
-msgid "Wrong credentials for \"%1$s\""
-msgstr ""
-
-#: src/pages/LoginForm.tsx:111
-#, c-format
-msgid "Account not found"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:142
-#, c-format
-msgid "Username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:156
-#, c-format
-msgid "username of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:175
-#, c-format
-msgid "Password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:188
-#, c-format
-msgid "password of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:223
-#, c-format
-msgid "Check"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:237
-#, c-format
-msgid "Log in"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:249
-#, c-format
-msgid "Register"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:52
-#, c-format
-msgid "Latest transactions"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:63
-#, c-format
-msgid "Date"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:71
-#, c-format
-msgid "Counterpart"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:75
-#, c-format
-msgid "Subject"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:111
-#, c-format
-msgid "sent"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:112
-#, c-format
-msgid "received"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:127
-#, c-format
-msgid "invalid value"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "to"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "from"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:202
-#, c-format
-msgid "First page"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:209
-#, c-format
-msgid "Next"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:86
-#, c-format
-msgid "Wire transfer completed!"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:93
-#, c-format
-msgid "The withdrawal has been aborted previously and can't be confirmed"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:100
-#, c-format
-msgid ""
-"The withdrawal operation can't be confirmed before a wallet accepted the "
-"transaction."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:107
-#, c-format
-msgid "The operation id is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:114
-#, c-format
-msgid "The operation was not found."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:121
-#, c-format
-msgid "Your balance is not enough for the operation."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:155
-#, c-format
-msgid ""
-"The reserve operation has been confirmed previously and can't be aborted"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:186
-#, fuzzy, c-format
-msgid "Confirm the withdrawal operation"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:203
-#, c-format
-msgid "Wire transfer details"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:217
-#, c-format
-msgid "Taler Exchange operator's account"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:228
-#, c-format
-msgid "Taler Exchange operator's name"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:317
-#, c-format
-msgid "Transfer"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:342
-#, c-format
-msgid "Authentication required"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:352
-#, c-format
-msgid "This operation was created with other username"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:209
-#, c-format
-msgid ""
-"Unauthorized to make the operation, maybe the session has expired or the "
-"password changed."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:218
-#, c-format
-msgid "The operation was rejected due to insufficient funds."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:268
-#, c-format
-msgid "Withdrawal confirmed"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:272
-#, c-format
-msgid ""
-"The wire transfer to the Taler operator has been initiated. You will soon "
-"receive the requested amount in your Taler wallet."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:287
-#, c-format
-msgid "Do not show this again"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:319
-#, c-format
-msgid "Close"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:399
-#, c-format
-msgid "On this device"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:404
-#, c-format
-msgid ""
-"If you are using a web browser on desktop you should access your wallet with "
-"the GNU Taler WebExtension now or click the link if your WebExtension have "
-"the \"Inject Taler support\" option enabled."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:417
-#, c-format
-msgid "Start"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:426
-#, c-format
-msgid "On a mobile phone"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:431
-#, c-format
-msgid "Scan the QR code with your mobile device."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:73
-#, c-format
-msgid "There is an operation already"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:75
-#, fuzzy, c-format
-msgid "Complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:84
-#, c-format
-msgid "this page"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:101
-#, c-format
-msgid "invalid"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:116
-#, c-format
-msgid "Server responded with an invalid withdraw URI"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:117
-#, fuzzy, c-format
-msgid "Withdraw URI: %1$s"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:132
-#, c-format
-msgid "The operation was rejected due to insufficient funds"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:253
-#, c-format
-msgid "Continue"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:282
-#, c-format
-msgid "Prepare your wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:285
-#, c-format
-msgid ""
-"After using your wallet you will need to confirm or cancel the operation on "
-"this site."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:295
-#, fuzzy, c-format
-msgid "You need a GNU Taler Wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:300
-#, c-format
-msgid "If you don't have one yet you can follow the instruction in"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:55
-#, c-format
-msgid "Send money"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:73
-#, c-format
-msgid "to a %1$s wallet"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:95
-#, c-format
-msgid "Withdraw digital money into your mobile wallet or browser extension"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:109
-#, c-format
-msgid "operation ready"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:129
-#, c-format
-msgid "to another bank account"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:149
-#, c-format
-msgid "Make a wire transfer to an account with known bank account number."
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:171
-#, fuzzy, c-format
-msgid "Transfer details"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:41
-#, c-format
-msgid "This is a demo bank"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:46
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work. In addition to using your own bank account, you can also see the "
-"transaction history of some %1$s."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:53
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:70
-#, c-format
-msgid "Pending account delete operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:72
-#, c-format
-msgid "Pending account update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:74
-#, c-format
-msgid "Pending password update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:76
-#, c-format
-msgid "Pending transaction operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:78
-#, c-format
-msgid "Pending withdrawal operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:80
-#, c-format
-msgid "Pending cashout operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:91
-#, c-format
-msgid "You can complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:64
-#, c-format
-msgid "Internal error, please report."
-msgstr ""
-
-#: src/pages/BankFrame.tsx:100
-#, c-format
-msgid "Preferences"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:184
-#, c-format
-msgid "Welcome, %1$s"
-msgstr ""
-
-#: src/pages/WireTransfer.tsx:79
-#, c-format
-msgid "Make a wire transfer"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:72
-#, c-format
-msgid "Accounts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:75
-#, c-format
-msgid "A list of all business account in the bank."
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:86
-#, c-format
-msgid "Create account"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:106
-#, c-format
-msgid "Name"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:110
-#, c-format
-msgid "Balance"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:112
-#, c-format
-msgid "Actions"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:151
-#, c-format
-msgid "unknown"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:170
-#, c-format
-msgid "change password"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:179
-#, c-format
-msgid "cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:189
-#, c-format
-msgid "remove"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:168
-#, c-format
-msgid "Cashout not implemented"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:184
-#, c-format
-msgid "Select a section"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:202
-#, c-format
-msgid "Last hour"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:208
-#, c-format
-msgid "Last day"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:216
-#, c-format
-msgid "Last month"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:222
-#, c-format
-msgid "Last year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:310
-#, c-format
-msgid "Last Year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:325
-#, c-format
-msgid "Trading volume on %1$s compared to %2$s"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:342
-#, c-format
-msgid "Cashin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:352
-#, c-format
-msgid "Cashout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:364
-#, c-format
-msgid "Payin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:374
-#, c-format
-msgid "Payout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:388
-#, c-format
-msgid "download stats as CSV"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:494
-#, c-format
-msgid "Decreased by"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:498
-#, c-format
-msgid "Increased by"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:89
-#, c-format
-msgid "Download bank stats"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:110
-#, c-format
-msgid "Include hour metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:143
-#, c-format
-msgid "Include day metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:173
-#, c-format
-msgid "Include month metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:206
-#, c-format
-msgid "Include year metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:239
-#, c-format
-msgid "Include table header"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:272
-#, c-format
-msgid "Add previous metric for compare"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:307
-#, c-format
-msgid "Fail on first error"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:364
-#, c-format
-msgid "Download"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:381
-#, c-format
-msgid "downloading... %1$s"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:399
-#, c-format
-msgid "Download completed"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:400
-#, c-format
-msgid "click here to save the file in your computer"
-msgstr ""
-
-#: src/pages/PublicHistoriesPage.tsx:78
-#, c-format
-msgid "History of public accounts"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:48
-#, c-format
-msgid "Currently, the bank is not accepting new registrations!"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:87
-#, c-format
-msgid "Missing name"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:91
-#, c-format
-msgid "Use letters and numbers only, and start with a lowercase letter"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:107
-#, c-format
-msgid "Passwords don't match"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:130
-#, c-format
-msgid "Server replied with invalid phone or email."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:137
-#, c-format
-msgid "Registration is disabled because the bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:144
-#, c-format
-msgid "No enough permission to create that account."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:151
-#, c-format
-msgid "That account id is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:158
-#, c-format
-msgid "That username is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:165
-#, c-format
-msgid "That username can't be used because is reserved."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:172
-#, c-format
-msgid "Only admin is allow to set debt limit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:179
-#, c-format
-msgid "No information for the selected authentication channel."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:186
-#, c-format
-msgid "Authentication channel is not supported."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:193
-#, c-format
-msgid "Only admin can create accounts with second factor authentication."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:233
-#, c-format
-msgid "Account registration"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:315
-#, c-format
-msgid "Repeat password"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:457
-#, c-format
-msgid "Create a random temporary user"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:110
-#, c-format
-msgid "If you have a Taler wallet installed in this device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:116
-#, c-format
-msgid ""
-"You will see the details of the operation in your wallet including the fees "
-"(if applies). If you still don't have one you can install it following "
-"instructions in"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:143
-#, fuzzy, c-format
-msgid "Withdraw"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:152
-#, c-format
-msgid "Or if you have the wallet in another device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:157
-#, fuzzy, c-format
-msgid "Scan the QR below to start the withdrawal."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:79
-#, c-format
-msgid "Operation aborted"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:82
-#, c-format
-msgid ""
-"The wire transfer to the Taler Exchange operator's account was aborted, your "
-"balance was not affected."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:88
-#, c-format
-msgid "You can close this page now or continue to the account page."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:147
-#, c-format
-msgid "Done"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:158
-#, c-format
-msgid "Operation canceled"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:173
-#, c-format
-msgid ""
-"The operation is marked as 'selected' but some step in the withdrawal failed"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:175
-#, c-format
-msgid "The account is selected but no withdrawal identification found."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:188
-#, c-format
-msgid ""
-"There is a withdrawal identification but no account has been selected or the "
-"selected account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:202
-#, c-format
-msgid ""
-"No withdrawal ID found and no account has been selected or the selected "
-"account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:259
-#, c-format
-msgid "Operation not found"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:263
-#, c-format
-msgid ""
-"This operation is not known by the server. The operation id is wrong or the "
-"server deleted the operation information before reaching here."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:278
-#, c-format
-msgid "Cotinue to dashboard"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:98
-#, c-format
-msgid "Cashout not found. It may be also mean that it was already aborted."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:136
-#, c-format
-msgid "Challenge not found."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:143
-#, c-format
-msgid "This user is not authorized to complete this challenge."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:150
-#, c-format
-msgid "Too many attempts, try another code."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:157
-#, c-format
-msgid "The confirmation code is wrong, try again."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:164
-#, c-format
-msgid "The operation expired."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:197
-#, c-format
-msgid "The operation failed."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:212
-#, c-format
-msgid "The operation needs another confirmation to complete."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:224
-#, c-format
-msgid "Account delete"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:226
-#, c-format
-msgid "Account update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:228
-#, c-format
-msgid "Password update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:230
-#, c-format
-msgid "Wire transfer"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:232
-#, fuzzy, c-format
-msgid "Withdrawal"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:248
-#, fuzzy, c-format
-msgid "Confirm the operation"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:271
-#, c-format
-msgid "Enter the confirmation code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:313
-#, c-format
-msgid "Confirm"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:348
-#, c-format
-msgid "Send again"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:359
-#, c-format
-msgid "Send code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:369
-#, c-format
-msgid "Operation details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:529
-#, c-format
-msgid "Challenge details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:536
-#, c-format
-msgid "Sent at"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:551
-#, c-format
-msgid "To phone"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:553
-#, c-format
-msgid "To email"
-msgstr ""
-
-#: src/pages/WithdrawalOperationPage.tsx:49
-#, c-format
-msgid "The Withdrawal URI is not valid"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:100
-#, c-format
-msgid "Latest cashouts"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:111
-#, c-format
-msgid "Created"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:115
-#, c-format
-msgid "Total debit"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:119
-#, c-format
-msgid "Total credit"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:70
-#, c-format
-msgid "Details"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:74
-#, c-format
-msgid "Delete"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:78
-#, c-format
-msgid "Credentials"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:82
-#, c-format
-msgid "Cashouts"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:95
-#, c-format
-msgid "Unable to create a cashout"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:96
-#, c-format
-msgid "The bank configuration does not support cashout operations."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:223
-#, c-format
-msgid "need to be higher due to fees"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:225
-#, c-format
-msgid "the total transfer at destination will be zero"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:250
-#, c-format
-msgid "Cashout created"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:272
-#, c-format
-msgid ""
-"Duplicated request detected, check if the operation succeeded or try again."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:279
-#, c-format
-msgid "The conversion rate was incorrectly applied"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:286
-#, c-format
-msgid "The account does not have sufficient funds"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:293
-#, c-format
-msgid "Cashouts are not supported"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:300
-#, c-format
-msgid "Missing cashout URI in the profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:307
-#, c-format
-msgid ""
-"Sending the confirmation message failed, retry later or contact the "
-"administrator."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:339
-#, c-format
-msgid "Conversion rate"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:360
-#, c-format
-msgid "Fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:374
-#, c-format
-msgid "To account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:381
-#, c-format
-msgid "No cashout account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:382
-#, c-format
-msgid "Before doing a cashout you need to complete your profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:440
-#, fuzzy, c-format
-msgid "Amount to send"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:441
-#, fuzzy, c-format
-msgid "Amount to receive"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:490
-#, c-format
-msgid "Total cost"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:505
-#, c-format
-msgid "Balance left"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:520
-#, c-format
-msgid "Before fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:533
-#, c-format
-msgid "Total cashout transfer"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:553
-#, c-format
-msgid "No cashout channel available"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:555
-#, c-format
-msgid ""
-"Before doing a cashout the server need to provide an second channel to "
-"confirm the operation"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:567
-#, c-format
-msgid "Second factor authentication"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:598
-#, c-format
-msgid "Email"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:600
-#, c-format
-msgid "add a email in your profile to enable this option"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:646
-#, c-format
-msgid "SMS"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:648
-#, c-format
-msgid "add a phone number in your profile to enable this option"
-msgstr ""
-
-#: src/pages/account/CashoutListForAccount.tsx:52
-#, c-format
-msgid "Cashout for account %1$s"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:165
-#, c-format
-msgid "it doesn't have the pattern of an IBAN number"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:185
-#, c-format
-msgid "it doesn't have the pattern of an email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:190
-#, c-format
-msgid "should start with +"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:192
-#, c-format
-msgid "phone number can't have other than numbers"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:329
-#, c-format
-msgid "account identification in the bank"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:365
-#, c-format
-msgid "name of the person owner the account"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:374
-#, c-format
-msgid "Internal IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:377
-#, c-format
-msgid "if empty a random account number will be assigned"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:378
-#, c-format
-msgid "account identification for bank transfer"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:423
-#, c-format
-msgid "Phone"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:451
-#, c-format
-msgid "Cashout IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:452
-#, c-format
-msgid "account number where the money is going to be sent when doing cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:470
-#, c-format
-msgid "Max debt"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:494
-#, c-format
-msgid "how much is user able to transfer after zero balance"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:508
-#, c-format
-msgid "Is this a Taler Exchange?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:549
-#, c-format
-msgid "This server doesn't support second factor authentication."
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:560
-#, c-format
-msgid "Enable second factor authentication"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:596
-#, c-format
-msgid "Using email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:654
-#, c-format
-msgid "Using SMS"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:691
-#, c-format
-msgid "Is this account public?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:719
-#, c-format
-msgid "public accounts have their balance publicly accessible"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:100
-#, c-format
-msgid "Account updated"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:107
-#, c-format
-msgid "The rights to change the account are not sufficient"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:114
-#, c-format
-msgid "The username was not found"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:121
-#, c-format
-msgid ""
-"You can't change the legal name, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:128
-#, c-format
-msgid ""
-"You can't change the debt limit, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:135
-#, c-format
-msgid ""
-"You can't change the cashout address, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:177
-#, c-format
-msgid "Account \"%1$s\""
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:190
-#, c-format
-msgid "Change details"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:235
-#, c-format
-msgid "Update"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:78
-#, c-format
-msgid "password doesn't match"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:95
-#, c-format
-msgid "Password changed"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:102
-#, c-format
-msgid "Not authorized to change the password, maybe the session is invalid."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:112
-#, c-format
-msgid ""
-"You need to provide the old password. If you don't have it contact your "
-"account administrator."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:117
-#, c-format
-msgid "Your current password doesn't match, can't change to a new password."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:149
-#, c-format
-msgid "Update password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:167
-#, c-format
-msgid "New password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:195
-#, c-format
-msgid "Type it again"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:217
-#, c-format
-msgid "repeat the same password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:227
-#, c-format
-msgid "Current password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:248
-#, c-format
-msgid "your current password, for security"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:272
-#, c-format
-msgid "Change"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:74
-#, c-format
-msgid ""
-"Account created with password \"%1$s\". The user must change the password on "
-"the next login."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:83
-#, c-format
-msgid "Server replied that phone or email is invalid"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:90
-#, c-format
-msgid "The rights to perform the operation are not sufficient"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:97
-#, c-format
-msgid "Account username is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:104
-#, c-format
-msgid "Account id is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:111
-#, c-format
-msgid "Bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:118
-#, c-format
-msgid "Account username can't be used because is reserved"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:160
-#, c-format
-msgid "Can't create accounts"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:161
-#, c-format
-msgid "Only system admin can create accounts."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:183
-#, c-format
-msgid "New business account"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:209
-#, c-format
-msgid "Create"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:94
-#, c-format
-msgid "Can't delete the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:95
-#, c-format
-msgid ""
-"The account can't be delete while still holding some balance. First make "
-"sure that the owner make a complete cashout."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:117
-#, c-format
-msgid "Account removed"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:124
-#, c-format
-msgid "No enough permission to delete the account."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:131
-#, c-format
-msgid "The username was not found."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:138
-#, c-format
-msgid "Can't delete a reserved username."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:145
-#, c-format
-msgid "Can't delete an account with balance different than zero."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:170
-#, c-format
-msgid "name doesn't match"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:180
-#, c-format
-msgid "You are going to remove the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:182
-#, c-format
-msgid "This step can't be undone."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:188
-#, c-format
-msgid "Deleting account \"%1$s\""
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:206
-#, c-format
-msgid "Verification"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:231
-#, c-format
-msgid "enter the account name that is going to be deleted"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:49
-#, c-format
-msgid "cashout id should be a number"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:65
-#, c-format
-msgid "This cashout not found. Maybe already aborted."
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:106
-#, c-format
-msgid "Cashout detail"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:139
-#, c-format
-msgid "Debited"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:154
-#, c-format
-msgid "Credited"
-msgstr ""
-
-#: src/Routing.tsx:140
-#, c-format
-msgid "Welcome to %1$s!"
-msgstr ""
-
-#, c-format
-#~ msgid "days"
-#~ msgstr ""
-
-#, c-format
-#~ msgid "hours"
-#~ msgstr ""
-
-#, c-format
-#~ msgid "minutes"
-#~ msgstr ""
-
-#, c-format
-#~ msgid "seconds"
-#~ msgstr ""
-
-#~ msgid "Go back"
-#~ msgstr ""
-
-#, fuzzy
-#~ msgid "Withdraw Money into a Taler wallet"
-#~ msgstr ""
-
-#~ msgid "Page has a problem: logged in but backend state is lost."
-#~ msgstr ""
-
-#, fuzzy
-#~ msgid "Welcome to the euFin bank!"
-#~ msgstr ""
-
-#~ msgid "Page has a problem:"
-#~ msgstr ""
-
-#~ msgid "Sign in"
-#~ msgstr ""
diff --git a/packages/demobank-ui/src/i18n/es.po b/packages/demobank-ui/src/i18n/es.po
deleted file mode 100644
index fb69822c5..000000000
--- a/packages/demobank-ui/src/i18n/es.po
+++ /dev/null
@@ -1,2063 +0,0 @@
-# This file is part of GNU Taler
-# (C) 2021 Taler Systems S.A.
-# GNU Taler is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-# You should have received a copy of the GNU General Public License along with
-# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Taler Wallet\n"
-"Report-Msgid-Bugs-To: taler@gnu.org\n"
-"POT-Creation-Date: 2016-11-23 00:00+0100\n"
-"PO-Revision-Date: 2024-02-13 14:40+0000\n"
-"Last-Translator: Stefan Kügel <skuegel@web.de>\n"
-"Language-Team: Spanish <https://weblate.taler.net/projects/gnu-taler/"
-"taler-bank-spa/es/>\n"
-"Language: es\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 5.2.1\n"
-
-#: src/utils.ts:137
-#, c-format
-msgid "Operation failed, please report"
-msgstr "La operaicón falló, por favor reportelo"
-
-#: src/utils.ts:156
-#, c-format
-msgid "Request timeout"
-msgstr "La petición al servidor agoto su tiempo"
-
-#: src/utils.ts:165
-#, c-format
-msgid "Request throttled"
-msgstr "La petición al servidor interrumpida"
-
-#: src/utils.ts:174
-#, c-format
-msgid "Malformed response"
-msgstr "Respuesta malformada"
-
-#: src/utils.ts:183
-#, c-format
-msgid "Network error"
-msgstr "Error de conexión"
-
-#: src/utils.ts:192
-#, c-format
-msgid "Unexpected request error"
-msgstr "Error de pedido inesperado"
-
-#: src/utils.ts:201
-#, c-format
-msgid "Unexpected error"
-msgstr "Error inesperado"
-
-#: src/utils.ts:377
-#, c-format
-msgid "IBAN numbers usually have more that 4 digits"
-msgstr "Los números IBAN usualmente tienen mas de 4 digitos"
-
-#: src/utils.ts:379
-#, c-format
-msgid "IBAN numbers usually have less that 34 digits"
-msgstr "Los números IBAN usualmente tienen menos de 34 digitos"
-
-#: src/utils.ts:387
-#, c-format
-msgid "IBAN country code not found"
-msgstr "Código de pais de IBAN no encontrado"
-
-#: src/utils.ts:401
-#, c-format
-msgid "IBAN number is not valid, checksum is wrong"
-msgstr "El número IBAN no es válido, falló la verificación"
-
-#: src/context/config.ts:136
-#, c-format
-msgid ""
-"the bank backend is not supported. supported version \"%1$s\", server "
-"version \"%2$s\""
-msgstr ""
-"El servidor de bank no esta spoportado. Version soportada \"%1$s\", version "
-"del server \"%2$s\""
-
-#: src/hooks/preferences.ts:55
-#, c-format
-msgid "Max withdrawal amount"
-msgstr "Monto máximo de extracción"
-
-#: src/hooks/preferences.ts:57
-#, c-format
-msgid "Show withdrawal confirmation"
-msgstr "Mostrar confirmación de extracción"
-
-#: src/hooks/preferences.ts:59
-#, c-format
-msgid "Show demo description"
-msgstr "Mostrar descripción de demo"
-
-#: src/hooks/preferences.ts:61
-#, c-format
-msgid "Show install wallet first"
-msgstr "Mostrar instalar la billetera primero"
-
-#: src/hooks/preferences.ts:63
-#, c-format
-msgid "Use fast withdrawal form"
-msgstr "Usar formulario de extracción rápida"
-
-#: src/hooks/preferences.ts:65
-#, c-format
-msgid "Show debug info"
-msgstr "Mostrar información de depuración"
-
-#: src/pages/PaytoWireTransferForm.tsx:90
-#, c-format
-msgid "required"
-msgstr "requerido"
-
-#: src/pages/PaytoWireTransferForm.tsx:92
-#, c-format
-msgid "IBAN should have just uppercased letters and numbers"
-msgstr "IBAN debería tener letras mayúsculas y números"
-
-#: src/pages/PaytoWireTransferForm.tsx:98
-#, c-format
-msgid "not valid"
-msgstr "no válido"
-
-#: src/pages/PaytoWireTransferForm.tsx:100
-#, c-format
-msgid "should be greater than 0"
-msgstr "Debería ser mas grande que 0"
-
-#: src/pages/PaytoWireTransferForm.tsx:102
-#, c-format
-msgid "balance is not enough"
-msgstr "el saldo no es suficiente"
-
-#: src/pages/PaytoWireTransferForm.tsx:112
-#, c-format
-msgid "does not follow the pattern"
-msgstr "no tiene un patrón valido"
-
-#: src/pages/PaytoWireTransferForm.tsx:114
-#, c-format
-msgid "only \"IBAN\" target are supported"
-msgstr "solo cuentas \"IBAN\" son soportadas"
-
-#: src/pages/PaytoWireTransferForm.tsx:116
-#, c-format
-msgid "use the \"amount\" parameter to specify the amount to be transferred"
-msgstr "usa el parámetro \"amount\" para indicar el monto a ser transferido"
-
-#: src/pages/PaytoWireTransferForm.tsx:118
-#, c-format
-msgid "the amount is not valid"
-msgstr "el monto no es válido"
-
-#: src/pages/PaytoWireTransferForm.tsx:120
-#, c-format
-msgid ""
-"use the \"message\" parameter to specify a reference text for the transfer"
-msgstr ""
-"usa el parámetro \"message\" para indicar un texto de referencia en la "
-"transferencia"
-
-#: src/pages/PaytoWireTransferForm.tsx:160
-#, c-format
-msgid "The request was invalid or the payto://-URI used unacceptable features."
-msgstr ""
-"El pedido era inválido o el URI payto:// usado tiene características "
-"inaceptables."
-
-#: src/pages/PaytoWireTransferForm.tsx:167
-#, c-format
-msgid "Not enough permission to complete the operation."
-msgstr "Sin permisos suficientes para completar la operación."
-
-#: src/pages/PaytoWireTransferForm.tsx:174
-#, c-format
-msgid "The destination account \"%1$s\" was not found."
-msgstr "La cuenta de destino \"%1$s\" no fue encontrada."
-
-#: src/pages/PaytoWireTransferForm.tsx:181
-#, c-format
-msgid "The origin and the destination of the transfer can't be the same."
-msgstr "El origen y destino de la transferencia no puede ser la misma."
-
-#: src/pages/PaytoWireTransferForm.tsx:188
-#, c-format
-msgid "Your balance is not enough."
-msgstr "El saldo no es suficiente."
-
-#: src/pages/PaytoWireTransferForm.tsx:195
-#, c-format
-msgid "The origin account \"%1$s\" was not found."
-msgstr "La cuenta origen \"%1$s\" no fue encontrada."
-
-#: src/pages/PaytoWireTransferForm.tsx:212
-#, c-format
-msgid "Wire transfer created!"
-msgstr "Transferencia bancaria creada!"
-
-#: src/pages/PaytoWireTransferForm.tsx:270
-#, c-format
-msgid "Using a form"
-msgstr "Usando un formulario"
-
-#: src/pages/PaytoWireTransferForm.tsx:310
-#, c-format
-msgid "Import payto:// URI"
-msgstr "Importando un URI payto://"
-
-#: src/pages/PaytoWireTransferForm.tsx:335
-#, c-format
-msgid "Recipient"
-msgstr "Destinatario"
-
-#: src/pages/PaytoWireTransferForm.tsx:359
-#, c-format
-msgid "IBAN of the recipient's account"
-msgstr "Numero IBAN de la cuenta destinataria"
-
-#: src/pages/PaytoWireTransferForm.tsx:369
-#, c-format
-msgid "Transfer subject"
-msgstr "Asunto de transferencia"
-
-#: src/pages/PaytoWireTransferForm.tsx:377
-#, c-format
-msgid "subject"
-msgstr "asunto"
-
-#: src/pages/PaytoWireTransferForm.tsx:390
-#, c-format
-msgid "some text to identify the transfer"
-msgstr "algún texto para identificar la transferencia"
-
-#: src/pages/PaytoWireTransferForm.tsx:400
-#, c-format
-msgid "Amount"
-msgstr "Monto"
-
-#: src/pages/PaytoWireTransferForm.tsx:415
-#, c-format
-msgid "amount to transfer"
-msgstr "monto a transferir"
-
-#: src/pages/PaytoWireTransferForm.tsx:425
-#, c-format
-msgid "payto URI:"
-msgstr "payto URI:"
-
-#: src/pages/PaytoWireTransferForm.tsx:436
-#, c-format
-msgid "uniform resource identifier of the target account"
-msgstr "identificador de recurso uniforme de la cuenta destino"
-
-#: src/pages/PaytoWireTransferForm.tsx:437
-#, c-format
-msgid "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]"
-msgstr "payto://iban/[iban-destinatario]?message=[asunto]&amount=[%1$s:X.Y]"
-
-#: src/pages/PaytoWireTransferForm.tsx:457
-#, c-format
-msgid "Cancel"
-msgstr "Cancelar"
-
-#: src/pages/PaytoWireTransferForm.tsx:471
-#, c-format
-msgid "Send"
-msgstr "Envíar"
-
-#: src/pages/LoginForm.tsx:71
-#, c-format
-msgid "Missing username"
-msgstr "Falta nombre de usuario"
-
-#: src/pages/LoginForm.tsx:75
-#, c-format
-msgid "Missing password"
-msgstr "Falta contraseña"
-
-#: src/pages/LoginForm.tsx:104
-#, c-format
-msgid "Wrong credentials for \"%1$s\""
-msgstr "Credenciales incorrectas para \"%1$s\""
-
-#: src/pages/LoginForm.tsx:111
-#, c-format
-msgid "Account not found"
-msgstr "Cuenta no encontrada"
-
-#: src/pages/LoginForm.tsx:142
-#, c-format
-msgid "Username"
-msgstr "Nombre de usuario"
-
-#: src/pages/LoginForm.tsx:156
-#, c-format
-msgid "username of the account"
-msgstr "nombre de usuario de la cuenta"
-
-#: src/pages/LoginForm.tsx:175
-#, c-format
-msgid "Password"
-msgstr "Contraseña"
-
-#: src/pages/LoginForm.tsx:188
-#, c-format
-msgid "password of the account"
-msgstr "contraseña de la cuenta"
-
-#: src/pages/LoginForm.tsx:223
-#, c-format
-msgid "Check"
-msgstr "Verificar"
-
-#: src/pages/LoginForm.tsx:237
-#, c-format
-msgid "Log in"
-msgstr "Acceso"
-
-#: src/pages/LoginForm.tsx:249
-#, c-format
-msgid "Register"
-msgstr "Registrarse"
-
-#: src/components/Transactions/views.tsx:52
-#, c-format
-msgid "Latest transactions"
-msgstr "Últimas transacciones"
-
-#: src/components/Transactions/views.tsx:63
-#, c-format
-msgid "Date"
-msgstr "Fecha"
-
-#: src/components/Transactions/views.tsx:71
-#, c-format
-msgid "Counterpart"
-msgstr "Contraparte"
-
-#: src/components/Transactions/views.tsx:75
-#, c-format
-msgid "Subject"
-msgstr "Asunto"
-
-#: src/components/Transactions/views.tsx:111
-#, c-format
-msgid "sent"
-msgstr "enviado"
-
-#: src/components/Transactions/views.tsx:112
-#, c-format
-msgid "received"
-msgstr "recibido"
-
-#: src/components/Transactions/views.tsx:127
-#, c-format
-msgid "invalid value"
-msgstr "valor inválido"
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "to"
-msgstr "hacia"
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "from"
-msgstr "desde"
-
-#: src/components/Transactions/views.tsx:202
-#, c-format
-msgid "First page"
-msgstr "Primera página"
-
-#: src/components/Transactions/views.tsx:209
-#, c-format
-msgid "Next"
-msgstr "Siguiente"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:86
-#, c-format
-msgid "Wire transfer completed!"
-msgstr "Transferencia bancaria completada!"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:93
-#, c-format
-msgid "The withdrawal has been aborted previously and can't be confirmed"
-msgstr "La extracción fue abortada anteriormente y no puede ser confirmada"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:100
-#, c-format
-msgid ""
-"The withdrawal operation can't be confirmed before a wallet accepted the "
-"transaction."
-msgstr ""
-"La operación de extracción no puede ser confirmada antes de que una "
-"billetera acepte la transaccion."
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:107
-#, c-format
-msgid "The operation id is invalid."
-msgstr "El id de operación es invalido."
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:114
-#, c-format
-msgid "The operation was not found."
-msgstr "La operación no se encontró."
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:121
-#, c-format
-msgid "Your balance is not enough for the operation."
-msgstr "El saldo no es suficiente para la operación."
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:155
-#, c-format
-msgid ""
-"The reserve operation has been confirmed previously and can't be aborted"
-msgstr ""
-"La operación en la reserva ya ha sido confirmada previamente y no puede ser "
-"abortada"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:186
-#, c-format
-msgid "Confirm the withdrawal operation"
-msgstr "Confirme la operación de extracción"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:203
-#, c-format
-msgid "Wire transfer details"
-msgstr "Detalle de transferencia bancaria"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:217
-#, c-format
-msgid "Taler Exchange operator's account"
-msgstr "Cuenta del operador del Taler Exchange"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:228
-#, c-format
-msgid "Taler Exchange operator's name"
-msgstr "Nombre del operador del Taler Exchange"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:317
-#, c-format
-msgid "Transfer"
-msgstr "Transferencia"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:342
-#, c-format
-msgid "Authentication required"
-msgstr "Autenticación requerida"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:352
-#, c-format
-msgid "This operation was created with other username"
-msgstr "Esta operación fue creada con otro usuario"
-
-#: src/pages/OperationState/views.tsx:209
-#, c-format
-msgid ""
-"Unauthorized to make the operation, maybe the session has expired or the "
-"password changed."
-msgstr ""
-"No autorizado para hacer la operación, quizá la sesión haya expirado or "
-"cambió la contraseña."
-
-#: src/pages/OperationState/views.tsx:218
-#, c-format
-msgid "The operation was rejected due to insufficient funds."
-msgstr "La operación fue rechazada debido a saldo insuficiente."
-
-#: src/pages/OperationState/views.tsx:268
-#, c-format
-msgid "Withdrawal confirmed"
-msgstr "La extracción fue confirmada"
-
-#: src/pages/OperationState/views.tsx:272
-#, c-format
-msgid ""
-"The wire transfer to the Taler operator has been initiated. You will soon "
-"receive the requested amount in your Taler wallet."
-msgstr ""
-"La transferencia bancaria al operador Taler fue iniciada. Pronto recibirás "
-"el monto pedido en tu billetera Taler."
-
-#: src/pages/OperationState/views.tsx:287
-#, c-format
-msgid "Do not show this again"
-msgstr "No mostrar otra vez"
-
-#: src/pages/OperationState/views.tsx:319
-#, c-format
-msgid "Close"
-msgstr "Cerrar"
-
-#: src/pages/OperationState/views.tsx:399
-#, c-format
-msgid "On this device"
-msgstr "En este dispositivo"
-
-#: src/pages/OperationState/views.tsx:404
-#, c-format
-msgid ""
-"If you are using a web browser on desktop you should access your wallet with "
-"the GNU Taler WebExtension now or click the link if your WebExtension have "
-"the \"Inject Taler support\" option enabled."
-msgstr ""
-"Si esta usando un explorador web de escritorio deberías acceder ahora a tu "
-"billletera con la GNU Taler WebExtension o hacer click en el link si tu "
-"extensión tiene la configuración \"Inyectar soporte para Taler\" habilitada."
-
-#: src/pages/OperationState/views.tsx:417
-#, c-format
-msgid "Start"
-msgstr "Comenzar"
-
-#: src/pages/OperationState/views.tsx:426
-#, c-format
-msgid "On a mobile phone"
-msgstr "En un dispotivo mobile"
-
-#: src/pages/OperationState/views.tsx:431
-#, c-format
-msgid "Scan the QR code with your mobile device."
-msgstr "Escanear el código QR con tu dispotivo móvil."
-
-#: src/pages/WalletWithdrawForm.tsx:73
-#, c-format
-msgid "There is an operation already"
-msgstr "Ya hay una operación"
-
-#: src/pages/WalletWithdrawForm.tsx:75
-#, c-format
-msgid "Complete or cancel the operation in"
-msgstr "Completa o cancela la operación en"
-
-#: src/pages/WalletWithdrawForm.tsx:84
-#, c-format
-msgid "this page"
-msgstr "esta página"
-
-#: src/pages/WalletWithdrawForm.tsx:101
-#, c-format
-msgid "invalid"
-msgstr "inválido"
-
-#: src/pages/WalletWithdrawForm.tsx:116
-#, c-format
-msgid "Server responded with an invalid withdraw URI"
-msgstr "El servidor respondió con una URI de extracción inválida"
-
-#: src/pages/WalletWithdrawForm.tsx:117
-#, c-format
-msgid "Withdraw URI: %1$s"
-msgstr "URI de extracción: %1$s"
-
-#: src/pages/WalletWithdrawForm.tsx:132
-#, c-format
-msgid "The operation was rejected due to insufficient funds"
-msgstr "La operación fue rechazada debido a fundos insuficientes"
-
-#: src/pages/WalletWithdrawForm.tsx:253
-#, c-format
-msgid "Continue"
-msgstr "Continuar"
-
-#: src/pages/WalletWithdrawForm.tsx:282
-#, c-format
-msgid "Prepare your wallet"
-msgstr "Prepare su billetera"
-
-#: src/pages/WalletWithdrawForm.tsx:285
-#, c-format
-msgid ""
-"After using your wallet you will need to confirm or cancel the operation on "
-"this site."
-msgstr ""
-"Despues de usar tu billetera necesitarás confirmar o cancelar la operación "
-"en este sitio."
-
-#: src/pages/WalletWithdrawForm.tsx:295
-#, c-format
-msgid "You need a GNU Taler Wallet"
-msgstr "Necesitas una GNU Taler Wallet"
-
-#: src/pages/WalletWithdrawForm.tsx:300
-#, c-format
-msgid "If you don't have one yet you can follow the instruction in"
-msgstr "Si no tienes una todavía puedes seguir las instrucciones en"
-
-#: src/pages/PaymentOptions.tsx:55
-#, c-format
-msgid "Send money"
-msgstr "Enviar dinero"
-
-#: src/pages/PaymentOptions.tsx:73
-#, c-format
-msgid "to a %1$s wallet"
-msgstr "a una billetera %1$s"
-
-#: src/pages/PaymentOptions.tsx:95
-#, c-format
-msgid "Withdraw digital money into your mobile wallet or browser extension"
-msgstr "Extraer dinero digital a tu billetera móvil o extesión web"
-
-#: src/pages/PaymentOptions.tsx:109
-#, c-format
-msgid "operation ready"
-msgstr "operación lista"
-
-#: src/pages/PaymentOptions.tsx:129
-#, c-format
-msgid "to another bank account"
-msgstr "a otra cuenta bancaria"
-
-#: src/pages/PaymentOptions.tsx:149
-#, c-format
-msgid "Make a wire transfer to an account with known bank account number."
-msgstr ""
-"Hacer una transferencia bancaria a una cuenta con un número de cuenta "
-"conocido."
-
-#: src/pages/PaymentOptions.tsx:171
-#, c-format
-msgid "Transfer details"
-msgstr "Detalles de transferencia"
-
-#: src/pages/AccountPage/views.tsx:41
-#, c-format
-msgid "This is a demo bank"
-msgstr "Este es un banco de demostración"
-
-#: src/pages/AccountPage/views.tsx:46
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work. In addition to using your own bank account, you can also see the "
-"transaction history of some %1$s."
-msgstr ""
-"Esta parte de la demostración muestra cómo funciona un banco que soporta "
-"Taler directamente. Además de usar tu propia cuenta de banco, también podrás "
-"ver el historial de transacciones de algunas %1$s."
-
-#: src/pages/AccountPage/views.tsx:53
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work."
-msgstr ""
-"Esta parte de la demostración muetra como un banco que soporta Taler "
-"directamente funcionaría."
-
-#: src/pages/AccountPage/views.tsx:70
-#, c-format
-msgid "Pending account delete operation"
-msgstr "Operación pendiente de eliminación de cuenta"
-
-#: src/pages/AccountPage/views.tsx:72
-#, c-format
-msgid "Pending account update operation"
-msgstr "Operación pendiente de actualización de cuenta"
-
-#: src/pages/AccountPage/views.tsx:74
-#, c-format
-msgid "Pending password update operation"
-msgstr "Operación pendiente de actualización de password"
-
-#: src/pages/AccountPage/views.tsx:76
-#, c-format
-msgid "Pending transaction operation"
-msgstr "Operación pendiente de transacción"
-
-#: src/pages/AccountPage/views.tsx:78
-#, c-format
-msgid "Pending withdrawal operation"
-msgstr "Operación pendiente de extracción"
-
-#: src/pages/AccountPage/views.tsx:80
-#, c-format
-msgid "Pending cashout operation"
-msgstr "Operación pendiente de egreso"
-
-#: src/pages/AccountPage/views.tsx:91
-#, c-format
-msgid "You can complete or cancel the operation in"
-msgstr "Puedes completar o cancelar la operación en"
-
-#: src/pages/BankFrame.tsx:64
-#, c-format
-msgid "Internal error, please report."
-msgstr "Error interno, por favor reporte el error."
-
-#: src/pages/BankFrame.tsx:100
-#, c-format
-msgid "Preferences"
-msgstr "Preferencias"
-
-#: src/pages/BankFrame.tsx:184
-#, c-format
-msgid "Welcome, %1$s"
-msgstr "Bienvenido/a, %1$s"
-
-#: src/pages/WireTransfer.tsx:79
-#, c-format
-msgid "Make a wire transfer"
-msgstr "Hacer una transferencia bancaria"
-
-#: src/pages/admin/AccountList.tsx:72
-#, c-format
-msgid "Accounts"
-msgstr "Cuentas"
-
-#: src/pages/admin/AccountList.tsx:75
-#, c-format
-msgid "A list of all business account in the bank."
-msgstr "Una lista de todas las cuentas en el banco."
-
-#: src/pages/admin/AccountList.tsx:86
-#, c-format
-msgid "Create account"
-msgstr "Crear cuenta"
-
-#: src/pages/admin/AccountList.tsx:106
-#, c-format
-msgid "Name"
-msgstr "Nombre"
-
-#: src/pages/admin/AccountList.tsx:110
-#, c-format
-msgid "Balance"
-msgstr "Saldo"
-
-#: src/pages/admin/AccountList.tsx:112
-#, c-format
-msgid "Actions"
-msgstr "Acciones"
-
-#: src/pages/admin/AccountList.tsx:151
-#, c-format
-msgid "unknown"
-msgstr "desconocido"
-
-#: src/pages/admin/AccountList.tsx:170
-#, c-format
-msgid "change password"
-msgstr "cambiar contraseña"
-
-#: src/pages/admin/AccountList.tsx:179
-#, c-format
-msgid "cashouts"
-msgstr "egresos"
-
-#: src/pages/admin/AccountList.tsx:189
-#, c-format
-msgid "remove"
-msgstr "elimiar"
-
-#: src/pages/admin/AdminHome.tsx:168
-#, c-format
-msgid "Cashout not implemented"
-msgstr "Egreso no soportado"
-
-#: src/pages/admin/AdminHome.tsx:184
-#, c-format
-msgid "Select a section"
-msgstr "Seleccione una sección"
-
-#: src/pages/admin/AdminHome.tsx:202
-#, c-format
-msgid "Last hour"
-msgstr "Última hora"
-
-#: src/pages/admin/AdminHome.tsx:208
-#, c-format
-msgid "Last day"
-msgstr "Último día"
-
-#: src/pages/admin/AdminHome.tsx:216
-#, c-format
-msgid "Last month"
-msgstr "Último mes"
-
-#: src/pages/admin/AdminHome.tsx:222
-#, c-format
-msgid "Last year"
-msgstr "Último año"
-
-#: src/pages/admin/AdminHome.tsx:310
-#, c-format
-msgid "Last Year"
-msgstr "Último Año"
-
-#: src/pages/admin/AdminHome.tsx:325
-#, c-format
-msgid "Trading volume on %1$s compared to %2$s"
-msgstr "Vólumen de comercio en %1$s comparado con %2$s"
-
-#: src/pages/admin/AdminHome.tsx:342
-#, c-format
-msgid "Cashin"
-msgstr "Ingreso"
-
-#: src/pages/admin/AdminHome.tsx:352
-#, c-format
-msgid "Cashout"
-msgstr "Egreso"
-
-#: src/pages/admin/AdminHome.tsx:364
-#, c-format
-msgid "Payin"
-msgstr "Envios de dinero"
-
-#: src/pages/admin/AdminHome.tsx:374
-#, c-format
-msgid "Payout"
-msgstr "Recibos de dinero"
-
-#: src/pages/admin/AdminHome.tsx:388
-#, c-format
-msgid "download stats as CSV"
-msgstr "descargar estadísticas en CSV"
-
-#: src/pages/admin/AdminHome.tsx:494
-#, c-format
-msgid "Decreased by"
-msgstr "Descendiente por"
-
-#: src/pages/admin/AdminHome.tsx:498
-#, c-format
-msgid "Increased by"
-msgstr "Ascendente por"
-
-#: src/pages/DownloadStats.tsx:89
-#, c-format
-msgid "Download bank stats"
-msgstr "Descargar estadísticas del banco"
-
-#: src/pages/DownloadStats.tsx:110
-#, c-format
-msgid "Include hour metric"
-msgstr "Incluir métrica horaria"
-
-#: src/pages/DownloadStats.tsx:143
-#, c-format
-msgid "Include day metric"
-msgstr "Incluir métrica diaria"
-
-#: src/pages/DownloadStats.tsx:173
-#, c-format
-msgid "Include month metric"
-msgstr "Incluir métrica mensual"
-
-#: src/pages/DownloadStats.tsx:206
-#, c-format
-msgid "Include year metric"
-msgstr "Incluir métrica anual"
-
-#: src/pages/DownloadStats.tsx:239
-#, c-format
-msgid "Include table header"
-msgstr "Incluir encabezado de tabla"
-
-#: src/pages/DownloadStats.tsx:272
-#, c-format
-msgid "Add previous metric for compare"
-msgstr "Agregar métrica previa para comparar"
-
-#: src/pages/DownloadStats.tsx:307
-#, c-format
-msgid "Fail on first error"
-msgstr "Fallar en el primer error"
-
-#: src/pages/DownloadStats.tsx:364
-#, c-format
-msgid "Download"
-msgstr "Descargar"
-
-#: src/pages/DownloadStats.tsx:381
-#, c-format
-msgid "downloading... %1$s"
-msgstr "descargando... %1$s"
-
-#: src/pages/DownloadStats.tsx:399
-#, c-format
-msgid "Download completed"
-msgstr "Descarga completada"
-
-#: src/pages/DownloadStats.tsx:400
-#, c-format
-msgid "click here to save the file in your computer"
-msgstr "click aquí para guardar el archivo en su computadora"
-
-#: src/pages/PublicHistoriesPage.tsx:78
-#, c-format
-msgid "History of public accounts"
-msgstr "Historial de cuentas públicas"
-
-#: src/pages/RegistrationPage.tsx:48
-#, c-format
-msgid "Currently, the bank is not accepting new registrations!"
-msgstr "Actualmente, el banco no está aceptado nuevos registros!"
-
-#: src/pages/RegistrationPage.tsx:87
-#, c-format
-msgid "Missing name"
-msgstr "Falta nombre"
-
-#: src/pages/RegistrationPage.tsx:91
-#, c-format
-msgid "Use letters and numbers only, and start with a lowercase letter"
-msgstr "Solo use letras y números, y comience con una letra minúscula"
-
-#: src/pages/RegistrationPage.tsx:107
-#, c-format
-msgid "Passwords don't match"
-msgstr "La contraseña no coincide"
-
-#: src/pages/RegistrationPage.tsx:130
-#, c-format
-msgid "Server replied with invalid phone or email."
-msgstr "El servidor repondio con teléfono o dirección de correo inválido."
-
-#: src/pages/RegistrationPage.tsx:137
-#, c-format
-msgid "Registration is disabled because the bank ran out of bonus credit."
-msgstr ""
-"El registro está deshabilitado porque el banco se quedó sin crédito bonus."
-
-#: src/pages/RegistrationPage.tsx:144
-#, c-format
-msgid "No enough permission to create that account."
-msgstr "Sin permisos suficientes para crear esa cuenta."
-
-#: src/pages/RegistrationPage.tsx:151
-#, c-format
-msgid "That account id is already taken."
-msgstr "El identificador de cuenta ya está tomado."
-
-#: src/pages/RegistrationPage.tsx:158
-#, c-format
-msgid "That username is already taken."
-msgstr "El nombre de usuario ya está tomado."
-
-#: src/pages/RegistrationPage.tsx:165
-#, c-format
-msgid "That username can't be used because is reserved."
-msgstr "El nombre de usuario no puede ser usado porque esta reservado."
-
-#: src/pages/RegistrationPage.tsx:172
-#, c-format
-msgid "Only admin is allow to set debt limit."
-msgstr "Solo el administrador tiene permitido cambiar el límite de deuda."
-
-#: src/pages/RegistrationPage.tsx:179
-#, c-format
-msgid "No information for the selected authentication channel."
-msgstr "No hay información para el canal de autenticación seleccionado."
-
-#: src/pages/RegistrationPage.tsx:186
-#, c-format
-msgid "Authentication channel is not supported."
-msgstr "Canal de autenticación no esta soportado."
-
-#: src/pages/RegistrationPage.tsx:193
-#, c-format
-msgid "Only admin can create accounts with second factor authentication."
-msgstr ""
-"Solo el administrador puede crear cuentas con el segundo factor de "
-"autenticación."
-
-#: src/pages/RegistrationPage.tsx:233
-#, c-format
-msgid "Account registration"
-msgstr "Registro de cuenta"
-
-#: src/pages/RegistrationPage.tsx:315
-#, c-format
-msgid "Repeat password"
-msgstr "Repita la contraseña"
-
-#: src/pages/RegistrationPage.tsx:457
-#, c-format
-msgid "Create a random temporary user"
-msgstr "Crear un usuario aleatorio temporal"
-
-#: src/pages/QrCodeSection.tsx:110
-#, c-format
-msgid "If you have a Taler wallet installed in this device"
-msgstr "Si tienes una billetera Taler instalada en este dispositivo"
-
-#: src/pages/QrCodeSection.tsx:116
-#, c-format
-msgid ""
-"You will see the details of the operation in your wallet including the fees "
-"(if applies). If you still don't have one you can install it following "
-"instructions in"
-msgstr ""
-"Veras los detalles de la operación en tu billetera incluyendo comisiones (si "
-"aplicán). Si todavía no tienes una puedes instalarla siguiendo las "
-"instrucciones en"
-
-#: src/pages/QrCodeSection.tsx:143
-#, c-format
-msgid "Withdraw"
-msgstr "Retirar"
-
-#: src/pages/QrCodeSection.tsx:152
-#, c-format
-msgid "Or if you have the wallet in another device"
-msgstr "O si tienes la billetera en otro dispositivo"
-
-#: src/pages/QrCodeSection.tsx:157
-#, c-format
-msgid "Scan the QR below to start the withdrawal."
-msgstr "Escanea el QR debajo para comenzar la extracción."
-
-#: src/pages/WithdrawalQRCode.tsx:79
-#, c-format
-msgid "Operation aborted"
-msgstr "Operación abortada"
-
-#: src/pages/WithdrawalQRCode.tsx:82
-#, c-format
-msgid ""
-"The wire transfer to the Taler Exchange operator's account was aborted, your "
-"balance was not affected."
-msgstr ""
-"La transferencia bancaria a la cuenta del operador del Taler Exchange fue "
-"abortada, su saldo no fue afectado."
-
-#: src/pages/WithdrawalQRCode.tsx:88
-#, c-format
-msgid "You can close this page now or continue to the account page."
-msgstr ""
-"Ya puedes cerrar esta pagina or continuar a la página de estado de cuenta."
-
-#: src/pages/WithdrawalQRCode.tsx:147
-#, c-format
-msgid "Done"
-msgstr "Listo"
-
-#: src/pages/WithdrawalQRCode.tsx:158
-#, c-format
-msgid "Operation canceled"
-msgstr "Operación cancelada"
-
-#: src/pages/WithdrawalQRCode.tsx:173
-#, c-format
-msgid ""
-"The operation is marked as 'selected' but some step in the withdrawal failed"
-msgstr ""
-"La operación está marcada como 'seleccionada' pero algunos pasos en la "
-"extracción fallaron"
-
-#: src/pages/WithdrawalQRCode.tsx:175
-#, c-format
-msgid "The account is selected but no withdrawal identification found."
-msgstr ""
-"La cuenta está seleccionada pero no se encontró el identificador de "
-"extracción."
-
-#: src/pages/WithdrawalQRCode.tsx:188
-#, c-format
-msgid ""
-"There is a withdrawal identification but no account has been selected or the "
-"selected account is invalid."
-msgstr ""
-"Hay un identificador de extracción pero la cuenta no ha sido seleccionada o "
-"la selccionada es inválida."
-
-#: src/pages/WithdrawalQRCode.tsx:202
-#, c-format
-msgid ""
-"No withdrawal ID found and no account has been selected or the selected "
-"account is invalid."
-msgstr ""
-"No hay un identificador de extracción y ninguna cuenta a sido seleccionada o "
-"la seleccionada es inválida."
-
-#: src/pages/WithdrawalQRCode.tsx:259
-#, c-format
-msgid "Operation not found"
-msgstr "Operación no encontrada"
-
-#: src/pages/WithdrawalQRCode.tsx:263
-#, c-format
-msgid ""
-"This operation is not known by the server. The operation id is wrong or the "
-"server deleted the operation information before reaching here."
-msgstr ""
-"Esta operación no es conocida por el servidor. El identificador de operación "
-"es incorrecto o el server borró la información de la operación antes de "
-"llegar hasta aquí."
-
-#: src/pages/WithdrawalQRCode.tsx:278
-#, c-format
-msgid "Cotinue to dashboard"
-msgstr "Continuar al panel"
-
-#: src/pages/SolveChallengePage.tsx:98
-#, c-format
-msgid "Cashout not found. It may be also mean that it was already aborted."
-msgstr "Egreso no econtrado. También puede significar que ya ha sido abortado."
-
-#: src/pages/SolveChallengePage.tsx:136
-#, c-format
-msgid "Challenge not found."
-msgstr "Desafío no encontrado."
-
-#: src/pages/SolveChallengePage.tsx:143
-#, c-format
-msgid "This user is not authorized to complete this challenge."
-msgstr "Este usuario no está autorizado para completar este desafío."
-
-#: src/pages/SolveChallengePage.tsx:150
-#, c-format
-msgid "Too many attempts, try another code."
-msgstr "Demasiados intentos, intente otro código."
-
-#: src/pages/SolveChallengePage.tsx:157
-#, c-format
-msgid "The confirmation code is wrong, try again."
-msgstr "El código de confirmación es erroneo, intente otra vez."
-
-#: src/pages/SolveChallengePage.tsx:164
-#, c-format
-msgid "The operation expired."
-msgstr "La operación expiró."
-
-#: src/pages/SolveChallengePage.tsx:197
-#, c-format
-msgid "The operation failed."
-msgstr "La operación falló."
-
-#: src/pages/SolveChallengePage.tsx:212
-#, c-format
-msgid "The operation needs another confirmation to complete."
-msgstr "La operación necesita otra confirmación para completar."
-
-#: src/pages/SolveChallengePage.tsx:224
-#, c-format
-msgid "Account delete"
-msgstr "Eliminación de cuenta"
-
-#: src/pages/SolveChallengePage.tsx:226
-#, c-format
-msgid "Account update"
-msgstr "Actualización de cuenta"
-
-#: src/pages/SolveChallengePage.tsx:228
-#, c-format
-msgid "Password update"
-msgstr "Actualización de contraseña"
-
-#: src/pages/SolveChallengePage.tsx:230
-#, c-format
-msgid "Wire transfer"
-msgstr "Transferencia bancaria"
-
-#: src/pages/SolveChallengePage.tsx:232
-#, c-format
-msgid "Withdrawal"
-msgstr "Extracción"
-
-#: src/pages/SolveChallengePage.tsx:248
-#, c-format
-msgid "Confirm the operation"
-msgstr "Confirmar la operación"
-
-#: src/pages/SolveChallengePage.tsx:271
-#, c-format
-msgid "Enter the confirmation code"
-msgstr "Ingresar el código de confirmación"
-
-#: src/pages/SolveChallengePage.tsx:313
-#, c-format
-msgid "Confirm"
-msgstr "Confirmar"
-
-#: src/pages/SolveChallengePage.tsx:348
-#, c-format
-msgid "Send again"
-msgstr "Enviar otra vez"
-
-#: src/pages/SolveChallengePage.tsx:359
-#, c-format
-msgid "Send code"
-msgstr "Enviar código"
-
-#: src/pages/SolveChallengePage.tsx:369
-#, c-format
-msgid "Operation details"
-msgstr "Detalles de operación"
-
-#: src/pages/SolveChallengePage.tsx:529
-#, c-format
-msgid "Challenge details"
-msgstr "Detalles del desafío"
-
-#: src/pages/SolveChallengePage.tsx:536
-#, c-format
-msgid "Sent at"
-msgstr "Enviado a"
-
-#: src/pages/SolveChallengePage.tsx:551
-#, c-format
-msgid "To phone"
-msgstr "Al teléfono"
-
-#: src/pages/SolveChallengePage.tsx:553
-#, c-format
-msgid "To email"
-msgstr "Al email"
-
-#: src/pages/WithdrawalOperationPage.tsx:49
-#, c-format
-msgid "The Withdrawal URI is not valid"
-msgstr "El URI de estracción no es válido"
-
-#: src/components/Cashouts/views.tsx:100
-#, c-format
-msgid "Latest cashouts"
-msgstr "Últimos egresos"
-
-#: src/components/Cashouts/views.tsx:111
-#, c-format
-msgid "Created"
-msgstr "Creado"
-
-#: src/components/Cashouts/views.tsx:115
-#, c-format
-msgid "Total debit"
-msgstr "Débito total"
-
-#: src/components/Cashouts/views.tsx:119
-#, c-format
-msgid "Total credit"
-msgstr "Crédito total"
-
-#: src/pages/ProfileNavigation.tsx:70
-#, c-format
-msgid "Details"
-msgstr "Detalles"
-
-#: src/pages/ProfileNavigation.tsx:74
-#, c-format
-msgid "Delete"
-msgstr "Borrar"
-
-#: src/pages/ProfileNavigation.tsx:78
-#, c-format
-msgid "Credentials"
-msgstr "Credenciales"
-
-#: src/pages/ProfileNavigation.tsx:82
-#, c-format
-msgid "Cashouts"
-msgstr "Egresos"
-
-#: src/pages/business/CreateCashout.tsx:95
-#, c-format
-msgid "Unable to create a cashout"
-msgstr "Imposible crear un egreso"
-
-#: src/pages/business/CreateCashout.tsx:96
-#, c-format
-msgid "The bank configuration does not support cashout operations."
-msgstr "La configuración del banco no soporta operaciones de egreso."
-
-#: src/pages/business/CreateCashout.tsx:223
-#, c-format
-msgid "need to be higher due to fees"
-msgstr "necesita ser mayor debido a las comisiones"
-
-#: src/pages/business/CreateCashout.tsx:225
-#, c-format
-msgid "the total transfer at destination will be zero"
-msgstr "el total de la transferencia en destino será cero"
-
-#: src/pages/business/CreateCashout.tsx:250
-#, c-format
-msgid "Cashout created"
-msgstr "Egreso creado"
-
-#: src/pages/business/CreateCashout.tsx:272
-#, c-format
-msgid ""
-"Duplicated request detected, check if the operation succeeded or try again."
-msgstr ""
-"Se detectó una petición duplicada, verifique si la operación tuvo éxito o "
-"intente otra vez."
-
-#: src/pages/business/CreateCashout.tsx:279
-#, c-format
-msgid "The conversion rate was incorrectly applied"
-msgstr "La tasa de conversión se aplicó incorrectamente"
-
-#: src/pages/business/CreateCashout.tsx:286
-#, c-format
-msgid "The account does not have sufficient funds"
-msgstr "La cuenta no tiene fondos suficientes"
-
-#: src/pages/business/CreateCashout.tsx:293
-#, c-format
-msgid "Cashouts are not supported"
-msgstr "Egresos no están soportados"
-
-#: src/pages/business/CreateCashout.tsx:300
-#, c-format
-msgid "Missing cashout URI in the profile"
-msgstr "Falta dirección de egreso en el perfíl"
-
-#: src/pages/business/CreateCashout.tsx:307
-#, c-format
-msgid ""
-"Sending the confirmation message failed, retry later or contact the "
-"administrator."
-msgstr ""
-"El envío del mensaje de confirmación falló, intente mas tarde o contacte al "
-"administrador."
-
-#: src/pages/business/CreateCashout.tsx:339
-#, c-format
-msgid "Conversion rate"
-msgstr "Tasa de conversión"
-
-#: src/pages/business/CreateCashout.tsx:360
-#, c-format
-msgid "Fee"
-msgstr "Comisión"
-
-#: src/pages/business/CreateCashout.tsx:374
-#, c-format
-msgid "To account"
-msgstr "Hacia cuenta"
-
-#: src/pages/business/CreateCashout.tsx:381
-#, c-format
-msgid "No cashout account"
-msgstr "No hay cuenta de egreso"
-
-#: src/pages/business/CreateCashout.tsx:382
-#, c-format
-msgid "Before doing a cashout you need to complete your profile"
-msgstr "Antes de hacer un egreso necesita completar su perfíl"
-
-#: src/pages/business/CreateCashout.tsx:440
-#, c-format
-msgid "Amount to send"
-msgstr "Monto a enviar"
-
-#: src/pages/business/CreateCashout.tsx:441
-#, c-format
-msgid "Amount to receive"
-msgstr "Monto a recibir"
-
-#: src/pages/business/CreateCashout.tsx:490
-#, c-format
-msgid "Total cost"
-msgstr "Costo total"
-
-#: src/pages/business/CreateCashout.tsx:505
-#, c-format
-msgid "Balance left"
-msgstr "Saldo remanente"
-
-#: src/pages/business/CreateCashout.tsx:520
-#, c-format
-msgid "Before fee"
-msgstr "Antes de comisión"
-
-#: src/pages/business/CreateCashout.tsx:533
-#, c-format
-msgid "Total cashout transfer"
-msgstr "Total de egreso"
-
-#: src/pages/business/CreateCashout.tsx:553
-#, c-format
-msgid "No cashout channel available"
-msgstr "No hay canal de egreso disponible"
-
-#: src/pages/business/CreateCashout.tsx:555
-#, c-format
-msgid ""
-"Before doing a cashout the server need to provide an second channel to "
-"confirm the operation"
-msgstr ""
-"Antes de hacer un egreso el servidor necesita proveer un segundo canal para "
-"confirmar la operación"
-
-#: src/pages/business/CreateCashout.tsx:567
-#, c-format
-msgid "Second factor authentication"
-msgstr "Segundo factor de autenticación"
-
-#: src/pages/business/CreateCashout.tsx:598
-#, c-format
-msgid "Email"
-msgstr "Correo eletrónico"
-
-#: src/pages/business/CreateCashout.tsx:600
-#, c-format
-msgid "add a email in your profile to enable this option"
-msgstr "agrege un correo en su perfíl para habilitar esta opción"
-
-#: src/pages/business/CreateCashout.tsx:646
-#, c-format
-msgid "SMS"
-msgstr "SMS"
-
-#: src/pages/business/CreateCashout.tsx:648
-#, c-format
-msgid "add a phone number in your profile to enable this option"
-msgstr "agregue un número de teléfono para habilitar esta opción"
-
-#: src/pages/account/CashoutListForAccount.tsx:52
-#, c-format
-msgid "Cashout for account %1$s"
-msgstr "Egreso para cuenta %1$s"
-
-#: src/pages/admin/AccountForm.tsx:165
-#, c-format
-msgid "it doesn't have the pattern of an IBAN number"
-msgstr "no tiene el patrón de un número IBAN"
-
-#: src/pages/admin/AccountForm.tsx:185
-#, c-format
-msgid "it doesn't have the pattern of an email"
-msgstr "no tiene el patrón de un correo electrónico"
-
-#: src/pages/admin/AccountForm.tsx:190
-#, c-format
-msgid "should start with +"
-msgstr "debería comenzar con un +"
-
-#: src/pages/admin/AccountForm.tsx:192
-#, c-format
-msgid "phone number can't have other than numbers"
-msgstr "número de teléfono no puede tener otra cosa que numeros"
-
-#: src/pages/admin/AccountForm.tsx:329
-#, c-format
-msgid "account identification in the bank"
-msgstr "identificador de cuenta en el banco"
-
-#: src/pages/admin/AccountForm.tsx:365
-#, c-format
-msgid "name of the person owner the account"
-msgstr "nombre de la persona dueña de la cuenta"
-
-#: src/pages/admin/AccountForm.tsx:374
-#, c-format
-msgid "Internal IBAN"
-msgstr "IBAN interno"
-
-#: src/pages/admin/AccountForm.tsx:377
-#, c-format
-msgid "if empty a random account number will be assigned"
-msgstr "si está vacío un número de cuenta aleatorio será asignado"
-
-#: src/pages/admin/AccountForm.tsx:378
-#, c-format
-msgid "account identification for bank transfer"
-msgstr "identificador de cuenta para transferencia bancaria"
-
-#: src/pages/admin/AccountForm.tsx:423
-#, c-format
-msgid "Phone"
-msgstr "Teléfono"
-
-#: src/pages/admin/AccountForm.tsx:451
-#, c-format
-msgid "Cashout IBAN"
-msgstr "IBAN de egreso"
-
-#: src/pages/admin/AccountForm.tsx:452
-#, c-format
-msgid "account number where the money is going to be sent when doing cashouts"
-msgstr ""
-"numero de cuenta donde el dinero será enviado cuando se ejecuten egresos"
-
-#: src/pages/admin/AccountForm.tsx:470
-#, c-format
-msgid "Max debt"
-msgstr "Máxima deuda"
-
-#: src/pages/admin/AccountForm.tsx:494
-#, c-format
-msgid "how much is user able to transfer after zero balance"
-msgstr "cuanto tiene habilitado a transferir despues de un saldo en cero"
-
-#: src/pages/admin/AccountForm.tsx:508
-#, c-format
-msgid "Is this a Taler Exchange?"
-msgstr "Es un Taler Exchange?"
-
-#: src/pages/admin/AccountForm.tsx:549
-#, c-format
-msgid "This server doesn't support second factor authentication."
-msgstr "Este servidor no tiene soporte para segundo factor de autenticación."
-
-#: src/pages/admin/AccountForm.tsx:560
-#, c-format
-msgid "Enable second factor authentication"
-msgstr "Hábilitar segundo factor de autenticación"
-
-#: src/pages/admin/AccountForm.tsx:596
-#, c-format
-msgid "Using email"
-msgstr "Usando correo eletrónico"
-
-#: src/pages/admin/AccountForm.tsx:654
-#, c-format
-msgid "Using SMS"
-msgstr "Usando SMS"
-
-#: src/pages/admin/AccountForm.tsx:691
-#, c-format
-msgid "Is this account public?"
-msgstr "Es una cuenta pública?"
-
-#: src/pages/admin/AccountForm.tsx:719
-#, c-format
-msgid "public accounts have their balance publicly accessible"
-msgstr "las cuentas públicas tienen su saldo accesible al público"
-
-#: src/pages/account/ShowAccountDetails.tsx:100
-#, c-format
-msgid "Account updated"
-msgstr "Cuenta actualizada"
-
-#: src/pages/account/ShowAccountDetails.tsx:107
-#, c-format
-msgid "The rights to change the account are not sufficient"
-msgstr "Los permisos para cambiar la cuenta no son suficientes"
-
-#: src/pages/account/ShowAccountDetails.tsx:114
-#, c-format
-msgid "The username was not found"
-msgstr "El nombre de usaurio no se encontró"
-
-#: src/pages/account/ShowAccountDetails.tsx:121
-#, c-format
-msgid ""
-"You can't change the legal name, please contact the your account "
-"administrator."
-msgstr ""
-"No puede cambiar el nombre legal, por favor contacte el administrador de la "
-"cuenta."
-
-#: src/pages/account/ShowAccountDetails.tsx:128
-#, c-format
-msgid ""
-"You can't change the debt limit, please contact the your account "
-"administrator."
-msgstr ""
-"No puede cambiar el límite de deuda, por favor contacte el administrador de "
-"la cuenta."
-
-#: src/pages/account/ShowAccountDetails.tsx:135
-#, c-format
-msgid ""
-"You can't change the cashout address, please contact the your account "
-"administrator."
-msgstr ""
-"No puede cambiar la dirección de egreso, por favor contacte al administrador "
-"de la cuenta."
-
-#: src/pages/account/ShowAccountDetails.tsx:177
-#, c-format
-msgid "Account \"%1$s\""
-msgstr "Cuenta \"%1$s\""
-
-#: src/pages/account/ShowAccountDetails.tsx:190
-#, c-format
-msgid "Change details"
-msgstr "Cambiar detalles"
-
-#: src/pages/account/ShowAccountDetails.tsx:235
-#, c-format
-msgid "Update"
-msgstr "Actualizar"
-
-#: src/pages/account/UpdateAccountPassword.tsx:78
-#, c-format
-msgid "password doesn't match"
-msgstr "la contraseña no coincide"
-
-#: src/pages/account/UpdateAccountPassword.tsx:95
-#, c-format
-msgid "Password changed"
-msgstr "La contraseña cambió"
-
-#: src/pages/account/UpdateAccountPassword.tsx:102
-#, c-format
-msgid "Not authorized to change the password, maybe the session is invalid."
-msgstr "No está autorizado a cambiar el password, quizá la sesión es invalida."
-
-#: src/pages/account/UpdateAccountPassword.tsx:112
-#, c-format
-msgid ""
-"You need to provide the old password. If you don't have it contact your "
-"account administrator."
-msgstr ""
-"Se necesita el password viejo para cambiar la contraseña. Si no lo tiene "
-"contacte a su administrador."
-
-#: src/pages/account/UpdateAccountPassword.tsx:117
-#, c-format
-msgid "Your current password doesn't match, can't change to a new password."
-msgstr ""
-"Su actual contraseña no coincide, no puede cambiar a una nueva contraseña."
-
-#: src/pages/account/UpdateAccountPassword.tsx:149
-#, c-format
-msgid "Update password"
-msgstr "Actualizar contraseña"
-
-#: src/pages/account/UpdateAccountPassword.tsx:167
-#, c-format
-msgid "New password"
-msgstr "Nueva contraseña"
-
-#: src/pages/account/UpdateAccountPassword.tsx:195
-#, c-format
-msgid "Type it again"
-msgstr "Escribalo otra vez"
-
-#: src/pages/account/UpdateAccountPassword.tsx:217
-#, c-format
-msgid "repeat the same password"
-msgstr "repita la misma contraseña"
-
-#: src/pages/account/UpdateAccountPassword.tsx:227
-#, c-format
-msgid "Current password"
-msgstr "Contraseña actual"
-
-#: src/pages/account/UpdateAccountPassword.tsx:248
-#, c-format
-msgid "your current password, for security"
-msgstr "su actual contraseña, por seguridad"
-
-#: src/pages/account/UpdateAccountPassword.tsx:272
-#, c-format
-msgid "Change"
-msgstr "Cambiar"
-
-#: src/pages/admin/CreateNewAccount.tsx:74
-#, c-format
-msgid ""
-"Account created with password \"%1$s\". The user must change the password on "
-"the next login."
-msgstr ""
-"Cuenta creada con contraseña \"%1$s\". El usuario debe cambiar la contraseña "
-"en el siguiente ingreso."
-
-#: src/pages/admin/CreateNewAccount.tsx:83
-#, c-format
-msgid "Server replied that phone or email is invalid"
-msgstr "El servidor respondió que el teléfono o correo eletrónico es invalido"
-
-#: src/pages/admin/CreateNewAccount.tsx:90
-#, c-format
-msgid "The rights to perform the operation are not sufficient"
-msgstr "Los permisos para ejecutar la operación no son suficientes"
-
-#: src/pages/admin/CreateNewAccount.tsx:97
-#, c-format
-msgid "Account username is already taken"
-msgstr "El nombre del usuario ya está tomado"
-
-#: src/pages/admin/CreateNewAccount.tsx:104
-#, c-format
-msgid "Account id is already taken"
-msgstr "El id de cuenta ya está tomado"
-
-#: src/pages/admin/CreateNewAccount.tsx:111
-#, c-format
-msgid "Bank ran out of bonus credit."
-msgstr "El banco no tiene mas crédito de bonus."
-
-#: src/pages/admin/CreateNewAccount.tsx:118
-#, c-format
-msgid "Account username can't be used because is reserved"
-msgstr ""
-"El nombre de usuario de la cuenta no puede userse porque está reservado"
-
-#: src/pages/admin/CreateNewAccount.tsx:160
-#, c-format
-msgid "Can't create accounts"
-msgstr "No puede crear cuentas"
-
-#: src/pages/admin/CreateNewAccount.tsx:161
-#, c-format
-msgid "Only system admin can create accounts."
-msgstr "Solo los administradores del sistema pueden crear cuentas."
-
-#: src/pages/admin/CreateNewAccount.tsx:183
-#, c-format
-msgid "New business account"
-msgstr "Nueva cuenta"
-
-#: src/pages/admin/CreateNewAccount.tsx:209
-#, c-format
-msgid "Create"
-msgstr "Crear"
-
-#: src/pages/admin/RemoveAccount.tsx:94
-#, c-format
-msgid "Can't delete the account"
-msgstr "No se puede eliminar la cuenta"
-
-#: src/pages/admin/RemoveAccount.tsx:95
-#, c-format
-msgid ""
-"The account can't be delete while still holding some balance. First make "
-"sure that the owner make a complete cashout."
-msgstr ""
-"La cuenta no puede ser eliminada mientras tiene saldo. Primero aseguresé que "
-"el dueño haga un egreso completo."
-
-#: src/pages/admin/RemoveAccount.tsx:117
-#, c-format
-msgid "Account removed"
-msgstr "Cuenta eliminada"
-
-#: src/pages/admin/RemoveAccount.tsx:124
-#, c-format
-msgid "No enough permission to delete the account."
-msgstr "No tiene permisos suficientes para eliminar la cuenta."
-
-#: src/pages/admin/RemoveAccount.tsx:131
-#, c-format
-msgid "The username was not found."
-msgstr "El nombr ede usuario no se encontró."
-
-#: src/pages/admin/RemoveAccount.tsx:138
-#, c-format
-msgid "Can't delete a reserved username."
-msgstr "No se puede eliminar un nombre de usuario reservado."
-
-#: src/pages/admin/RemoveAccount.tsx:145
-#, c-format
-msgid "Can't delete an account with balance different than zero."
-msgstr "No se puede eliminar una cuenta con saldo diferente a cero."
-
-#: src/pages/admin/RemoveAccount.tsx:170
-#, c-format
-msgid "name doesn't match"
-msgstr "el nombre no coincide"
-
-#: src/pages/admin/RemoveAccount.tsx:180
-#, c-format
-msgid "You are going to remove the account"
-msgstr "Está por eliminar la cuenta"
-
-#: src/pages/admin/RemoveAccount.tsx:182
-#, c-format
-msgid "This step can't be undone."
-msgstr "Este paso no puede ser deshecho."
-
-#: src/pages/admin/RemoveAccount.tsx:188
-#, c-format
-msgid "Deleting account \"%1$s\""
-msgstr "Borrando cuenta \"%1$s\""
-
-#: src/pages/admin/RemoveAccount.tsx:206
-#, c-format
-msgid "Verification"
-msgstr "Verificación"
-
-#: src/pages/admin/RemoveAccount.tsx:231
-#, c-format
-msgid "enter the account name that is going to be deleted"
-msgstr "ingrese el nombre de cuenta que será eliminado"
-
-#: src/pages/business/ShowCashoutDetails.tsx:49
-#, c-format
-msgid "cashout id should be a number"
-msgstr "debería ser un correo electrónico"
-
-#: src/pages/business/ShowCashoutDetails.tsx:65
-#, c-format
-msgid "This cashout not found. Maybe already aborted."
-msgstr "Este egreso no se encontró. Quizá fue abortado."
-
-#: src/pages/business/ShowCashoutDetails.tsx:106
-#, c-format
-msgid "Cashout detail"
-msgstr "Detalles de egreso"
-
-#: src/pages/business/ShowCashoutDetails.tsx:139
-#, c-format
-msgid "Debited"
-msgstr "Debitado"
-
-#: src/pages/business/ShowCashoutDetails.tsx:154
-#, c-format
-msgid "Credited"
-msgstr "Acreditado"
-
-#: src/Routing.tsx:140
-#, c-format
-msgid "Welcome to %1$s!"
-msgstr "Bienvenido a %1$s!"
-
-#, c-format
-#~ msgid ""
-#~ "You can't change the contact data, please contact the your account "
-#~ "administrator."
-#~ msgstr ""
-#~ "No puede cambiar los datos de contacto, por favor contacte al "
-#~ "administrador de la cuenta."
-
-#, c-format
-#~ msgid "Account not found."
-#~ msgstr "Cuenta no encontrada."
-
-#, c-format
-#~ msgid "Confirmed"
-#~ msgstr "Confirmado"
-
-#, c-format
-#~ msgid "Status"
-#~ msgstr "Estado"
-
-#, c-format
-#~ msgid "never"
-#~ msgstr "nunca"
-
-#, c-format
-#~ msgid "Cashout was already confimed."
-#~ msgstr "Egreso ya fue confirmado."
-
-#, c-format
-#~ msgid "Cashout operation is not supported."
-#~ msgstr "Operación de egreso no soportada."
-
-#, c-format
-#~ msgid "The cashout operation is already aborted."
-#~ msgstr "La operación de egreso ya está abortada."
-
-#, c-format
-#~ msgid "Missing destination account."
-#~ msgstr "Falta cuenta destino."
-
-#, c-format
-#~ msgid "Too many failed attempts."
-#~ msgstr "Demasiados intentos fallidos."
-
-#, c-format
-#~ msgid "The code for this cashout is invalid."
-#~ msgstr "El código para este egreso es invalido."
-
-#, c-format
-#~ msgid "Abort"
-#~ msgstr "Abortar"
-
-#, fuzzy, c-format
-#~ msgid ""
-#~ "The Taler Exchange operator is selected but the Taler Exchange operator "
-#~ "account is missing or invalid."
-#~ msgstr ""
-#~ "El operador esta seleccionado pero la URI payto del operador falta o es "
-#~ "invalida."
-
-#, c-format
-#~ msgid "could not be parsed"
-#~ msgstr "inválido"
-
-#, c-format
-#~ msgid "Confirmation the operation using"
-#~ msgstr "Confirme la operación usando"
-
-#, c-format
-#~ msgid "Is public"
-#~ msgstr "es publica"
-
-#, c-format
-#~ msgid "Logout"
-#~ msgstr "Cierre de sesión"
-
-#, c-format
-#~ msgid "Skip to main content"
-#~ msgstr "Saltar el menú de navegación"
-
-#, c-format
-#~ msgid "Taler logo"
-#~ msgstr "Logo Taler"
-
-#, c-format
-#~ msgid "Please login!"
-#~ msgstr "Por favor inicia sesión!"
-
-#, c-format
-#~ msgid "Login"
-#~ msgstr "Iniciar sesión"
-
-#, c-format
-#~ msgid "Missing IBAN"
-#~ msgstr "Falta IBAN"
-
-#, c-format
-#~ msgid "Missing subject"
-#~ msgstr "Falta asunto"
-
-#, c-format
-#~ msgid "Receiver IBAN:"
-#~ msgstr "IBAN receptor:"
-
-#, c-format
-#~ msgid "Amount:"
-#~ msgstr "Monto:"
-
-#, c-format
-#~ msgid "Field(s) missing."
-#~ msgstr "Faltan campo(s)."
-
-#, c-format
-#~ msgid "Want to try the raw payto://-format?"
-#~ msgstr "Quieres probar el formato payto:// ?"
-
-#, c-format
-#~ msgid "Missing payto address"
-#~ msgstr "Falta direccion payto"
-
-#, c-format
-#~ msgid "Transfer money to account identified by payto:// URI:"
-#~ msgstr "Transferir dinero a la cuenta identificada por la URI payto://:"
-
-#, c-format
-#~ msgid "payto address"
-#~ msgstr "direccion payto"
-
-#, c-format
-#~ msgid "Could not create the wire transfer"
-#~ msgstr "No se pudo create la transferencia bancaria"
-
-#, c-format
-#~ msgid "Transfer creation gave response error"
-#~ msgstr "La creación de la transferencia dió una respuesta erronea"
-
-#, c-format
-#~ msgid "No credentials given."
-#~ msgstr "Se dieron las credenciales incorrectas."
-
-#, c-format
-#~ msgid "Withdrawal creation gave response error"
-#~ msgstr "La creación de retiro dió una respuesta errónea"
-
-#, c-format
-#~ msgid "Obtain digital cash"
-#~ msgstr "Obtener dinero digital"
-
-#, c-format
-#~ msgid "Click %1$s to open your Taler wallet!"
-#~ msgstr "Click %1$s para abrir una cartera Taler!"
-
-#, c-format
-#~ msgid "Authorize withdrawal by solving challenge"
-#~ msgstr "Autorizar retiro resolviendo una pregunta"
-
-#, c-format
-#~ msgid "What is"
-#~ msgstr "Cuanto es"
-
-#, c-format
-#~ msgid "Answer is wrong."
-#~ msgstr "La respuesta es incorrecta."
-
-#, c-format
-#~ msgid ""
-#~ "A this point, a %1$s bank would ask for an additional authentication "
-#~ "proof (PIN/TAN, one time password, ..), instead of a simple calculation."
-#~ msgstr ""
-#~ "En este punto, un banco %1$s preguntaría por una prueba adicional de "
-#~ "autenticación (PIN/TAN, password de un solo uso, ....), en vez de un "
-#~ "simple cálculo."
-
-#, c-format
-#~ msgid "Could not confirm the withdrawal"
-#~ msgstr "No se pudo confirmar la retirada"
-
-#, c-format
-#~ msgid "Withdrawal confirmation gave response error"
-#~ msgstr "La confirmación de retiro dió una respuesta errónea"
-
-#, c-format
-#~ msgid "Withdrawal aborted!"
-#~ msgstr "Este retiro fue cancelado!"
-
-#, c-format
-#~ msgid "withdrawal (%1$s) was never (correctly) created at the bank..."
-#~ msgstr "retiro (%1$s) nunca fue (correctamente) generado en el banco..."
-
-#, c-format
-#~ msgid "Username or account label '%1$s' not found. Won't login."
-#~ msgstr ""
-#~ "Nombre de usuario o etiqueta de cuenta '%1$s' no encontrada. No se "
-#~ "iniciará sesión."
-
-#, c-format
-#~ msgid "Account information could not be retrieved."
-#~ msgstr "La información de la cuenta no pudo ser accedida."
-
-#, c-format
-#~ msgid "Bank account balance"
-#~ msgstr "Balance de cuenta bancaria"
-
-#, c-format
-#~ msgid "Payments"
-#~ msgstr "Pagos"
-
-#, c-format
-#~ msgid "List of public accounts could not be retrieved."
-#~ msgstr "La lista de cuentas públicas no pudo ser accedida."
-
-#, c-format
-#~ msgid "Please register!"
-#~ msgstr "Por favor, registrese!"
-
-#, c-format
-#~ msgid "New registration gave response error"
-#~ msgstr "Nuevo registro dió una respuesta errónea"
-
-#, c-format
-#~ msgid "Bank menu"
-#~ msgstr "Menu del banco"
-
-#, c-format
-#~ msgid "Select option2"
-#~ msgstr "Seleccione opción 2"
-
-#, c-format
-#~ msgid "days"
-#~ msgstr "días"
-
-#, c-format
-#~ msgid "hours"
-#~ msgstr "horas"
-
-#, c-format
-#~ msgid "minutes"
-#~ msgstr "minutos"
-
-#, c-format
-#~ msgid "seconds"
-#~ msgstr "segundos"
-
-#~ msgid "this link"
-#~ msgstr "este link"
diff --git a/packages/demobank-ui/src/i18n/fr.po b/packages/demobank-ui/src/i18n/fr.po
deleted file mode 100644
index b02cbe618..000000000
--- a/packages/demobank-ui/src/i18n/fr.po
+++ /dev/null
@@ -1,1752 +0,0 @@
-# This file is part of GNU Taler
-# (C) 2022-2024 Taler Systems S.A.
-#
-# GNU Taler is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-#
-# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Taler Bank\n"
-"Report-Msgid-Bugs-To: taler@gnu.org\n"
-"PO-Revision-Date: 2024-02-28 08:07+0000\n"
-"Last-Translator: d0p1 <contact@d0p1.eu>\n"
-"Language-Team: French <https://weblate.taler.net/projects/gnu-taler/"
-"taler-bank-spa/fr/>\n"
-"Language: fr\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 5.2.1\n"
-
-#: src/utils.ts:137
-#, c-format
-msgid "Operation failed, please report"
-msgstr "L'opération a échoué, veuillez le signaler"
-
-#: src/utils.ts:156
-#, c-format
-msgid "Request timeout"
-msgstr ""
-
-#: src/utils.ts:165
-#, c-format
-msgid "Request throttled"
-msgstr ""
-
-#: src/utils.ts:174
-#, c-format
-msgid "Malformed response"
-msgstr ""
-
-#: src/utils.ts:183
-#, c-format
-msgid "Network error"
-msgstr "Erreur réseau"
-
-#: src/utils.ts:192
-#, c-format
-msgid "Unexpected request error"
-msgstr ""
-
-#: src/utils.ts:201
-#, c-format
-msgid "Unexpected error"
-msgstr ""
-
-#: src/utils.ts:377
-#, c-format
-msgid "IBAN numbers usually have more that 4 digits"
-msgstr ""
-
-#: src/utils.ts:379
-#, c-format
-msgid "IBAN numbers usually have less that 34 digits"
-msgstr ""
-
-#: src/utils.ts:387
-#, c-format
-msgid "IBAN country code not found"
-msgstr ""
-
-#: src/utils.ts:401
-#, c-format
-msgid "IBAN number is not valid, checksum is wrong"
-msgstr ""
-
-#: src/context/config.ts:136
-#, c-format
-msgid ""
-"the bank backend is not supported. supported version \"%1$s\", server "
-"version \"%2$s\""
-msgstr ""
-
-#: src/hooks/preferences.ts:55
-#, c-format
-msgid "Max withdrawal amount"
-msgstr ""
-
-#: src/hooks/preferences.ts:57
-#, c-format
-msgid "Show withdrawal confirmation"
-msgstr ""
-
-#: src/hooks/preferences.ts:59
-#, c-format
-msgid "Show demo description"
-msgstr ""
-
-#: src/hooks/preferences.ts:61
-#, c-format
-msgid "Show install wallet first"
-msgstr ""
-
-#: src/hooks/preferences.ts:63
-#, c-format
-msgid "Use fast withdrawal form"
-msgstr ""
-
-#: src/hooks/preferences.ts:65
-#, c-format
-msgid "Show debug info"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:90
-#, c-format
-msgid "required"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:92
-#, c-format
-msgid "IBAN should have just uppercased letters and numbers"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:98
-#, c-format
-msgid "not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:100
-#, c-format
-msgid "should be greater than 0"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:102
-#, c-format
-msgid "balance is not enough"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:112
-#, c-format
-msgid "does not follow the pattern"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:114
-#, c-format
-msgid "only \"IBAN\" target are supported"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:116
-#, c-format
-msgid "use the \"amount\" parameter to specify the amount to be transferred"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:118
-#, c-format
-msgid "the amount is not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:120
-#, c-format
-msgid ""
-"use the \"message\" parameter to specify a reference text for the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:160
-#, c-format
-msgid "The request was invalid or the payto://-URI used unacceptable features."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:167
-#, c-format
-msgid "Not enough permission to complete the operation."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:174
-#, c-format
-msgid "The destination account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:181
-#, c-format
-msgid "The origin and the destination of the transfer can't be the same."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:188
-#, c-format
-msgid "Your balance is not enough."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:195
-#, c-format
-msgid "The origin account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:212
-#, c-format
-msgid "Wire transfer created!"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:270
-#, c-format
-msgid "Using a form"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:310
-#, c-format
-msgid "Import payto:// URI"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:335
-#, c-format
-msgid "Recipient"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:359
-#, c-format
-msgid "IBAN of the recipient's account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:369
-#, c-format
-msgid "Transfer subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:377
-#, c-format
-msgid "subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:390
-#, c-format
-msgid "some text to identify the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:400
-#, c-format
-msgid "Amount"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:415
-#, c-format
-msgid "amount to transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:425
-#, c-format
-msgid "payto URI:"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:436
-#, c-format
-msgid "uniform resource identifier of the target account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:437
-#, c-format
-msgid "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:457
-#, c-format
-msgid "Cancel"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:471
-#, c-format
-msgid "Send"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:71
-#, c-format
-msgid "Missing username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:75
-#, c-format
-msgid "Missing password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:104
-#, c-format
-msgid "Wrong credentials for \"%1$s\""
-msgstr ""
-
-#: src/pages/LoginForm.tsx:111
-#, c-format
-msgid "Account not found"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:142
-#, c-format
-msgid "Username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:156
-#, c-format
-msgid "username of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:175
-#, c-format
-msgid "Password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:188
-#, c-format
-msgid "password of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:223
-#, c-format
-msgid "Check"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:237
-#, c-format
-msgid "Log in"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:249
-#, c-format
-msgid "Register"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:52
-#, c-format
-msgid "Latest transactions"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:63
-#, c-format
-msgid "Date"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:71
-#, c-format
-msgid "Counterpart"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:75
-#, c-format
-msgid "Subject"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:111
-#, c-format
-msgid "sent"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:112
-#, c-format
-msgid "received"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:127
-#, c-format
-msgid "invalid value"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "to"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "from"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:202
-#, c-format
-msgid "First page"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:209
-#, c-format
-msgid "Next"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:86
-#, c-format
-msgid "Wire transfer completed!"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:93
-#, c-format
-msgid "The withdrawal has been aborted previously and can't be confirmed"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:100
-#, c-format
-msgid ""
-"The withdrawal operation can't be confirmed before a wallet accepted the "
-"transaction."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:107
-#, c-format
-msgid "The operation id is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:114
-#, c-format
-msgid "The operation was not found."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:121
-#, c-format
-msgid "Your balance is not enough for the operation."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:155
-#, c-format
-msgid ""
-"The reserve operation has been confirmed previously and can't be aborted"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:186
-#, c-format
-msgid "Confirm the withdrawal operation"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:203
-#, c-format
-msgid "Wire transfer details"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:217
-#, c-format
-msgid "Taler Exchange operator's account"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:228
-#, c-format
-msgid "Taler Exchange operator's name"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:317
-#, c-format
-msgid "Transfer"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:342
-#, c-format
-msgid "Authentication required"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:352
-#, c-format
-msgid "This operation was created with other username"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:209
-#, c-format
-msgid ""
-"Unauthorized to make the operation, maybe the session has expired or the "
-"password changed."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:218
-#, c-format
-msgid "The operation was rejected due to insufficient funds."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:268
-#, c-format
-msgid "Withdrawal confirmed"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:272
-#, c-format
-msgid ""
-"The wire transfer to the Taler operator has been initiated. You will soon "
-"receive the requested amount in your Taler wallet."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:287
-#, c-format
-msgid "Do not show this again"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:319
-#, c-format
-msgid "Close"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:399
-#, c-format
-msgid "On this device"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:404
-#, c-format
-msgid ""
-"If you are using a web browser on desktop you should access your wallet with "
-"the GNU Taler WebExtension now or click the link if your WebExtension have "
-"the \"Inject Taler support\" option enabled."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:417
-#, c-format
-msgid "Start"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:426
-#, c-format
-msgid "On a mobile phone"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:431
-#, c-format
-msgid "Scan the QR code with your mobile device."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:73
-#, c-format
-msgid "There is an operation already"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:75
-#, c-format
-msgid "Complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:84
-#, c-format
-msgid "this page"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:101
-#, c-format
-msgid "invalid"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:116
-#, c-format
-msgid "Server responded with an invalid withdraw URI"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:117
-#, c-format
-msgid "Withdraw URI: %1$s"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:132
-#, c-format
-msgid "The operation was rejected due to insufficient funds"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:253
-#, c-format
-msgid "Continue"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:282
-#, c-format
-msgid "Prepare your wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:285
-#, c-format
-msgid ""
-"After using your wallet you will need to confirm or cancel the operation on "
-"this site."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:295
-#, c-format
-msgid "You need a GNU Taler Wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:300
-#, c-format
-msgid "If you don't have one yet you can follow the instruction in"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:55
-#, c-format
-msgid "Send money"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:73
-#, c-format
-msgid "to a %1$s wallet"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:95
-#, c-format
-msgid "Withdraw digital money into your mobile wallet or browser extension"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:109
-#, c-format
-msgid "operation ready"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:129
-#, c-format
-msgid "to another bank account"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:149
-#, c-format
-msgid "Make a wire transfer to an account with known bank account number."
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:171
-#, c-format
-msgid "Transfer details"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:41
-#, c-format
-msgid "This is a demo bank"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:46
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work. In addition to using your own bank account, you can also see the "
-"transaction history of some %1$s."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:53
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:70
-#, c-format
-msgid "Pending account delete operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:72
-#, c-format
-msgid "Pending account update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:74
-#, c-format
-msgid "Pending password update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:76
-#, c-format
-msgid "Pending transaction operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:78
-#, c-format
-msgid "Pending withdrawal operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:80
-#, c-format
-msgid "Pending cashout operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:91
-#, c-format
-msgid "You can complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:64
-#, c-format
-msgid "Internal error, please report."
-msgstr ""
-
-#: src/pages/BankFrame.tsx:100
-#, c-format
-msgid "Preferences"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:184
-#, c-format
-msgid "Welcome, %1$s"
-msgstr ""
-
-#: src/pages/WireTransfer.tsx:79
-#, c-format
-msgid "Make a wire transfer"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:72
-#, c-format
-msgid "Accounts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:75
-#, c-format
-msgid "A list of all business account in the bank."
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:86
-#, c-format
-msgid "Create account"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:106
-#, c-format
-msgid "Name"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:110
-#, c-format
-msgid "Balance"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:112
-#, c-format
-msgid "Actions"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:151
-#, c-format
-msgid "unknown"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:170
-#, c-format
-msgid "change password"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:179
-#, c-format
-msgid "cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:189
-#, c-format
-msgid "remove"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:168
-#, c-format
-msgid "Cashout not implemented"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:184
-#, c-format
-msgid "Select a section"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:202
-#, c-format
-msgid "Last hour"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:208
-#, c-format
-msgid "Last day"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:216
-#, c-format
-msgid "Last month"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:222
-#, c-format
-msgid "Last year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:310
-#, c-format
-msgid "Last Year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:325
-#, c-format
-msgid "Trading volume on %1$s compared to %2$s"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:342
-#, c-format
-msgid "Cashin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:352
-#, c-format
-msgid "Cashout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:364
-#, c-format
-msgid "Payin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:374
-#, c-format
-msgid "Payout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:388
-#, c-format
-msgid "download stats as CSV"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:494
-#, c-format
-msgid "Decreased by"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:498
-#, c-format
-msgid "Increased by"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:89
-#, c-format
-msgid "Download bank stats"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:110
-#, c-format
-msgid "Include hour metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:143
-#, c-format
-msgid "Include day metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:173
-#, c-format
-msgid "Include month metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:206
-#, c-format
-msgid "Include year metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:239
-#, c-format
-msgid "Include table header"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:272
-#, c-format
-msgid "Add previous metric for compare"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:307
-#, c-format
-msgid "Fail on first error"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:364
-#, c-format
-msgid "Download"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:381
-#, c-format
-msgid "downloading... %1$s"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:399
-#, c-format
-msgid "Download completed"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:400
-#, c-format
-msgid "click here to save the file in your computer"
-msgstr ""
-
-#: src/pages/PublicHistoriesPage.tsx:78
-#, c-format
-msgid "History of public accounts"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:48
-#, c-format
-msgid "Currently, the bank is not accepting new registrations!"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:87
-#, c-format
-msgid "Missing name"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:91
-#, c-format
-msgid "Use letters and numbers only, and start with a lowercase letter"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:107
-#, c-format
-msgid "Passwords don't match"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:130
-#, c-format
-msgid "Server replied with invalid phone or email."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:137
-#, c-format
-msgid "Registration is disabled because the bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:144
-#, c-format
-msgid "No enough permission to create that account."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:151
-#, c-format
-msgid "That account id is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:158
-#, c-format
-msgid "That username is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:165
-#, c-format
-msgid "That username can't be used because is reserved."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:172
-#, c-format
-msgid "Only admin is allow to set debt limit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:179
-#, c-format
-msgid "No information for the selected authentication channel."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:186
-#, c-format
-msgid "Authentication channel is not supported."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:193
-#, c-format
-msgid "Only admin can create accounts with second factor authentication."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:233
-#, c-format
-msgid "Account registration"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:315
-#, c-format
-msgid "Repeat password"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:457
-#, c-format
-msgid "Create a random temporary user"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:110
-#, c-format
-msgid "If you have a Taler wallet installed in this device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:116
-#, c-format
-msgid ""
-"You will see the details of the operation in your wallet including the fees "
-"(if applies). If you still don't have one you can install it following "
-"instructions in"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:143
-#, c-format
-msgid "Withdraw"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:152
-#, c-format
-msgid "Or if you have the wallet in another device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:157
-#, c-format
-msgid "Scan the QR below to start the withdrawal."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:79
-#, c-format
-msgid "Operation aborted"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:82
-#, c-format
-msgid ""
-"The wire transfer to the Taler Exchange operator's account was aborted, your "
-"balance was not affected."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:88
-#, c-format
-msgid "You can close this page now or continue to the account page."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:147
-#, c-format
-msgid "Done"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:158
-#, c-format
-msgid "Operation canceled"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:173
-#, c-format
-msgid ""
-"The operation is marked as 'selected' but some step in the withdrawal failed"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:175
-#, c-format
-msgid "The account is selected but no withdrawal identification found."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:188
-#, c-format
-msgid ""
-"There is a withdrawal identification but no account has been selected or the "
-"selected account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:202
-#, c-format
-msgid ""
-"No withdrawal ID found and no account has been selected or the selected "
-"account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:259
-#, c-format
-msgid "Operation not found"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:263
-#, c-format
-msgid ""
-"This operation is not known by the server. The operation id is wrong or the "
-"server deleted the operation information before reaching here."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:278
-#, c-format
-msgid "Cotinue to dashboard"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:98
-#, c-format
-msgid "Cashout not found. It may be also mean that it was already aborted."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:136
-#, c-format
-msgid "Challenge not found."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:143
-#, c-format
-msgid "This user is not authorized to complete this challenge."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:150
-#, c-format
-msgid "Too many attempts, try another code."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:157
-#, c-format
-msgid "The confirmation code is wrong, try again."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:164
-#, c-format
-msgid "The operation expired."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:197
-#, c-format
-msgid "The operation failed."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:212
-#, c-format
-msgid "The operation needs another confirmation to complete."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:224
-#, c-format
-msgid "Account delete"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:226
-#, c-format
-msgid "Account update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:228
-#, c-format
-msgid "Password update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:230
-#, c-format
-msgid "Wire transfer"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:232
-#, c-format
-msgid "Withdrawal"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:248
-#, c-format
-msgid "Confirm the operation"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:271
-#, c-format
-msgid "Enter the confirmation code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:313
-#, c-format
-msgid "Confirm"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:348
-#, c-format
-msgid "Send again"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:359
-#, c-format
-msgid "Send code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:369
-#, c-format
-msgid "Operation details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:529
-#, c-format
-msgid "Challenge details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:536
-#, c-format
-msgid "Sent at"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:551
-#, c-format
-msgid "To phone"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:553
-#, c-format
-msgid "To email"
-msgstr ""
-
-#: src/pages/WithdrawalOperationPage.tsx:49
-#, c-format
-msgid "The Withdrawal URI is not valid"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:100
-#, c-format
-msgid "Latest cashouts"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:111
-#, c-format
-msgid "Created"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:115
-#, c-format
-msgid "Total debit"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:119
-#, c-format
-msgid "Total credit"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:70
-#, c-format
-msgid "Details"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:74
-#, c-format
-msgid "Delete"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:78
-#, c-format
-msgid "Credentials"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:82
-#, c-format
-msgid "Cashouts"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:95
-#, c-format
-msgid "Unable to create a cashout"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:96
-#, c-format
-msgid "The bank configuration does not support cashout operations."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:223
-#, c-format
-msgid "need to be higher due to fees"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:225
-#, c-format
-msgid "the total transfer at destination will be zero"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:250
-#, c-format
-msgid "Cashout created"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:272
-#, c-format
-msgid ""
-"Duplicated request detected, check if the operation succeeded or try again."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:279
-#, c-format
-msgid "The conversion rate was incorrectly applied"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:286
-#, c-format
-msgid "The account does not have sufficient funds"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:293
-#, c-format
-msgid "Cashouts are not supported"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:300
-#, c-format
-msgid "Missing cashout URI in the profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:307
-#, c-format
-msgid ""
-"Sending the confirmation message failed, retry later or contact the "
-"administrator."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:339
-#, c-format
-msgid "Conversion rate"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:360
-#, c-format
-msgid "Fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:374
-#, c-format
-msgid "To account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:381
-#, c-format
-msgid "No cashout account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:382
-#, c-format
-msgid "Before doing a cashout you need to complete your profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:440
-#, c-format
-msgid "Amount to send"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:441
-#, c-format
-msgid "Amount to receive"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:490
-#, c-format
-msgid "Total cost"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:505
-#, c-format
-msgid "Balance left"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:520
-#, c-format
-msgid "Before fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:533
-#, c-format
-msgid "Total cashout transfer"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:553
-#, c-format
-msgid "No cashout channel available"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:555
-#, c-format
-msgid ""
-"Before doing a cashout the server need to provide an second channel to "
-"confirm the operation"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:567
-#, c-format
-msgid "Second factor authentication"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:598
-#, c-format
-msgid "Email"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:600
-#, c-format
-msgid "add a email in your profile to enable this option"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:646
-#, c-format
-msgid "SMS"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:648
-#, c-format
-msgid "add a phone number in your profile to enable this option"
-msgstr ""
-
-#: src/pages/account/CashoutListForAccount.tsx:52
-#, c-format
-msgid "Cashout for account %1$s"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:165
-#, c-format
-msgid "it doesn't have the pattern of an IBAN number"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:185
-#, c-format
-msgid "it doesn't have the pattern of an email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:190
-#, c-format
-msgid "should start with +"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:192
-#, c-format
-msgid "phone number can't have other than numbers"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:329
-#, c-format
-msgid "account identification in the bank"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:365
-#, c-format
-msgid "name of the person owner the account"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:374
-#, c-format
-msgid "Internal IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:377
-#, c-format
-msgid "if empty a random account number will be assigned"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:378
-#, c-format
-msgid "account identification for bank transfer"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:423
-#, c-format
-msgid "Phone"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:451
-#, c-format
-msgid "Cashout IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:452
-#, c-format
-msgid "account number where the money is going to be sent when doing cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:470
-#, c-format
-msgid "Max debt"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:494
-#, c-format
-msgid "how much is user able to transfer after zero balance"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:508
-#, c-format
-msgid "Is this a Taler Exchange?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:549
-#, c-format
-msgid "This server doesn't support second factor authentication."
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:560
-#, c-format
-msgid "Enable second factor authentication"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:596
-#, c-format
-msgid "Using email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:654
-#, c-format
-msgid "Using SMS"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:691
-#, c-format
-msgid "Is this account public?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:719
-#, c-format
-msgid "public accounts have their balance publicly accessible"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:100
-#, c-format
-msgid "Account updated"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:107
-#, c-format
-msgid "The rights to change the account are not sufficient"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:114
-#, c-format
-msgid "The username was not found"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:121
-#, c-format
-msgid ""
-"You can't change the legal name, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:128
-#, c-format
-msgid ""
-"You can't change the debt limit, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:135
-#, c-format
-msgid ""
-"You can't change the cashout address, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:177
-#, c-format
-msgid "Account \"%1$s\""
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:190
-#, c-format
-msgid "Change details"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:235
-#, c-format
-msgid "Update"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:78
-#, c-format
-msgid "password doesn't match"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:95
-#, c-format
-msgid "Password changed"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:102
-#, c-format
-msgid "Not authorized to change the password, maybe the session is invalid."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:112
-#, c-format
-msgid ""
-"You need to provide the old password. If you don't have it contact your "
-"account administrator."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:117
-#, c-format
-msgid "Your current password doesn't match, can't change to a new password."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:149
-#, c-format
-msgid "Update password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:167
-#, c-format
-msgid "New password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:195
-#, c-format
-msgid "Type it again"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:217
-#, c-format
-msgid "repeat the same password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:227
-#, c-format
-msgid "Current password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:248
-#, c-format
-msgid "your current password, for security"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:272
-#, c-format
-msgid "Change"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:74
-#, c-format
-msgid ""
-"Account created with password \"%1$s\". The user must change the password on "
-"the next login."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:83
-#, c-format
-msgid "Server replied that phone or email is invalid"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:90
-#, c-format
-msgid "The rights to perform the operation are not sufficient"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:97
-#, c-format
-msgid "Account username is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:104
-#, c-format
-msgid "Account id is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:111
-#, c-format
-msgid "Bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:118
-#, c-format
-msgid "Account username can't be used because is reserved"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:160
-#, c-format
-msgid "Can't create accounts"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:161
-#, c-format
-msgid "Only system admin can create accounts."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:183
-#, c-format
-msgid "New business account"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:209
-#, c-format
-msgid "Create"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:94
-#, c-format
-msgid "Can't delete the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:95
-#, c-format
-msgid ""
-"The account can't be delete while still holding some balance. First make "
-"sure that the owner make a complete cashout."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:117
-#, c-format
-msgid "Account removed"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:124
-#, c-format
-msgid "No enough permission to delete the account."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:131
-#, c-format
-msgid "The username was not found."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:138
-#, c-format
-msgid "Can't delete a reserved username."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:145
-#, c-format
-msgid "Can't delete an account with balance different than zero."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:170
-#, c-format
-msgid "name doesn't match"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:180
-#, c-format
-msgid "You are going to remove the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:182
-#, c-format
-msgid "This step can't be undone."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:188
-#, c-format
-msgid "Deleting account \"%1$s\""
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:206
-#, c-format
-msgid "Verification"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:231
-#, c-format
-msgid "enter the account name that is going to be deleted"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:49
-#, c-format
-msgid "cashout id should be a number"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:65
-#, c-format
-msgid "This cashout not found. Maybe already aborted."
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:106
-#, c-format
-msgid "Cashout detail"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:139
-#, c-format
-msgid "Debited"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:154
-#, c-format
-msgid "Credited"
-msgstr ""
-
-#: src/Routing.tsx:140
-#, c-format
-msgid "Welcome to %1$s!"
-msgstr ""
diff --git a/packages/demobank-ui/src/i18n/it.po b/packages/demobank-ui/src/i18n/it.po
deleted file mode 100644
index 7aeaca3a8..000000000
--- a/packages/demobank-ui/src/i18n/it.po
+++ /dev/null
@@ -1,1843 +0,0 @@
-# This file is part of GNU Taler
-# (C) 2021 Taler Systems S.A.
-# GNU Taler is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-# You should have received a copy of the GNU General Public License along with
-# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Taler Wallet\n"
-"Report-Msgid-Bugs-To: taler@gnu.org\n"
-"POT-Creation-Date: 2016-11-23 00:00+0100\n"
-"PO-Revision-Date: 2023-08-15 07:28+0000\n"
-"Last-Translator: Krystian Baran <kiszkot@murena.io>\n"
-"Language-Team: Italian <https://weblate.taler.net/projects/gnu-taler/taler-"
-"bank-spa/it/>\n"
-"Language: it\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=n != 1;\n"
-"X-Generator: Weblate 4.13.1\n"
-
-#: src/utils.ts:137
-#, fuzzy, c-format
-msgid "Operation failed, please report"
-msgstr "Registrazione"
-
-#: src/utils.ts:156
-#, c-format
-msgid "Request timeout"
-msgstr ""
-
-#: src/utils.ts:165
-#, c-format
-msgid "Request throttled"
-msgstr ""
-
-#: src/utils.ts:174
-#, c-format
-msgid "Malformed response"
-msgstr ""
-
-#: src/utils.ts:183
-#, c-format
-msgid "Network error"
-msgstr ""
-
-#: src/utils.ts:192
-#, c-format
-msgid "Unexpected request error"
-msgstr ""
-
-#: src/utils.ts:201
-#, c-format
-msgid "Unexpected error"
-msgstr ""
-
-#: src/utils.ts:377
-#, c-format
-msgid "IBAN numbers usually have more that 4 digits"
-msgstr ""
-
-#: src/utils.ts:379
-#, c-format
-msgid "IBAN numbers usually have less that 34 digits"
-msgstr ""
-
-#: src/utils.ts:387
-#, c-format
-msgid "IBAN country code not found"
-msgstr ""
-
-#: src/utils.ts:401
-#, c-format
-msgid "IBAN number is not valid, checksum is wrong"
-msgstr ""
-
-#: src/context/config.ts:136
-#, c-format
-msgid ""
-"the bank backend is not supported. supported version \"%1$s\", server "
-"version \"%2$s\""
-msgstr ""
-
-#: src/hooks/preferences.ts:55
-#, fuzzy, c-format
-msgid "Max withdrawal amount"
-msgstr "Questo ritiro è stato annullato!"
-
-#: src/hooks/preferences.ts:57
-#, fuzzy, c-format
-msgid "Show withdrawal confirmation"
-msgstr "Questo ritiro è stato annullato!"
-
-#: src/hooks/preferences.ts:59
-#, c-format
-msgid "Show demo description"
-msgstr ""
-
-#: src/hooks/preferences.ts:61
-#, c-format
-msgid "Show install wallet first"
-msgstr ""
-
-#: src/hooks/preferences.ts:63
-#, fuzzy, c-format
-msgid "Use fast withdrawal form"
-msgstr "Ritira contante"
-
-#: src/hooks/preferences.ts:65
-#, c-format
-msgid "Show debug info"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:90
-#, c-format
-msgid "required"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:92
-#, c-format
-msgid "IBAN should have just uppercased letters and numbers"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:98
-#, c-format
-msgid "not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:100
-#, c-format
-msgid "should be greater than 0"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:102
-#, c-format
-msgid "balance is not enough"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:112
-#, c-format
-msgid "does not follow the pattern"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:114
-#, c-format
-msgid "only \"IBAN\" target are supported"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:116
-#, c-format
-msgid "use the \"amount\" parameter to specify the amount to be transferred"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:118
-#, c-format
-msgid "the amount is not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:120
-#, c-format
-msgid ""
-"use the \"message\" parameter to specify a reference text for the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:160
-#, c-format
-msgid "The request was invalid or the payto://-URI used unacceptable features."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:167
-#, fuzzy, c-format
-msgid "Not enough permission to complete the operation."
-msgstr "La banca sta creando l'operazione..."
-
-#: src/pages/PaytoWireTransferForm.tsx:174
-#, fuzzy, c-format
-msgid "The destination account \"%1$s\" was not found."
-msgstr "Lista conti pubblici non trovata."
-
-#: src/pages/PaytoWireTransferForm.tsx:181
-#, c-format
-msgid "The origin and the destination of the transfer can't be the same."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:188
-#, c-format
-msgid "Your balance is not enough."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:195
-#, fuzzy, c-format
-msgid "The origin account \"%1$s\" was not found."
-msgstr "Lista conti pubblici non trovata."
-
-#: src/pages/PaytoWireTransferForm.tsx:212
-#, fuzzy, c-format
-msgid "Wire transfer created!"
-msgstr "Bonifico"
-
-#: src/pages/PaytoWireTransferForm.tsx:270
-#, c-format
-msgid "Using a form"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:310
-#, c-format
-msgid "Import payto:// URI"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:335
-#, c-format
-msgid "Recipient"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:359
-#, c-format
-msgid "IBAN of the recipient's account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:369
-#, fuzzy, c-format
-msgid "Transfer subject"
-msgstr "Trasferisci fondi a un altro conto di questa banca:"
-
-#: src/pages/PaytoWireTransferForm.tsx:377
-#, fuzzy, c-format
-msgid "subject"
-msgstr "Soggetto"
-
-#: src/pages/PaytoWireTransferForm.tsx:390
-#, c-format
-msgid "some text to identify the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:400
-#, c-format
-msgid "Amount"
-msgstr "Importo"
-
-#: src/pages/PaytoWireTransferForm.tsx:415
-#, fuzzy, c-format
-msgid "amount to transfer"
-msgstr "Somma da ritirare"
-
-#: src/pages/PaytoWireTransferForm.tsx:425
-#, c-format
-msgid "payto URI:"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:436
-#, c-format
-msgid "uniform resource identifier of the target account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:437
-#, c-format
-msgid "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:457
-#, c-format
-msgid "Cancel"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:471
-#, c-format
-msgid "Send"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:71
-#, c-format
-msgid "Missing username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:75
-#, c-format
-msgid "Missing password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:104
-#, fuzzy, c-format
-msgid "Wrong credentials for \"%1$s\""
-msgstr "Credenziali invalide."
-
-#: src/pages/LoginForm.tsx:111
-#, c-format
-msgid "Account not found"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:142
-#, c-format
-msgid "Username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:156
-#, fuzzy, c-format
-msgid "username of the account"
-msgstr "Trasferisci fondi a un altro conto di questa banca:"
-
-#: src/pages/LoginForm.tsx:175
-#, c-format
-msgid "Password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:188
-#, fuzzy, c-format
-msgid "password of the account"
-msgstr "Storico dei conti pubblici"
-
-#: src/pages/LoginForm.tsx:223
-#, c-format
-msgid "Check"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:237
-#, c-format
-msgid "Log in"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:249
-#, c-format
-msgid "Register"
-msgstr "Registrati"
-
-#: src/components/Transactions/views.tsx:52
-#, fuzzy, c-format
-msgid "Latest transactions"
-msgstr "Ultime transazioni:"
-
-#: src/components/Transactions/views.tsx:63
-#, c-format
-msgid "Date"
-msgstr "Data"
-
-#: src/components/Transactions/views.tsx:71
-#, c-format
-msgid "Counterpart"
-msgstr "Controparte"
-
-#: src/components/Transactions/views.tsx:75
-#, c-format
-msgid "Subject"
-msgstr "Soggetto"
-
-#: src/components/Transactions/views.tsx:111
-#, c-format
-msgid "sent"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:112
-#, c-format
-msgid "received"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:127
-#, c-format
-msgid "invalid value"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "to"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "from"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:202
-#, c-format
-msgid "First page"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:209
-#, c-format
-msgid "Next"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:86
-#, fuzzy, c-format
-msgid "Wire transfer completed!"
-msgstr "Bonifico"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:93
-#, c-format
-msgid "The withdrawal has been aborted previously and can't be confirmed"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:100
-#, c-format
-msgid ""
-"The withdrawal operation can't be confirmed before a wallet accepted the "
-"transaction."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:107
-#, c-format
-msgid "The operation id is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:114
-#, fuzzy, c-format
-msgid "The operation was not found."
-msgstr "Lista conti pubblici non trovata."
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:121
-#, c-format
-msgid "Your balance is not enough for the operation."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:155
-#, c-format
-msgid ""
-"The reserve operation has been confirmed previously and can't be aborted"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:186
-#, fuzzy, c-format
-msgid "Confirm the withdrawal operation"
-msgstr "Conferma il ritiro"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:203
-#, fuzzy, c-format
-msgid "Wire transfer details"
-msgstr "Bonifico"
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:217
-#, c-format
-msgid "Taler Exchange operator's account"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:228
-#, c-format
-msgid "Taler Exchange operator's name"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:317
-#, c-format
-msgid "Transfer"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:342
-#, c-format
-msgid "Authentication required"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:352
-#, c-format
-msgid "This operation was created with other username"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:209
-#, c-format
-msgid ""
-"Unauthorized to make the operation, maybe the session has expired or the "
-"password changed."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:218
-#, c-format
-msgid "The operation was rejected due to insufficient funds."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:268
-#, fuzzy, c-format
-msgid "Withdrawal confirmed"
-msgstr "Questo ritiro è stato annullato!"
-
-#: src/pages/OperationState/views.tsx:272
-#, c-format
-msgid ""
-"The wire transfer to the Taler operator has been initiated. You will soon "
-"receive the requested amount in your Taler wallet."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:287
-#, c-format
-msgid "Do not show this again"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:319
-#, c-format
-msgid "Close"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:399
-#, c-format
-msgid "On this device"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:404
-#, c-format
-msgid ""
-"If you are using a web browser on desktop you should access your wallet with "
-"the GNU Taler WebExtension now or click the link if your WebExtension have "
-"the \"Inject Taler support\" option enabled."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:417
-#, c-format
-msgid "Start"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:426
-#, c-format
-msgid "On a mobile phone"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:431
-#, fuzzy, c-format
-msgid "Scan the QR code with your mobile device."
-msgstr "Usa questo codice QR per ritirare contante nel tuo wallet:"
-
-#: src/pages/WalletWithdrawForm.tsx:73
-#, c-format
-msgid "There is an operation already"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:75
-#, fuzzy, c-format
-msgid "Complete or cancel the operation in"
-msgstr "Conferma il ritiro"
-
-#: src/pages/WalletWithdrawForm.tsx:84
-#, c-format
-msgid "this page"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:101
-#, c-format
-msgid "invalid"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:116
-#, c-format
-msgid "Server responded with an invalid withdraw URI"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:117
-#, fuzzy, c-format
-msgid "Withdraw URI: %1$s"
-msgstr "Prelevare"
-
-#: src/pages/WalletWithdrawForm.tsx:132
-#, c-format
-msgid "The operation was rejected due to insufficient funds"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:253
-#, c-format
-msgid "Continue"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:282
-#, c-format
-msgid "Prepare your wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:285
-#, c-format
-msgid ""
-"After using your wallet you will need to confirm or cancel the operation on "
-"this site."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:295
-#, fuzzy, c-format
-msgid "You need a GNU Taler Wallet"
-msgstr "Ritira contante nel portafoglio Taler"
-
-#: src/pages/WalletWithdrawForm.tsx:300
-#, c-format
-msgid "If you don't have one yet you can follow the instruction in"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:55
-#, c-format
-msgid "Send money"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:73
-#, c-format
-msgid "to a %1$s wallet"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:95
-#, c-format
-msgid "Withdraw digital money into your mobile wallet or browser extension"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:109
-#, c-format
-msgid "operation ready"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:129
-#, fuzzy, c-format
-msgid "to another bank account"
-msgstr "Trasferisci fondi a un altro conto di questa banca:"
-
-#: src/pages/PaymentOptions.tsx:149
-#, c-format
-msgid "Make a wire transfer to an account with known bank account number."
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:171
-#, fuzzy, c-format
-msgid "Transfer details"
-msgstr "Effettua un bonifico"
-
-#: src/pages/AccountPage/views.tsx:41
-#, c-format
-msgid "This is a demo bank"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:46
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work. In addition to using your own bank account, you can also see the "
-"transaction history of some %1$s."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:53
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would "
-"work."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:70
-#, c-format
-msgid "Pending account delete operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:72
-#, c-format
-msgid "Pending account update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:74
-#, c-format
-msgid "Pending password update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:76
-#, c-format
-msgid "Pending transaction operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:78
-#, c-format
-msgid "Pending withdrawal operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:80
-#, c-format
-msgid "Pending cashout operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:91
-#, c-format
-msgid "You can complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:64
-#, fuzzy, c-format
-msgid "Internal error, please report."
-msgstr "Registrazione"
-
-#: src/pages/BankFrame.tsx:100
-#, c-format
-msgid "Preferences"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:184
-#, c-format
-msgid "Welcome, %1$s"
-msgstr ""
-
-#: src/pages/WireTransfer.tsx:79
-#, fuzzy, c-format
-msgid "Make a wire transfer"
-msgstr "Chiudi il bonifico"
-
-#: src/pages/admin/AccountList.tsx:72
-#, fuzzy, c-format
-msgid "Accounts"
-msgstr "Importo"
-
-#: src/pages/admin/AccountList.tsx:75
-#, c-format
-msgid "A list of all business account in the bank."
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:86
-#, c-format
-msgid "Create account"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:106
-#, c-format
-msgid "Name"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:110
-#, c-format
-msgid "Balance"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:112
-#, c-format
-msgid "Actions"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:151
-#, c-format
-msgid "unknown"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:170
-#, c-format
-msgid "change password"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:179
-#, fuzzy, c-format
-msgid "cashouts"
-msgstr "Ultime transazioni:"
-
-#: src/pages/admin/AccountList.tsx:189
-#, c-format
-msgid "remove"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:168
-#, c-format
-msgid "Cashout not implemented"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:184
-#, c-format
-msgid "Select a section"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:202
-#, c-format
-msgid "Last hour"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:208
-#, c-format
-msgid "Last day"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:216
-#, c-format
-msgid "Last month"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:222
-#, c-format
-msgid "Last year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:310
-#, c-format
-msgid "Last Year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:325
-#, c-format
-msgid "Trading volume on %1$s compared to %2$s"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:342
-#, c-format
-msgid "Cashin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:352
-#, c-format
-msgid "Cashout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:364
-#, c-format
-msgid "Payin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:374
-#, c-format
-msgid "Payout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:388
-#, c-format
-msgid "download stats as CSV"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:494
-#, c-format
-msgid "Decreased by"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:498
-#, c-format
-msgid "Increased by"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:89
-#, c-format
-msgid "Download bank stats"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:110
-#, c-format
-msgid "Include hour metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:143
-#, c-format
-msgid "Include day metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:173
-#, c-format
-msgid "Include month metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:206
-#, c-format
-msgid "Include year metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:239
-#, c-format
-msgid "Include table header"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:272
-#, c-format
-msgid "Add previous metric for compare"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:307
-#, c-format
-msgid "Fail on first error"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:364
-#, c-format
-msgid "Download"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:381
-#, c-format
-msgid "downloading... %1$s"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:399
-#, c-format
-msgid "Download completed"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:400
-#, c-format
-msgid "click here to save the file in your computer"
-msgstr ""
-
-#: src/pages/PublicHistoriesPage.tsx:78
-#, c-format
-msgid "History of public accounts"
-msgstr "Storico dei conti pubblici"
-
-#: src/pages/RegistrationPage.tsx:48
-#, c-format
-msgid "Currently, the bank is not accepting new registrations!"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:87
-#, fuzzy, c-format
-msgid "Missing name"
-msgstr "indirizzo Payto"
-
-#: src/pages/RegistrationPage.tsx:91
-#, c-format
-msgid "Use letters and numbers only, and start with a lowercase letter"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:107
-#, c-format
-msgid "Passwords don't match"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:130
-#, c-format
-msgid "Server replied with invalid phone or email."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:137
-#, c-format
-msgid "Registration is disabled because the bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:144
-#, c-format
-msgid "No enough permission to create that account."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:151
-#, c-format
-msgid "That account id is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:158
-#, c-format
-msgid "That username is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:165
-#, c-format
-msgid "That username can't be used because is reserved."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:172
-#, c-format
-msgid "Only admin is allow to set debt limit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:179
-#, c-format
-msgid "No information for the selected authentication channel."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:186
-#, c-format
-msgid "Authentication channel is not supported."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:193
-#, c-format
-msgid "Only admin can create accounts with second factor authentication."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:233
-#, c-format
-msgid "Account registration"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:315
-#, c-format
-msgid "Repeat password"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:457
-#, c-format
-msgid "Create a random temporary user"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:110
-#, c-format
-msgid "If you have a Taler wallet installed in this device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:116
-#, c-format
-msgid ""
-"You will see the details of the operation in your wallet including the fees "
-"(if applies). If you still don't have one you can install it following "
-"instructions in"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:143
-#, c-format
-msgid "Withdraw"
-msgstr "Prelevare"
-
-#: src/pages/QrCodeSection.tsx:152
-#, c-format
-msgid "Or if you have the wallet in another device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:157
-#, fuzzy, c-format
-msgid "Scan the QR below to start the withdrawal."
-msgstr "Chiudi il ritiro Taler"
-
-#: src/pages/WithdrawalQRCode.tsx:79
-#, c-format
-msgid "Operation aborted"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:82
-#, c-format
-msgid ""
-"The wire transfer to the Taler Exchange operator's account was aborted, your "
-"balance was not affected."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:88
-#, c-format
-msgid "You can close this page now or continue to the account page."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:147
-#, c-format
-msgid "Done"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:158
-#, c-format
-msgid "Operation canceled"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:173
-#, c-format
-msgid ""
-"The operation is marked as 'selected' but some step in the withdrawal failed"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:175
-#, c-format
-msgid "The account is selected but no withdrawal identification found."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:188
-#, c-format
-msgid ""
-"There is a withdrawal identification but no account has been selected or the "
-"selected account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:202
-#, c-format
-msgid ""
-"No withdrawal ID found and no account has been selected or the selected "
-"account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:259
-#, c-format
-msgid "Operation not found"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:263
-#, c-format
-msgid ""
-"This operation is not known by the server. The operation id is wrong or the "
-"server deleted the operation information before reaching here."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:278
-#, c-format
-msgid "Cotinue to dashboard"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:98
-#, c-format
-msgid "Cashout not found. It may be also mean that it was already aborted."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:136
-#, c-format
-msgid "Challenge not found."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:143
-#, c-format
-msgid "This user is not authorized to complete this challenge."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:150
-#, c-format
-msgid "Too many attempts, try another code."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:157
-#, c-format
-msgid "The confirmation code is wrong, try again."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:164
-#, c-format
-msgid "The operation expired."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:197
-#, fuzzy, c-format
-msgid "The operation failed."
-msgstr "Questo ritiro è stato annullato!"
-
-#: src/pages/SolveChallengePage.tsx:212
-#, c-format
-msgid "The operation needs another confirmation to complete."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:224
-#, c-format
-msgid "Account delete"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:226
-#, c-format
-msgid "Account update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:228
-#, c-format
-msgid "Password update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:230
-#, fuzzy, c-format
-msgid "Wire transfer"
-msgstr "Bonifico"
-
-#: src/pages/SolveChallengePage.tsx:232
-#, fuzzy, c-format
-msgid "Withdrawal"
-msgstr "Prelevare"
-
-#: src/pages/SolveChallengePage.tsx:248
-#, fuzzy, c-format
-msgid "Confirm the operation"
-msgstr "Conferma il ritiro"
-
-#: src/pages/SolveChallengePage.tsx:271
-#, c-format
-msgid "Enter the confirmation code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:313
-#, c-format
-msgid "Confirm"
-msgstr "Conferma"
-
-#: src/pages/SolveChallengePage.tsx:348
-#, c-format
-msgid "Send again"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:359
-#, c-format
-msgid "Send code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:369
-#, c-format
-msgid "Operation details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:529
-#, c-format
-msgid "Challenge details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:536
-#, c-format
-msgid "Sent at"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:551
-#, c-format
-msgid "To phone"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:553
-#, c-format
-msgid "To email"
-msgstr ""
-
-#: src/pages/WithdrawalOperationPage.tsx:49
-#, fuzzy, c-format
-msgid "The Withdrawal URI is not valid"
-msgstr "Questo ritiro è stato annullato!"
-
-#: src/components/Cashouts/views.tsx:100
-#, fuzzy, c-format
-msgid "Latest cashouts"
-msgstr "Ultime transazioni:"
-
-#: src/components/Cashouts/views.tsx:111
-#, c-format
-msgid "Created"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:115
-#, c-format
-msgid "Total debit"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:119
-#, c-format
-msgid "Total credit"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:70
-#, c-format
-msgid "Details"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:74
-#, c-format
-msgid "Delete"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:78
-#, fuzzy, c-format
-msgid "Credentials"
-msgstr "Credenziali invalide."
-
-#: src/pages/ProfileNavigation.tsx:82
-#, c-format
-msgid "Cashouts"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:95
-#, c-format
-msgid "Unable to create a cashout"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:96
-#, c-format
-msgid "The bank configuration does not support cashout operations."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:223
-#, c-format
-msgid "need to be higher due to fees"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:225
-#, c-format
-msgid "the total transfer at destination will be zero"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:250
-#, c-format
-msgid "Cashout created"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:272
-#, c-format
-msgid ""
-"Duplicated request detected, check if the operation succeeded or try again."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:279
-#, c-format
-msgid "The conversion rate was incorrectly applied"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:286
-#, c-format
-msgid "The account does not have sufficient funds"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:293
-#, c-format
-msgid "Cashouts are not supported"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:300
-#, c-format
-msgid "Missing cashout URI in the profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:307
-#, c-format
-msgid ""
-"Sending the confirmation message failed, retry later or contact the "
-"administrator."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:339
-#, c-format
-msgid "Conversion rate"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:360
-#, c-format
-msgid "Fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:374
-#, c-format
-msgid "To account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:381
-#, c-format
-msgid "No cashout account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:382
-#, c-format
-msgid "Before doing a cashout you need to complete your profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:440
-#, fuzzy, c-format
-msgid "Amount to send"
-msgstr "Somma da ritirare"
-
-#: src/pages/business/CreateCashout.tsx:441
-#, fuzzy, c-format
-msgid "Amount to receive"
-msgstr "Somma da ritirare"
-
-#: src/pages/business/CreateCashout.tsx:490
-#, c-format
-msgid "Total cost"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:505
-#, c-format
-msgid "Balance left"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:520
-#, c-format
-msgid "Before fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:533
-#, c-format
-msgid "Total cashout transfer"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:553
-#, c-format
-msgid "No cashout channel available"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:555
-#, c-format
-msgid ""
-"Before doing a cashout the server need to provide an second channel to "
-"confirm the operation"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:567
-#, c-format
-msgid "Second factor authentication"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:598
-#, c-format
-msgid "Email"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:600
-#, c-format
-msgid "add a email in your profile to enable this option"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:646
-#, c-format
-msgid "SMS"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:648
-#, c-format
-msgid "add a phone number in your profile to enable this option"
-msgstr ""
-
-#: src/pages/account/CashoutListForAccount.tsx:52
-#, c-format
-msgid "Cashout for account %1$s"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:165
-#, c-format
-msgid "it doesn't have the pattern of an IBAN number"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:185
-#, c-format
-msgid "it doesn't have the pattern of an email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:190
-#, c-format
-msgid "should start with +"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:192
-#, c-format
-msgid "phone number can't have other than numbers"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:329
-#, c-format
-msgid "account identification in the bank"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:365
-#, c-format
-msgid "name of the person owner the account"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:374
-#, c-format
-msgid "Internal IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:377
-#, c-format
-msgid "if empty a random account number will be assigned"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:378
-#, c-format
-msgid "account identification for bank transfer"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:423
-#, c-format
-msgid "Phone"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:451
-#, c-format
-msgid "Cashout IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:452
-#, c-format
-msgid "account number where the money is going to be sent when doing cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:470
-#, c-format
-msgid "Max debt"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:494
-#, c-format
-msgid "how much is user able to transfer after zero balance"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:508
-#, c-format
-msgid "Is this a Taler Exchange?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:549
-#, c-format
-msgid "This server doesn't support second factor authentication."
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:560
-#, c-format
-msgid "Enable second factor authentication"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:596
-#, c-format
-msgid "Using email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:654
-#, c-format
-msgid "Using SMS"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:691
-#, c-format
-msgid "Is this account public?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:719
-#, c-format
-msgid "public accounts have their balance publicly accessible"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:100
-#, c-format
-msgid "Account updated"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:107
-#, c-format
-msgid "The rights to change the account are not sufficient"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:114
-#, c-format
-msgid "The username was not found"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:121
-#, c-format
-msgid ""
-"You can't change the legal name, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:128
-#, c-format
-msgid ""
-"You can't change the debt limit, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:135
-#, c-format
-msgid ""
-"You can't change the cashout address, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:177
-#, c-format
-msgid "Account \"%1$s\""
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:190
-#, c-format
-msgid "Change details"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:235
-#, c-format
-msgid "Update"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:78
-#, c-format
-msgid "password doesn't match"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:95
-#, c-format
-msgid "Password changed"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:102
-#, c-format
-msgid "Not authorized to change the password, maybe the session is invalid."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:112
-#, c-format
-msgid ""
-"You need to provide the old password. If you don't have it contact your "
-"account administrator."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:117
-#, c-format
-msgid "Your current password doesn't match, can't change to a new password."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:149
-#, c-format
-msgid "Update password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:167
-#, c-format
-msgid "New password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:195
-#, c-format
-msgid "Type it again"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:217
-#, c-format
-msgid "repeat the same password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:227
-#, c-format
-msgid "Current password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:248
-#, c-format
-msgid "your current password, for security"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:272
-#, c-format
-msgid "Change"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:74
-#, c-format
-msgid ""
-"Account created with password \"%1$s\". The user must change the password on "
-"the next login."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:83
-#, c-format
-msgid "Server replied that phone or email is invalid"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:90
-#, c-format
-msgid "The rights to perform the operation are not sufficient"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:97
-#, c-format
-msgid "Account username is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:104
-#, c-format
-msgid "Account id is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:111
-#, c-format
-msgid "Bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:118
-#, c-format
-msgid "Account username can't be used because is reserved"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:160
-#, c-format
-msgid "Can't create accounts"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:161
-#, c-format
-msgid "Only system admin can create accounts."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:183
-#, c-format
-msgid "New business account"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:209
-#, c-format
-msgid "Create"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:94
-#, c-format
-msgid "Can't delete the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:95
-#, c-format
-msgid ""
-"The account can't be delete while still holding some balance. First make "
-"sure that the owner make a complete cashout."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:117
-#, c-format
-msgid "Account removed"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:124
-#, c-format
-msgid "No enough permission to delete the account."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:131
-#, c-format
-msgid "The username was not found."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:138
-#, c-format
-msgid "Can't delete a reserved username."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:145
-#, c-format
-msgid "Can't delete an account with balance different than zero."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:170
-#, c-format
-msgid "name doesn't match"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:180
-#, c-format
-msgid "You are going to remove the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:182
-#, c-format
-msgid "This step can't be undone."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:188
-#, c-format
-msgid "Deleting account \"%1$s\""
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:206
-#, c-format
-msgid "Verification"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:231
-#, c-format
-msgid "enter the account name that is going to be deleted"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:49
-#, c-format
-msgid "cashout id should be a number"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:65
-#, c-format
-msgid "This cashout not found. Maybe already aborted."
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:106
-#, c-format
-msgid "Cashout detail"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:139
-#, c-format
-msgid "Debited"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:154
-#, c-format
-msgid "Credited"
-msgstr ""
-
-#: src/Routing.tsx:140
-#, c-format
-msgid "Welcome to %1$s!"
-msgstr ""
-
-#, fuzzy, c-format
-#~ msgid "Account not found."
-#~ msgstr "Lista conti pubblici non trovata."
-
-#, fuzzy, c-format
-#~ msgid "Confirmed"
-#~ msgstr "Conferma"
-
-#, c-format
-#~ msgid "Abort"
-#~ msgstr "Annulla"
-
-#, c-format
-#~ msgid "Skip to main content"
-#~ msgstr "Saltare il menu di navigazione"
-
-#, c-format
-#~ msgid "Please login!"
-#~ msgstr "Accedi!"
-
-#, c-format
-#~ msgid "Login"
-#~ msgstr "Accedi"
-
-#, fuzzy, c-format
-#~ msgid "Amount:"
-#~ msgstr "Somma"
-
-#, c-format
-#~ msgid "Want to try the raw payto://-format?"
-#~ msgstr "Prova il trasferimento tramite il formato Payto!"
-
-#, fuzzy, c-format
-#~ msgid "Transfer money to account identified by payto:// URI:"
-#~ msgstr "Trasferisci fondi a un altro conto di questa banca:"
-
-#, c-format
-#~ msgid "payto address"
-#~ msgstr "indirizzo Payto"
-
-#, fuzzy, c-format
-#~ msgid "No credentials given."
-#~ msgstr "Credenziali invalide."
-
-#, c-format
-#~ msgid "Username or account label '%1$s' not found. Won't login."
-#~ msgstr "L'utente '%1$s' non esiste. Login impossibile"
-
-#, c-format
-#~ msgid "Account information could not be retrieved."
-#~ msgstr "Impossibile ricevere le informazioni relative al conto."
-
-#, fuzzy, c-format
-#~ msgid "Bank account balance"
-#~ msgstr "Bilancio:"
-
-#, c-format
-#~ msgid "List of public accounts could not be retrieved."
-#~ msgstr "Lista conti pubblici non pervenuta."
-
-#, fuzzy, c-format
-#~ msgid "Please register!"
-#~ msgstr "Accedi!"
-
-#~ msgid "this link"
-#~ msgstr "questo link"
-
-#~ msgid "Clear"
-#~ msgstr "Cancella"
-
-#~ msgid "Demo Bank"
-#~ msgstr "Banca 'demo'"
-
-#~ msgid "Go back"
-#~ msgstr "Indietro"
-
-#~ msgid "Transfer money via the Payto system:"
-#~ msgstr "Effettua un bonifico tramite il sistema Payto:"
-
-#~ msgid "Withdraw Money into a Taler wallet"
-#~ msgstr "Ritira contante nel portafoglio Taler"
-
-#~ msgid "Register to the euFin bank!"
-#~ msgstr "Apri un conto in banca euFin!"
-
-#~ msgid "Page has a problem: logged in but backend state is lost."
-#~ msgstr ""
-#~ "Stato inconsistente: accesso utente effettuato ma stato con server perso."
-
-#, fuzzy
-#~ msgid "Welcome to the euFin bank!"
-#~ msgstr "Benvenuti in banca euFin!"
diff --git a/packages/demobank-ui/src/i18n/poheader b/packages/demobank-ui/src/i18n/poheader
deleted file mode 100644
index d7a371934..000000000
--- a/packages/demobank-ui/src/i18n/poheader
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file is part of GNU Taler
-# (C) 2022-2024 Taler Systems S.A.
-#
-# GNU Taler is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-#
-# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-#
-#, fuzzy
-msgid ""
-msgstr ""
-"Project-Id-Version: Taler Bank\n"
-"Report-Msgid-Bugs-To: taler@gnu.org\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
diff --git a/packages/demobank-ui/src/i18n/strings.ts b/packages/demobank-ui/src/i18n/strings.ts
deleted file mode 100644
index f55e5efbc..000000000
--- a/packages/demobank-ui/src/i18n/strings.ts
+++ /dev/null
@@ -1,2295 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-export interface StringsType {
- // X-Domain or 'messages'
- domain: string;
- lang: string;
- completeness: number;
- plural_forms: string;
- locale_data: {
- messages: Record<string, unknown>;
- };
-}
-export const strings: Record<string, StringsType> = {};
-
-strings["it"] = {
- locale_data: {
- messages: {
- "": {
- domain: "messages",
- plural_forms: "nplurals=2; plural=n != 1;",
- lang: "it",
- },
- "Operation failed, please report": ["Registrazione"],
- "Request timeout": [""],
- "Request throttled": [""],
- "Malformed response": [""],
- "Network error": [""],
- "Unexpected request error": [""],
- "Unexpected error": [""],
- "IBAN numbers usually have more that 4 digits": [""],
- "IBAN numbers usually have less that 34 digits": [""],
- "IBAN country code not found": [""],
- "IBAN number is not valid, checksum is wrong": [""],
- "Max withdrawal amount": ["Questo ritiro è stato annullato!"],
- "Show withdrawal confirmation": ["Questo ritiro è stato annullato!"],
- "Show demo description": [""],
- "Show install wallet first": [""],
- "Use fast withdrawal form": ["Ritira contante"],
- "Show debug info": [""],
- "The reserve operation has been confirmed previously and can't be aborted":
- [""],
- "The operation id is invalid.": [""],
- "The operation was not found.": ["Lista conti pubblici non trovata."],
- "If you have a Taler wallet installed in this device": [""],
- "You will see the details of the operation in your wallet including the fees (if applies). If you still don't have one you can install it following instructions in":
- [""],
- "this page": [""],
- Withdraw: ["Prelevare"],
- "Or if you have the wallet in another device": [""],
- "Scan the QR below to start the withdrawal.": ["Chiudi il ritiro Taler"],
- required: [""],
- "IBAN should have just uppercased letters and numbers": [""],
- "not valid": [""],
- "should be greater than 0": [""],
- "balance is not enough": [""],
- "does not follow the pattern": [""],
- 'only "IBAN" target are supported': [""],
- 'use the "amount" parameter to specify the amount to be transferred': [
- "",
- ],
- "the amount is not valid": [""],
- 'use the "message" parameter to specify a reference text for the transfer':
- [""],
- "The request was invalid or the payto://-URI used unacceptable features.":
- [""],
- "Not enough permission to complete the operation.": [
- "La banca sta creando l'operazione...",
- ],
- 'The destination account "%1$s" was not found.': [
- "Lista conti pubblici non trovata.",
- ],
- "The origin and the destination of the transfer can't be the same.": [""],
- "Your balance is not enough.": [""],
- 'The origin account "%1$s" was not found.': [
- "Lista conti pubblici non trovata.",
- ],
- "Using a form": [""],
- "Import payto:// URI": [""],
- Recipient: [""],
- "IBAN of the recipient's account": [""],
- "Transfer subject": [
- "Trasferisci fondi a un altro conto di questa banca:",
- ],
- subject: ["Soggetto"],
- "some text to identify the transfer": [""],
- Amount: ["Importo"],
- "amount to transfer": ["Somma da ritirare"],
- "payto URI:": [""],
- "uniform resource identifier of the target account": [""],
- "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]": [""],
- Cancel: [""],
- Send: [""],
- "Missing username": [""],
- "Missing password": [""],
- 'Wrong credentials for "%1$s"': ["Credenziali invalide."],
- "Account not found": [""],
- Username: [""],
- "username of the account": [
- "Trasferisci fondi a un altro conto di questa banca:",
- ],
- Password: [""],
- "password of the account": ["Storico dei conti pubblici"],
- Check: [""],
- "Log in": [""],
- Register: ["Registrati"],
- "Wire transfer completed!": ["Bonifico"],
- "The withdrawal has been aborted previously and can't be confirmed": [""],
- "The withdrawal operation can't be confirmed before a wallet accepted the transaction.":
- [""],
- "Your balance is not enough for the operation.": [""],
- "Confirm the withdrawal operation": ["Conferma il ritiro"],
- "Wire transfer details": ["Bonifico"],
- "Taler Exchange operator's account": [""],
- "Taler Exchange operator's name": [""],
- Transfer: [""],
- "Authentication required": [""],
- "This operation was created with other username": [""],
- "Operation aborted": [""],
- "The wire transfer to the Taler Exchange operator's account was aborted, your balance was not affected.":
- [""],
- "You can close this page now or continue to the account page.": [""],
- Continue: [""],
- "Withdrawal confirmed": ["Questo ritiro è stato annullato!"],
- "The wire transfer to the Taler operator has been initiated. You will soon receive the requested amount in your Taler wallet.":
- [""],
- Done: [""],
- "Operation canceled": [""],
- "The operation is marked as 'selected' but some step in the withdrawal failed":
- [""],
- "The account is selected but no withdrawal identification found.": [""],
- "There is a withdrawal identification but no account has been selected or the selected account is invalid.":
- [""],
- "No withdrawal ID found and no account has been selected or the selected account is invalid.":
- [""],
- "Operation not found": [""],
- "This operation is not known by the server. The operation id is wrong or the server deleted the operation information before reaching here.":
- [""],
- "Cotinue to dashboard": [""],
- "The Withdrawal URI is not valid": ["Questo ritiro è stato annullato!"],
- 'the bank backend is not supported. supported version "%1$s", server version "%2$s"':
- [""],
- "Internal error, please report.": ["Registrazione"],
- Preferences: [""],
- "Welcome, %1$s": [""],
- "Latest transactions": ["Ultime transazioni:"],
- Date: ["Data"],
- Counterpart: ["Controparte"],
- Subject: ["Soggetto"],
- sent: [""],
- received: [""],
- "invalid value": [""],
- to: [""],
- from: [""],
- "First page": [""],
- Next: [""],
- "History of public accounts": ["Storico dei conti pubblici"],
- "Currently, the bank is not accepting new registrations!": [""],
- "Missing name": ["indirizzo Payto"],
- "Use letters and numbers only, and start with a lowercase letter": [""],
- "Passwords don't match": [""],
- "Server replied with invalid phone or email.": [""],
- "Registration is disabled because the bank ran out of bonus credit.": [
- "",
- ],
- "No enough permission to create that account.": [""],
- "That account id is already taken.": [""],
- "That username is already taken.": [""],
- "That username can't be used because is reserved.": [""],
- "Only admin is allow to set debt limit.": [""],
- "No information for the selected authentication channel.": [""],
- "Authentication channel is not supported.": [""],
- "Only admin can create accounts with second factor authentication.": [""],
- "Account registration": [""],
- "Repeat password": [""],
- Name: [""],
- "Create a random temporary user": [""],
- "Make a wire transfer": ["Chiudi il bonifico"],
- "Wire transfer created!": ["Bonifico"],
- Accounts: ["Importo"],
- "A list of all business account in the bank.": [""],
- "Create account": [""],
- Balance: [""],
- Actions: [""],
- unknown: [""],
- "change password": [""],
- remove: [""],
- "Select a section": [""],
- "Last hour": [""],
- "Last day": [""],
- "Last month": [""],
- "Last year": [""],
- "Last Year": [""],
- "Trading volume on %1$s compared to %2$s": [""],
- Cashin: [""],
- Cashout: [""],
- Payin: [""],
- Payout: [""],
- "download stats as CSV": [""],
- "Descreased by": [""],
- "Increased by": [""],
- "Unable to create a cashout": [""],
- "The bank configuration does not support cashout operations.": [""],
- invalid: [""],
- "need to be higher due to fees": [""],
- "the total transfer at destination will be zero": [""],
- "Cashout created": [""],
- "Duplicated request detected, check if the operation succeded or try again.":
- [""],
- "The conversion rate was incorrectly applied": [""],
- "The account does not have sufficient funds": [""],
- "Cashouts are not supported": [""],
- "Missing cashout URI in the profile": [""],
- "Sending the confirmation message failed, retry later or contact the administrator.":
- [""],
- "Convertion rate": [""],
- Fee: [""],
- "To account": [""],
- "No cashout account": [""],
- "Before doing a cashout you need to complete your profile": [""],
- "Amount to send": ["Somma da ritirare"],
- "Amount to receive": ["Somma da ritirare"],
- "Total cost": [""],
- "Balance left": [""],
- "Before fee": [""],
- "Total cashout transfer": [""],
- "No cashout channel available": [""],
- "Before doing a cashout the server need to provide an second channel to confirm the operation":
- [""],
- "Second factor authentication": [""],
- Email: [""],
- "add a email in your profile to enable this option": [""],
- SMS: [""],
- "add a phone number in your profile to enable this option": [""],
- Details: [""],
- Delete: [""],
- Credentials: ["Credenziali invalide."],
- Cashouts: [""],
- "it doesnt have the pattern of an IBAN number": [""],
- "it doesnt have the pattern of an email": [""],
- "should start with +": [""],
- "phone number can't have other than numbers": [""],
- "account identification in the bank": [""],
- "name of the person owner the account": [""],
- "Internal IBAN": [""],
- "if empty a random account number will be assigned": [""],
- "account identification for bank transfer": [""],
- Phone: [""],
- "Cashout IBAN": [""],
- "account number where the money is going to be sent when doing cashouts":
- [""],
- "Max debt": [""],
- "how much is user able to transfer after zero balance": [""],
- "Is this a Taler Exchange?": [""],
- "This server doesn't support second factor authentication.": [""],
- "Enable second factor authentication": [""],
- "Using email": [""],
- "Using SMS": [""],
- "Is this account public?": [""],
- "public accounts have their balance publicly accesible": [""],
- "Account updated": [""],
- "The rights to change the account are not sufficient": [""],
- "The username was not found": [""],
- "You can't change the legal name, please contact the your account administrator.":
- [""],
- "You can't change the debt limit, please contact the your account administrator.":
- [""],
- "You can't change the cashout address, please contact the your account administrator.":
- [""],
- "You can't change the contact data, please contact the your account administrator.":
- [""],
- 'Account "%1$s"': [""],
- "Change details": [""],
- Update: [""],
- "password doesn't match": [""],
- "Password changed": [""],
- "Not authorized to change the password, maybe the session is invalid.": [
- "",
- ],
- "You need to provide the old password. If you don't have it contact your account administrator.":
- [""],
- "Your current password doesn't match, can't change to a new password.": [
- "",
- ],
- "Update password": [""],
- "New password": [""],
- "Type it again": [""],
- "repeat the same password": [""],
- "Current password": [""],
- "your current password, for security": [""],
- Change: [""],
- "Can't delete the account": [""],
- "The account can't be delete while still holding some balance. First make sure that the owner make a complete cashout.":
- [""],
- "Account removed": [""],
- "No enough permission to delete the account.": [""],
- "The username was not found.": [""],
- "Can't delete a reserved username.": [""],
- "Can't delete an account with balance different than zero.": [""],
- "name doesn't match": [""],
- "You are going to remove the account": [""],
- "This step can't be undone.": [""],
- 'Deleting account "%1$s"': [""],
- Verification: [""],
- "enter the account name that is going to be deleted": [""],
- 'Account created with password "%1$s". The user must change the password on the next login.':
- [""],
- "Server replied that phone or email is invalid": [""],
- "The rights to perform the operation are not sufficient": [""],
- "Account username is already taken": [""],
- "Account id is already taken": [""],
- "Bank ran out of bonus credit.": [""],
- "Account username can't be used because is reserved": [""],
- "Can't create accounts": [""],
- "Only system admin can create accounts.": [""],
- "New business account": [""],
- Create: [""],
- "Cashout not supported.": [""],
- "Account not found.": ["Lista conti pubblici non trovata."],
- "Latest cashouts": ["Ultime transazioni:"],
- Created: [""],
- Confirmed: ["Conferma"],
- "Total debit": [""],
- "Total credit": [""],
- Status: [""],
- never: [""],
- "Cashout for account %1$s": [""],
- "This cashout not found. Maybe already aborted.": [""],
- "Cashout not found. It may be also mean that it was already aborted.": [
- "",
- ],
- "Cashout was already confimed.": [""],
- "Cashout operation is not supported.": [""],
- "The cashout operation is already aborted.": [""],
- "Missing destination account.": [""],
- "Too many failed attempts.": [""],
- "The code for this cashout is invalid.": [""],
- "Cashout detail": [""],
- Debited: [""],
- Credited: [""],
- "Enter the confirmation code": [""],
- Abort: ["Annulla"],
- Confirm: ["Conferma"],
- "Unauthorized to make the operation, maybe the session has expired or the password changed.":
- [""],
- "The operation was rejected due to insufficient funds.": [""],
- "Do not show this again": [""],
- Close: [""],
- "On this device": [""],
- 'If you are using a web browser on desktop you should access your wallet with the GNU Taler WebExtension now or click the link if your WebExtension have the "Inject Taler support" option enabled.':
- [""],
- Start: [""],
- "On a mobile phone": [""],
- "Scan the QR code with your mobile device.": [
- "Usa questo codice QR per ritirare contante nel tuo wallet:",
- ],
- "There is an operation already": [""],
- "Complete or cancel the operation in": ["Conferma il ritiro"],
- "Server responded with an invalid withdraw URI": [""],
- "Withdraw URI: %1$s": ["Prelevare"],
- "The operation was rejected due to insufficient funds": [""],
- "Prepare your wallet": [""],
- "After using your wallet you will need to confirm or cancel the operation on this site.":
- [""],
- "You need a GNU Taler Wallet": ["Ritira contante nel portafoglio Taler"],
- "If you don't have one yet you can follow the instruction in": [""],
- "Send money": [""],
- "to a %1$s wallet": [""],
- "Withdraw digital money into your mobile wallet or browser extension": [
- "",
- ],
- "operation ready": [""],
- "to another bank account": [
- "Trasferisci fondi a un altro conto di questa banca:",
- ],
- "Make a wire transfer to an account with known bank account number.": [
- "",
- ],
- "Transfer details": ["Effettua un bonifico"],
- "This is a demo bank": [""],
- "This part of the demo shows how a bank that supports Taler directly would work. In addition to using your own bank account, you can also see the transaction history of some %1$s.":
- [""],
- "This part of the demo shows how a bank that supports Taler directly would work.":
- [""],
- "Pending account delete operation": [""],
- "Pending account update operation": [""],
- "Pending password update operation": [""],
- "Pending transaction operation": [""],
- "Pending withdrawal operation": [""],
- "Pending cashout operation": [""],
- "You can complete or cancel the operation in": [""],
- "Download bank stats": [""],
- "Include hour metric": [""],
- "Include day metric": [""],
- "Include month metric": [""],
- "Include year metric": [""],
- "Include table header": [""],
- "Add previous metric for compare": [""],
- "Fail on first error": [""],
- Download: [""],
- "downloading... %1$s": [""],
- "Download completed": [""],
- "click here to save the file in your computer": [""],
- "Challenge not found.": [""],
- "This user is not authorized to complete this challenge.": [""],
- "Too many attemps, try another code.": [""],
- "The confirmation code is wrong, try again.": [""],
- "The operation expired.": [""],
- "The operation failed.": ["Questo ritiro è stato annullato!"],
- "The operation needs another confirmation to complete.": [""],
- "Account delete": [""],
- "Account update": [""],
- "Password update": [""],
- "Wire transfer": ["Bonifico"],
- Withdrawal: ["Prelevare"],
- "Confirm the operation": ["Conferma il ritiro"],
- "Send again": [""],
- "Send code": [""],
- "Operation details": [""],
- "Challenge details": [""],
- "Sent at": [""],
- "To phone": [""],
- "To email": [""],
- "Welcome to %1$s!": [""],
- },
- },
- domain: "messages",
- plural_forms: "nplurals=2; plural=n != 1;",
- lang: "it",
- completeness: 14,
-};
-
-strings["fr"] = {
- locale_data: {
- messages: {
- "": {
- domain: "messages",
- plural_forms: "nplurals=2; plural=n > 1;",
- lang: "fr",
- },
- "Operation failed, please report": [""],
- "Request timeout": [""],
- "Request throttled": [""],
- "Malformed response": [""],
- "Network error": [""],
- "Unexpected request error": [""],
- "Unexpected error": [""],
- "IBAN numbers usually have more that 4 digits": [""],
- "IBAN numbers usually have less that 34 digits": [""],
- "IBAN country code not found": [""],
- "IBAN number is not valid, checksum is wrong": [""],
- "Max withdrawal amount": [""],
- "Show withdrawal confirmation": [""],
- "Show demo description": [""],
- "Show install wallet first": [""],
- "Use fast withdrawal form": [""],
- "Show debug info": [""],
- "The reserve operation has been confirmed previously and can't be aborted":
- [""],
- "The operation id is invalid.": [""],
- "The operation was not found.": [""],
- "If you have a Taler wallet installed in this device": [""],
- "You will see the details of the operation in your wallet including the fees (if applies). If you still don't have one you can install it following instructions in":
- [""],
- "this page": [""],
- Withdraw: [""],
- "Or if you have the wallet in another device": [""],
- "Scan the QR below to start the withdrawal.": [""],
- required: [""],
- "IBAN should have just uppercased letters and numbers": [""],
- "not valid": [""],
- "should be greater than 0": [""],
- "balance is not enough": [""],
- "does not follow the pattern": [""],
- 'only "IBAN" target are supported': [""],
- 'use the "amount" parameter to specify the amount to be transferred': [
- "",
- ],
- "the amount is not valid": [""],
- 'use the "message" parameter to specify a reference text for the transfer':
- [""],
- "The request was invalid or the payto://-URI used unacceptable features.":
- [""],
- "Not enough permission to complete the operation.": [""],
- 'The destination account "%1$s" was not found.': [""],
- "The origin and the destination of the transfer can't be the same.": [""],
- "Your balance is not enough.": [""],
- 'The origin account "%1$s" was not found.': [""],
- "Using a form": [""],
- "Import payto:// URI": [""],
- Recipient: [""],
- "IBAN of the recipient's account": [""],
- "Transfer subject": [""],
- subject: [""],
- "some text to identify the transfer": [""],
- Amount: [""],
- "amount to transfer": [""],
- "payto URI:": [""],
- "uniform resource identifier of the target account": [""],
- "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]": [""],
- Cancel: [""],
- Send: [""],
- "Missing username": [""],
- "Missing password": [""],
- 'Wrong credentials for "%1$s"': [""],
- "Account not found": [""],
- Username: [""],
- "username of the account": [""],
- Password: [""],
- "password of the account": [""],
- Check: [""],
- "Log in": [""],
- Register: [""],
- "Wire transfer completed!": [""],
- "The withdrawal has been aborted previously and can't be confirmed": [""],
- "The withdrawal operation can't be confirmed before a wallet accepted the transaction.":
- [""],
- "Your balance is not enough for the operation.": [""],
- "Confirm the withdrawal operation": [""],
- "Wire transfer details": [""],
- "Taler Exchange operator's account": [""],
- "Taler Exchange operator's name": [""],
- Transfer: [""],
- "Authentication required": [""],
- "This operation was created with other username": [""],
- "Operation aborted": [""],
- "The wire transfer to the Taler Exchange operator's account was aborted, your balance was not affected.":
- [""],
- "You can close this page now or continue to the account page.": [""],
- Continue: [""],
- "Withdrawal confirmed": [""],
- "The wire transfer to the Taler operator has been initiated. You will soon receive the requested amount in your Taler wallet.":
- [""],
- Done: [""],
- "Operation canceled": [""],
- "The operation is marked as 'selected' but some step in the withdrawal failed":
- [""],
- "The account is selected but no withdrawal identification found.": [""],
- "There is a withdrawal identification but no account has been selected or the selected account is invalid.":
- [""],
- "No withdrawal ID found and no account has been selected or the selected account is invalid.":
- [""],
- "Operation not found": [""],
- "This operation is not known by the server. The operation id is wrong or the server deleted the operation information before reaching here.":
- [""],
- "Cotinue to dashboard": [""],
- "The Withdrawal URI is not valid": [""],
- 'the bank backend is not supported. supported version "%1$s", server version "%2$s"':
- [""],
- "Internal error, please report.": [""],
- Preferences: [""],
- "Welcome, %1$s": [""],
- "Latest transactions": [""],
- Date: [""],
- Counterpart: [""],
- Subject: [""],
- sent: [""],
- received: [""],
- "invalid value": [""],
- to: [""],
- from: [""],
- "First page": [""],
- Next: [""],
- "History of public accounts": [""],
- "Currently, the bank is not accepting new registrations!": [""],
- "Missing name": [""],
- "Use letters and numbers only, and start with a lowercase letter": [""],
- "Passwords don't match": [""],
- "Server replied with invalid phone or email.": [""],
- "Registration is disabled because the bank ran out of bonus credit.": [
- "",
- ],
- "No enough permission to create that account.": [""],
- "That account id is already taken.": [""],
- "That username is already taken.": [""],
- "That username can't be used because is reserved.": [""],
- "Only admin is allow to set debt limit.": [""],
- "No information for the selected authentication channel.": [""],
- "Authentication channel is not supported.": [""],
- "Only admin can create accounts with second factor authentication.": [""],
- "Account registration": [""],
- "Repeat password": [""],
- Name: [""],
- "Create a random temporary user": [""],
- "Make a wire transfer": [""],
- "Wire transfer created!": [""],
- Accounts: [""],
- "A list of all business account in the bank.": [""],
- "Create account": [""],
- Balance: [""],
- Actions: [""],
- unknown: [""],
- "change password": [""],
- remove: [""],
- "Select a section": [""],
- "Last hour": [""],
- "Last day": [""],
- "Last month": [""],
- "Last year": [""],
- "Last Year": [""],
- "Trading volume on %1$s compared to %2$s": [""],
- Cashin: [""],
- Cashout: [""],
- Payin: [""],
- Payout: [""],
- "download stats as CSV": [""],
- "Descreased by": [""],
- "Increased by": [""],
- "Unable to create a cashout": [""],
- "The bank configuration does not support cashout operations.": [""],
- invalid: [""],
- "need to be higher due to fees": [""],
- "the total transfer at destination will be zero": [""],
- "Cashout created": [""],
- "Duplicated request detected, check if the operation succeded or try again.":
- [""],
- "The conversion rate was incorrectly applied": [""],
- "The account does not have sufficient funds": [""],
- "Cashouts are not supported": [""],
- "Missing cashout URI in the profile": [""],
- "Sending the confirmation message failed, retry later or contact the administrator.":
- [""],
- "Convertion rate": [""],
- Fee: [""],
- "To account": [""],
- "No cashout account": [""],
- "Before doing a cashout you need to complete your profile": [""],
- "Amount to send": [""],
- "Amount to receive": [""],
- "Total cost": [""],
- "Balance left": [""],
- "Before fee": [""],
- "Total cashout transfer": [""],
- "No cashout channel available": [""],
- "Before doing a cashout the server need to provide an second channel to confirm the operation":
- [""],
- "Second factor authentication": [""],
- Email: [""],
- "add a email in your profile to enable this option": [""],
- SMS: [""],
- "add a phone number in your profile to enable this option": [""],
- Details: [""],
- Delete: [""],
- Credentials: [""],
- Cashouts: [""],
- "it doesnt have the pattern of an IBAN number": [""],
- "it doesnt have the pattern of an email": [""],
- "should start with +": [""],
- "phone number can't have other than numbers": [""],
- "account identification in the bank": [""],
- "name of the person owner the account": [""],
- "Internal IBAN": [""],
- "if empty a random account number will be assigned": [""],
- "account identification for bank transfer": [""],
- Phone: [""],
- "Cashout IBAN": [""],
- "account number where the money is going to be sent when doing cashouts":
- [""],
- "Max debt": [""],
- "how much is user able to transfer after zero balance": [""],
- "Is this a Taler Exchange?": [""],
- "This server doesn't support second factor authentication.": [""],
- "Enable second factor authentication": [""],
- "Using email": [""],
- "Using SMS": [""],
- "Is this account public?": [""],
- "public accounts have their balance publicly accesible": [""],
- "Account updated": [""],
- "The rights to change the account are not sufficient": [""],
- "The username was not found": [""],
- "You can't change the legal name, please contact the your account administrator.":
- [""],
- "You can't change the debt limit, please contact the your account administrator.":
- [""],
- "You can't change the cashout address, please contact the your account administrator.":
- [""],
- "You can't change the contact data, please contact the your account administrator.":
- [""],
- 'Account "%1$s"': [""],
- "Change details": [""],
- Update: [""],
- "password doesn't match": [""],
- "Password changed": [""],
- "Not authorized to change the password, maybe the session is invalid.": [
- "",
- ],
- "You need to provide the old password. If you don't have it contact your account administrator.":
- [""],
- "Your current password doesn't match, can't change to a new password.": [
- "",
- ],
- "Update password": [""],
- "New password": [""],
- "Type it again": [""],
- "repeat the same password": [""],
- "Current password": [""],
- "your current password, for security": [""],
- Change: [""],
- "Can't delete the account": [""],
- "The account can't be delete while still holding some balance. First make sure that the owner make a complete cashout.":
- [""],
- "Account removed": [""],
- "No enough permission to delete the account.": [""],
- "The username was not found.": [""],
- "Can't delete a reserved username.": [""],
- "Can't delete an account with balance different than zero.": [""],
- "name doesn't match": [""],
- "You are going to remove the account": [""],
- "This step can't be undone.": [""],
- 'Deleting account "%1$s"': [""],
- Verification: [""],
- "enter the account name that is going to be deleted": [""],
- 'Account created with password "%1$s". The user must change the password on the next login.':
- [""],
- "Server replied that phone or email is invalid": [""],
- "The rights to perform the operation are not sufficient": [""],
- "Account username is already taken": [""],
- "Account id is already taken": [""],
- "Bank ran out of bonus credit.": [""],
- "Account username can't be used because is reserved": [""],
- "Can't create accounts": [""],
- "Only system admin can create accounts.": [""],
- "New business account": [""],
- Create: [""],
- "Cashout not supported.": [""],
- "Account not found.": [""],
- "Latest cashouts": [""],
- Created: [""],
- Confirmed: [""],
- "Total debit": [""],
- "Total credit": [""],
- Status: [""],
- never: [""],
- "Cashout for account %1$s": [""],
- "This cashout not found. Maybe already aborted.": [""],
- "Cashout not found. It may be also mean that it was already aborted.": [
- "",
- ],
- "Cashout was already confimed.": [""],
- "Cashout operation is not supported.": [""],
- "The cashout operation is already aborted.": [""],
- "Missing destination account.": [""],
- "Too many failed attempts.": [""],
- "The code for this cashout is invalid.": [""],
- "Cashout detail": [""],
- Debited: [""],
- Credited: [""],
- "Enter the confirmation code": [""],
- Abort: [""],
- Confirm: [""],
- "Unauthorized to make the operation, maybe the session has expired or the password changed.":
- [""],
- "The operation was rejected due to insufficient funds.": [""],
- "Do not show this again": [""],
- Close: [""],
- "On this device": [""],
- 'If you are using a web browser on desktop you should access your wallet with the GNU Taler WebExtension now or click the link if your WebExtension have the "Inject Taler support" option enabled.':
- [""],
- Start: [""],
- "On a mobile phone": [""],
- "Scan the QR code with your mobile device.": [""],
- "There is an operation already": [""],
- "Complete or cancel the operation in": [""],
- "Server responded with an invalid withdraw URI": [""],
- "Withdraw URI: %1$s": [""],
- "The operation was rejected due to insufficient funds": [""],
- "Prepare your wallet": [""],
- "After using your wallet you will need to confirm or cancel the operation on this site.":
- [""],
- "You need a GNU Taler Wallet": [""],
- "If you don't have one yet you can follow the instruction in": [""],
- "Send money": [""],
- "to a %1$s wallet": [""],
- "Withdraw digital money into your mobile wallet or browser extension": [
- "",
- ],
- "operation ready": [""],
- "to another bank account": [""],
- "Make a wire transfer to an account with known bank account number.": [
- "",
- ],
- "Transfer details": [""],
- "This is a demo bank": [""],
- "This part of the demo shows how a bank that supports Taler directly would work. In addition to using your own bank account, you can also see the transaction history of some %1$s.":
- [""],
- "This part of the demo shows how a bank that supports Taler directly would work.":
- [""],
- "Pending account delete operation": [""],
- "Pending account update operation": [""],
- "Pending password update operation": [""],
- "Pending transaction operation": [""],
- "Pending withdrawal operation": [""],
- "Pending cashout operation": [""],
- "You can complete or cancel the operation in": [""],
- "Download bank stats": [""],
- "Include hour metric": [""],
- "Include day metric": [""],
- "Include month metric": [""],
- "Include year metric": [""],
- "Include table header": [""],
- "Add previous metric for compare": [""],
- "Fail on first error": [""],
- Download: [""],
- "downloading... %1$s": [""],
- "Download completed": [""],
- "click here to save the file in your computer": [""],
- "Challenge not found.": [""],
- "This user is not authorized to complete this challenge.": [""],
- "Too many attemps, try another code.": [""],
- "The confirmation code is wrong, try again.": [""],
- "The operation expired.": [""],
- "The operation failed.": [""],
- "The operation needs another confirmation to complete.": [""],
- "Account delete": [""],
- "Account update": [""],
- "Password update": [""],
- "Wire transfer": [""],
- Withdrawal: [""],
- "Confirm the operation": [""],
- "Send again": [""],
- "Send code": [""],
- "Operation details": [""],
- "Challenge details": [""],
- "Sent at": [""],
- "To phone": [""],
- "To email": [""],
- "Welcome to %1$s!": [""],
- },
- },
- domain: "messages",
- plural_forms: "nplurals=2; plural=n > 1;",
- lang: "fr",
- completeness: 0,
-};
-
-strings["es"] = {
- locale_data: {
- messages: {
- "": {
- domain: "messages",
- plural_forms: "nplurals=2; plural=n != 1;",
- lang: "es",
- },
- "Operation failed, please report": [
- "La operaicón falló, por favor reportelo",
- ],
- "Request timeout": ["La petición al servidor agoto su tiempo"],
- "Request throttled": ["La petición al servidor interrumpida"],
- "Malformed response": ["Respuesta malformada"],
- "Network error": ["Error de conexión"],
- "Unexpected request error": ["Error de pedido inesperado"],
- "Unexpected error": ["Error inesperado"],
- "IBAN numbers usually have more that 4 digits": [
- "Los números IBAN usualmente tienen mas de 4 digitos",
- ],
- "IBAN numbers usually have less that 34 digits": [
- "Los números IBAN usualmente tienen menos de 34 digitos",
- ],
- "IBAN country code not found": ["Código de pais de IBAN no encontrado"],
- "IBAN number is not valid, checksum is wrong": [
- "El número IBAN no es válido, falló la verificación",
- ],
- "Max withdrawal amount": ["Monto máximo de extracción"],
- "Show withdrawal confirmation": ["Mostrar confirmación de extracción"],
- "Show demo description": ["Mostrar descripción de demo"],
- "Show install wallet first": ["Mostrar instalar la billetera primero"],
- "Use fast withdrawal form": ["Usar formulario de extracción rápida"],
- "Show debug info": ["Mostrar información de depuración"],
- "The reserve operation has been confirmed previously and can't be aborted":
- [
- "La operación en la reserva ya ha sido confirmada previamente y no puede ser abortada",
- ],
- "The operation id is invalid.": ["El id de operación es invalido."],
- "The operation was not found.": ["La operación no se encontró."],
- "If you have a Taler wallet installed in this device": [
- "Si tienes una billetera Taler instalada en este dispositivo",
- ],
- "You will see the details of the operation in your wallet including the fees (if applies). If you still don't have one you can install it following instructions in":
- [
- "Veras los detalles de la operación en tu billetera incluyendo comisiones (si aplicán). Si todavía no tienes una puedes instalarla siguiendo las instrucciones en",
- ],
- "this page": ["esta página"],
- Withdraw: ["Retirar"],
- "Or if you have the wallet in another device": [
- "O si tienes la billetera en otro dispositivo",
- ],
- "Scan the QR below to start the withdrawal.": [
- "Escanea el QR debajo para comenzar la extracción.",
- ],
- required: ["requerido"],
- "IBAN should have just uppercased letters and numbers": [
- "IBAN debería tener letras mayúsculas y números",
- ],
- "not valid": ["no válido"],
- "should be greater than 0": ["Debería ser mas grande que 0"],
- "balance is not enough": ["el saldo no es suficiente"],
- "does not follow the pattern": ["no tiene un patrón valido"],
- 'only "IBAN" target are supported': [
- 'solo cuentas "IBAN" son soportadas',
- ],
- 'use the "amount" parameter to specify the amount to be transferred': [
- 'usa el parámetro "amount" para indicar el monto a ser transferido',
- ],
- "the amount is not valid": ["el monto no es válido"],
- 'use the "message" parameter to specify a reference text for the transfer':
- [
- 'usa el parámetro "message" para indicar un texto de referencia en la transferencia',
- ],
- "The request was invalid or the payto://-URI used unacceptable features.":
- [
- "El pedido era inválido o el URI payto:// usado tiene características inaceptables.",
- ],
- "Not enough permission to complete the operation.": [
- "Sin permisos suficientes para completar la operación.",
- ],
- 'The destination account "%1$s" was not found.': [
- 'La cuenta de destino "%1$s" no fue encontrada.',
- ],
- "The origin and the destination of the transfer can't be the same.": [
- "El origen y destino de la transferencia no puede ser la misma.",
- ],
- "Your balance is not enough.": ["El saldo no es suficiente."],
- 'The origin account "%1$s" was not found.': [
- 'La cuenta origen "%1$s" no fue encontrada.',
- ],
- "Using a form": ["Usando un formulario"],
- "Import payto:// URI": ["Importando un URI payto://"],
- Recipient: ["Destinatario"],
- "IBAN of the recipient's account": [
- "Numero IBAN de la cuenta destinataria",
- ],
- "Transfer subject": ["Asunto de transferencia"],
- subject: ["asunto"],
- "some text to identify the transfer": [
- "algún texto para identificar la transferencia",
- ],
- Amount: ["Monto"],
- "amount to transfer": ["monto a transferir"],
- "payto URI:": ["payto URI:"],
- "uniform resource identifier of the target account": [
- "identificador de recurso uniforme de la cuenta destino",
- ],
- "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]": [
- "payto://iban/[iban-destinatario]?message=[asunto]&amount=[%1$s:X.Y]",
- ],
- Cancel: ["Cancelar"],
- Send: ["Envíar"],
- "Missing username": ["Falta nombre de usuario"],
- "Missing password": ["Falta contraseña"],
- 'Wrong credentials for "%1$s"': ['Credenciales incorrectas para "%1$s"'],
- "Account not found": ["Cuenta no encontrada"],
- Username: ["Nombre de usuario"],
- "username of the account": ["nombre de usuario de la cuenta"],
- Password: ["Contraseña"],
- "password of the account": ["contraseña de la cuenta"],
- Check: ["Verificar"],
- "Log in": ["Acceso"],
- Register: ["Registrarse"],
- "Wire transfer completed!": ["Transferencia bancaria completada!"],
- "The withdrawal has been aborted previously and can't be confirmed": [
- "La extracción fue abortada anteriormente y no puede ser confirmada",
- ],
- "The withdrawal operation can't be confirmed before a wallet accepted the transaction.":
- [
- "La operación de extracción no puede ser confirmada antes de que una billetera acepte la transaccion.",
- ],
- "Your balance is not enough for the operation.": [
- "El saldo no es suficiente para la operación.",
- ],
- "Confirm the withdrawal operation": [
- "Confirme la operación de extracción",
- ],
- "Wire transfer details": ["Detalle de transferencia bancaria"],
- "Taler Exchange operator's account": [
- "Cuenta del operador del Taler Exchange",
- ],
- "Taler Exchange operator's name": [
- "Nombre del operador del Taler Exchange",
- ],
- Transfer: ["Transferencia"],
- "Authentication required": ["Autenticación requerida"],
- "This operation was created with other username": [
- "Esta operación fue creada con otro usuario",
- ],
- "Operation aborted": ["Operación abortada"],
- "The wire transfer to the Taler Exchange operator's account was aborted, your balance was not affected.":
- [
- "La transferencia bancaria a la cuenta del operador del Taler Exchange fue abortada, su saldo no fue afectado.",
- ],
- "You can close this page now or continue to the account page.": [
- "Ya puedes cerrar esta pagina or continuar a la página de estado de cuenta.",
- ],
- Continue: ["Continuar"],
- "Withdrawal confirmed": ["La extracción fue confirmada"],
- "The wire transfer to the Taler operator has been initiated. You will soon receive the requested amount in your Taler wallet.":
- [
- "La transferencia bancaria al operador Taler fue iniciada. Pronto recibirás el monto pedido en tu billetera Taler.",
- ],
- Done: ["Listo"],
- "Operation canceled": ["Operación cancelada"],
- "The operation is marked as 'selected' but some step in the withdrawal failed":
- [
- "La operación está marcada como 'seleccionada' pero algunos pasos en la extracción fallaron",
- ],
- "The account is selected but no withdrawal identification found.": [
- "La cuenta está seleccionada pero no se encontró el identificador de extracción.",
- ],
- "There is a withdrawal identification but no account has been selected or the selected account is invalid.":
- [
- "Hay un identificador de extracción pero la cuenta no ha sido seleccionada o la selccionada es inválida.",
- ],
- "No withdrawal ID found and no account has been selected or the selected account is invalid.":
- [
- "No hay un identificador de extracción y ninguna cuenta a sido seleccionada o la seleccionada es inválida.",
- ],
- "Operation not found": ["Operación no encontrada"],
- "This operation is not known by the server. The operation id is wrong or the server deleted the operation information before reaching here.":
- [
- "Esta operación no es conocida por el servidor. El identificador de operación es incorrecto o el server borró la información de la operación antes de llegar hasta aquí.",
- ],
- "Cotinue to dashboard": ["Continuar al panel"],
- "The Withdrawal URI is not valid": ["El URI de estracción no es válido"],
- 'the bank backend is not supported. supported version "%1$s", server version "%2$s"':
- [
- 'El servidor de bank no esta spoportado. Version soportada "%1$s", version del server "%2$s"',
- ],
- "Internal error, please report.": [
- "Error interno, por favor reporte el error.",
- ],
- Preferences: ["Preferencias"],
- "Welcome, %1$s": ["Bienvenido/a, %1$s"],
- "Latest transactions": ["Últimas transacciones"],
- Date: ["Fecha"],
- Counterpart: ["Contraparte"],
- Subject: ["Asunto"],
- sent: ["enviado"],
- received: ["recibido"],
- "invalid value": ["valor inválido"],
- to: ["hacia"],
- from: ["desde"],
- "First page": ["Primera página"],
- Next: ["Siguiente"],
- "History of public accounts": ["Historial de cuentas públicas"],
- "Currently, the bank is not accepting new registrations!": [
- "Actualmente, el banco no está aceptado nuevos registros!",
- ],
- "Missing name": ["Falta nombre"],
- "Use letters and numbers only, and start with a lowercase letter": [
- "Solo use letras y números, y comience con una letra minúscula",
- ],
- "Passwords don't match": ["La contraseña no coincide"],
- "Server replied with invalid phone or email.": [
- "El servidor repondio con teléfono o dirección de correo inválido.",
- ],
- "Registration is disabled because the bank ran out of bonus credit.": [
- "El registro está deshabilitado porque el banco se quedó sin crédito bonus.",
- ],
- "No enough permission to create that account.": [
- "Sin permisos suficientes para crear esa cuenta.",
- ],
- "That account id is already taken.": [
- "El identificador de cuenta ya está tomado.",
- ],
- "That username is already taken.": [
- "El nombre de usuario ya está tomado.",
- ],
- "That username can't be used because is reserved.": [
- "El nombre de usuario no puede ser usado porque esta reservado.",
- ],
- "Only admin is allow to set debt limit.": [
- "Solo el administrador tiene permitido cambiar el límite de deuda.",
- ],
- "No information for the selected authentication channel.": [
- "No hay información para el canal de autenticación seleccionado.",
- ],
- "Authentication channel is not supported.": [
- "Canal de autenticación no esta soportado.",
- ],
- "Only admin can create accounts with second factor authentication.": [
- "Solo el administrador puede crear cuentas con el segundo factor de autenticación.",
- ],
- "Account registration": ["Registro de cuenta"],
- "Repeat password": ["Repita la contraseña"],
- Name: ["Nombre"],
- "Create a random temporary user": ["Crear un usuario aleatorio temporal"],
- "Make a wire transfer": ["Hacer una transferencia bancaria"],
- "Wire transfer created!": ["Transferencia bancaria creada!"],
- Accounts: ["Cuentas"],
- "A list of all business account in the bank.": [
- "Una lista de todas las cuentas en el banco.",
- ],
- "Create account": ["Crear cuenta"],
- Balance: ["Saldo"],
- Actions: ["Acciones"],
- unknown: ["desconocido"],
- "change password": ["cambiar contraseña"],
- remove: ["elimiar"],
- "Select a section": ["Seleccione una sección"],
- "Last hour": ["Última hora"],
- "Last day": ["Último día"],
- "Last month": ["Último mes"],
- "Last year": ["Último año"],
- "Last Year": ["Último Año"],
- "Trading volume on %1$s compared to %2$s": [
- "Vólumen de comercio en %1$s comparado con %2$s",
- ],
- Cashin: ["Ingreso"],
- Cashout: ["Egreso"],
- Payin: ["Envios de dinero"],
- Payout: ["Recibos de dinero"],
- "download stats as CSV": ["descargar estadísticas en CSV"],
- "Descreased by": ["Descendiente por"],
- "Increased by": ["Ascendente por"],
- "Unable to create a cashout": ["Imposible crear un egreso"],
- "The bank configuration does not support cashout operations.": [
- "La configuración del banco no soporta operaciones de egreso.",
- ],
- invalid: ["inválido"],
- "need to be higher due to fees": [
- "necesita ser mayor debido a las comisiones",
- ],
- "the total transfer at destination will be zero": [
- "el total de la transferencia en destino será cero",
- ],
- "Cashout created": ["Egreso creado"],
- "Duplicated request detected, check if the operation succeded or try again.":
- [
- "Se detectó una petición duplicada, verifique si la operación tuvo éxito o intente otra vez.",
- ],
- "The conversion rate was incorrectly applied": [
- "La tasa de conversión se aplicó incorrectamente",
- ],
- "The account does not have sufficient funds": [
- "La cuenta no tiene fondos suficientes",
- ],
- "Cashouts are not supported": ["Egresos no están soportados"],
- "Missing cashout URI in the profile": [
- "Falta dirección de egreso en el perfíl",
- ],
- "Sending the confirmation message failed, retry later or contact the administrator.":
- [
- "El envío del mensaje de confirmación falló, intente mas tarde o contacte al administrador.",
- ],
- "Convertion rate": ["Tasa de conversión"],
- Fee: ["Comisión"],
- "To account": ["Hacia cuenta"],
- "No cashout account": ["No hay cuenta de egreso"],
- "Before doing a cashout you need to complete your profile": [
- "Antes de hacer un egreso necesita completar su perfíl",
- ],
- "Amount to send": ["Monto a enviar"],
- "Amount to receive": ["Monto a recibir"],
- "Total cost": ["Costo total"],
- "Balance left": ["Saldo remanente"],
- "Before fee": ["Antes de comisión"],
- "Total cashout transfer": ["Total de egreso"],
- "No cashout channel available": ["No hay canal de egreso disponible"],
- "Before doing a cashout the server need to provide an second channel to confirm the operation":
- [
- "Antes de hacer un egreso el servidor necesita proveer un segundo canal para confirmar la operación",
- ],
- "Second factor authentication": ["Segundo factor de autenticación"],
- Email: ["Correo eletrónico"],
- "add a email in your profile to enable this option": [
- "agrege un correo en su perfíl para habilitar esta opción",
- ],
- SMS: ["SMS"],
- "add a phone number in your profile to enable this option": [
- "agregue un número de teléfono para habilitar esta opción",
- ],
- Details: ["Detalles"],
- Delete: ["Borrar"],
- Credentials: ["Credenciales"],
- Cashouts: ["Egresos"],
- "it doesnt have the pattern of an IBAN number": [
- "no tiene el patrón de un número IBAN",
- ],
- "it doesnt have the pattern of an email": [
- "no tiene el patrón de un correo electrónico",
- ],
- "should start with +": ["debería comenzar con un +"],
- "phone number can't have other than numbers": [
- "número de teléfono no puede tener otra cosa que numeros",
- ],
- "account identification in the bank": [
- "identificador de cuenta en el banco",
- ],
- "name of the person owner the account": [
- "nombre de la persona dueña de la cuenta",
- ],
- "Internal IBAN": ["IBAN interno"],
- "if empty a random account number will be assigned": [
- "si está vacío un número de cuenta aleatorio será asignado",
- ],
- "account identification for bank transfer": [
- "identificador de cuenta para transferencia bancaria",
- ],
- Phone: ["Teléfono"],
- "Cashout IBAN": ["IBAN de egreso"],
- "account number where the money is going to be sent when doing cashouts":
- [
- "numero de cuenta donde el dinero será enviado cuando se ejecuten egresos",
- ],
- "Max debt": ["Máxima deuda"],
- "how much is user able to transfer after zero balance": [
- "cuanto tiene habilitado a transferir despues de un saldo en cero",
- ],
- "Is this a Taler Exchange?": ["Es un Taler Exchange?"],
- "This server doesn't support second factor authentication.": [
- "Este servidor no tiene soporte para segundo factor de autenticación.",
- ],
- "Enable second factor authentication": [
- "Hábilitar segundo factor de autenticación",
- ],
- "Using email": ["Usando correo eletrónico"],
- "Using SMS": ["Usando SMS"],
- "Is this account public?": ["Es una cuenta pública?"],
- "public accounts have their balance publicly accesible": [
- "las cuentas públicas tienen su saldo accesible al público",
- ],
- "Account updated": ["Cuenta actualizada"],
- "The rights to change the account are not sufficient": [
- "Los permisos para cambiar la cuenta no son suficientes",
- ],
- "The username was not found": ["El nombre de usaurio no se encontró"],
- "You can't change the legal name, please contact the your account administrator.":
- [
- "No puede cambiar el nombre legal, por favor contacte el administrador de la cuenta.",
- ],
- "You can't change the debt limit, please contact the your account administrator.":
- [
- "No puede cambiar el límite de deuda, por favor contacte el administrador de la cuenta.",
- ],
- "You can't change the cashout address, please contact the your account administrator.":
- [
- "No puede cambiar la dirección de egreso, por favor contacte al administrador de la cuenta.",
- ],
- "You can't change the contact data, please contact the your account administrator.":
- [
- "No puede cambiar los datos de contacto, por favor contacte al administrador de la cuenta.",
- ],
- 'Account "%1$s"': ['Cuenta "%1$s"'],
- "Change details": ["Cambiar detalles"],
- Update: ["Actualizar"],
- "password doesn't match": ["la contraseña no coincide"],
- "Password changed": ["La contraseña cambió"],
- "Not authorized to change the password, maybe the session is invalid.": [
- "No está autorizado a cambiar el password, quizá la sesión es invalida.",
- ],
- "You need to provide the old password. If you don't have it contact your account administrator.":
- [
- "Se necesita el password viejo para cambiar la contraseña. Si no lo tiene contacte a su administrador.",
- ],
- "Your current password doesn't match, can't change to a new password.": [
- "Su actual contraseña no coincide, no puede cambiar a una nueva contraseña.",
- ],
- "Update password": ["Actualizar contraseña"],
- "New password": ["Nueva contraseña"],
- "Type it again": ["Escribalo otra vez"],
- "repeat the same password": ["repita la misma contraseña"],
- "Current password": ["Contraseña actual"],
- "your current password, for security": [
- "su actual contraseña, por seguridad",
- ],
- Change: ["Cambiar"],
- "Can't delete the account": ["No se puede eliminar la cuenta"],
- "The account can't be delete while still holding some balance. First make sure that the owner make a complete cashout.":
- [
- "La cuenta no puede ser eliminada mientras tiene saldo. Primero aseguresé que el dueño haga un egreso completo.",
- ],
- "Account removed": ["Cuenta eliminada"],
- "No enough permission to delete the account.": [
- "No tiene permisos suficientes para eliminar la cuenta.",
- ],
- "The username was not found.": ["El nombr ede usuario no se encontró."],
- "Can't delete a reserved username.": [
- "No se puede eliminar un nombre de usuario reservado.",
- ],
- "Can't delete an account with balance different than zero.": [
- "No se puede eliminar una cuenta con saldo diferente a cero.",
- ],
- "name doesn't match": ["el nombre no coincide"],
- "You are going to remove the account": ["Está por eliminar la cuenta"],
- "This step can't be undone.": ["Este paso no puede ser deshecho."],
- 'Deleting account "%1$s"': ['Borrando cuenta "%1$s"'],
- Verification: ["Verificación"],
- "enter the account name that is going to be deleted": [
- "ingrese el nombre de cuenta que será eliminado",
- ],
- 'Account created with password "%1$s". The user must change the password on the next login.':
- [
- 'Cuenta creada con contraseña "%1$s". El usuario debe cambiar la contraseña en el siguiente ingreso.',
- ],
- "Server replied that phone or email is invalid": [
- "El servidor respondió que el teléfono o correo eletrónico es invalido",
- ],
- "The rights to perform the operation are not sufficient": [
- "Los permisos para ejecutar la operación no son suficientes",
- ],
- "Account username is already taken": [
- "El nombre del usuario ya está tomado",
- ],
- "Account id is already taken": ["El id de cuenta ya está tomado"],
- "Bank ran out of bonus credit.": [
- "El banco no tiene mas crédito de bonus.",
- ],
- "Account username can't be used because is reserved": [
- "El nombre de usuario de la cuenta no puede userse porque está reservado",
- ],
- "Can't create accounts": ["No puede crear cuentas"],
- "Only system admin can create accounts.": [
- "Solo los administradores del sistema pueden crear cuentas.",
- ],
- "New business account": ["Nueva cuenta"],
- Create: ["Crear"],
- "Cashout not supported.": ["Egreso no soportado."],
- "Account not found.": ["Cuenta no encontrada."],
- "Latest cashouts": ["Últimos egresos"],
- Created: ["Creado"],
- Confirmed: ["Confirmado"],
- "Total debit": ["Débito total"],
- "Total credit": ["Crédito total"],
- Status: ["Estado"],
- never: ["nunca"],
- "Cashout for account %1$s": ["Egreso para cuenta %1$s"],
- "This cashout not found. Maybe already aborted.": [
- "Este egreso no se encontró. Quizá fue abortado.",
- ],
- "Cashout not found. It may be also mean that it was already aborted.": [
- "Egreso no econtrado. También puede significar que ya ha sido abortado.",
- ],
- "Cashout was already confimed.": ["Egreso ya fue confirmado."],
- "Cashout operation is not supported.": [
- "Operación de egreso no soportada.",
- ],
- "The cashout operation is already aborted.": [
- "La operación de egreso ya está abortada.",
- ],
- "Missing destination account.": ["Falta cuenta destino."],
- "Too many failed attempts.": ["Demasiados intentos fallidos."],
- "The code for this cashout is invalid.": [
- "El código para este egreso es invalido.",
- ],
- "Cashout detail": ["Detalles de egreso"],
- Debited: ["Debitado"],
- Credited: ["Acreditado"],
- "Enter the confirmation code": ["Ingresar el código de confirmación"],
- Abort: ["Abortar"],
- Confirm: ["Confirmar"],
- "Unauthorized to make the operation, maybe the session has expired or the password changed.":
- [
- "No autorizado para hacer la operación, quizá la sesión haya expirado or cambió la contraseña.",
- ],
- "The operation was rejected due to insufficient funds.": [
- "La operación fue rechazada debido a saldo insuficiente.",
- ],
- "Do not show this again": ["No mostrar otra vez"],
- Close: ["Cerrar"],
- "On this device": ["En este dispositivo"],
- 'If you are using a web browser on desktop you should access your wallet with the GNU Taler WebExtension now or click the link if your WebExtension have the "Inject Taler support" option enabled.':
- [
- 'Si esta usando un explorador web de escritorio deberías acceder ahora a tu billletera con la GNU Taler WebExtension o hacer click en el link si tu extensión tiene la configuración "Inyectar soporte para Taler" habilitada.',
- ],
- Start: ["Comenzar"],
- "On a mobile phone": ["En un dispotivo mobile"],
- "Scan the QR code with your mobile device.": [
- "Escanear el código QR con tu dispotivo móvil.",
- ],
- "There is an operation already": ["Ya hay una operación"],
- "Complete or cancel the operation in": [
- "Completa o cancela la operación en",
- ],
- "Server responded with an invalid withdraw URI": [
- "El servidor respondió con una URI de extracción inválida",
- ],
- "Withdraw URI: %1$s": ["URI de extracción: %1$s"],
- "The operation was rejected due to insufficient funds": [
- "La operación fue rechazada debido a fundos insuficientes",
- ],
- "Prepare your wallet": ["Prepare su billetera"],
- "After using your wallet you will need to confirm or cancel the operation on this site.":
- [
- "Despues de usar tu billetera necesitarás confirmar o cancelar la operación en este sitio.",
- ],
- "You need a GNU Taler Wallet": ["Necesitas una GNU Taler Wallet"],
- "If you don't have one yet you can follow the instruction in": [
- "Si no tienes una todavía puedes seguir las instrucciones en",
- ],
- "Send money": ["Enviar dinero"],
- "to a %1$s wallet": ["a una billetera %1$s"],
- "Withdraw digital money into your mobile wallet or browser extension": [
- "Extraer dinero digital a tu billetera móvil o extesión web",
- ],
- "operation ready": ["operación lista"],
- "to another bank account": ["a otra cuenta bancaria"],
- "Make a wire transfer to an account with known bank account number.": [
- "Hacer una transferencia bancaria a una cuenta con un número de cuenta conocido.",
- ],
- "Transfer details": ["Detalles de transferencia"],
- "This is a demo bank": ["Este es un banco de demostración"],
- "This part of the demo shows how a bank that supports Taler directly would work. In addition to using your own bank account, you can also see the transaction history of some %1$s.":
- [
- "Esta parte de la demostración muestra cómo funciona un banco que soporta Taler directamente. Además de usar tu propia cuenta de banco, también podrás ver el historial de transacciones de algunas %1$s.",
- ],
- "This part of the demo shows how a bank that supports Taler directly would work.":
- [
- "Esta parte de la demostración muetra como un banco que soporta Taler directamente funcionaría.",
- ],
- "Pending account delete operation": [
- "Operación pendiente de eliminación de cuenta",
- ],
- "Pending account update operation": [
- "Operación pendiente de actualización de cuenta",
- ],
- "Pending password update operation": [
- "Operación pendiente de actualización de password",
- ],
- "Pending transaction operation": ["Operación pendiente de transacción"],
- "Pending withdrawal operation": ["Operación pendiente de extracción"],
- "Pending cashout operation": ["Operación pendiente de egreso"],
- "You can complete or cancel the operation in": [
- "Puedes completar o cancelar la operación en",
- ],
- "Download bank stats": ["Descargar estadísticas del banco"],
- "Include hour metric": ["Incluir métrica horaria"],
- "Include day metric": ["Incluir métrica diaria"],
- "Include month metric": ["Incluir métrica mensual"],
- "Include year metric": ["Incluir métrica anual"],
- "Include table header": ["Incluir encabezado de tabla"],
- "Add previous metric for compare": [
- "Agregar métrica previa para comparar",
- ],
- "Fail on first error": ["Fallar en el primer error"],
- Download: ["Descargar"],
- "downloading... %1$s": ["descargando... %1$s"],
- "Download completed": ["Descarga completada"],
- "click here to save the file in your computer": [
- "click aquí para guardar el archivo en su computadora",
- ],
- "Challenge not found.": ["Desafío no encontrado."],
- "This user is not authorized to complete this challenge.": [
- "Este usuario no está autorizado para completar este desafío.",
- ],
- "Too many attemps, try another code.": [
- "Demasiados intentos, intente otro código.",
- ],
- "The confirmation code is wrong, try again.": [
- "El código de confirmación es erroneo, intente otra vez.",
- ],
- "The operation expired.": ["La operación expiró."],
- "The operation failed.": ["La operación falló."],
- "The operation needs another confirmation to complete.": [
- "La operación necesita otra confirmación para completar.",
- ],
- "Account delete": ["Eliminación de cuenta"],
- "Account update": ["Actualización de cuenta"],
- "Password update": ["Actualización de contraseña"],
- "Wire transfer": ["Transferencia bancaria"],
- Withdrawal: ["Extracción"],
- "Confirm the operation": ["Confirmar la operación"],
- "Send again": ["Enviar otra vez"],
- "Send code": ["Enviar código"],
- "Operation details": ["Detalles de operación"],
- "Challenge details": ["Detalles del desafío"],
- "Sent at": ["Enviado a"],
- "To phone": ["Al teléfono"],
- "To email": ["Al email"],
- "Welcome to %1$s!": ["Bienvenido a %1$s!"],
- },
- },
- domain: "messages",
- plural_forms: "nplurals=2; plural=n != 1;",
- lang: "es",
- completeness: 100,
-};
-
-strings["en"] = {
- locale_data: {
- messages: {
- "": {
- domain: "messages",
- plural_forms: "nplurals=2; plural=(n != 1);",
- lang: "en",
- },
- "Operation failed, please report": [""],
- "Request timeout": [""],
- "Request throttled": [""],
- "Malformed response": [""],
- "Network error": [""],
- "Unexpected request error": [""],
- "Unexpected error": [""],
- "IBAN numbers usually have more that 4 digits": [""],
- "IBAN numbers usually have less that 34 digits": [""],
- "IBAN country code not found": [""],
- "IBAN number is not valid, checksum is wrong": [""],
- "Max withdrawal amount": [""],
- "Show withdrawal confirmation": [""],
- "Show demo description": [""],
- "Show install wallet first": [""],
- "Use fast withdrawal form": [""],
- "Show debug info": [""],
- "The reserve operation has been confirmed previously and can't be aborted":
- [""],
- "The operation id is invalid.": [""],
- "The operation was not found.": [""],
- "If you have a Taler wallet installed in this device": [""],
- "You will see the details of the operation in your wallet including the fees (if applies). If you still don't have one you can install it following instructions in":
- [""],
- "this page": [""],
- Withdraw: [""],
- "Or if you have the wallet in another device": [""],
- "Scan the QR below to start the withdrawal.": [""],
- required: [""],
- "IBAN should have just uppercased letters and numbers": [""],
- "not valid": [""],
- "should be greater than 0": [""],
- "balance is not enough": [""],
- "does not follow the pattern": [""],
- 'only "IBAN" target are supported': [""],
- 'use the "amount" parameter to specify the amount to be transferred': [
- "",
- ],
- "the amount is not valid": [""],
- 'use the "message" parameter to specify a reference text for the transfer':
- [""],
- "The request was invalid or the payto://-URI used unacceptable features.":
- [""],
- "Not enough permission to complete the operation.": [""],
- 'The destination account "%1$s" was not found.': [""],
- "The origin and the destination of the transfer can't be the same.": [""],
- "Your balance is not enough.": [""],
- 'The origin account "%1$s" was not found.': [""],
- "Using a form": [""],
- "Import payto:// URI": [""],
- Recipient: [""],
- "IBAN of the recipient's account": [""],
- "Transfer subject": [""],
- subject: [""],
- "some text to identify the transfer": [""],
- Amount: [""],
- "amount to transfer": [""],
- "payto URI:": [""],
- "uniform resource identifier of the target account": [""],
- "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]": [""],
- Cancel: [""],
- Send: [""],
- "Missing username": [""],
- "Missing password": [""],
- 'Wrong credentials for "%1$s"': [""],
- "Account not found": [""],
- Username: [""],
- "username of the account": [""],
- Password: [""],
- "password of the account": [""],
- Check: [""],
- "Log in": [""],
- Register: [""],
- "Wire transfer completed!": [""],
- "The withdrawal has been aborted previously and can't be confirmed": [""],
- "The withdrawal operation can't be confirmed before a wallet accepted the transaction.":
- [""],
- "Your balance is not enough for the operation.": [""],
- "Confirm the withdrawal operation": [""],
- "Wire transfer details": [""],
- "Taler Exchange operator's account": [""],
- "Taler Exchange operator's name": [""],
- Transfer: [""],
- "Authentication required": [""],
- "This operation was created with other username": [""],
- "Operation aborted": [""],
- "The wire transfer to the Taler Exchange operator's account was aborted, your balance was not affected.":
- [""],
- "You can close this page now or continue to the account page.": [""],
- Continue: [""],
- "Withdrawal confirmed": [""],
- "The wire transfer to the Taler operator has been initiated. You will soon receive the requested amount in your Taler wallet.":
- [""],
- Done: [""],
- "Operation canceled": [""],
- "The operation is marked as 'selected' but some step in the withdrawal failed":
- [""],
- "The account is selected but no withdrawal identification found.": [""],
- "There is a withdrawal identification but no account has been selected or the selected account is invalid.":
- [""],
- "No withdrawal ID found and no account has been selected or the selected account is invalid.":
- [""],
- "Operation not found": [""],
- "This operation is not known by the server. The operation id is wrong or the server deleted the operation information before reaching here.":
- [""],
- "Cotinue to dashboard": [""],
- "The Withdrawal URI is not valid": [""],
- 'the bank backend is not supported. supported version "%1$s", server version "%2$s"':
- [""],
- "Internal error, please report.": [""],
- Preferences: [""],
- "Welcome, %1$s": [""],
- "Latest transactions": [""],
- Date: [""],
- Counterpart: [""],
- Subject: [""],
- sent: [""],
- received: [""],
- "invalid value": [""],
- to: [""],
- from: [""],
- "First page": [""],
- Next: [""],
- "History of public accounts": [""],
- "Currently, the bank is not accepting new registrations!": [""],
- "Missing name": [""],
- "Use letters and numbers only, and start with a lowercase letter": [""],
- "Passwords don't match": [""],
- "Server replied with invalid phone or email.": [""],
- "Registration is disabled because the bank ran out of bonus credit.": [
- "",
- ],
- "No enough permission to create that account.": [""],
- "That account id is already taken.": [""],
- "That username is already taken.": [""],
- "That username can't be used because is reserved.": [""],
- "Only admin is allow to set debt limit.": [""],
- "No information for the selected authentication channel.": [""],
- "Authentication channel is not supported.": [""],
- "Only admin can create accounts with second factor authentication.": [""],
- "Account registration": [""],
- "Repeat password": [""],
- Name: [""],
- "Create a random temporary user": [""],
- "Make a wire transfer": [""],
- "Wire transfer created!": [""],
- Accounts: [""],
- "A list of all business account in the bank.": [""],
- "Create account": [""],
- Balance: [""],
- Actions: [""],
- unknown: [""],
- "change password": [""],
- remove: [""],
- "Select a section": [""],
- "Last hour": [""],
- "Last day": [""],
- "Last month": [""],
- "Last year": [""],
- "Last Year": [""],
- "Trading volume on %1$s compared to %2$s": [""],
- Cashin: [""],
- Cashout: [""],
- Payin: [""],
- Payout: [""],
- "download stats as CSV": [""],
- "Descreased by": [""],
- "Increased by": [""],
- "Unable to create a cashout": [""],
- "The bank configuration does not support cashout operations.": [""],
- invalid: [""],
- "need to be higher due to fees": [""],
- "the total transfer at destination will be zero": [""],
- "Cashout created": [""],
- "Duplicated request detected, check if the operation succeded or try again.":
- [""],
- "The conversion rate was incorrectly applied": [""],
- "The account does not have sufficient funds": [""],
- "Cashouts are not supported": [""],
- "Missing cashout URI in the profile": [""],
- "Sending the confirmation message failed, retry later or contact the administrator.":
- [""],
- "Convertion rate": [""],
- Fee: [""],
- "To account": [""],
- "No cashout account": [""],
- "Before doing a cashout you need to complete your profile": [""],
- "Amount to send": [""],
- "Amount to receive": [""],
- "Total cost": [""],
- "Balance left": [""],
- "Before fee": [""],
- "Total cashout transfer": [""],
- "No cashout channel available": [""],
- "Before doing a cashout the server need to provide an second channel to confirm the operation":
- [""],
- "Second factor authentication": [""],
- Email: [""],
- "add a email in your profile to enable this option": [""],
- SMS: [""],
- "add a phone number in your profile to enable this option": [""],
- Details: [""],
- Delete: [""],
- Credentials: [""],
- Cashouts: [""],
- "it doesnt have the pattern of an IBAN number": [""],
- "it doesnt have the pattern of an email": [""],
- "should start with +": [""],
- "phone number can't have other than numbers": [""],
- "account identification in the bank": [""],
- "name of the person owner the account": [""],
- "Internal IBAN": [""],
- "if empty a random account number will be assigned": [""],
- "account identification for bank transfer": [""],
- Phone: [""],
- "Cashout IBAN": [""],
- "account number where the money is going to be sent when doing cashouts":
- [""],
- "Max debt": [""],
- "how much is user able to transfer after zero balance": [""],
- "Is this a Taler Exchange?": [""],
- "This server doesn't support second factor authentication.": [""],
- "Enable second factor authentication": [""],
- "Using email": [""],
- "Using SMS": [""],
- "Is this account public?": [""],
- "public accounts have their balance publicly accesible": [""],
- "Account updated": [""],
- "The rights to change the account are not sufficient": [""],
- "The username was not found": [""],
- "You can't change the legal name, please contact the your account administrator.":
- [""],
- "You can't change the debt limit, please contact the your account administrator.":
- [""],
- "You can't change the cashout address, please contact the your account administrator.":
- [""],
- "You can't change the contact data, please contact the your account administrator.":
- [""],
- 'Account "%1$s"': [""],
- "Change details": [""],
- Update: [""],
- "password doesn't match": [""],
- "Password changed": [""],
- "Not authorized to change the password, maybe the session is invalid.": [
- "",
- ],
- "You need to provide the old password. If you don't have it contact your account administrator.":
- [""],
- "Your current password doesn't match, can't change to a new password.": [
- "",
- ],
- "Update password": [""],
- "New password": [""],
- "Type it again": [""],
- "repeat the same password": [""],
- "Current password": [""],
- "your current password, for security": [""],
- Change: [""],
- "Can't delete the account": [""],
- "The account can't be delete while still holding some balance. First make sure that the owner make a complete cashout.":
- [""],
- "Account removed": [""],
- "No enough permission to delete the account.": [""],
- "The username was not found.": [""],
- "Can't delete a reserved username.": [""],
- "Can't delete an account with balance different than zero.": [""],
- "name doesn't match": [""],
- "You are going to remove the account": [""],
- "This step can't be undone.": [""],
- 'Deleting account "%1$s"': [""],
- Verification: [""],
- "enter the account name that is going to be deleted": [""],
- 'Account created with password "%1$s". The user must change the password on the next login.':
- [""],
- "Server replied that phone or email is invalid": [""],
- "The rights to perform the operation are not sufficient": [""],
- "Account username is already taken": [""],
- "Account id is already taken": [""],
- "Bank ran out of bonus credit.": [""],
- "Account username can't be used because is reserved": [""],
- "Can't create accounts": [""],
- "Only system admin can create accounts.": [""],
- "New business account": [""],
- Create: [""],
- "Cashout not supported.": [""],
- "Account not found.": [""],
- "Latest cashouts": [""],
- Created: [""],
- Confirmed: [""],
- "Total debit": [""],
- "Total credit": [""],
- Status: [""],
- never: [""],
- "Cashout for account %1$s": [""],
- "This cashout not found. Maybe already aborted.": [""],
- "Cashout not found. It may be also mean that it was already aborted.": [
- "",
- ],
- "Cashout was already confimed.": [""],
- "Cashout operation is not supported.": [""],
- "The cashout operation is already aborted.": [""],
- "Missing destination account.": [""],
- "Too many failed attempts.": [""],
- "The code for this cashout is invalid.": [""],
- "Cashout detail": [""],
- Debited: [""],
- Credited: [""],
- "Enter the confirmation code": [""],
- Abort: [""],
- Confirm: [""],
- "Unauthorized to make the operation, maybe the session has expired or the password changed.":
- [""],
- "The operation was rejected due to insufficient funds.": [""],
- "Do not show this again": [""],
- Close: [""],
- "On this device": [""],
- 'If you are using a web browser on desktop you should access your wallet with the GNU Taler WebExtension now or click the link if your WebExtension have the "Inject Taler support" option enabled.':
- [""],
- Start: [""],
- "On a mobile phone": [""],
- "Scan the QR code with your mobile device.": [""],
- "There is an operation already": [""],
- "Complete or cancel the operation in": [""],
- "Server responded with an invalid withdraw URI": [""],
- "Withdraw URI: %1$s": [""],
- "The operation was rejected due to insufficient funds": [""],
- "Prepare your wallet": [""],
- "After using your wallet you will need to confirm or cancel the operation on this site.":
- [""],
- "You need a GNU Taler Wallet": [""],
- "If you don't have one yet you can follow the instruction in": [""],
- "Send money": [""],
- "to a %1$s wallet": [""],
- "Withdraw digital money into your mobile wallet or browser extension": [
- "",
- ],
- "operation ready": [""],
- "to another bank account": [""],
- "Make a wire transfer to an account with known bank account number.": [
- "",
- ],
- "Transfer details": [""],
- "This is a demo bank": [""],
- "This part of the demo shows how a bank that supports Taler directly would work. In addition to using your own bank account, you can also see the transaction history of some %1$s.":
- [""],
- "This part of the demo shows how a bank that supports Taler directly would work.":
- [""],
- "Pending account delete operation": [""],
- "Pending account update operation": [""],
- "Pending password update operation": [""],
- "Pending transaction operation": [""],
- "Pending withdrawal operation": [""],
- "Pending cashout operation": [""],
- "You can complete or cancel the operation in": [""],
- "Download bank stats": [""],
- "Include hour metric": [""],
- "Include day metric": [""],
- "Include month metric": [""],
- "Include year metric": [""],
- "Include table header": [""],
- "Add previous metric for compare": [""],
- "Fail on first error": [""],
- Download: [""],
- "downloading... %1$s": [""],
- "Download completed": [""],
- "click here to save the file in your computer": [""],
- "Challenge not found.": [""],
- "This user is not authorized to complete this challenge.": [""],
- "Too many attemps, try another code.": [""],
- "The confirmation code is wrong, try again.": [""],
- "The operation expired.": [""],
- "The operation failed.": [""],
- "The operation needs another confirmation to complete.": [""],
- "Account delete": [""],
- "Account update": [""],
- "Password update": [""],
- "Wire transfer": [""],
- Withdrawal: [""],
- "Confirm the operation": [""],
- "Send again": [""],
- "Send code": [""],
- "Operation details": [""],
- "Challenge details": [""],
- "Sent at": [""],
- "To phone": [""],
- "To email": [""],
- "Welcome to %1$s!": [""],
- },
- },
- domain: "messages",
- plural_forms: "nplurals=2; plural=(n != 1);",
- lang: "en",
- completeness: 100,
-};
-
-strings["de"] = {
- locale_data: {
- messages: {
- "": {
- domain: "messages",
- plural_forms: "nplurals=2; plural=n != 1;",
- lang: "de",
- },
- "Operation failed, please report": [""],
- "Request timeout": [""],
- "Request throttled": [""],
- "Malformed response": [""],
- "Network error": [""],
- "Unexpected request error": [""],
- "Unexpected error": [""],
- "IBAN numbers usually have more that 4 digits": [""],
- "IBAN numbers usually have less that 34 digits": [""],
- "IBAN country code not found": [""],
- "IBAN number is not valid, checksum is wrong": [""],
- "Max withdrawal amount": [""],
- "Show withdrawal confirmation": [""],
- "Show demo description": [""],
- "Show install wallet first": [""],
- "Use fast withdrawal form": [""],
- "Show debug info": [""],
- "The reserve operation has been confirmed previously and can't be aborted":
- [""],
- "The operation id is invalid.": [""],
- "The operation was not found.": [""],
- "If you have a Taler wallet installed in this device": [""],
- "You will see the details of the operation in your wallet including the fees (if applies). If you still don't have one you can install it following instructions in":
- [""],
- "this page": [""],
- Withdraw: [""],
- "Or if you have the wallet in another device": [""],
- "Scan the QR below to start the withdrawal.": [""],
- required: [""],
- "IBAN should have just uppercased letters and numbers": [""],
- "not valid": [""],
- "should be greater than 0": [""],
- "balance is not enough": [""],
- "does not follow the pattern": [""],
- 'only "IBAN" target are supported': [""],
- 'use the "amount" parameter to specify the amount to be transferred': [
- "",
- ],
- "the amount is not valid": [""],
- 'use the "message" parameter to specify a reference text for the transfer':
- [""],
- "The request was invalid or the payto://-URI used unacceptable features.":
- [""],
- "Not enough permission to complete the operation.": [""],
- 'The destination account "%1$s" was not found.': [""],
- "The origin and the destination of the transfer can't be the same.": [""],
- "Your balance is not enough.": [""],
- 'The origin account "%1$s" was not found.': [""],
- "Using a form": [""],
- "Import payto:// URI": [""],
- Recipient: [""],
- "IBAN of the recipient's account": [""],
- "Transfer subject": [""],
- subject: ["Verwendungszweck"],
- "some text to identify the transfer": [""],
- Amount: ["Betrag"],
- "amount to transfer": ["Betrag"],
- "payto URI:": [""],
- "uniform resource identifier of the target account": [""],
- "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]": [""],
- Cancel: [""],
- Send: [""],
- "Missing username": [""],
- "Missing password": [""],
- 'Wrong credentials for "%1$s"': [""],
- "Account not found": [""],
- Username: [""],
- "username of the account": [""],
- Password: [""],
- "password of the account": ["Buchungen auf öffentlich sichtbaren Konten"],
- Check: [""],
- "Log in": [""],
- Register: [""],
- "Wire transfer completed!": [""],
- "The withdrawal has been aborted previously and can't be confirmed": [""],
- "The withdrawal operation can't be confirmed before a wallet accepted the transaction.":
- [""],
- "Your balance is not enough for the operation.": [""],
- "Confirm the withdrawal operation": ["Abhebung bestätigen"],
- "Wire transfer details": [""],
- "Taler Exchange operator's account": [""],
- "Taler Exchange operator's name": [""],
- Transfer: [""],
- "Authentication required": [""],
- "This operation was created with other username": [""],
- "Operation aborted": [""],
- "The wire transfer to the Taler Exchange operator's account was aborted, your balance was not affected.":
- [""],
- "You can close this page now or continue to the account page.": [""],
- Continue: [""],
- "Withdrawal confirmed": [""],
- "The wire transfer to the Taler operator has been initiated. You will soon receive the requested amount in your Taler wallet.":
- [""],
- Done: [""],
- "Operation canceled": [""],
- "The operation is marked as 'selected' but some step in the withdrawal failed":
- [""],
- "The account is selected but no withdrawal identification found.": [""],
- "There is a withdrawal identification but no account has been selected or the selected account is invalid.":
- [""],
- "No withdrawal ID found and no account has been selected or the selected account is invalid.":
- [""],
- "Operation not found": [""],
- "This operation is not known by the server. The operation id is wrong or the server deleted the operation information before reaching here.":
- [""],
- "Cotinue to dashboard": [""],
- "The Withdrawal URI is not valid": [""],
- 'the bank backend is not supported. supported version "%1$s", server version "%2$s"':
- [""],
- "Internal error, please report.": [""],
- Preferences: [""],
- "Welcome, %1$s": [""],
- "Latest transactions": [""],
- Date: ["Datum"],
- Counterpart: ["Empfänger"],
- Subject: ["Verwendungszweck"],
- sent: [""],
- received: [""],
- "invalid value": [""],
- to: [""],
- from: [""],
- "First page": [""],
- Next: [""],
- "History of public accounts": [
- "Buchungen auf öffentlich sichtbaren Konten",
- ],
- "Currently, the bank is not accepting new registrations!": [""],
- "Missing name": [""],
- "Use letters and numbers only, and start with a lowercase letter": [""],
- "Passwords don't match": [""],
- "Server replied with invalid phone or email.": [""],
- "Registration is disabled because the bank ran out of bonus credit.": [
- "",
- ],
- "No enough permission to create that account.": [""],
- "That account id is already taken.": [""],
- "That username is already taken.": [""],
- "That username can't be used because is reserved.": [""],
- "Only admin is allow to set debt limit.": [""],
- "No information for the selected authentication channel.": [""],
- "Authentication channel is not supported.": [""],
- "Only admin can create accounts with second factor authentication.": [""],
- "Account registration": [""],
- "Repeat password": [""],
- Name: [""],
- "Create a random temporary user": [""],
- "Make a wire transfer": [""],
- "Wire transfer created!": [""],
- Accounts: ["Betrag"],
- "A list of all business account in the bank.": [""],
- "Create account": [""],
- Balance: [""],
- Actions: [""],
- unknown: [""],
- "change password": [""],
- remove: [""],
- "Select a section": [""],
- "Last hour": [""],
- "Last day": [""],
- "Last month": [""],
- "Last year": [""],
- "Last Year": [""],
- "Trading volume on %1$s compared to %2$s": [""],
- Cashin: [""],
- Cashout: [""],
- Payin: [""],
- Payout: [""],
- "download stats as CSV": [""],
- "Descreased by": [""],
- "Increased by": [""],
- "Unable to create a cashout": [""],
- "The bank configuration does not support cashout operations.": [""],
- invalid: [""],
- "need to be higher due to fees": [""],
- "the total transfer at destination will be zero": [""],
- "Cashout created": [""],
- "Duplicated request detected, check if the operation succeded or try again.":
- [""],
- "The conversion rate was incorrectly applied": [""],
- "The account does not have sufficient funds": [""],
- "Cashouts are not supported": [""],
- "Missing cashout URI in the profile": [""],
- "Sending the confirmation message failed, retry later or contact the administrator.":
- [""],
- "Convertion rate": [""],
- Fee: [""],
- "To account": [""],
- "No cashout account": [""],
- "Before doing a cashout you need to complete your profile": [""],
- "Amount to send": ["Betrag"],
- "Amount to receive": [""],
- "Total cost": [""],
- "Balance left": [""],
- "Before fee": [""],
- "Total cashout transfer": [""],
- "No cashout channel available": [""],
- "Before doing a cashout the server need to provide an second channel to confirm the operation":
- [""],
- "Second factor authentication": [""],
- Email: [""],
- "add a email in your profile to enable this option": [""],
- SMS: [""],
- "add a phone number in your profile to enable this option": [""],
- Details: [""],
- Delete: [""],
- Credentials: [""],
- Cashouts: [""],
- "it doesnt have the pattern of an IBAN number": [""],
- "it doesnt have the pattern of an email": [""],
- "should start with +": [""],
- "phone number can't have other than numbers": [""],
- "account identification in the bank": [""],
- "name of the person owner the account": [""],
- "Internal IBAN": [""],
- "if empty a random account number will be assigned": [""],
- "account identification for bank transfer": [""],
- Phone: [""],
- "Cashout IBAN": [""],
- "account number where the money is going to be sent when doing cashouts":
- [""],
- "Max debt": [""],
- "how much is user able to transfer after zero balance": [""],
- "Is this a Taler Exchange?": [""],
- "This server doesn't support second factor authentication.": [""],
- "Enable second factor authentication": [""],
- "Using email": [""],
- "Using SMS": [""],
- "Is this account public?": [""],
- "public accounts have their balance publicly accesible": [""],
- "Account updated": [""],
- "The rights to change the account are not sufficient": [""],
- "The username was not found": [""],
- "You can't change the legal name, please contact the your account administrator.":
- [""],
- "You can't change the debt limit, please contact the your account administrator.":
- [""],
- "You can't change the cashout address, please contact the your account administrator.":
- [""],
- "You can't change the contact data, please contact the your account administrator.":
- [""],
- 'Account "%1$s"': [""],
- "Change details": [""],
- Update: [""],
- "password doesn't match": [""],
- "Password changed": [""],
- "Not authorized to change the password, maybe the session is invalid.": [
- "",
- ],
- "You need to provide the old password. If you don't have it contact your account administrator.":
- [""],
- "Your current password doesn't match, can't change to a new password.": [
- "",
- ],
- "Update password": [""],
- "New password": [""],
- "Type it again": [""],
- "repeat the same password": [""],
- "Current password": [""],
- "your current password, for security": [""],
- Change: [""],
- "Can't delete the account": [""],
- "The account can't be delete while still holding some balance. First make sure that the owner make a complete cashout.":
- [""],
- "Account removed": [""],
- "No enough permission to delete the account.": [""],
- "The username was not found.": [""],
- "Can't delete a reserved username.": [""],
- "Can't delete an account with balance different than zero.": [""],
- "name doesn't match": [""],
- "You are going to remove the account": [""],
- "This step can't be undone.": [""],
- 'Deleting account "%1$s"': [""],
- Verification: [""],
- "enter the account name that is going to be deleted": [""],
- 'Account created with password "%1$s". The user must change the password on the next login.':
- [""],
- "Server replied that phone or email is invalid": [""],
- "The rights to perform the operation are not sufficient": [""],
- "Account username is already taken": [""],
- "Account id is already taken": [""],
- "Bank ran out of bonus credit.": [""],
- "Account username can't be used because is reserved": [""],
- "Can't create accounts": [""],
- "Only system admin can create accounts.": [""],
- "New business account": [""],
- Create: [""],
- "Cashout not supported.": [""],
- "Account not found.": [""],
- "Latest cashouts": [""],
- Created: [""],
- Confirmed: ["Bestätigen"],
- "Total debit": [""],
- "Total credit": [""],
- Status: [""],
- never: [""],
- "Cashout for account %1$s": [""],
- "This cashout not found. Maybe already aborted.": [""],
- "Cashout not found. It may be also mean that it was already aborted.": [
- "",
- ],
- "Cashout was already confimed.": [""],
- "Cashout operation is not supported.": [""],
- "The cashout operation is already aborted.": [""],
- "Missing destination account.": [""],
- "Too many failed attempts.": [""],
- "The code for this cashout is invalid.": [""],
- "Cashout detail": [""],
- Debited: [""],
- Credited: [""],
- "Enter the confirmation code": [""],
- Abort: [""],
- Confirm: ["Bestätigen"],
- "Unauthorized to make the operation, maybe the session has expired or the password changed.":
- [""],
- "The operation was rejected due to insufficient funds.": [""],
- "Do not show this again": [""],
- Close: [""],
- "On this device": [""],
- 'If you are using a web browser on desktop you should access your wallet with the GNU Taler WebExtension now or click the link if your WebExtension have the "Inject Taler support" option enabled.':
- [""],
- Start: [""],
- "On a mobile phone": [""],
- "Scan the QR code with your mobile device.": [""],
- "There is an operation already": [""],
- "Complete or cancel the operation in": ["Abhebung bestätigen"],
- "Server responded with an invalid withdraw URI": [""],
- "Withdraw URI: %1$s": [""],
- "The operation was rejected due to insufficient funds": [""],
- "Prepare your wallet": [""],
- "After using your wallet you will need to confirm or cancel the operation on this site.":
- [""],
- "You need a GNU Taler Wallet": [""],
- "If you don't have one yet you can follow the instruction in": [""],
- "Send money": [""],
- "to a %1$s wallet": [""],
- "Withdraw digital money into your mobile wallet or browser extension": [
- "",
- ],
- "operation ready": [""],
- "to another bank account": [""],
- "Make a wire transfer to an account with known bank account number.": [
- "",
- ],
- "Transfer details": [""],
- "This is a demo bank": [""],
- "This part of the demo shows how a bank that supports Taler directly would work. In addition to using your own bank account, you can also see the transaction history of some %1$s.":
- [""],
- "This part of the demo shows how a bank that supports Taler directly would work.":
- [""],
- "Pending account delete operation": [""],
- "Pending account update operation": [""],
- "Pending password update operation": [""],
- "Pending transaction operation": [""],
- "Pending withdrawal operation": [""],
- "Pending cashout operation": [""],
- "You can complete or cancel the operation in": [""],
- "Download bank stats": [""],
- "Include hour metric": [""],
- "Include day metric": [""],
- "Include month metric": [""],
- "Include year metric": [""],
- "Include table header": [""],
- "Add previous metric for compare": [""],
- "Fail on first error": [""],
- Download: [""],
- "downloading... %1$s": [""],
- "Download completed": [""],
- "click here to save the file in your computer": [""],
- "Challenge not found.": [""],
- "This user is not authorized to complete this challenge.": [""],
- "Too many attemps, try another code.": [""],
- "The confirmation code is wrong, try again.": [""],
- "The operation expired.": [""],
- "The operation failed.": [""],
- "The operation needs another confirmation to complete.": [""],
- "Account delete": [""],
- "Account update": [""],
- "Password update": [""],
- "Wire transfer": [""],
- Withdrawal: ["Abhebung bestätigen"],
- "Confirm the operation": ["Abhebung bestätigen"],
- "Send again": [""],
- "Send code": [""],
- "Operation details": [""],
- "Challenge details": [""],
- "Sent at": [""],
- "To phone": [""],
- "To email": [""],
- "Welcome to %1$s!": [""],
- },
- },
- domain: "messages",
- plural_forms: "nplurals=2; plural=n != 1;",
- lang: "de",
- completeness: 4,
-};
diff --git a/packages/demobank-ui/src/i18n/uk.po b/packages/demobank-ui/src/i18n/uk.po
deleted file mode 100644
index a8b41e32f..000000000
--- a/packages/demobank-ui/src/i18n/uk.po
+++ /dev/null
@@ -1,1743 +0,0 @@
-# This file is part of GNU Taler
-# (C) 2022-2024 Taler Systems S.A.
-#
-# GNU Taler is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 3, or (at your option) any later version.
-#
-# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along with
-# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: Taler Bank\n"
-"Report-Msgid-Bugs-To: taler@gnu.org\n"
-"PO-Revision-Date: 2024-03-07 07:04+0000\n"
-"Last-Translator: Tim Vutor <flukes.ostrich0p@icloud.com>\n"
-"Language-Team: Ukrainian <https://weblate.taler.net/projects/gnu-taler/"
-"taler-bank-spa/uk/>\n"
-"Language: uk\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
-"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
-"X-Generator: Weblate 5.2.1\n"
-
-#: src/utils.ts:137
-#, c-format, fuzzy
-msgid "Operation failed, please report"
-msgstr "Помилка операції, повідомте"
-
-#: src/utils.ts:156
-#, c-format
-msgid "Request timeout"
-msgstr "Тайм-аут запиту"
-
-#: src/utils.ts:165
-#, c-format, fuzzy
-msgid "Request throttled"
-msgstr "Запит до сервера перервано"
-
-#: src/utils.ts:174
-#, c-format
-msgid "Malformed response"
-msgstr "Некоректна відповідь"
-
-#: src/utils.ts:183
-#, c-format
-msgid "Network error"
-msgstr "Мережева помилка"
-
-#: src/utils.ts:192
-#, c-format
-msgid "Unexpected request error"
-msgstr "Неочікувана помилка запиту"
-
-#: src/utils.ts:201
-#, c-format
-msgid "Unexpected error"
-msgstr "Неочікувана помилка"
-
-#: src/utils.ts:377
-#, c-format, fuzzy
-msgid "IBAN numbers usually have more that 4 digits"
-msgstr "Номера IBAN зазвичай мають більше 4ьох цифр"
-
-#: src/utils.ts:379
-#, c-format, fuzzy
-msgid "IBAN numbers usually have less that 34 digits"
-msgstr "Номера IBAN зазвичай мають менше 34ьох цифр"
-
-#: src/utils.ts:387
-#, c-format, fuzzy
-msgid "IBAN country code not found"
-msgstr "Код країни IBAN не знайдено"
-
-#: src/utils.ts:401
-#, c-format, fuzzy
-msgid "IBAN number is not valid, checksum is wrong"
-msgstr "Номер IBAN невірний, контрольна сума не сходиться"
-
-#: src/context/config.ts:136
-#, c-format
-msgid ""
-"the bank backend is not supported. supported version \"%1$s\", server version "
-"\"%2$s\""
-msgstr ""
-
-#: src/hooks/preferences.ts:55
-#, c-format
-msgid "Max withdrawal amount"
-msgstr "Максимальна сумма для виведення"
-
-#: src/hooks/preferences.ts:57
-#, c-format
-msgid "Show withdrawal confirmation"
-msgstr "Показати підтвердження виводу"
-
-#: src/hooks/preferences.ts:59
-#, c-format
-msgid "Show demo description"
-msgstr "Показати демо опис"
-
-#: src/hooks/preferences.ts:61
-#, c-format
-msgid "Show install wallet first"
-msgstr ""
-
-#: src/hooks/preferences.ts:63
-#, c-format
-msgid "Use fast withdrawal form"
-msgstr ""
-
-#: src/hooks/preferences.ts:65
-#, c-format
-msgid "Show debug info"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:90
-#, c-format
-msgid "required"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:92
-#, c-format
-msgid "IBAN should have just uppercased letters and numbers"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:98
-#, c-format
-msgid "not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:100
-#, c-format
-msgid "should be greater than 0"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:102
-#, c-format
-msgid "balance is not enough"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:112
-#, c-format
-msgid "does not follow the pattern"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:114
-#, c-format
-msgid "only \"IBAN\" target are supported"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:116
-#, c-format
-msgid "use the \"amount\" parameter to specify the amount to be transferred"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:118
-#, c-format
-msgid "the amount is not valid"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:120
-#, c-format
-msgid "use the \"message\" parameter to specify a reference text for the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:160
-#, c-format
-msgid "The request was invalid or the payto://-URI used unacceptable features."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:167
-#, c-format
-msgid "Not enough permission to complete the operation."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:174
-#, c-format
-msgid "The destination account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:181
-#, c-format
-msgid "The origin and the destination of the transfer can't be the same."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:188
-#, c-format
-msgid "Your balance is not enough."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:195
-#, c-format
-msgid "The origin account \"%1$s\" was not found."
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:212
-#, c-format
-msgid "Wire transfer created!"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:270
-#, c-format
-msgid "Using a form"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:310
-#, c-format
-msgid "Import payto:// URI"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:335
-#, c-format
-msgid "Recipient"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:359
-#, c-format
-msgid "IBAN of the recipient's account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:369
-#, c-format
-msgid "Transfer subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:377
-#, c-format
-msgid "subject"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:390
-#, c-format
-msgid "some text to identify the transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:400
-#, c-format
-msgid "Amount"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:415
-#, c-format
-msgid "amount to transfer"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:425
-#, c-format
-msgid "payto URI:"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:436
-#, c-format
-msgid "uniform resource identifier of the target account"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:437
-#, c-format
-msgid "payto://iban/[receiver-iban]?message=[subject]&amount=[%1$s:X.Y]"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:457
-#, c-format
-msgid "Cancel"
-msgstr ""
-
-#: src/pages/PaytoWireTransferForm.tsx:471
-#, c-format
-msgid "Send"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:71
-#, c-format
-msgid "Missing username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:75
-#, c-format
-msgid "Missing password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:104
-#, c-format
-msgid "Wrong credentials for \"%1$s\""
-msgstr ""
-
-#: src/pages/LoginForm.tsx:111
-#, c-format
-msgid "Account not found"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:142
-#, c-format
-msgid "Username"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:156
-#, c-format
-msgid "username of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:175
-#, c-format
-msgid "Password"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:188
-#, c-format
-msgid "password of the account"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:223
-#, c-format
-msgid "Check"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:237
-#, c-format
-msgid "Log in"
-msgstr ""
-
-#: src/pages/LoginForm.tsx:249
-#, c-format
-msgid "Register"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:52
-#, c-format
-msgid "Latest transactions"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:63
-#, c-format
-msgid "Date"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:71
-#, c-format
-msgid "Counterpart"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:75
-#, c-format
-msgid "Subject"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:111
-#, c-format
-msgid "sent"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:112
-#, c-format
-msgid "received"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:127
-#, c-format
-msgid "invalid value"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "to"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:136
-#, c-format
-msgid "from"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:202
-#, c-format
-msgid "First page"
-msgstr ""
-
-#: src/components/Transactions/views.tsx:209
-#, c-format
-msgid "Next"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:86
-#, c-format
-msgid "Wire transfer completed!"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:93
-#, c-format
-msgid "The withdrawal has been aborted previously and can't be confirmed"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:100
-#, c-format
-msgid ""
-"The withdrawal operation can't be confirmed before a wallet accepted the "
-"transaction."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:107
-#, c-format
-msgid "The operation id is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:114
-#, c-format
-msgid "The operation was not found."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:121
-#, c-format
-msgid "Your balance is not enough for the operation."
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:155
-#, c-format
-msgid "The reserve operation has been confirmed previously and can't be aborted"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:186
-#, c-format
-msgid "Confirm the withdrawal operation"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:203
-#, c-format
-msgid "Wire transfer details"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:217
-#, c-format
-msgid "Taler Exchange operator's account"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:228
-#, c-format
-msgid "Taler Exchange operator's name"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:317
-#, c-format
-msgid "Transfer"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:342
-#, c-format
-msgid "Authentication required"
-msgstr ""
-
-#: src/pages/WithdrawalConfirmationQuestion.tsx:352
-#, c-format
-msgid "This operation was created with other username"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:209
-#, c-format
-msgid ""
-"Unauthorized to make the operation, maybe the session has expired or the "
-"password changed."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:218
-#, c-format
-msgid "The operation was rejected due to insufficient funds."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:268
-#, c-format
-msgid "Withdrawal confirmed"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:272
-#, c-format
-msgid ""
-"The wire transfer to the Taler operator has been initiated. You will soon "
-"receive the requested amount in your Taler wallet."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:287
-#, c-format
-msgid "Do not show this again"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:319
-#, c-format
-msgid "Close"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:399
-#, c-format
-msgid "On this device"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:404
-#, c-format
-msgid ""
-"If you are using a web browser on desktop you should access your wallet with the "
-"GNU Taler WebExtension now or click the link if your WebExtension have the "
-"\"Inject Taler support\" option enabled."
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:417
-#, c-format
-msgid "Start"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:426
-#, c-format
-msgid "On a mobile phone"
-msgstr ""
-
-#: src/pages/OperationState/views.tsx:431
-#, c-format
-msgid "Scan the QR code with your mobile device."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:73
-#, c-format
-msgid "There is an operation already"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:75
-#, c-format
-msgid "Complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:84
-#, c-format
-msgid "this page"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:101
-#, c-format
-msgid "invalid"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:116
-#, c-format
-msgid "Server responded with an invalid withdraw URI"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:117
-#, c-format
-msgid "Withdraw URI: %1$s"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:132
-#, c-format
-msgid "The operation was rejected due to insufficient funds"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:253
-#, c-format
-msgid "Continue"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:282
-#, c-format
-msgid "Prepare your wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:285
-#, c-format
-msgid ""
-"After using your wallet you will need to confirm or cancel the operation on this "
-"site."
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:295
-#, c-format
-msgid "You need a GNU Taler Wallet"
-msgstr ""
-
-#: src/pages/WalletWithdrawForm.tsx:300
-#, c-format
-msgid "If you don't have one yet you can follow the instruction in"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:55
-#, c-format
-msgid "Send money"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:73
-#, c-format
-msgid "to a %1$s wallet"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:95
-#, c-format
-msgid "Withdraw digital money into your mobile wallet or browser extension"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:109
-#, c-format
-msgid "operation ready"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:129
-#, c-format
-msgid "to another bank account"
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:149
-#, c-format
-msgid "Make a wire transfer to an account with known bank account number."
-msgstr ""
-
-#: src/pages/PaymentOptions.tsx:171
-#, c-format
-msgid "Transfer details"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:41
-#, c-format
-msgid "This is a demo bank"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:46
-#, c-format
-msgid ""
-"This part of the demo shows how a bank that supports Taler directly would work. "
-"In addition to using your own bank account, you can also see the transaction "
-"history of some %1$s."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:53
-#, c-format
-msgid "This part of the demo shows how a bank that supports Taler directly would work."
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:70
-#, c-format
-msgid "Pending account delete operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:72
-#, c-format
-msgid "Pending account update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:74
-#, c-format
-msgid "Pending password update operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:76
-#, c-format
-msgid "Pending transaction operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:78
-#, c-format
-msgid "Pending withdrawal operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:80
-#, c-format
-msgid "Pending cashout operation"
-msgstr ""
-
-#: src/pages/AccountPage/views.tsx:91
-#, c-format
-msgid "You can complete or cancel the operation in"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:64
-#, c-format
-msgid "Internal error, please report."
-msgstr ""
-
-#: src/pages/BankFrame.tsx:100
-#, c-format
-msgid "Preferences"
-msgstr ""
-
-#: src/pages/BankFrame.tsx:184
-#, c-format
-msgid "Welcome, %1$s"
-msgstr ""
-
-#: src/pages/WireTransfer.tsx:79
-#, c-format
-msgid "Make a wire transfer"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:72
-#, c-format
-msgid "Accounts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:75
-#, c-format
-msgid "A list of all business account in the bank."
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:86
-#, c-format
-msgid "Create account"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:106
-#, c-format
-msgid "Name"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:110
-#, c-format
-msgid "Balance"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:112
-#, c-format
-msgid "Actions"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:151
-#, c-format
-msgid "unknown"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:170
-#, c-format
-msgid "change password"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:179
-#, c-format
-msgid "cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountList.tsx:189
-#, c-format
-msgid "remove"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:168
-#, c-format
-msgid "Cashout not implemented"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:184
-#, c-format
-msgid "Select a section"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:202
-#, c-format
-msgid "Last hour"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:208
-#, c-format
-msgid "Last day"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:216
-#, c-format
-msgid "Last month"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:222
-#, c-format
-msgid "Last year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:310
-#, c-format
-msgid "Last Year"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:325
-#, c-format
-msgid "Trading volume on %1$s compared to %2$s"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:342
-#, c-format
-msgid "Cashin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:352
-#, c-format
-msgid "Cashout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:364
-#, c-format
-msgid "Payin"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:374
-#, c-format
-msgid "Payout"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:388
-#, c-format
-msgid "download stats as CSV"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:494
-#, c-format
-msgid "Decreased by"
-msgstr ""
-
-#: src/pages/admin/AdminHome.tsx:498
-#, c-format
-msgid "Increased by"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:89
-#, c-format
-msgid "Download bank stats"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:110
-#, c-format
-msgid "Include hour metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:143
-#, c-format
-msgid "Include day metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:173
-#, c-format
-msgid "Include month metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:206
-#, c-format
-msgid "Include year metric"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:239
-#, c-format
-msgid "Include table header"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:272
-#, c-format
-msgid "Add previous metric for compare"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:307
-#, c-format
-msgid "Fail on first error"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:364
-#, c-format
-msgid "Download"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:381
-#, c-format
-msgid "downloading... %1$s"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:399
-#, c-format
-msgid "Download completed"
-msgstr ""
-
-#: src/pages/DownloadStats.tsx:400
-#, c-format
-msgid "click here to save the file in your computer"
-msgstr ""
-
-#: src/pages/PublicHistoriesPage.tsx:78
-#, c-format
-msgid "History of public accounts"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:48
-#, c-format
-msgid "Currently, the bank is not accepting new registrations!"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:87
-#, c-format
-msgid "Missing name"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:91
-#, c-format
-msgid "Use letters and numbers only, and start with a lowercase letter"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:107
-#, c-format
-msgid "Passwords don't match"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:130
-#, c-format
-msgid "Server replied with invalid phone or email."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:137
-#, c-format
-msgid "Registration is disabled because the bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:144
-#, c-format
-msgid "No enough permission to create that account."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:151
-#, c-format
-msgid "That account id is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:158
-#, c-format
-msgid "That username is already taken."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:165
-#, c-format
-msgid "That username can't be used because is reserved."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:172
-#, c-format
-msgid "Only admin is allow to set debt limit."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:179
-#, c-format
-msgid "No information for the selected authentication channel."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:186
-#, c-format
-msgid "Authentication channel is not supported."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:193
-#, c-format
-msgid "Only admin can create accounts with second factor authentication."
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:233
-#, c-format
-msgid "Account registration"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:315
-#, c-format
-msgid "Repeat password"
-msgstr ""
-
-#: src/pages/RegistrationPage.tsx:457
-#, c-format
-msgid "Create a random temporary user"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:110
-#, c-format
-msgid "If you have a Taler wallet installed in this device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:116
-#, c-format
-msgid ""
-"You will see the details of the operation in your wallet including the fees (if "
-"applies). If you still don't have one you can install it following instructions "
-"in"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:143
-#, c-format
-msgid "Withdraw"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:152
-#, c-format
-msgid "Or if you have the wallet in another device"
-msgstr ""
-
-#: src/pages/QrCodeSection.tsx:157
-#, c-format
-msgid "Scan the QR below to start the withdrawal."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:79
-#, c-format
-msgid "Operation aborted"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:82
-#, c-format
-msgid ""
-"The wire transfer to the Taler Exchange operator's account was aborted, your "
-"balance was not affected."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:88
-#, c-format
-msgid "You can close this page now or continue to the account page."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:147
-#, c-format
-msgid "Done"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:158
-#, c-format
-msgid "Operation canceled"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:173
-#, c-format
-msgid "The operation is marked as 'selected' but some step in the withdrawal failed"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:175
-#, c-format
-msgid "The account is selected but no withdrawal identification found."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:188
-#, c-format
-msgid ""
-"There is a withdrawal identification but no account has been selected or the "
-"selected account is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:202
-#, c-format
-msgid ""
-"No withdrawal ID found and no account has been selected or the selected account "
-"is invalid."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:259
-#, c-format
-msgid "Operation not found"
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:263
-#, c-format
-msgid ""
-"This operation is not known by the server. The operation id is wrong or the "
-"server deleted the operation information before reaching here."
-msgstr ""
-
-#: src/pages/WithdrawalQRCode.tsx:278
-#, c-format
-msgid "Cotinue to dashboard"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:98
-#, c-format
-msgid "Cashout not found. It may be also mean that it was already aborted."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:136
-#, c-format
-msgid "Challenge not found."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:143
-#, c-format
-msgid "This user is not authorized to complete this challenge."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:150
-#, c-format
-msgid "Too many attempts, try another code."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:157
-#, c-format
-msgid "The confirmation code is wrong, try again."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:164
-#, c-format
-msgid "The operation expired."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:197
-#, c-format
-msgid "The operation failed."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:212
-#, c-format
-msgid "The operation needs another confirmation to complete."
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:224
-#, c-format
-msgid "Account delete"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:226
-#, c-format
-msgid "Account update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:228
-#, c-format
-msgid "Password update"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:230
-#, c-format
-msgid "Wire transfer"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:232
-#, c-format
-msgid "Withdrawal"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:248
-#, c-format
-msgid "Confirm the operation"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:271
-#, c-format
-msgid "Enter the confirmation code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:313
-#, c-format
-msgid "Confirm"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:348
-#, c-format
-msgid "Send again"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:359
-#, c-format
-msgid "Send code"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:369
-#, c-format
-msgid "Operation details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:529
-#, c-format
-msgid "Challenge details"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:536
-#, c-format
-msgid "Sent at"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:551
-#, c-format
-msgid "To phone"
-msgstr ""
-
-#: src/pages/SolveChallengePage.tsx:553
-#, c-format
-msgid "To email"
-msgstr ""
-
-#: src/pages/WithdrawalOperationPage.tsx:49
-#, c-format
-msgid "The Withdrawal URI is not valid"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:100
-#, c-format
-msgid "Latest cashouts"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:111
-#, c-format
-msgid "Created"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:115
-#, c-format
-msgid "Total debit"
-msgstr ""
-
-#: src/components/Cashouts/views.tsx:119
-#, c-format
-msgid "Total credit"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:70
-#, c-format
-msgid "Details"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:74
-#, c-format
-msgid "Delete"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:78
-#, c-format
-msgid "Credentials"
-msgstr ""
-
-#: src/pages/ProfileNavigation.tsx:82
-#, c-format
-msgid "Cashouts"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:95
-#, c-format
-msgid "Unable to create a cashout"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:96
-#, c-format
-msgid "The bank configuration does not support cashout operations."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:223
-#, c-format
-msgid "need to be higher due to fees"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:225
-#, c-format
-msgid "the total transfer at destination will be zero"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:250
-#, c-format
-msgid "Cashout created"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:272
-#, c-format
-msgid "Duplicated request detected, check if the operation succeeded or try again."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:279
-#, c-format
-msgid "The conversion rate was incorrectly applied"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:286
-#, c-format
-msgid "The account does not have sufficient funds"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:293
-#, c-format
-msgid "Cashouts are not supported"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:300
-#, c-format
-msgid "Missing cashout URI in the profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:307
-#, c-format
-msgid ""
-"Sending the confirmation message failed, retry later or contact the "
-"administrator."
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:339
-#, c-format
-msgid "Conversion rate"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:360
-#, c-format
-msgid "Fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:374
-#, c-format
-msgid "To account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:381
-#, c-format
-msgid "No cashout account"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:382
-#, c-format
-msgid "Before doing a cashout you need to complete your profile"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:440
-#, c-format
-msgid "Amount to send"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:441
-#, c-format
-msgid "Amount to receive"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:490
-#, c-format
-msgid "Total cost"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:505
-#, c-format
-msgid "Balance left"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:520
-#, c-format
-msgid "Before fee"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:533
-#, c-format
-msgid "Total cashout transfer"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:553
-#, c-format
-msgid "No cashout channel available"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:555
-#, c-format
-msgid ""
-"Before doing a cashout the server need to provide an second channel to confirm "
-"the operation"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:567
-#, c-format
-msgid "Second factor authentication"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:598
-#, c-format
-msgid "Email"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:600
-#, c-format
-msgid "add a email in your profile to enable this option"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:646
-#, c-format
-msgid "SMS"
-msgstr ""
-
-#: src/pages/business/CreateCashout.tsx:648
-#, c-format
-msgid "add a phone number in your profile to enable this option"
-msgstr ""
-
-#: src/pages/account/CashoutListForAccount.tsx:52
-#, c-format
-msgid "Cashout for account %1$s"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:165
-#, c-format
-msgid "it doesn't have the pattern of an IBAN number"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:185
-#, c-format
-msgid "it doesn't have the pattern of an email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:190
-#, c-format
-msgid "should start with +"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:192
-#, c-format
-msgid "phone number can't have other than numbers"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:329
-#, c-format
-msgid "account identification in the bank"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:365
-#, c-format
-msgid "name of the person owner the account"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:374
-#, c-format
-msgid "Internal IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:377
-#, c-format
-msgid "if empty a random account number will be assigned"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:378
-#, c-format
-msgid "account identification for bank transfer"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:423
-#, c-format
-msgid "Phone"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:451
-#, c-format
-msgid "Cashout IBAN"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:452
-#, c-format
-msgid "account number where the money is going to be sent when doing cashouts"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:470
-#, c-format
-msgid "Max debt"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:494
-#, c-format
-msgid "how much is user able to transfer after zero balance"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:508
-#, c-format
-msgid "Is this a Taler Exchange?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:549
-#, c-format
-msgid "This server doesn't support second factor authentication."
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:560
-#, c-format
-msgid "Enable second factor authentication"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:596
-#, c-format
-msgid "Using email"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:654
-#, c-format
-msgid "Using SMS"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:691
-#, c-format
-msgid "Is this account public?"
-msgstr ""
-
-#: src/pages/admin/AccountForm.tsx:719
-#, c-format
-msgid "public accounts have their balance publicly accessible"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:100
-#, c-format
-msgid "Account updated"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:107
-#, c-format
-msgid "The rights to change the account are not sufficient"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:114
-#, c-format
-msgid "The username was not found"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:121
-#, c-format
-msgid "You can't change the legal name, please contact the your account administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:128
-#, c-format
-msgid "You can't change the debt limit, please contact the your account administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:135
-#, c-format
-msgid ""
-"You can't change the cashout address, please contact the your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:177
-#, c-format
-msgid "Account \"%1$s\""
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:190
-#, c-format
-msgid "Change details"
-msgstr ""
-
-#: src/pages/account/ShowAccountDetails.tsx:235
-#, c-format
-msgid "Update"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:78
-#, c-format
-msgid "password doesn't match"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:95
-#, c-format
-msgid "Password changed"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:102
-#, c-format
-msgid "Not authorized to change the password, maybe the session is invalid."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:112
-#, c-format
-msgid ""
-"You need to provide the old password. If you don't have it contact your account "
-"administrator."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:117
-#, c-format
-msgid "Your current password doesn't match, can't change to a new password."
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:149
-#, c-format
-msgid "Update password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:167
-#, c-format
-msgid "New password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:195
-#, c-format
-msgid "Type it again"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:217
-#, c-format
-msgid "repeat the same password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:227
-#, c-format
-msgid "Current password"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:248
-#, c-format
-msgid "your current password, for security"
-msgstr ""
-
-#: src/pages/account/UpdateAccountPassword.tsx:272
-#, c-format
-msgid "Change"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:74
-#, c-format
-msgid ""
-"Account created with password \"%1$s\". The user must change the password on the "
-"next login."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:83
-#, c-format
-msgid "Server replied that phone or email is invalid"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:90
-#, c-format
-msgid "The rights to perform the operation are not sufficient"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:97
-#, c-format
-msgid "Account username is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:104
-#, c-format
-msgid "Account id is already taken"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:111
-#, c-format
-msgid "Bank ran out of bonus credit."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:118
-#, c-format
-msgid "Account username can't be used because is reserved"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:160
-#, c-format
-msgid "Can't create accounts"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:161
-#, c-format
-msgid "Only system admin can create accounts."
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:183
-#, c-format
-msgid "New business account"
-msgstr ""
-
-#: src/pages/admin/CreateNewAccount.tsx:209
-#, c-format
-msgid "Create"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:94
-#, c-format
-msgid "Can't delete the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:95
-#, c-format
-msgid ""
-"The account can't be delete while still holding some balance. First make sure "
-"that the owner make a complete cashout."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:117
-#, c-format
-msgid "Account removed"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:124
-#, c-format
-msgid "No enough permission to delete the account."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:131
-#, c-format
-msgid "The username was not found."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:138
-#, c-format
-msgid "Can't delete a reserved username."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:145
-#, c-format
-msgid "Can't delete an account with balance different than zero."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:170
-#, c-format
-msgid "name doesn't match"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:180
-#, c-format
-msgid "You are going to remove the account"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:182
-#, c-format
-msgid "This step can't be undone."
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:188
-#, c-format
-msgid "Deleting account \"%1$s\""
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:206
-#, c-format
-msgid "Verification"
-msgstr ""
-
-#: src/pages/admin/RemoveAccount.tsx:231
-#, c-format
-msgid "enter the account name that is going to be deleted"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:49
-#, c-format
-msgid "cashout id should be a number"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:65
-#, c-format
-msgid "This cashout not found. Maybe already aborted."
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:106
-#, c-format
-msgid "Cashout detail"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:139
-#, c-format
-msgid "Debited"
-msgstr ""
-
-#: src/pages/business/ShowCashoutDetails.tsx:154
-#, c-format
-msgid "Credited"
-msgstr ""
-
-#: src/Routing.tsx:140
-#, c-format
-msgid "Welcome to %1$s!"
-msgstr ""
diff --git a/packages/demobank-ui/src/index.html b/packages/demobank-ui/src/index.html
deleted file mode 100644
index 0789ecf89..000000000
--- a/packages/demobank-ui/src/index.html
+++ /dev/null
@@ -1,41 +0,0 @@
-<!--
- This file is part of GNU Taler
- (C) 2021--2022 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-
- @author Sebastian Javier Marchano
--->
-<!doctype html>
-<html lang="en" class="h-full bg-gray-100">
- <head>
- <meta http-equiv="content-type" content="text/html; charset=utf-8" />
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width,initial-scale=1" />
- <meta name="taler-support" content="uri,api" />
- <meta name="mobile-web-app-capable" content="yes" />
- <meta name="apple-mobile-web-app-capable" content="yes" />
- <link
- rel="icon"
- href="data:;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAAAAAAAAD///////////////////////////////////////////////////////////////////////////////////////////////////7//v38//78/P/+/fz//vz7///+/v/+/f3//vz7///+/v/+/fz//v38///////////////////////+/v3///7+/////////////////////////////////////////////////////////v3//v79///////+/v3///////r28v/ct5//06SG/9Gffv/Xqo7/7N/V/9e2nf/bsJb/6uDW/9Sskf/euKH/+/j2///////+/v3//////+3azv+/eE3/2rWd/9Kkhv/Vr5T/48i2/8J+VP/Qn3//3ryn/795Tf/WrpP/2LCW/8B6T//w4Nb///////Pn4P+/d0v/9u3n/+7d0v/EhV7//v///+HDr//fxLD/zph2/+TJt//8/Pv/woBX//Lm3f/y5dz/v3hN//bu6f/JjGn/4sW0///////Df1j/8OLZ//v6+P+/elH/+vj1//jy7f+/elL//////+zYzP/Eg13//////967p//MlHT/wn5X///////v4Nb/yY1s///////jw7H/06KG////////////z5t9/+fNvf//////x4pn//Pp4v/8+vn/w39X/8WEX///////5s/A/9CbfP//////27Oc/9y2n////////////9itlf/gu6f//////86Vdf/r2Mz//////8SCXP/Df1j//////+7d0v/KkG7//////+HBrf/VpYr////////////RnoH/5sq6///////Ii2n/8ubf//39/P/Cf1j/xohk/+bNvv//////wn5W//Tq4//58/D/wHxV//7+/f/59fH/v3xU//39/P/w4Nf/xIFb///////hw7H/yo9t/+/f1f/AeU3/+/n2/+nSxP/FhmD//////9qzm//Upon/4MSx/96+qf//////xINc/+3bz//48e3/v3hN//Pn3///////6M+//752S//gw6//06aK/8J+VP/kzLr/zZd1/8OCWv/q18r/17KZ/9Ooi//fv6r/v3dK/+vWyP///////v39///////27un/1aeK/9Opjv/m1cf/1KCC/9a0nP/n08T/0Jx8/82YdP/QnHz/16yR//jx7P///////v39///////+/f3///7+///////+//7//v7+///////+/v7//v/+/////////////////////////v7//v79///////////////////+/v/+/Pv//v39///+/v/+/Pv///7+//7+/f/+/Pv//v39//79/P/+/Pv///7+////////////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
- />
- <link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
- <title>Bank</title>
- <!-- Entry point for the bank SPA. -->
- <script type="module" src="index.js"></script>
- <link rel="stylesheet" href="index.css" />
- </head>
-
- <body class="h-full">
- <div id="app"></div>
- </body>
-</html>
diff --git a/packages/demobank-ui/src/index.tsx b/packages/demobank-ui/src/index.tsx
deleted file mode 100644
index f559288a3..000000000
--- a/packages/demobank-ui/src/index.tsx
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { App } from "./app.js";
-import { h, render } from "preact";
-import "./scss/main.css";
-
-const app = document.getElementById("app");
-
-if (app) {
- render(<App />, app);
-} else {
- console.error("HTML element with id 'app' not found.");
-}
diff --git a/packages/demobank-ui/src/manifest.json b/packages/demobank-ui/src/manifest.json
deleted file mode 100644
index 8790b10c9..000000000
--- a/packages/demobank-ui/src/manifest.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "name": "taler-bank",
- "short_name": "taler-bank",
- "start_url": "/",
- "display": "standalone",
- "orientation": "portrait",
- "background_color": "#fff",
- "theme_color": "#673ab8",
- "icons": [
- {
- "src": "/assets/icons/android-chrome-192x192.png",
- "type": "image/png",
- "sizes": "192x192"
- },
- {
- "src": "/assets/icons/android-chrome-512x512.png",
- "type": "image/png",
- "sizes": "512x512"
- }
- ]
-}
diff --git a/packages/demobank-ui/src/pages/AccountPage/index.ts b/packages/demobank-ui/src/pages/AccountPage/index.ts
deleted file mode 100644
index 0223b12db..000000000
--- a/packages/demobank-ui/src/pages/AccountPage/index.ts
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- AmountJson,
- TalerCorebankApi,
- TalerError,
-} from "@gnu-taler/taler-util";
-import { Loading, utils } from "@gnu-taler/web-util/browser";
-import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
-import { LoginForm } from "../LoginForm.js";
-import { useComponentState } from "./state.js";
-import { InvalidIbanView, ReadyView } from "./views.js";
-import { RouteDefinition } from "../../route.js";
-
-export interface Props {
- account: string;
- onAuthorizationRequired: () => void;
- onOperationCreated: (wopid: string) => void;
- onClose: () => void;
- tab: "charge-wallet" | "wire-transfer" | undefined;
- routeClose: RouteDefinition;
- routeCashout: RouteDefinition;
- routeChargeWallet: RouteDefinition;
- routeWireTransfer: RouteDefinition<{
- account?: string;
- subject?: string;
- amount?: string;
- }>;
- routePublicAccounts: RouteDefinition;
- routeCreateWireTransfer: RouteDefinition<{
- account?: string;
- subject?: string;
- amount?: string;
- }>;
- routeOperationDetails: RouteDefinition<{ wopid: string }>;
- routeSolveSecondFactor: RouteDefinition;
-}
-
-export type State =
- | State.Loading
- | State.LoadingError
- | State.Ready
- | State.InvalidIban
- | State.UserNotFound;
-
-export namespace State {
- export interface Loading {
- status: "loading";
- error: undefined;
- }
-
- export interface LoadingError {
- status: "loading-error";
- error: TalerError;
- }
-
- export interface BaseInfo {
- error: undefined;
- }
-
- export interface Ready extends BaseInfo {
- status: "ready";
- error: undefined;
- account: string;
- tab: "charge-wallet" | "wire-transfer" | undefined;
- limit: AmountJson;
- onAuthorizationRequired: () => void;
- onOperationCreated: (wopid: string) => void;
- onClose: () => void;
- routeClose: RouteDefinition;
- routeCashout: RouteDefinition;
- routeChargeWallet: RouteDefinition;
- routePublicAccounts: RouteDefinition;
- routeWireTransfer: RouteDefinition<{
- account?: string,
- subject?: string,
- amount?: string,
- }>;
- routeCreateWireTransfer: RouteDefinition<{
- account?: string,
- subject?: string,
- amount?: string,
- }>;
- routeOperationDetails: RouteDefinition<{ wopid: string }>;
- routeSolveSecondFactor: RouteDefinition;
- }
-
- export interface InvalidIban {
- status: "invalid-iban";
- error: TalerCorebankApi.AccountData;
- }
-
- export interface UserNotFound {
- status: "login";
- reason: "not-found" | "forbidden";
- routeRegister?: RouteDefinition;
- }
-}
-
-export interface Transaction {
- negative: boolean;
- counterpart: string;
- when: AbsoluteTime;
- amount: AmountJson | undefined;
- subject: string;
-}
-
-const viewMapping: utils.StateViewMap<State> = {
- loading: Loading,
- login: LoginForm,
- "invalid-iban": InvalidIbanView,
- "loading-error": ErrorLoadingWithDebug,
- ready: ReadyView,
-};
-
-export const AccountPage = utils.compose(
- (p: Props) => useComponentState(p),
- viewMapping,
-);
diff --git a/packages/demobank-ui/src/pages/AccountPage/state.ts b/packages/demobank-ui/src/pages/AccountPage/state.ts
deleted file mode 100644
index e84fef025..000000000
--- a/packages/demobank-ui/src/pages/AccountPage/state.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- Amounts,
- HttpStatusCode,
- TalerError,
- assertUnreachable,
- parsePaytoUri,
-} from "@gnu-taler/taler-util";
-import { useAccountDetails } from "../../hooks/account.js";
-import { Props, State } from "./index.js";
-
-export function useComponentState({
- account,
- tab,
- routeChargeWallet,
- routeCreateWireTransfer,
- routePublicAccounts,
- routeSolveSecondFactor,
- routeOperationDetails,
- routeWireTransfer,
- routeCashout,
- onOperationCreated,
- onClose,
- routeClose,
- onAuthorizationRequired,
-}: Props): State {
- const result = useAccountDetails(account);
-
- if (!result) {
- return {
- status: "loading",
- error: undefined,
- };
- }
-
- if (result instanceof TalerError) {
- return {
- status: "loading-error",
- error: result,
- };
- }
-
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.Unauthorized:
- return {
- status: "login",
- reason: "forbidden",
- };
- case HttpStatusCode.NotFound:
- return {
- status: "login",
- reason: "not-found",
- };
- default: {
- assertUnreachable(result);
- }
- }
- }
-
- const { body: data } = result;
-
- const balance = Amounts.parseOrThrow(data.balance.amount);
-
- const debitThreshold = Amounts.parseOrThrow(data.debit_threshold);
- const payto = parsePaytoUri(data.payto_uri);
-
- if (
- !payto ||
- !payto.isKnown ||
- (payto.targetType !== "iban" && payto.targetType !== "x-taler-bank")
- ) {
- return {
- status: "invalid-iban",
- error: data,
- };
- }
-
- const balanceIsDebit = data.balance.credit_debit_indicator == "debit";
- const limit = balanceIsDebit
- ? Amounts.sub(debitThreshold, balance).amount
- : Amounts.add(balance, debitThreshold).amount;
-
- return {
- status: "ready",
- onOperationCreated,
- error: undefined,
- tab,
- routeCashout,
- routeOperationDetails,
- routeCreateWireTransfer,
- routePublicAccounts,
- routeSolveSecondFactor,
- onAuthorizationRequired,
- onClose,
- routeClose,
- routeChargeWallet,
- routeWireTransfer,
- account,
- limit,
- };
-}
diff --git a/packages/demobank-ui/src/pages/AccountPage/stories.tsx b/packages/demobank-ui/src/pages/AccountPage/stories.tsx
deleted file mode 100644
index fe09a4f89..000000000
--- a/packages/demobank-ui/src/pages/AccountPage/stories.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { ReadyView } from "./views.js";
-
-export default {
- title: "account page",
-};
-
-export const Ready = tests.createExample(ReadyView, {});
diff --git a/packages/demobank-ui/src/pages/AccountPage/test.ts b/packages/demobank-ui/src/pages/AccountPage/test.ts
deleted file mode 100644
index 14c8be948..000000000
--- a/packages/demobank-ui/src/pages/AccountPage/test.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-// import * as tests from "@gnu-taler/web-util/testing";
-// import { SwrMockEnvironment } from "@gnu-taler/web-util/testing";
-// import { expect } from "chai";
-// import { CASHOUT_API_EXAMPLE } from "../../endpoints.js";
-// import { Props } from "./index.js";
-// import { useComponentState } from "./state.js";
-
-describe("Account states", () => {
- it("should do some tests", async () => {});
-});
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx
deleted file mode 100644
index 7165c28b6..000000000
--- a/packages/demobank-ui/src/pages/AccountPage/views.tsx
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { TranslatedString } from "@gnu-taler/taler-util";
-import { Attention, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { Transactions } from "../../components/Transactions/index.js";
-import { useBankState } from "../../hooks/bank-state.js";
-import { usePreferences } from "../../hooks/preferences.js";
-import { PaymentOptions } from "../PaymentOptions.js";
-import { State } from "./index.js";
-import { RouteDefinition } from "../../route.js";
-
-export function InvalidIbanView({ error }: State.InvalidIban) {
- return (
- <div>Payto from server is not valid &quot;{error.payto_uri}&quot;</div>
- );
-}
-
-const IS_PUBLIC_ACCOUNT_ENABLED = false;
-
-function ShowDemoInfo({ routePublicAccounts }: {
- routePublicAccounts: RouteDefinition;
-}): VNode {
- const { i18n } = useTranslationContext();
- const [settings, updateSettings] = usePreferences();
- if (!settings.showDemoDescription) return <Fragment />;
- return (
- <Attention
- title={i18n.str`This is a demo bank`}
- onClose={() => {
- updateSettings("showDemoDescription", false);
- }}
- >
- {IS_PUBLIC_ACCOUNT_ENABLED ? (
- <i18n.Translate>
- This part of the demo shows how a bank that supports Taler directly
- would work. In addition to using your own bank account, you can also
- see the transaction history of some{" "}
- <a name="public account" href={routePublicAccounts.url({})}>Public Accounts</a>.
- </i18n.Translate>
- ) : (
- <i18n.Translate>
- This part of the demo shows how a bank that supports Taler directly
- would work.
- </i18n.Translate>
- )}
- </Attention>
- );
-}
-
-function ShowPedingOperation({ routeSolveSecondFactor }: {
- routeSolveSecondFactor: RouteDefinition;
-}): VNode {
- const { i18n } = useTranslationContext();
- const [bankState, updateBankState] = useBankState();
- if (!bankState.currentChallenge) return <Fragment />;
- const title = ((op): TranslatedString => {
- switch (op) {
- case "delete-account":
- return i18n.str`Pending account delete operation`;
- case "update-account":
- return i18n.str`Pending account update operation`;
- case "update-password":
- return i18n.str`Pending password update operation`;
- case "create-transaction":
- return i18n.str`Pending transaction operation`;
- case "confirm-withdrawal":
- return i18n.str`Pending withdrawal operation`;
- case "create-cashout":
- return i18n.str`Pending cashout operation`;
- }
- })(bankState.currentChallenge.operation);
- return (
- <Attention
- title={title}
- type="warning"
- onClose={() => {
- updateBankState("currentChallenge", undefined);
- }}
- >
- <i18n.Translate>
- You can complete or cancel the operation in
- </i18n.Translate>{" "}
- <a
- class="font-semibold text-yellow-700 hover:text-yellow-600"
- name="complete operation"
- href={routeSolveSecondFactor.url({})}
- >
- <i18n.Translate>this page</i18n.Translate>
- </a>
- </Attention>
- );
-}
-
-export function ReadyView({
- tab,
- account,
- routeChargeWallet,
- routeWireTransfer,
- limit,
- routeCashout,
- routeCreateWireTransfer,
- routePublicAccounts,
- routeOperationDetails,
- routeSolveSecondFactor,
- onClose,
- routeClose,
- onOperationCreated,
- onAuthorizationRequired,
-}: State.Ready): VNode {
- return (
- <Fragment>
- <ShowPedingOperation routeSolveSecondFactor={routeSolveSecondFactor} />
- <ShowDemoInfo routePublicAccounts={routePublicAccounts} />
- <PaymentOptions
- tab={tab}
- routeOperationDetails={routeOperationDetails}
- routeCashout={routeCashout}
- routeChargeWallet={routeChargeWallet}
- routeWireTransfer={routeWireTransfer}
- limit={limit}
- routeClose={routeClose}
- onClose={onClose}
- onOperationCreated={onOperationCreated}
- onAuthorizationRequired={onAuthorizationRequired}
- />
- <Transactions account={account} routeCreateWireTransfer={routeCreateWireTransfer} />
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/BankFrame.stories.tsx b/packages/demobank-ui/src/pages/BankFrame.stories.tsx
deleted file mode 100644
index c874ac4ca..000000000
--- a/packages/demobank-ui/src/pages/BankFrame.stories.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { BankFrame } from "./BankFrame.js";
-
-export default {
- title: "bank frame",
-};
-
-export const Ready = tests.createExample(BankFrame, {});
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx
deleted file mode 100644
index 427e9a156..000000000
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { Amounts, TalerError, TranslatedString } from "@gnu-taler/taler-util";
-import {
- Footer,
- Header,
- Loading,
- ToastBanner,
- notifyError,
- notifyException,
- useTranslationContext
-} from "@gnu-taler/web-util/browser";
-import { ComponentChildren, VNode, h } from "preact";
-import { useEffect, useErrorBoundary } from "preact/hooks";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useSettingsContext } from "../context/settings.js";
-import { useAccountDetails } from "../hooks/account.js";
-import { useSessionState } from "../hooks/session.js";
-import { useBankState } from "../hooks/bank-state.js";
-import {
- getAllBooleanPreferences,
- getLabelForPreferences,
- usePreferences,
-} from "../hooks/preferences.js";
-import { RouteDefinition } from "../route.js";
-import { RenderAmount } from "./PaytoWireTransferForm.js";
-
-const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
-const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
-
-export function BankFrame({
- children,
- account,
- routeAccountDetails,
-}: {
- account?: string;
- routeAccountDetails?: RouteDefinition;
- children: ComponentChildren;
-}): VNode {
- const { i18n } = useTranslationContext();
- const session = useSessionState();
- const settings = useSettingsContext();
- const [preferences, updatePreferences] = usePreferences();
- const [, , resetBankState] = useBankState();
-
- const [error, resetError] = useErrorBoundary();
-
- useEffect(() => {
- if (error) {
- if (error instanceof Error) {
- console.log("Internal error, please report", error);
- notifyException(i18n.str`Internal error, please report.`, error);
- } else {
- console.log("Internal error, please report", error);
- notifyError(
- i18n.str`Internal error, please report.`,
- String(error) as TranslatedString,
- );
- }
- resetError();
- }
- }, [error]);
-
- return (
- <div
- class="min-h-full flex flex-col m-0 bg-slate-200"
- style="min-height: 100vh;"
- >
- <div class="bg-indigo-600 pb-32">
- <Header
- title="Bank"
- iconLinkURL={settings.iconLinkURL ?? "#"}
- profileURL={routeAccountDetails?.url({})}
- onLogout={
- session.state.status !== "loggedIn"
- ? undefined
- : () => {
- session.logOut();
- resetBankState();
- }
- }
- sites={
- !settings.topNavSites ? [] : Object.entries(settings.topNavSites)
- }
- supportedLangs={["en", "es", "de"]}
- >
- <li>
- <div class="text-xs font-semibold leading-6 text-gray-400">
- <i18n.Translate>Preferences</i18n.Translate>
- </div>
- <ul role="list" class="space-y-1">
- {getAllBooleanPreferences().map((set) => {
- const isOn: boolean = !!preferences[set];
- return (
- <li key={set} class="mt-2 pl-2">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- {getLabelForPreferences(set, i18n)}
- </span>
- </span>
- <button
- type="button"
- name={`${set} switch`}
- data-enabled={isOn}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- updatePreferences(set, !isOn);
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={isOn}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </li>
- );
- })}
- </ul>
- </li>
- </Header>
- </div>
-
- <div class="fixed z-20 w-full">
- <div class="mx-auto w-4/5">
- <ToastBanner />
- </div>
- </div>
-
- <main class="-mt-32 flex-1">
- {account && routeAccountDetails && (
- <header class="py-5 bg-indigo-600 ">
- <div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
- <h1 class=" flex flex-wrap items-center justify-between sm:flex-nowrap">
- <span class="text-2xl font-bold tracking-tight text-white">
- <WelcomeAccount account={account} routeAccountDetails={routeAccountDetails} />
- </span>
- <span class="text-2xl font-bold tracking-tight text-white">
- <AccountBalance account={account} />
- </span>
- </h1>
- </div>
- </header>
- )}
-
- <div class="mx-auto max-w-7xl px-4 pb-12 sm:px-6 lg:px-8">
- <div class="rounded-lg bg-white px-5 py-6 shadow sm:px-6">
- {children}
- </div>
- </div>
- </main>
-
- <Footer
- testingUrlKey="corebank-api-base-url"
- GIT_HASH={GIT_HASH}
- VERSION={VERSION}
- />
- </div>
- );
-}
-
-function WelcomeAccount({ account, routeAccountDetails }: {
- account: string,
- routeAccountDetails: RouteDefinition;
-}): VNode {
- const { i18n } = useTranslationContext();
- const result = useAccountDetails(account);
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <div />;
- }
- if (result.type === "fail") {
- return (
- <a name="account details"
- href={routeAccountDetails.url({})}
- class="underline underline-offset-2"
- >
- <i18n.Translate>Welcome</i18n.Translate>
- </a>
- );
- }
- return (
- <a name="account details"
- href={routeAccountDetails.url({})}
- class="underline underline-offset-2"
- >
- <i18n.Translate>
- Welcome, <span class="whitespace-nowrap">{result.body.name}</span>
- </i18n.Translate>
- </a>
- );
-}
-
-function AccountBalance({ account }: { account: string }): VNode {
- const result = useAccountDetails(account);
- const { config } = useBankCoreApiContext();
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <div />;
- }
- if (result.type === "fail") return <div />;
-
- return (
- <RenderAmount
- value={Amounts.parseOrThrow(result.body.balance.amount)}
- negative={result.body.balance.credit_debit_indicator === "debit"}
- spec={config.currency_specification}
- />
- );
-}
diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx
deleted file mode 100644
index bd20e79c8..000000000
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- HttpStatusCode
-} from "@gnu-taler/taler-util";
-import {
- Button,
- LocalNotificationBanner,
- ShowInputErrorLabel,
- useLocalNotificationHandler,
- useTranslationContext
-} from "@gnu-taler/web-util/browser";
-import { VNode, h } from "preact";
-import { useEffect, useRef, useState } from "preact/hooks";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useSessionState } from "../hooks/session.js";
-import { RouteDefinition } from "../route.js";
-import { undefinedIfEmpty } from "../utils.js";
-import { doAutoFocus } from "./PaytoWireTransferForm.js";
-
-/**
- * Collect and submit login data.
- */
-export function LoginForm({
- currentUser,
- fixedUser,
- routeRegister,
-}: {
- fixedUser?: boolean;
- currentUser?: string;
- routeRegister?: RouteDefinition;
-}): VNode {
- const session = useSessionState();
-
- const sessionUser =
- session.state.status !== "loggedOut" ? session.state.username : undefined;
- const [username, setUsername] = useState<string | undefined>(
- currentUser ?? sessionUser,
- );
- const [password, setPassword] = useState<string | undefined>();
- const { i18n } = useTranslationContext();
- const { authenticator } = useBankCoreApiContext();
- const [notification, withErrorHandler] = useLocalNotificationHandler();
- const { config } = useBankCoreApiContext();
-
- const ref = useRef<HTMLInputElement>(null);
- useEffect(function focusInput() {
- ref.current?.focus();
- }, []);
-
- const errors =
- undefinedIfEmpty({
- username: !username
- ? i18n.str`Missing username`
- : // : !USERNAME_REGEX.test(username)
- // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- undefined,
- password: !password ? i18n.str`Missing password` : undefined,
- });
-
- async function doLogout() {
- session.logOut();
- }
-
- const loginHandler = !username || !password ? undefined : withErrorHandler(
- async () => authenticator(username)
- .createAccessToken(password, {
- // scope: "readwrite" as "write", // FIX: different than merchant
- scope: "readwrite",
- duration: { d_us: "forever" },
- refreshable: true,
- }),
- (result) => {
- session.logIn({ username, token: result.body.access_token })
- },
- (fail) => {
- switch (fail.case) {
- case HttpStatusCode.Unauthorized: return i18n.str`Wrong credentials for "${username}"`;
- case HttpStatusCode.NotFound: return i18n.str`Account not found`;
- }
- }
- )
-
- return (
- <div class="flex min-h-full flex-col justify-center ">
- <LocalNotificationBanner notification={notification} />
- <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
- <form
- class="space-y-6"
- noValidate
- onSubmit={(e) => {
- e.preventDefault();
- }}
- autoCapitalize="none"
- autoCorrect="off"
- >
- <div>
- <label
- for="username"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Username</i18n.Translate>
- </label>
- <div class="mt-2">
- <input
- ref={doAutoFocus}
- type="text"
- name="username"
- id="username"
- class="block w-full disabled:bg-gray-200 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={username ?? ""}
- disabled={fixedUser}
- enterkeyhint="next"
- placeholder="identification"
- autocomplete="username"
- title={i18n.str`Username of the account`}
- required
- onInput={(e): void => {
- setUsername(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.username}
- isDirty={username !== undefined}
- />
- </div>
- </div>
-
- <div>
- <div class="flex items-center justify-between">
- <label
- for="password"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Password</i18n.Translate>
- </label>
- </div>
- <div class="mt-2">
- <input
- type="password"
- name="password"
- id="password"
- autocomplete="current-password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- enterkeyhint="send"
- value={password ?? ""}
- placeholder="Password"
- title={i18n.str`Password of the account`}
- required
- onInput={(e): void => {
- setPassword(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.password}
- isDirty={password !== undefined}
- />
- </div>
- </div>
-
- {session.state.status !== "loggedOut" ? (
- <div class="flex justify-between">
- <button
- type="submit"
- name="cancel"
- class="rounded-md bg-white-600 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-gray-100 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-600"
- onClick={(e) => {
- e.preventDefault();
- doLogout();
- }}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
-
- <Button
- type="submit"
- name="check"
- class="rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- handler={loginHandler}
- >
- <i18n.Translate>Check</i18n.Translate>
- </Button>
- </div>
- ) : (
- <div>
- <Button
- type="submit"
- name="login"
- class="flex w-full justify-center rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- handler={loginHandler}
- >
- <i18n.Translate>Log in</i18n.Translate>
- </Button>
- </div>
- )}
- </form>
-
- {config.allow_registrations && routeRegister && (
- <a
- name="register"
- href={routeRegister.url({})}
- class="flex justify-center border-t mt-4 rounded-md bg-blue-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-blue-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600"
- >
- <i18n.Translate>Register</i18n.Translate>
- </a>
- )}
- </div>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/pages/OperationState/index.ts b/packages/demobank-ui/src/pages/OperationState/index.ts
deleted file mode 100644
index e4d9d45e3..000000000
--- a/packages/demobank-ui/src/pages/OperationState/index.ts
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- AmountJson,
- TalerCoreBankErrorsByMethod,
- TalerError,
- WithdrawUriResult,
-} from "@gnu-taler/taler-util";
-import { Loading, utils } from "@gnu-taler/web-util/browser";
-import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
-import { useComponentState } from "./state.js";
-import {
- AbortedView,
- ConfirmedView,
- FailedView,
- InvalidPaytoView,
- InvalidReserveView,
- InvalidWithdrawalView,
- NeedConfirmationView,
- ReadyView,
-} from "./views.js";
-import { RouteDefinition } from "../../route.js";
-
-export interface Props {
- currency: string;
- onAuthorizationRequired: () => void;
- routeClose: RouteDefinition;
- onAbort: () => void;
- routeHere: RouteDefinition<{ wopid: string }>;
-}
-
-export type State =
- | State.Loading
- | State.LoadingError
- | State.Ready
- | State.Failed
- | State.Aborted
- | State.Confirmed
- | State.InvalidPayto
- | State.InvalidWithdrawal
- | State.InvalidReserve
- | State.NeedConfirmation;
-
-export namespace State {
- export interface Loading {
- status: "loading";
- error: undefined;
- }
-
- export interface Failed {
- status: "failed";
- error: TalerCoreBankErrorsByMethod<"createWithdrawal">;
- }
-
- export interface LoadingError {
- status: "loading-error";
- error: TalerError;
- }
-
- /**
- * Need to open the wallet
- */
- export interface Ready {
- status: "ready";
- error: undefined;
- uri: WithdrawUriResult;
- onAbort: () => Promise<
- TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined
- >;
- routeClose: RouteDefinition;
- }
-
- export interface InvalidPayto {
- status: "invalid-payto";
- error: undefined;
- payto: string | undefined;
- }
- export interface InvalidWithdrawal {
- status: "invalid-withdrawal";
- error: undefined;
- uri: string;
- }
- export interface InvalidReserve {
- status: "invalid-reserve";
- error: undefined;
- reserve: string | undefined;
- }
- export interface NeedConfirmation {
- status: "need-confirmation";
- onAuthorizationRequired: () => void;
- account: string;
- routeHere: RouteDefinition<{ wopid: string }>;
- onAbort:
- | undefined
- | (() => Promise<
- TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined
- >);
- onConfirm:
- | undefined
- | (() => Promise<
- TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined
- >);
- error: undefined;
- id: string;
- }
- export interface Aborted {
- status: "aborted";
- error: undefined;
- routeClose: RouteDefinition;
- }
- export interface Confirmed {
- status: "confirmed";
- error: undefined;
- routeClose: RouteDefinition;
- }
-}
-
-export interface Transaction {
- negative: boolean;
- counterpart: string;
- when: AbsoluteTime;
- amount: AmountJson | undefined;
- subject: string;
-}
-
-const viewMapping: utils.StateViewMap<State> = {
- loading: Loading,
- failed: FailedView,
- "invalid-payto": InvalidPaytoView,
- "invalid-withdrawal": InvalidWithdrawalView,
- "invalid-reserve": InvalidReserveView,
- "need-confirmation": NeedConfirmationView,
- aborted: AbortedView,
- confirmed: ConfirmedView,
- "loading-error": ErrorLoadingWithDebug,
- ready: ReadyView,
-};
-
-export const OperationState = utils.compose(
- (p: Props) => useComponentState(p),
- viewMapping,
-);
diff --git a/packages/demobank-ui/src/pages/OperationState/state.ts b/packages/demobank-ui/src/pages/OperationState/state.ts
deleted file mode 100644
index 5baf2d51c..000000000
--- a/packages/demobank-ui/src/pages/OperationState/state.ts
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- Amounts,
- HttpStatusCode,
- TalerCoreBankErrorsByMethod,
- TalerError,
- assertUnreachable,
- parsePaytoUri,
- parseWithdrawUri,
- stringifyWithdrawUri,
-} from "@gnu-taler/taler-util";
-import { utils } from "@gnu-taler/web-util/browser";
-import { useEffect, useState } from "preact/hooks";
-import { mutate } from "swr";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useWithdrawalDetails } from "../../hooks/account.js";
-import { useSessionState } from "../../hooks/session.js";
-import { useBankState } from "../../hooks/bank-state.js";
-import { usePreferences } from "../../hooks/preferences.js";
-import { Props, State } from "./index.js";
-
-export function useComponentState({
- currency,
- routeClose,
- onAbort,
- routeHere,
- onAuthorizationRequired,
-}: Props): utils.RecursiveState<State> {
- const [settings] = usePreferences();
- const [bankState, updateBankState] = useBankState();
- const { state: credentials } = useSessionState();
- const creds = credentials.status !== "loggedIn" ? undefined : credentials;
- const { bank } = useBankCoreApiContext();
-
- const [failure, setFailure] = useState<
- TalerCoreBankErrorsByMethod<"createWithdrawal"> | undefined
- >();
- const amount = settings.maxWithdrawalAmount;
-
- async function doSilentStart() {
- // FIXME: if amount is not enough use balance
- const parsedAmount = Amounts.parseOrThrow(`${currency}:${amount}`);
- if (!creds) return;
- const resp = await bank.createWithdrawal(creds, {
- amount: Amounts.stringify(parsedAmount),
- });
- if (resp.type === "fail") {
- setFailure(resp);
- return;
- }
- updateBankState("currentWithdrawalOperationId", resp.body.withdrawal_id);
- }
-
- const withdrawalOperationId = bankState.currentWithdrawalOperationId;
- useEffect(() => {
- if (withdrawalOperationId === undefined) {
- doSilentStart();
- }
- }, [settings.fastWithdrawal, amount]);
-
- if (failure) {
- return {
- status: "failed",
- error: failure,
- };
- }
-
- if (!withdrawalOperationId) {
- return {
- status: "loading",
- error: undefined,
- };
- }
-
- const wid = withdrawalOperationId;
-
- async function doAbort() {
- if (!creds) return;
- const resp = await bank.abortWithdrawalById(creds, wid);
- if (resp.type === "ok") {
- // updateBankState("currentWithdrawalOperationId", undefined)
- onAbort();
- } else {
- return resp;
- }
- }
-
- async function doConfirm(): Promise<
- TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined
- > {
- if (!creds) return;
- const resp = await bank.confirmWithdrawalById(creds, wid);
- if (resp.type === "ok") {
- mutate(() => true); //clean withdrawal state
- } else {
- return resp;
- }
- }
-
- const uri = stringifyWithdrawUri({
- bankIntegrationApiBaseUrl: bank.getIntegrationAPI(),
- withdrawalOperationId,
- });
- const parsedUri = parseWithdrawUri(uri);
- if (!parsedUri) {
- return {
- status: "invalid-withdrawal",
- error: undefined,
- uri,
- };
- }
-
- return (): utils.RecursiveState<State> => {
- const result = useWithdrawalDetails(withdrawalOperationId);
- const shouldCreateNewOperation = result && !(result instanceof TalerError);
-
- useEffect(() => {
- if (shouldCreateNewOperation) {
- doSilentStart();
- }
- }, []);
- if (!result) {
- return {
- status: "loading",
- error: undefined,
- };
- }
- if (result instanceof TalerError) {
- return {
- status: "loading-error",
- error: result,
- };
- }
-
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.BadRequest:
- case HttpStatusCode.NotFound: {
- return {
- status: "aborted",
- error: undefined,
- routeClose,
- };
- }
- default:
- assertUnreachable(result);
- }
- }
-
- const { body: data } = result;
- if (data.status === "aborted") {
- return {
- status: "aborted",
- error: undefined,
- routeClose,
- };
- }
-
- if (data.status === "confirmed") {
- if (!settings.showWithdrawalSuccess) {
- updateBankState("currentWithdrawalOperationId", undefined);
- // onClose()
- }
- return {
- status: "confirmed",
- error: undefined,
- routeClose,
- };
- }
-
- if (data.status === "pending") {
- return {
- status: "ready",
- error: undefined,
- uri: parsedUri,
- routeClose,
- onAbort: !creds
- ? async () => {
- onAbort();
- return undefined;
- }
- : doAbort,
- };
- }
-
- if (!data.selected_reserve_pub) {
- return {
- status: "invalid-reserve",
- error: undefined,
- reserve: data.selected_reserve_pub,
- };
- }
-
- const account = !data.selected_exchange_account
- ? undefined
- : parsePaytoUri(data.selected_exchange_account);
-
- if (!account) {
- return {
- status: "invalid-payto",
- error: undefined,
- payto: data.selected_exchange_account,
- };
- }
-
- return {
- status: "need-confirmation",
- error: undefined,
- routeHere,
- onAuthorizationRequired,
- account: data.username,
- id: withdrawalOperationId,
- onAbort: !creds ? undefined : doAbort,
- onConfirm: !creds ? undefined : doConfirm,
- };
- };
-}
diff --git a/packages/demobank-ui/src/pages/OperationState/stories.tsx b/packages/demobank-ui/src/pages/OperationState/stories.tsx
deleted file mode 100644
index 82253b82c..000000000
--- a/packages/demobank-ui/src/pages/OperationState/stories.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { ReadyView } from "./views.js";
-
-export default {
- title: "operation status page",
-};
-
-export const Ready = tests.createExample(ReadyView, {});
diff --git a/packages/demobank-ui/src/pages/OperationState/test.ts b/packages/demobank-ui/src/pages/OperationState/test.ts
deleted file mode 100644
index d47cb64a2..000000000
--- a/packages/demobank-ui/src/pages/OperationState/test.ts
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-// import * as tests from "@gnu-taler/web-util/testing";
-// import { SwrMockEnvironment } from "@gnu-taler/web-util/testing";
-// import { expect } from "chai";
-// import { CASHOUT_API_EXAMPLE } from "../../endpoints.js";
-// import { Props } from "./index.js";
-// import { useComponentState } from "./state.js";
-
-describe("Withdrawal operation states", () => {
- it("should do some tests", async () => {});
-});
diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx b/packages/demobank-ui/src/pages/OperationState/views.tsx
deleted file mode 100644
index 6eee6daa9..000000000
--- a/packages/demobank-ui/src/pages/OperationState/views.tsx
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- HttpStatusCode,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
- stringifyWithdrawUri,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- LocalNotificationBanner,
- notifyInfo,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useEffect } from "preact/hooks";
-import { QR } from "../../components/QR.js";
-import { useBankState } from "../../hooks/bank-state.js";
-import { usePreferences } from "../../hooks/preferences.js";
-import { ShouldBeSameUser } from "../WithdrawalConfirmationQuestion.js";
-import { State } from "./index.js";
-import { useTalerWalletIntegrationAPI } from "../../context/wallet-integration.js";
-
-export function InvalidPaytoView({ payto }: State.InvalidPayto) {
- return <div>Payto from server is not valid &quot;{payto}&quot;</div>;
-}
-export function InvalidWithdrawalView({ uri }: State.InvalidWithdrawal) {
- return <div>Withdrawal uri from server is not valid &quot;{uri}&quot;</div>;
-}
-export function InvalidReserveView({ reserve }: State.InvalidReserve) {
- return <div>Reserve from server is not valid &quot;{reserve}&quot;</div>;
-}
-
-export function NeedConfirmationView({
- onAbort: doAbort,
- onConfirm: doConfirm,
- routeHere,
- account,
- id,
- onAuthorizationRequired,
-}: State.NeedConfirmation) {
- const { i18n } = useTranslationContext();
- const [settings] = usePreferences();
- const [notification, notify, errorHandler] = useLocalNotification();
- const [, updateBankState] = useBankState();
-
- async function onCancel() {
- errorHandler(async () => {
- if (!doAbort) return;
- const resp = await doAbort();
- if (!resp) return;
- switch (resp.case) {
- case HttpStatusCode.Conflict:
- return notify({
- type: "error",
- title: i18n.str`The reserve operation has been confirmed previously and can't be aborted`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.BadRequest:
- return notify({
- type: "error",
- title: i18n.str`The operation id is invalid.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`The operation was not found.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- default:
- assertUnreachable(resp);
- }
- });
- }
-
- async function onConfirm() {
- errorHandler(async () => {
- if (!doConfirm) return;
- const resp = await doConfirm();
- if (!resp) {
- if (!settings.showWithdrawalSuccess) {
- notifyInfo(i18n.str`Wire transfer completed!`);
- }
- return;
- }
- switch (resp.case) {
- case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT:
- return notify({
- type: "error",
- title: i18n.str`The withdrawal has been aborted previously and can't be confirmed`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
- return notify({
- type: "error",
- title: i18n.str`The withdrawal operation can't be confirmed before a wallet accepted the transaction.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.BadRequest:
- return notify({
- type: "error",
- title: i18n.str`The operation id is invalid.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`The operation was not found.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_UNALLOWED_DEBIT:
- return notify({
- type: "error",
- title: i18n.str`Your balance is not enough.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Accepted: {
- updateBankState("currentChallenge", {
- operation: "confirm-withdrawal",
- id: String(resp.body.challenge_id),
- sent: AbsoluteTime.never(),
- location: routeHere.url({ wopid: id }),
- request: id,
-
- });
- return onAuthorizationRequired();
- }
- default:
- assertUnreachable(resp);
- }
- });
- }
-
- return (
- <div class="bg-white shadow sm:rounded-lg">
- <LocalNotificationBanner notification={notification} />
- <div class="px-4 py-5 sm:p-6">
- <h3 class="text-base font-semibold text-gray-900">
- <i18n.Translate>Confirm the withdrawal operation</i18n.Translate>
- </h3>
- <div class="mt-3 text-sm leading-6">
- <ShouldBeSameUser username={account}>
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <button
- type="button"
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- onClick={(e) => {
- e.preventDefault();
- onCancel();
- }}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
- <button
- type="submit"
- name="transfer"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- onClick={(e) => {
- e.preventDefault();
- onConfirm();
- }}
- >
- <i18n.Translate>Transfer</i18n.Translate>
- </button>
- </div>
- </form>
- </ShouldBeSameUser>
- </div>
- </div>
- </div>
- );
-}
-export function FailedView({ error }: State.Failed) {
- const { i18n } = useTranslationContext();
- switch (error.case) {
- case HttpStatusCode.Unauthorized:
- return (
- <Attention
- type="danger"
- title={i18n.str`Unauthorized to make the operation, maybe the session has expired or the password changed.`}
- >
- <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div>
- </Attention>
- );
- case HttpStatusCode.Conflict:
- return (
- <Attention
- type="danger"
- title={i18n.str`The operation was rejected due to insufficient funds.`}
- >
- <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div>
- </Attention>
- );
- case HttpStatusCode.NotFound:
- return (
- <Attention
- type="danger"
- title={i18n.str`The operation was rejected due to insufficient funds.`}
- >
- <div class="mt-2 text-sm text-red-700">{error.detail.hint}</div>
- </Attention>
- );
- default:
- assertUnreachable(error);
- }
-}
-
-export function AbortedView() {
- return <div>aborted</div>;
-}
-
-export function ConfirmedView({ routeClose }: State.Confirmed) {
- const { i18n } = useTranslationContext();
- const [settings, updateSettings] = usePreferences();
- return (
- <Fragment>
- <div class="relative ml-auto mr-auto transform overflow-hidden rounded-lg bg-white p-4 text-left shadow-xl transition-all ">
- <div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
- <svg
- class="h-6 w-6 text-green-600"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- aria-hidden="true"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M4.5 12.75l6 6 9-13.5"
- />
- </svg>
- </div>
- <div class="mt-3 text-center sm:mt-5">
- <h3
- class="text-base font-semibold leading-6 text-gray-900"
- id="modal-title"
- >
- <i18n.Translate>Withdrawal confirmed</i18n.Translate>
- </h3>
- <div class="mt-2">
- <p class="text-sm text-gray-500">
- <i18n.Translate>
- The wire transfer to the Taler operator has been initiated. You
- will soon receive the requested amount in your Taler wallet.
- </i18n.Translate>
- </p>
- </div>
- </div>
- </div>
- <div class="mt-4">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Do not show this again</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name="toggle withdrawal"
- data-enabled={!settings.showWithdrawalSuccess}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- updateSettings(
- "showWithdrawalSuccess",
- !settings.showWithdrawalSuccess,
- );
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={!settings.showWithdrawalSuccess}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- <div class="mt-5 sm:mt-6">
- <a
- href={routeClose.url({})}
- type="button"
- name="close"
- class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Close</i18n.Translate>
- </a>
- </div>
- </Fragment>
- );
-}
-
-export function ReadyView({
- uri,
- onAbort: doAbort,
-}: State.Ready): VNode {
- const { i18n } = useTranslationContext();
- const walletInegrationApi = useTalerWalletIntegrationAPI();
- const [notification, notify, errorHandler] = useLocalNotification();
-
- const talerWithdrawUri = stringifyWithdrawUri(uri);
- useEffect(() => {
- walletInegrationApi.publishTalerAction(uri);
- }, []);
-
- async function onAbort() {
- errorHandler(async () => {
- const hasError = await doAbort();
- if (!hasError) return;
- switch (hasError.case) {
- case HttpStatusCode.Conflict:
- return notify({
- type: "error",
- title: i18n.str`The reserve operation has been confirmed previously and can't be aborted`,
- description: hasError.detail.hint as TranslatedString,
- debug: hasError.detail,
- });
- case HttpStatusCode.BadRequest:
- return notify({
- type: "error",
- title: i18n.str`The operation id is invalid.`,
- description: hasError.detail.hint as TranslatedString,
- debug: hasError.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`The operation was not found.`,
- description: hasError.detail.hint as TranslatedString,
- debug: hasError.detail,
- });
- default:
- assertUnreachable(hasError);
- }
- });
- }
-
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} />
-
- <div class="flex justify-end mt-4">
- <button
- type="button"
- name="cancel"
- class="inline-flex items-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
- onClick={onAbort}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
- </div>
-
- <div class="bg-white shadow sm:rounded-lg mt-4">
- <div class="p-4">
- <h3 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>On this device</i18n.Translate>
- </h3>
- <div class="mt-2 sm:flex sm:items-start sm:justify-between">
- <div class="max-w-xl text-sm text-gray-500">
- <p>
- <i18n.Translate>
- If you are using a web browser on desktop you can also
- </i18n.Translate>
- </p>
- </div>
- <div class="mt-5 sm:ml-6 sm:mt-0 sm:flex sm:flex-shrink-0 sm:items-center">
- <a
- href={talerWithdrawUri}
- name="start"
- class="inline-flex items-center disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Start</i18n.Translate>
- </a>
- </div>
- </div>
- </div>
- </div>
- <div class="bg-white shadow sm:rounded-lg mt-2">
- <div class="p-4">
- <h3 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>On a mobile phone</i18n.Translate>
- </h3>
- <div class="mt-2 sm:flex sm:items-start sm:justify-between">
- <div class="max-w-xl text-sm text-gray-500">
- <p>
- <i18n.Translate>
- Scan the QR code with your mobile device.
- </i18n.Translate>
- </p>
- </div>
- </div>
- <div class="mt-2 max-w-md ml-auto mr-auto">
- <QR text={talerWithdrawUri} />
- </div>
- </div>
- </div>
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/PaymentOptions.stories.tsx b/packages/demobank-ui/src/pages/PaymentOptions.stories.tsx
deleted file mode 100644
index 78af886a8..000000000
--- a/packages/demobank-ui/src/pages/PaymentOptions.stories.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { PaymentOptions } from "./PaymentOptions.js";
-
-export default {
- title: "PaymentOptions",
-};
-
-export const USD = tests.createExample(PaymentOptions, {
- limit: {
- currency: "USD",
- fraction: 0,
- value: 1,
- },
-});
diff --git a/packages/demobank-ui/src/pages/PaymentOptions.tsx b/packages/demobank-ui/src/pages/PaymentOptions.tsx
deleted file mode 100644
index 48ecc7525..000000000
--- a/packages/demobank-ui/src/pages/PaymentOptions.tsx
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { AmountJson, TalerError } from "@gnu-taler/taler-util";
-import { Fragment, VNode, h } from "preact";
-import { useBankState } from "../hooks/bank-state.js";
-import { PaytoWireTransferForm } from "./PaytoWireTransferForm.js";
-import { WalletWithdrawForm } from "./WalletWithdrawForm.js";
-import { EmptyObject, RouteDefinition } from "../route.js";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { useWithdrawalDetails } from "../hooks/account.js";
-import { useEffect } from "preact/hooks";
-import { useSessionState } from "../hooks/session.js";
-
-function ShowOperationPendingTag({
- woid,
- onOperationAlreadyCompleted,
-}: {
- woid: string;
- onOperationAlreadyCompleted?: () => void;
-}): VNode {
- const { i18n } = useTranslationContext();
- const { state: credentials } = useSessionState();
- const result = useWithdrawalDetails(woid);
- const loading = !result
- const error =
- !loading && (result instanceof TalerError || result.type === "fail");
- const pending =
- !loading && !error &&
- (result.body.status === "pending" || result.body.status === "selected")
- && credentials.status === "loggedIn"
- && credentials.username === result.body.username;
- useEffect(() => {
- if (!loading && !pending && onOperationAlreadyCompleted) {
- onOperationAlreadyCompleted();
- }
- }, [pending]);
-
- if (error || !pending) {
- return <Fragment />;
- }
-
- return (
- <span class="flex items-center gap-x-1.5 w-fit rounded-md bg-green-100 px-2 py-1 text-xs font-medium text-green-700 whitespace-pre">
- <svg
- class="h-1.5 w-1.5 fill-green-500"
- viewBox="0 0 6 6"
- aria-hidden="true"
- >
- <circle cx="3" cy="3" r="3" />
- </svg>
- <i18n.Translate>Operation ready</i18n.Translate>
- </span>
- );
-}
-
-/**
- * Let the user choose a payment option,
- * then specify the details trigger the action.
- */
-export function PaymentOptions({
- routeClose,
- routeCashout,
- routeChargeWallet,
- routeWireTransfer,
- tab,
- limit,
- onOperationCreated,
- onClose,
- routeOperationDetails,
- onAuthorizationRequired,
-}: {
- limit: AmountJson;
- tab: "charge-wallet" | "wire-transfer" | undefined;
- onAuthorizationRequired: () => void;
- onOperationCreated: (wopid: string) => void;
- onClose: () => void;
-
- routeOperationDetails: RouteDefinition<{ wopid: string }>;
- routeClose: RouteDefinition;
- routeCashout: RouteDefinition;
- routeChargeWallet: RouteDefinition;
- routeWireTransfer: RouteDefinition<{
- account?: string,
- subject?: string,
- amount?: string,
- }>;
-}): VNode {
- const { i18n } = useTranslationContext();
- const [bankState, updateBankState] = useBankState();
-
- return (
- <div class="mt-4">
- <fieldset>
- <legend class="px-4 text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Send money</i18n.Translate>
- </legend>
-
- <div class="px-4 mt-4 grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-4">
- {/* <!-- Active: "border-indigo-600 ring-2 ring-indigo-600", Not Active: "border-gray-300" --> */}
- <a name="charge wallet" href={routeChargeWallet.url({})}>
- <label
- class={
- "relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" +
- (tab === "charge-wallet"
- ? "border-indigo-600 ring-2 ring-indigo-600"
- : "border-gray-300")
- }
- >
- <div class="flex flex-col">
- <span class="flex">
- <div class="text-4xl mr-4 my-auto">&#x1F4B5;</div>
- <span class="grow self-center text-lg text-gray-900 align-middle text-center">
- <i18n.Translate>
- to a Taler wallet
- </i18n.Translate>
- </span>
- <svg
- class="self-center flex-none h-5 w-5 text-indigo-600"
- style={{
- visibility:
- tab === "charge-wallet" ? "visible" : "hidden",
- }}
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </span>
- <div class="mt-1 flex items-center text-sm text-gray-500">
- <i18n.Translate>
- Withdraw digital money into your mobile wallet or browser
- extension
- </i18n.Translate>
- </div>
- {!!bankState.currentWithdrawalOperationId && (
- <ShowOperationPendingTag
- woid={bankState.currentWithdrawalOperationId}
- onOperationAlreadyCompleted={() => {
- updateBankState(
- "currentWithdrawalOperationId",
- undefined,
- );
- }}
- />
- )}
- </div>
- </label>
- </a>
-
- <a name="wire transfer" href={routeWireTransfer.url({})}>
- <label
- class={
- "relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" +
- (tab === "wire-transfer"
- ? "border-indigo-600 ring-2 ring-indigo-600"
- : "border-gray-300")
- }
- >
- <div class="flex flex-col">
- <span class="flex">
- <div class="text-4xl mr-4 my-auto">&#x2194;</div>
- <span class="grow self-center text-lg font-medium text-gray-900 align-middle text-center">
- <i18n.Translate>to another bank account</i18n.Translate>
- </span>
- <svg
- class="self-center flex-none h-5 w-5 text-indigo-600"
- style={{
- visibility:
- tab === "wire-transfer" ? "visible" : "hidden",
- }}
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </span>
- <div class="mt-1 flex items-center text-sm text-gray-500">
- <i18n.Translate>
- Make a wire transfer to an account with known bank account
- number.
- </i18n.Translate>
- </div>
- </div>
- </label>
- </a>
- </div>
- {tab === "charge-wallet" && (
- <WalletWithdrawForm
- routeOperationDetails={routeOperationDetails}
- focus
- limit={limit}
- onAuthorizationRequired={onAuthorizationRequired}
- onOperationCreated={onOperationCreated}
- onOperationAborted={onClose}
- routeCancel={routeClose}
- />
- )}
- {tab === "wire-transfer" && (
- <PaytoWireTransferForm
- focus
- title={i18n.str`Transfer details`}
- routeHere={routeWireTransfer}
- limit={limit}
- onAuthorizationRequired={onAuthorizationRequired}
- onSuccess={onClose}
- routeCashout={routeCashout}
- routeCancel={routeClose}
- />
- )}
- </fieldset>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.stories.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.stories.tsx
deleted file mode 100644
index 61cfb5629..000000000
--- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.stories.tsx
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { PaytoWireTransferForm } from "./PaytoWireTransferForm.js";
-
-export default {
- title: "PaytoWireTransferForm",
-};
-
-export const USD = tests.createExample(PaytoWireTransferForm, {
- limit: {
- currency: "USD",
- fraction: 0,
- value: 1,
- },
-});
diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
deleted file mode 100644
index 791a3b440..000000000
--- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- AmountJson,
- AmountString,
- Amounts,
- CurrencySpecification,
- FRAC_SEPARATOR,
- HttpStatusCode,
- PaytoString,
- PaytoUri,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
- buildPayto,
- parsePaytoUri,
- stringifyPaytoUri
-} from "@gnu-taler/taler-util";
-import {
- InternationalizationAPI,
- LocalNotificationBanner,
- ShowInputErrorLabel,
- notifyInfo,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { ComponentChildren, Fragment, Ref, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { mutate } from "swr";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useSessionState } from "../hooks/session.js";
-import { useBankState } from "../hooks/bank-state.js";
-import { EmptyObject, RouteDefinition } from "../route.js";
-import { undefinedIfEmpty, validateIBAN, validateTalerBank } from "../utils.js";
-
-interface Props {
- title: TranslatedString;
- focus?: boolean;
- withAccount?: string;
- withSubject?: string;
- withAmount?: string;
- onSuccess: () => void;
- onAuthorizationRequired: () => void;
- routeCancel?: RouteDefinition;
- routeCashout?: RouteDefinition;
- routeHere: RouteDefinition<{
- account?: string,
- subject?: string,
- amount?: string,
- }>;
- limit: AmountJson;
-}
-
-export function PaytoWireTransferForm({
- focus,
- title,
- withAccount,
- withSubject,
- withAmount,
- onSuccess,
- routeCancel,
- routeCashout,
- routeHere,
- onAuthorizationRequired,
- limit,
-}: Props): VNode {
- const [isRawPayto, setIsRawPayto] = useState(false);
- const { state: credentials } = useSessionState();
- const { bank: api, config, url } = useBankCoreApiContext();
-
- const sendingToFixedAccount = withAccount !== undefined;
-
- const [account, setAccount] = useState<string | undefined>(withAccount);
- const [subject, setSubject] = useState<string | undefined>(withSubject);
- const [amount, setAmount] = useState<string | undefined>(withAmount);
- const [, updateBankState] = useBankState();
-
- const [rawPaytoInput, rawPaytoInputSetter] = useState<string | undefined>(
- undefined,
- );
- const { i18n } = useTranslationContext();
-
- const trimmedAmountStr = amount?.trim();
- const parsedAmount = Amounts.parse(`${limit.currency}:${trimmedAmountStr}`);
- const [notification, notify, handleError] = useLocalNotification();
-
- const paytoType = config.wire_type === "X_TALER_BANK" ? "x-taler-bank" as const : "iban" as const;
-
- const errorsWire = undefinedIfEmpty({
- account: !account
- ? i18n.str`Required`
- : paytoType === "iban" ? validateIBAN(account, i18n) :
- paytoType === "x-taler-bank" ? validateTalerBank(account, i18n) :
- undefined,
- subject: !subject ? i18n.str`Required` : validateSubject(subject, i18n),
- amount: !trimmedAmountStr
- ? i18n.str`Required`
- : !parsedAmount
- ? i18n.str`Not valid`
- : validateAmount(parsedAmount, limit, i18n),
- });
-
- const parsed = !rawPaytoInput ? undefined : parsePaytoUri(rawPaytoInput);
-
-
- const errorsPayto = undefinedIfEmpty({
- rawPaytoInput: !rawPaytoInput
- ? i18n.str`Required`
- : !parsed ? i18n.str`Does not follow the pattern`
- : validateRawPayto(parsed, limit, url.host, i18n, paytoType),
- });
-
- async function doSend() {
- let payto_uri: PaytoString | undefined;
- let sendingAmount: AmountString | undefined;
-
- if (credentials.status !== "loggedIn") return;
- if (isRawPayto) {
- const p = parsePaytoUri(rawPaytoInput!);
- if (!p) return;
- sendingAmount = p.params.amount as AmountString;
- delete p.params.amount;
- // if this payto is valid then it already have message
- payto_uri = stringifyPaytoUri(p);
- } else {
- if (!account || !subject) return;
- let payto;
- switch (paytoType) {
- case "x-taler-bank": {
- payto = buildPayto("x-taler-bank", url.host, account);
- break;
- }
- case "iban": {
- payto = buildPayto("iban", account, undefined);
- break;
- }
- default: assertUnreachable(paytoType)
- }
-
- payto.params.message = encodeURIComponent(subject);
- payto_uri = stringifyPaytoUri(payto);
- sendingAmount = `${limit.currency}:${trimmedAmountStr}` as AmountString;
- }
- const puri = payto_uri;
- const sAmount = sendingAmount;
-
- await handleError(async () => {
- const request = {
- payto_uri: puri,
- amount: sAmount,
- };
- const resp = await api.createTransaction(credentials, request);
- mutate(() => true);
- if (resp.type === "fail") {
- switch (resp.case) {
- case HttpStatusCode.BadRequest:
- return notify({
- type: "error",
- title: i18n.str`The request was invalid or the payto://-URI used unacceptable features.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Unauthorized:
- return notify({
- type: "error",
- title: i18n.str`Not enough permission to complete the operation.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_UNKNOWN_CREDITOR:
- return notify({
- type: "error",
- title: i18n.str`The destination account "${puri}" was not found.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_SAME_ACCOUNT:
- return notify({
- type: "error",
- title: i18n.str`The origin and the destination of the transfer can't be the same.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_UNALLOWED_DEBIT:
- return notify({
- type: "error",
- title: i18n.str`Your balance is not enough.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`The origin account "${puri}" was not found.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Accepted: {
- updateBankState("currentChallenge", {
- operation: "create-transaction",
- id: String(resp.body.challenge_id),
- location: routeHere.url({ account: account ?? "", amount, subject }),
- sent: AbsoluteTime.never(),
- request,
- });
- return onAuthorizationRequired();
- }
- default:
- assertUnreachable(resp);
- }
- }
- notifyInfo(i18n.str`Wire transfer created!`);
- onSuccess();
- setAmount(undefined);
- setAccount(undefined);
- setSubject(undefined);
- rawPaytoInputSetter(undefined);
- });
- }
-
- return (
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- {/**
- * FIXME: Scan a qr code
- */}
- <div class="">
- <h2 class="text-base font-semibold leading-7 text-gray-900">{title}</h2>
- <div class="px-2 mt-2 grid grid-cols-1 gap-y-4 sm:gap-x-4">
- <label
- class={
- "relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" +
- (!isRawPayto
- ? "border-indigo-600 ring-2 ring-indigo-600"
- : "border-gray-300")
- }
- >
- <input
- type="radio"
- name="project-type"
- value="Newsletter"
- class="sr-only"
- aria-labelledby="project-type-0-label"
- aria-describedby="project-type-0-description-0 project-type-0-description-1"
- onChange={() => {
- if (parsed && parsed.isKnown) {
- switch (parsed.targetType) {
- case "iban": {
- setAccount(parsed.iban);
- break;
- }
- case "x-taler-bank": {
- setAccount(parsed.account);
- break;
- }
- case "bitcoin": {
- break;
- }
- default: {
- assertUnreachable(parsed)
- }
- }
- const amountStr = !parsed.params ? undefined : parsed.params["amount"];
- if (amountStr) {
- const amount = Amounts.parse(amountStr);
- if (amount) {
- setAmount(Amounts.stringifyValue(amount));
- }
- }
- const subject = parsed.params["message"];
- if (subject) {
- setSubject(subject);
- }
- }
- setIsRawPayto(false);
- }}
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span class="block text-sm font-medium text-gray-900">
- <i18n.Translate>Using a form</i18n.Translate>
- </span>
- </span>
- </span>
- </label>
-
- {sendingToFixedAccount ? undefined : (
- <label
- class={
- "relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none" +
- (isRawPayto
- ? "border-indigo-600 ring-2 ring-indigo-600"
- : "border-gray-300")
- }
- >
- <input
- type="radio"
- name="project-type"
- value="Existing Customers"
- class="sr-only"
- aria-labelledby="project-type-1-label"
- aria-describedby="project-type-1-description-0 project-type-1-description-1"
- onChange={() => {
- if (account) {
- let payto;
- switch (paytoType) {
- case "x-taler-bank": {
- payto = buildPayto("x-taler-bank", url.host, account);
- if (parsedAmount) {
- payto.params["amount"] =
- Amounts.stringify(parsedAmount);
- }
- if (subject) {
- payto.params["message"] = subject;
- }
- break;
- }
- case "iban": {
- payto = buildPayto("iban", account, undefined);
- if (parsedAmount) {
- payto.params["amount"] =
- Amounts.stringify(parsedAmount);
- }
- if (subject) {
- payto.params["message"] = subject;
- }
- break;
- }
- default: assertUnreachable(paytoType)
- }
- rawPaytoInputSetter(stringifyPaytoUri(payto));
- }
- setIsRawPayto(true);
- }}
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span class="block text-sm font-medium text-gray-900">
- <i18n.Translate>Import payto:// URI</i18n.Translate>
- </span>
- </span>
- </span>
- </label>
- )}
- {routeCashout ? (
- <a
- name="do cashout"
- href={routeCashout.url({})}
- class="bg-white p-4 rounded-lg text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cashout</i18n.Translate>
- </a>
- ) : (
- undefined
- )}
- </div>
- </div>
-
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 rounded-md sm:rounded-xl md:col-span-2 w-fit mx-auto"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="p-4 sm:p-8">
- {!isRawPayto ? (
- <div class="grid max-w-xs grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- {(() => {
- switch (paytoType) {
- case "x-taler-bank": {
- return <TextField
- id="x-taler-bank"
- label={i18n.str`Recipient`}
- help={i18n.str`Id of the recipient's account`}
- error={errorsWire?.account}
- onChange={setAccount}
- value={account}
- placeholder={i18n.str`username`}
- focus={focus}
- disabled={sendingToFixedAccount}
- />
- }
- case "iban": {
- return <TextField
- id="iban"
- label={i18n.str`Recipient`}
- help={i18n.str`IBAN of the recipient's account`}
- placeholder={"CC0123456789" as TranslatedString}
- error={errorsWire?.account}
- onChange={(v) => setAccount(v.toUpperCase())}
- value={account}
- focus={focus}
- disabled={sendingToFixedAccount}
- />
- }
- default: assertUnreachable(paytoType)
- }
- })()}
-
- <div class="sm:col-span-5">
- <label
- for="subject"
- class="block text-sm font-medium leading-6 text-gray-900"
- >{i18n.str`Transfer subject`}</label>
- <div class="mt-2">
- <input
- type="text"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="subject"
- id="subject"
- autocomplete="off"
- placeholder={i18n.str`Subject`}
- value={subject ?? ""}
- required
- onInput={(e): void => {
- setSubject(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errorsWire?.subject}
- isDirty={subject !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>
- Some text to identify the transfer
- </i18n.Translate>
- </p>
- </div>
-
- <div class="sm:col-span-5">
- <label
- for="amount"
- class="block text-sm font-medium leading-6 text-gray-900"
- >{i18n.str`Amount`}</label>
- <InputAmount
- name="amount"
- left
- currency={limit.currency}
- value={trimmedAmountStr}
- onChange={(d) => {
- setAmount(d);
- }}
- />
- <ShowInputErrorLabel
- message={errorsWire?.amount}
- isDirty={trimmedAmountStr !== undefined}
- />
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Amount to transfer</i18n.Translate>
- </p>
- </div>
- </div>
- ) : (
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6 w-full">
- <div class="sm:col-span-6">
- <label
- for="address"
- class="block text-sm font-medium leading-6 text-gray-900"
- >{i18n.str`Payto URI:`}</label>
- <div class="mt-2">
- <textarea
- ref={focus ? doAutoFocus : undefined}
- name="address"
- id="address"
- type="textarea"
- rows={5}
- class="block overflow-hidden w-44 sm:w-96 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={rawPaytoInput ?? ""}
- required
- title={i18n.str`Uniform resource identifier of the target account`}
-
- placeholder={((): TranslatedString => {
- switch (paytoType) {
- case "x-taler-bank": return i18n.str`payto://x-taler-bank/[bank-host]/[receiver-account]?message=[subject]&amount=[${limit.currency}:X.Y]`
- case "iban": return i18n.str`payto://iban/[receiver-iban]?message=[subject]&amount=[${limit.currency}:X.Y]`
- }
- })()}
- onInput={(e): void => {
- rawPaytoInputSetter(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errorsPayto?.rawPaytoInput}
- isDirty={rawPaytoInput !== undefined}
- />
- </div>
- </div>
- </div>
- )}
- </div>
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- {routeCancel ? (
- <a
- name="cancel"
- href={routeCancel.url({})}
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- ) : (
- <div />
- )}
- <button
- type="submit"
- name="send"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={isRawPayto ? !!errorsPayto : !!errorsWire}
- onClick={(e) => {
- e.preventDefault();
- doSend();
- }}
- >
- <i18n.Translate>Send</i18n.Translate>
- </button>
- </div>
- <LocalNotificationBanner notification={notification} />
- </form>
- </div>
- );
-}
-
-/**
- * Show the element when the load ended
- * @param element
- */
-export function doAutoFocus(element: HTMLElement | null) {
- if (element) {
- setTimeout(() => {
- element.focus({ preventScroll: true });
- element.scrollIntoView({
- behavior: "smooth",
- block: "center",
- inline: "center",
- });
- }, 100);
- }
-}
-
-export function InputAmount(
- {
- currency,
- name,
- value,
- error,
- left,
- onChange,
- }: {
- error?: string;
- currency: string;
- name: string;
- left?: boolean | undefined;
- value: string | undefined;
- onChange?: (s: string) => void;
- },
- ref: Ref<HTMLInputElement>,
-): VNode {
- const { config } = useBankCoreApiContext();
- return (
- <div class="mt-2">
- <div class="flex rounded-md shadow-sm border-0 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600">
- <div class="pointer-events-none inset-y-0 flex items-center px-3">
- <span class="text-gray-500 sm:text-sm">{currency}</span>
- </div>
- <input
- type="number"
- data-left={left}
- class="disabled:bg-gray-200 text-right rounded-md rounded-l-none data-[left=true]:text-left w-full py-1.5 pl-3 text-gray-900 placeholder:text-gray-400 sm:text-sm sm:leading-6"
- placeholder="0.00"
- aria-describedby="price-currency"
- ref={ref}
- name={name}
- id={name}
- autocomplete="off"
- value={value ?? ""}
- disabled={!onChange}
- onInput={(e) => {
- if (!onChange) return;
- const l = e.currentTarget.value.length;
- const sep_pos = e.currentTarget.value.indexOf(FRAC_SEPARATOR);
- if (
- sep_pos !== -1 &&
- l - sep_pos - 1 >
- config.currency_specification.num_fractional_input_digits
- ) {
- e.currentTarget.value = e.currentTarget.value.substring(
- 0,
- sep_pos +
- config.currency_specification.num_fractional_input_digits +
- 1,
- );
- }
- onChange(e.currentTarget.value);
- }}
- />
- </div>
- <ShowInputErrorLabel message={error} isDirty={value !== undefined} />
- </div>
- );
-}
-
-export function RenderAmount({
- value,
- spec,
- negative,
- withColor,
- hideSmall,
-}: {
- spec: CurrencySpecification;
- value: AmountJson;
- hideSmall?: boolean;
- negative?: boolean;
- withColor?: boolean;
-}): VNode {
- const neg = !!negative; // convert to true or false
-
- const { currency, normal, small } = Amounts.stringifyValueWithSpec(
- value,
- spec,
- );
-
- return (
- <span
- data-negative={withColor ? neg : undefined}
- class="whitespace-nowrap data-[negative=false]:text-green-600 data-[negative=true]:text-red-600"
- >
- {negative ? "- " : undefined}
- {currency} {normal}{" "}
- {!hideSmall && small && <sup class="-ml-1">{small}</sup>}
- </span>
- );
-}
-
-
-function validateRawPayto(parsed: PaytoUri, limit: AmountJson, host: string, i18n: InternationalizationAPI, type: "iban" | "x-taler-bank"): TranslatedString | undefined {
- if (!parsed.isKnown) {
- return i18n.str`The target type is unknown, use "${type}"`
- }
- let result: TranslatedString | undefined;
- switch (type) {
- case "x-taler-bank": {
- if (parsed.targetType !== "x-taler-bank") {
- return i18n.str`Only "x-taler-bank" target are supported`
- }
-
- if (parsed.host !== host) {
- return i18n.str`Only this host is allowed. Use "${host}"`
- }
-
- if (!parsed.account) {
- return i18n.str`Missing account name`
- }
- const result = validateTalerBank(parsed.account, i18n)
- if (result) return result
- break;
- }
- case "iban": {
- if (parsed.targetType !== "iban") {
- return i18n.str`Only "IBAN" target are supported`
- }
- const result = validateIBAN(parsed.iban, i18n)
- if (result) return result
- break;
- }
- default: assertUnreachable(type)
- }
- if (!parsed.params.amount) {
- return i18n.str`Missing "amount" parameter to specify the amount to be transferred`
- }
- const amount = Amounts.parse(parsed.params.amount)
- if (!amount) {
- return i18n.str`The "amount" parameter is not valid`
- }
- result = validateAmount(amount, limit, i18n)
- if (result) return result;
-
- if (!parsed.params.message) {
- return i18n.str`Missing the "message" parameter to specify a reference text for the transfer`
- }
- const subject = parsed.params.message
- result = validateSubject(subject, i18n)
- if (result) return result;
-
- return undefined
-}
-
-function validateAmount(amount: AmountJson, limit: AmountJson, i18n: InternationalizationAPI): TranslatedString | undefined {
- if (amount.currency !== limit.currency) {
- return i18n.str`The only currency allowed is "${limit.currency}"`
- }
- if (Amounts.isZero(amount)) {
- return i18n.str`Can't transfer zero amount`
- }
- if (Amounts.cmp(limit, amount) === -1) {
- return i18n.str`Balance is not enough`
- }
- return undefined
-}
-
-function validateSubject(text: string, i18n: InternationalizationAPI): TranslatedString | undefined {
- if (text.length < 2) {
- return i18n.str`Use a longer subject`
- }
- return undefined
-}
-
-interface PaytoFieldProps {
- id: string,
- label: TranslatedString;
- help?: TranslatedString;
- placeholder?: TranslatedString;
- error: string | undefined;
- value: string | undefined;
- rightIcons?: VNode;
- onChange: (p: string) => void;
- focus?: boolean;
- disabled?: boolean;
-}
-
-function Wrapper({ withIcon, children }: { withIcon: boolean, children: ComponentChildren }): VNode {
- if (withIcon) {
- return <div class="flex justify-between">
- {children}
- </div>
- }
- return <Fragment>{children}</Fragment>
-}
-
-export function TextField({
- id,
- label,
- help,
- focus,
- disabled,
- onChange,
- placeholder,
- rightIcons,
- value,
- error,
-}: PaytoFieldProps): VNode {
- return <div class="sm:col-span-5">
- <label
- for={id}
- class="block text-sm font-medium leading-6 text-gray-900"
- >{label}</label>
- <div class="mt-2">
- <Wrapper withIcon={rightIcons !== undefined}>
- <input
- ref={focus ? doAutoFocus : undefined}
- type="text"
- class="block w-full disabled:bg-gray-200 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name={id}
- id={id}
- disabled={disabled}
- value={value ?? ""}
- placeholder={placeholder}
- autocomplete="off"
- required
- onInput={(e): void => {
- onChange(e.currentTarget.value);
- }}
- />
- {rightIcons}
- </Wrapper>
- <ShowInputErrorLabel
- message={error}
- isDirty={value !== undefined}
- />
- </div>
- {help &&
- <p class="mt-2 text-sm text-gray-500">
- {help}
- </p>
- }
- </div>
-}
diff --git a/packages/demobank-ui/src/pages/ProfileNavigation.tsx b/packages/demobank-ui/src/pages/ProfileNavigation.tsx
deleted file mode 100644
index 10497f015..000000000
--- a/packages/demobank-ui/src/pages/ProfileNavigation.tsx
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import { assertUnreachable } from "@gnu-taler/taler-util";
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useNavigationContext } from "../context/navigation.js";
-import { useSessionState } from "../hooks/session.js";
-import { RouteDefinition } from "../route.js";
-
-export function ProfileNavigation({
- current,
- routeMyAccountCashout,
- routeMyAccountDelete,
- routeMyAccountDetails,
- routeMyAccountPassword,
- routeConversionConfig
-}: {
- current: "details" | "delete" | "credentials" | "cashouts" | "conversion",
- routeMyAccountDetails: RouteDefinition;
- routeMyAccountDelete: RouteDefinition;
- routeMyAccountPassword: RouteDefinition;
- routeMyAccountCashout: RouteDefinition;
- routeConversionConfig: RouteDefinition;
-}): VNode {
- const { i18n } = useTranslationContext();
- const { config } = useBankCoreApiContext();
- const { state: credentials } = useSessionState();
- const isAdminUser =
- credentials.status !== "loggedIn"
- ? false
- : credentials.isUserAdministrator;
- const nonAdminUser = !isAdminUser;
-
- const { navigateTo } = useNavigationContext();
- return (
- <div>
- <div class="sm:hidden">
- <label for="tabs" class="sr-only">
- <i18n.Translate>Select a section</i18n.Translate>
- </label>
- <select
- id="tabs"
- name="tabs"
- class="block w-full rounded-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500"
- onChange={(e) => {
- const op = e.currentTarget.value as typeof current;
- switch (op) {
- case "details": {
- navigateTo(routeMyAccountDetails.url({}));
- return;
- }
- case "delete": {
- navigateTo(routeMyAccountDelete.url({}));
- return;
- }
- case "credentials": {
- navigateTo(routeMyAccountPassword.url({}));
- return;
- }
- case "cashouts": {
- navigateTo(routeMyAccountCashout.url({}));
- return;
- }
- case "conversion": {
- navigateTo(routeConversionConfig.url({}));
- return;
- }
- default:
- assertUnreachable(op);
- }
- }}
- >
- <option value="details" selected={current == "details"}>
- <i18n.Translate>Details</i18n.Translate>
- </option>
- {!config.allow_deletions ? undefined : (
- <option value="delete" selected={current == "delete"}>
- <i18n.Translate>Delete</i18n.Translate>
- </option>
- )}
- <option value="credentials" selected={current == "credentials"}>
- <i18n.Translate>Credentials</i18n.Translate>
- </option>
- {config.allow_conversion ? (
- <Fragment>
- <option value="cashouts" selected={current == "cashouts"}>
- <i18n.Translate>Cashouts</i18n.Translate>
- </option>
- <option value="conversion" selected={current == "cashouts"}>
- <i18n.Translate>Conversion</i18n.Translate>
- </option>
- </Fragment>
- ) : undefined}
- </select>
- </div>
- <div class="hidden sm:block">
- <nav
- class="isolate flex divide-x divide-gray-200 rounded-lg shadow"
- aria-label="Tabs"
- >
- <a
- name="my account details"
- href={routeMyAccountDetails.url({})}
- data-selected={current == "details"}
- class="rounded-l-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Details</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={current == "details"}
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </a>
- {!config.allow_deletions ? undefined : (
- <a
- name="my account delete"
- href={routeMyAccountDelete.url({})}
- data-selected={current == "delete"}
- aria-current="page"
- class=" text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Delete</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={current == "delete"}
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </a>
- )}
- <a
- name="my account password"
- href={routeMyAccountPassword.url({})}
- data-selected={current == "credentials"}
- aria-current="page"
- class=" text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Credentials</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={current == "credentials"}
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </a>
- {config.allow_conversion && nonAdminUser ? (
- <a
- name="my account cashout"
- href={routeMyAccountCashout.url({})}
- data-selected={current == "cashouts"}
- class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Cashouts</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={current == "cashouts"}
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </a>
- ) : undefined}
- {config.allow_conversion && isAdminUser ? (
- <a
- name="conversion config"
- href={routeConversionConfig.url({})}
- data-selected={current == "conversion"}
- class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Conversion</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={current == "conversion"}
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </a>
- ) : undefined}
- </nav>
- </div>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx b/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx
deleted file mode 100644
index 84d703cbe..000000000
--- a/packages/demobank-ui/src/pages/PublicHistoriesPage.tsx
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { TalerError } from "@gnu-taler/taler-util";
-import { Loading, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { Transactions } from "../components/Transactions/index.js";
-import { usePublicAccounts } from "../hooks/account.js";
-
-/**
- * Show histories of public accounts.
- */
-export function PublicHistoriesPage(): VNode {
- const { i18n } = useTranslationContext();
-
- // TODO: implemented filter by account name
- const result = usePublicAccounts(undefined);
- const firstAccount =
- result &&
- !(result instanceof TalerError) &&
- result.data.public_accounts.length > 0
- ? result.data.public_accounts[0].username
- : undefined;
-
- const [showAccount, setShowAccount] = useState(firstAccount);
-
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <Loading />;
- }
-
- const { data } = result;
-
- const txs: Record<string, h.JSX.Element> = {};
- const accountsBar = [];
-
- // Ask story of all the public accounts.
- for (const account of data.public_accounts) {
- const isSelected = account.username == showAccount;
- accountsBar.push(
- <li
- class={
- isSelected
- ? "pure-menu-selected pure-menu-item"
- : "pure-menu-item pure-menu"
- }
- >
- <a
- href="#"
- name={`show account ${account.username}`}
- class="pure-menu-link"
- onClick={() => setShowAccount(account.username)}
- >
- {account.username}
- </a>
- </li>,
- );
- txs[account.username] = <Transactions account={account.username} routeCreateWireTransfer={undefined} />;
- }
-
- return (
- <Fragment>
- <h1 class="nav">{i18n.str`History of public accounts`}</h1>
- <section id="main">
- <article>
- <div class="pure-menu pure-menu-horizontal" name="accountMenu">
- <ul class="pure-menu-list">{accountsBar}</ul>
- {typeof showAccount !== "undefined" ? (
- txs[showAccount]
- ) : (
- <p>No public transactions found.</p>
- )}
- <br />
- </div>
- </article>
- </section>
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/QrCodeSection.stories.tsx b/packages/demobank-ui/src/pages/QrCodeSection.stories.tsx
deleted file mode 100644
index d53d2e7b4..000000000
--- a/packages/demobank-ui/src/pages/QrCodeSection.stories.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-
-import * as tests from "@gnu-taler/web-util/testing";
-import { QrCodeSection } from "./QrCodeSection.js";
-import { parseWithdrawUri } from "@gnu-taler/taler-util";
-
-export default {
- title: "Qr Code Selection",
-};
-
-export const SimpleExample = tests.createExample(QrCodeSection, {
- withdrawUri: parseWithdrawUri("taler://withdraw/bank.com/operationId"),
-});
diff --git a/packages/demobank-ui/src/pages/QrCodeSection.tsx b/packages/demobank-ui/src/pages/QrCodeSection.tsx
deleted file mode 100644
index da11e631d..000000000
--- a/packages/demobank-ui/src/pages/QrCodeSection.tsx
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- HttpStatusCode,
- stringifyWithdrawUri,
- WithdrawUriResult
-} from "@gnu-taler/taler-util";
-import {
- Button,
- LocalNotificationBanner,
- useLocalNotificationHandler,
- useTranslationContext
-} from "@gnu-taler/web-util/browser";
-import { Fragment, h, VNode } from "preact";
-import { useEffect } from "preact/hooks";
-import { QR } from "../components/QR.js";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useTalerWalletIntegrationAPI } from "../context/wallet-integration.js";
-import { useSessionState } from "../hooks/session.js";
-
-export function QrCodeSection({
- withdrawUri,
- onAborted,
-}: {
- withdrawUri: WithdrawUriResult;
- onAborted: () => void;
-}): VNode {
- const { i18n } = useTranslationContext();
- const walletInegrationApi = useTalerWalletIntegrationAPI();
- const talerWithdrawUri = stringifyWithdrawUri(withdrawUri);
- const { state: credentials } = useSessionState();
- const creds = credentials.status !== "loggedIn" ? undefined : credentials;
-
- useEffect(() => {
- walletInegrationApi.publishTalerAction(withdrawUri);
- }, []);
-
- const [notification, handleError] = useLocalNotificationHandler();
-
- const { bank: api } = useBankCoreApiContext();
-
- const onAbortHandler = handleError(
- async () => {
- if (!creds) return undefined;
- return api.abortWithdrawalById(
- creds,
- withdrawUri.withdrawalOperationId,
- )
- },
- onAborted,
- (fail) => {
- switch (fail.case) {
- case HttpStatusCode.BadRequest: return i18n.str`The operation id is invalid.`;
- case HttpStatusCode.NotFound: return i18n.str`The operation was not found.`;
- case HttpStatusCode.Conflict: return i18n.str`The reserve operation has been confirmed previously and can't be aborted`;
- }
- }
- )
-
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} />
- <div class="bg-white shadow-xl sm:rounded-lg">
- <div class="px-4 py-5 sm:p-6">
- <h3 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>
- If you have a Taler wallet installed in this device
- </i18n.Translate>
- </h3>
- <div class="mt-4 mb-4 text-sm text-gray-500">
- <p>
- <i18n.Translate>
- You will see the details of the operation in your wallet
- including the fees (if applies). If you still don't have one you
- can install it following instructions in
- </i18n.Translate>{" "}
- <a
- class="font-semibold text-gray-500 hover:text-gray-400"
- name="wallet page"
- href="https://taler.net/en/wallet.html"
- >
- <i18n.Translate>this page</i18n.Translate>
- </a>
- .
- </p>
- </div>
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 pt-2 mt-2 ">
- <Button
- type="button"
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- handler={onAbortHandler}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </Button>
- <a
- href={talerWithdrawUri}
- name="withdraw"
- class="inline-flex items-center disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Withdraw</i18n.Translate>
- </a>
- </div>
- </div>
- </div>
-
- <div class="bg-white shadow-xl sm:rounded-lg mt-8">
- <div class="px-4 py-5 sm:p-6">
- <h3 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>
- Or if you have the Taler wallet in another device
- </i18n.Translate>
- </h3>
- <div class="mt-4 max-w-xl text-sm text-gray-500">
- <i18n.Translate>
- Scan the QR below to start the withdrawal.
- </i18n.Translate>
- </div>
- <div class="mt-2 max-w-md ml-auto mr-auto">
- <QR text={talerWithdrawUri} />
- </div>
- </div>
- <div class="flex items-center justify-center gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <Button
- type="button"
- // class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md px-3 py-2 text-sm font-semibold text-black shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
- class="text-sm font-semibold leading-6 text-gray-900"
- handler={onAbortHandler}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </Button>
- </div>
- </div>
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx
deleted file mode 100644
index e9f7e602f..000000000
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ /dev/null
@@ -1,415 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- AccessToken,
- HttpStatusCode,
- OperationFail,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- LocalNotificationBanner,
- ShowInputErrorLabel,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useSettingsContext } from "../context/settings.js";
-import { RouteDefinition } from "../route.js";
-import { undefinedIfEmpty } from "../utils.js";
-import { getRandomPassword, getRandomUsername } from "./rnd.js";
-
-export function RegistrationPage({
- onRegistrationSuccesful,
- routeCancel,
-}: {
- onRegistrationSuccesful: (user: string, password: string) => void;
- routeCancel: RouteDefinition;
-}): VNode {
- const { i18n } = useTranslationContext();
- const { config } = useBankCoreApiContext();
- if (!config.allow_registrations) {
- return (
- <p>{i18n.str`Currently, the bank is not accepting new registrations!`}</p>
- );
- }
- return (
- <RegistrationForm
- onRegistrationSuccesful={onRegistrationSuccesful}
- routeCancel={routeCancel}
- />
- );
-}
-
-export const USERNAME_REGEX = /^[a-z][a-zA-Z0-9-]*$/;
-export const PHONE_REGEX = /^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/;
-export const EMAIL_REGEX = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/;
-
-/**
- * Collect and submit registration data.
- */
-function RegistrationForm({
- onRegistrationSuccesful,
- routeCancel,
-}: {
- onRegistrationSuccesful: (user: string, password: string) => void;
- routeCancel: RouteDefinition;
-}): VNode {
- const [username, setUsername] = useState<string | undefined>();
- const [name, setName] = useState<string | undefined>();
- const [password, setPassword] = useState<string | undefined>();
- // const [phone, setPhone] = useState<string | undefined>();
- // const [email, setEmail] = useState<string | undefined>();
- const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
- const [notification, _, handleError] = useLocalNotification();
- const settings = useSettingsContext();
-
- const { bank: api } = useBankCoreApiContext();
- // const { register } = useTestingAPI();
- const { i18n } = useTranslationContext();
-
- const errors = undefinedIfEmpty({
- name: !name ? i18n.str`Missing name` : undefined,
- username: !username
- ? i18n.str`Missing username`
- : !USERNAME_REGEX.test(username)
- ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- : undefined,
- // phone: !phone
- // ? undefined
- // : !PHONE_REGEX.test(phone)
- // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- // : undefined,
- // email: !email
- // ? undefined
- // : !EMAIL_REGEX.test(email)
- // ? i18n.str`Use letters and numbers only, and start with a lowercase letter`
- // : undefined,
- password: !password ? i18n.str`Missing password` : undefined,
- repeatPassword: !repeatPassword
- ? i18n.str`Missing password`
- : repeatPassword !== password
- ? i18n.str`Passwords don't match`
- : undefined,
- });
-
- async function doRegistrationAndLogin(
- name: string,
- username: string,
- password: string,
- onComplete: () => void,
- ) {
- await handleError(async (onError) => {
- const resp = await api.createAccount("" as AccessToken, {
- name,
- username,
- password,
- });
- if (resp.type === "ok") {
- onComplete();
- } else {
- onError(resp, (_case) => {
- switch(_case) {
- case HttpStatusCode.BadRequest: return i18n.str`Server replied with invalid phone or email.`;
- case HttpStatusCode.Unauthorized: return i18n.str`No enough permission to create that account.`;
- case TalerErrorCode.BANK_UNALLOWED_DEBIT: return i18n.str`Registration is disabled because the bank ran out of bonus credit.`;
- case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT: return i18n.str`That username can't be used because is reserved.`;
- case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE: return i18n.str`That username is already taken.`;
- case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE: return i18n.str`That account id is already taken.`;
- case TalerErrorCode.BANK_MISSING_TAN_INFO: return i18n.str`No information for the selected authentication channel.`;
- case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: return i18n.str`Authentication channel is not supported.`;
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT: return i18n.str`Only admin is allow to set debt limit.`;
- case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL: return i18n.str`Only admin can create accounts with second factor authentication.`;
- }
- })
- }
- });
- }
-
- async function doRegistrationStep() {
- if (!username || !password || !name) return;
- await doRegistrationAndLogin(name, username, password, () => {
- setUsername(undefined);
- setPassword(undefined);
- setRepeatPassword(undefined);
- onRegistrationSuccesful(username, password);
- });
- }
-
- async function doRandomRegistration() {
- const user = getRandomUsername();
-
- const password = settings.simplePasswordForRandomAccounts
- ? "123"
- : getRandomPassword();
- const username = `_${user.first}-${user.second}_`;
- const name = `${capitalizeFirstLetter(user.first)} ${capitalizeFirstLetter(
- user.second,
- )}`;
- await doRegistrationAndLogin(name, username, password, () => {
- onRegistrationSuccesful(username, password);
- });
- }
-
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} />
-
- <div class="flex min-h-full flex-col justify-center">
- <div class="sm:mx-auto sm:w-full sm:max-w-sm">
- <h2 class="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">{i18n.str`Account registration`}</h2>
- </div>
-
- <div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
- <form
- class="space-y-6"
- noValidate
- onSubmit={(e) => {
- e.preventDefault();
- }}
- autoCapitalize="none"
- autoCorrect="off"
- >
- <div>
- <label
- for="username"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Login username</i18n.Translate>
- <b style={{ color: "red" }}> *</b>
- </label>
- <div class="mt-2">
- <input
- autoFocus
- type="text"
- name="username"
- id="username"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={username ?? ""}
- enterkeyhint="next"
- placeholder="account identification to login"
- autocomplete="username"
- required
- onInput={(e): void => {
- setUsername(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.username}
- isDirty={username !== undefined}
- />
- </div>
- </div>
-
- <div>
- <div class="flex items-center justify-between">
- <label
- for="password"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Password</i18n.Translate>
- <b style={{ color: "red" }}> *</b>
- </label>
- </div>
- <div class="mt-2">
- <input
- type="password"
- name="password"
- id="password"
- autocomplete="current-password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- enterkeyhint="send"
- value={password ?? ""}
- placeholder="Password"
- required
- onInput={(e): void => {
- setPassword(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.password}
- isDirty={password !== undefined}
- />
- </div>
- </div>
-
- <div>
- <div class="flex items-center justify-between">
- <label
- for="register-repeat"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Repeat password</i18n.Translate>
- <b style={{ color: "red" }}> *</b>
- </label>
- </div>
- <div class="mt-2">
- <input
- type="password"
- name="register-repeat"
- id="register-repeat"
- autocomplete="current-password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- enterkeyhint="send"
- value={repeatPassword ?? ""}
- placeholder="Same password"
- required
- onInput={(e): void => {
- setRepeatPassword(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.repeatPassword}
- isDirty={repeatPassword !== undefined}
- />
- </div>
- </div>
-
- <div>
- <div class="flex items-center justify-between">
- <label
- for="name"
- class="block text-sm font-medium leading-6 text-gray-900"
- >
- <i18n.Translate>Full name</i18n.Translate>
- <b style={{ color: "red" }}> *</b>
- </label>
- </div>
- <div class="mt-2">
- <input
- autoFocus
- type="text"
- name="name"
- id="name"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={name ?? ""}
- enterkeyhint="next"
- placeholder="John Doe"
- autocomplete="name"
- required
- onInput={(e): void => {
- setName(e.currentTarget.value);
- }}
- />
- {/* <ShowInputErrorLabel
- message={errors?.name}
- isDirty={name !== undefined}
- /> */}
- </div>
- </div>
-
- {/* <div>
- <label for="phone" class="block text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Phone</i18n.Translate>
- </label>
- <div class="mt-2">
- <input
- autoFocus
- type="text"
- name="phone"
- id="phone"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={phone ?? ""}
- enterkeyhint="next"
- placeholder="your phone"
- autocomplete="none"
- onInput={(e): void => {
- setPhone(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.phone}
- isDirty={phone !== undefined}
- />
- </div>
- </div>
- <div>
- <label for="email" class="block text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Email</i18n.Translate>
- </label>
- <div class="mt-2">
- <input
- autoFocus
- type="text"
- name="email"
- id="email"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={email ?? ""}
- enterkeyhint="next"
- placeholder="your email"
- autocomplete="email"
- onInput={(e): void => {
- setEmail(e.currentTarget.value);
- }}
- />
- <ShowInputErrorLabel
- message={errors?.email}
- isDirty={email !== undefined}
- />
- </div>
- </div> */}
-
- <div class="flex w-full justify-between">
- <a
- name="cancel"
- href={routeCancel.url({})}
- class="ring-1 ring-gray-600 rounded-md bg-white disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-black shadow-sm hover:bg-white-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="register"
- class=" rounded-md bg-indigo-600 disabled:bg-gray-300 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- onClick={async (e) => {
- e.preventDefault();
-
- doRegistrationStep();
- }}
- >
- <i18n.Translate>Register</i18n.Translate>
- </button>
- </div>
- </form>
-
- {settings.allowRandomAccountCreation && (
- <p class="mt-10 text-center text-sm text-gray-500 border-t">
- <button
- type="submit"
- name="create random"
- class="flex mt-4 w-full justify-center rounded-md bg-green-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-green-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-green-600"
- onClick={(e) => {
- e.preventDefault();
- doRandomRegistration();
- }}
- >
- <i18n.Translate>Create a random temporary user</i18n.Translate>
- </button>
- </p>
- )}
- </div>
- </div>
- </Fragment>
- );
-}
-
-function capitalizeFirstLetter(str: string) {
- return str.charAt(0).toUpperCase() + str.slice(1);
-}
diff --git a/packages/demobank-ui/src/pages/SolveChallengePage.tsx b/packages/demobank-ui/src/pages/SolveChallengePage.tsx
deleted file mode 100644
index b2e053b3c..000000000
--- a/packages/demobank-ui/src/pages/SolveChallengePage.tsx
+++ /dev/null
@@ -1,716 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- Amounts,
- Duration,
- HttpStatusCode,
- TalerCorebankApi,
- TalerError,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
- parsePaytoUri,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- Loading,
- LocalNotificationBanner,
- ShowInputErrorLabel,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
-import { Fragment, VNode, h } from "preact";
-import { useEffect, useState } from "preact/hooks";
-import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useWithdrawalDetails } from "../hooks/account.js";
-import { useSessionState } from "../hooks/session.js";
-import { ChallengeInProgess, useBankState } from "../hooks/bank-state.js";
-import { useConversionInfo } from "../hooks/regional.js";
-import { RouteDefinition } from "../route.js";
-import { undefinedIfEmpty } from "../utils.js";
-import { RenderAmount } from "./PaytoWireTransferForm.js";
-import { OperationNotFound } from "./WithdrawalQRCode.js";
-import { useNavigationContext } from "../context/navigation.js";
-import { Time } from "../components/Time.js";
-
-export function SolveChallengePage({
- onChallengeCompleted,
- routeClose,
-}: {
- onChallengeCompleted: () => void;
- routeClose: RouteDefinition;
-}): VNode {
- const { bank: api } = useBankCoreApiContext();
- const { i18n } = useTranslationContext();
- const [bankState, updateBankState] = useBankState();
- const [code, setCode] = useState<string | undefined>(undefined);
- const [notification, notify, handleError] = useLocalNotification();
- const { state } = useSessionState();
- const creds = state.status !== "loggedIn" ? undefined : state;
- const { navigateTo } = useNavigationContext();
-
- if (!bankState.currentChallenge) {
- return (
- <div>
- <span>no challenge to solve </span>
- <a
- href={routeClose.url({})}
- name="close"
- class="inline-flex items-center rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-500"
- >
- <i18n.Translate>Continue</i18n.Translate>
- </a>
- </div>
- );
- }
-
- const ch = bankState.currentChallenge;
- const errors = undefinedIfEmpty({
- code: !code ? i18n.str`Required` : undefined,
- });
-
- async function startChallenge() {
- if (!creds) return;
- await handleError(async () => {
- const resp = await api.sendChallenge(creds, ch.id);
- if (resp.type === "ok") {
- const newCh = structuredClone(ch);
- newCh.sent = AbsoluteTime.now();
- newCh.info = resp.body;
- updateBankState("currentChallenge", newCh);
- } else {
- const newCh = structuredClone(ch);
- newCh.sent = AbsoluteTime.now();
- newCh.info = undefined;
- updateBankState("currentChallenge", newCh);
- switch (resp.case) {
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`Cashout not found. It may be also mean that it was already aborted.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Unauthorized:
- return notify({
- type: "error",
- title: i18n.str`Cashout not found. It may be also mean that it was already aborted.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
- return notify({
- type: "error",
- title: i18n.str`Cashout not found. It may be also mean that it was already aborted.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- default:
- assertUnreachable(resp);
- }
- }
- });
- }
-
- async function completeChallenge() {
- if (!creds || !code) return;
- await handleError(async () => {
- {
- const resp = await api.confirmChallenge(creds, ch.id, {
- tan: code,
- });
- if (resp.type === "fail") {
- setCode("");
- switch (resp.case) {
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`Challenge not found.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Unauthorized:
- return notify({
- type: "error",
- title: i18n.str`This user is not authorized to complete this challenge.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.TooManyRequests:
- return notify({
- type: "error",
- title: i18n.str`Too many attempts, try another code.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_TAN_CHALLENGE_FAILED:
- return notify({
- type: "error",
- title: i18n.str`The confirmation code is wrong, try again.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_TAN_CHALLENGE_EXPIRED:
- return notify({
- type: "error",
- title: i18n.str`The operation expired.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- default:
- assertUnreachable(resp);
- }
- }
- }
- {
- const resp = await (async (ch: ChallengeInProgess) => {
- switch (ch.operation) {
- case "delete-account":
- return await api.deleteAccount(creds, ch.id);
- case "update-account":
- return await api.updateAccount(creds, ch.request, ch.id);
- case "update-password":
- return await api.updatePassword(creds, ch.request, ch.id);
- case "create-transaction":
- return await api.createTransaction(creds, ch.request, ch.id);
- case "confirm-withdrawal":
- return await api.confirmWithdrawalById(creds, ch.request, ch.id);
- case "create-cashout":
- return await api.createCashout(creds, ch.request, ch.id);
- default:
- assertUnreachable(ch);
- }
- })(ch);
-
- if (resp.type === "fail") {
- if (resp.case !== HttpStatusCode.Accepted) {
- return notify({
- type: "error",
- title: i18n.str`The operation failed.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- }
- // another challenge required, save the request and the ID
- // @ts-expect-error no need to check the type of request, since it will be the same as the previous request
- updateBankState("currentChallenge", {
- operation: ch.operation,
- id: String(resp.body.challenge_id),
- location: ch.location,
- sent: AbsoluteTime.never(),
- request: ch.request,
- });
- return notify({
- type: "info",
- title: i18n.str`The operation needs another confirmation to complete.`,
- });
- }
- updateBankState("currentChallenge", undefined);
- return onChallengeCompleted();
- }
- });
- }
-
- const subtitle = ((op): TranslatedString => {
- switch (op) {
- case "delete-account":
- return i18n.str`Account delete`;
- case "update-account":
- return i18n.str`Account update`;
- case "update-password":
- return i18n.str`Password update`;
- case "create-transaction":
- return i18n.str`Wire transfer`;
- case "confirm-withdrawal":
- return i18n.str`Withdrawal`;
- case "create-cashout":
- return i18n.str`Cashout`;
- }
- })(ch.operation);
-
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} />
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <span
- class="text-sm text-black font-semibold leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Confirm the operation</i18n.Translate>
- </span>
- </h2>
- <span>{subtitle}</span>
- </div>
-
- <div class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2">
- <ChallengeDetails
- challenge={bankState.currentChallenge}
- onStart={startChallenge}
- onCancel={() => {
- updateBankState("currentChallenge", undefined);
- navigateTo(ch.location)
- }}
- />
- {ch.info && (
- <div class="mt-2">
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="px-4 py-4">
- <label for="withdraw-amount">
- <i18n.Translate>Enter the confirmation code</i18n.Translate>
- </label>
- <div class="mt-2">
- <div class="relative rounded-md shadow-sm">
- <input
- type="text"
- // class="block w-full rounded-md border-0 py-1.5 pl-16 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- aria-describedby="answer"
- autoFocus
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- value={code ?? ""}
- required
- name="answer"
- id="answer"
- autocomplete="off"
- onChange={(e): void => {
- setCode(e.currentTarget.value);
- }}
- />
- </div>
- <ShowInputErrorLabel
- message={errors?.code}
- isDirty={code !== undefined}
- />
- </div>
- </div>
- <div class="flex items-center justify-between border-gray-900/10 px-4 py-4 ">
- <div />
- <button
- type="submit"
- name="confirm"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- onClick={(e) => {
- completeChallenge();
- e.preventDefault();
- }}
- >
- <i18n.Translate>Confirm</i18n.Translate>
- </button>
- </div>
- </form>
- </div>
- )}
- </div>
- </div>
- </Fragment>
- );
-}
-
-function ChallengeDetails({
- challenge,
- onStart,
- onCancel,
-}: {
- challenge: ChallengeInProgess;
- onStart: () => void;
- onCancel: () => void;
-}): VNode {
- const { i18n, dateLocale } = useTranslationContext();
- const { config } = useBankCoreApiContext();
-
- const firstTime = AbsoluteTime.isNever(challenge.sent)
- useEffect(() => {
- if (firstTime) {
- onStart()
- }
- }, [])
- return (
- <div class="px-4 mt-4 ">
- <div class="w-full">
- <div class="border-gray-100">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <span
- class="text-sm text-black font-semibold leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Operation details</i18n.Translate>
- </span>
- </h2>
- <dl class="divide-y divide-gray-100">
- {((): VNode => {
- switch (challenge.operation) {
- case "delete-account":
- return (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Account</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.request}
- </dd>
- </div>
- );
- case "create-transaction": {
- const payto = parsePaytoUri(challenge.request.payto_uri)!;
- return (
- <Fragment>
- {challenge.request.amount && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Amount</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- <RenderAmount
- value={Amounts.parseOrThrow(
- challenge.request.amount,
- )}
- spec={config.currency_specification}
- />
- </dd>
- </div>
- )}
- {payto.isKnown && payto.targetType === "iban" && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>To account</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {payto.iban}
- </dd>
- </div>
- )}
- </Fragment>
- );
- }
- case "confirm-withdrawal":
- return <ShowWithdrawalDetails id={challenge.request} />;
- case "create-cashout": {
- return <ShowCashoutDetails request={challenge.request} />;
- }
- case "update-account": {
- return (
- <Fragment>
- {challenge.request.cashout_payto_uri !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Cashout account</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.request.cashout_payto_uri}
- </dd>
- </div>
- )}
- {challenge.request.contact_data?.email !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Email</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.request.contact_data?.email}
- </dd>
- </div>
- )}
- {challenge.request.contact_data?.phone !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Phone</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.request.contact_data?.phone}
- </dd>
- </div>
- )}
- {challenge.request.debit_threshold !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Debit threshold</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- <RenderAmount
- value={Amounts.parseOrThrow(
- challenge.request.debit_threshold,
- )}
- spec={config.currency_specification}
- />
- </dd>
- </div>
- )}
- {challenge.request.is_public !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>
- Is this account public?
- </i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.request.is_public
- ? i18n.str`Enable`
- : i18n.str`Disable`}
- </dd>
- </div>
- )}
- {challenge.request.name !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Name</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.request.name}
- </dd>
- </div>
- )}
- {challenge.request.tan_channel !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>
- Authentication channel
- </i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.request.tan_channel ?? i18n.str`Remove`}
- </dd>
- </div>
- )}
- </Fragment>
- );
- }
- case "update-password": {
- return (
- <Fragment>
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>New password</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.request.new_password}
- </dd>
- </div>
- </Fragment>
- );
- }
- default:
- assertUnreachable(challenge);
- }
- })()}
-
- {challenge.info && (
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <span
- class="text-sm text-black font-semibold leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Challenge details</i18n.Translate>
- </span>
- </h2>
- )}
- {challenge.sent.t_ms !== "never" && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Sent at</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- <Time format="dd/MM/yyyy HH:mm:ss"
- timestamp={challenge.sent}
- relative={Duration.fromSpec({ days: 1 })} />
- </dd>
- </div>
- )}
- {challenge.info && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- {((ch: TalerCorebankApi.TanChannel): VNode => {
- switch (ch) {
- case TalerCorebankApi.TanChannel.SMS:
- return <i18n.Translate>To phone</i18n.Translate>;
- case TalerCorebankApi.TanChannel.EMAIL:
- return <i18n.Translate>To email</i18n.Translate>;
- default:
- assertUnreachable(ch);
- }
- })(challenge.info.tan_channel)}
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {challenge.info.tan_info}
- </dd>
- </div>
- )}
- </dl>
- </div>
- <div class="mt-6 mb-4 flex justify-between">
- <button
- type="button"
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- onClick={onCancel}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
- {challenge.info ? (
- <button
- type="submit"
- name="send again"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- onClick={(e) => {
- onStart();
- e.preventDefault();
- }}
- >
- <i18n.Translate>Send again</i18n.Translate>
- </button>
- ) : (
- <div> sending code ...</div>
- )}
- </div>
- </div>
- </div>
- );
-}
-
-function ShowWithdrawalDetails({ id }: { id: string }): VNode {
- const details = useWithdrawalDetails(id);
- const { i18n } = useTranslationContext();
- const { config } = useBankCoreApiContext();
- if (!details) {
- return <Loading />;
- }
- if (details instanceof TalerError) {
- return <ErrorLoadingWithDebug error={details} />;
- }
- if (details.type === "fail") {
- switch (details.case) {
- case HttpStatusCode.BadRequest:
- case HttpStatusCode.NotFound:
- return <OperationNotFound routeClose={undefined} />;
- default:
- assertUnreachable(details);
- }
- }
-
- return (
- <Fragment>
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">Amount</dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- <RenderAmount
- value={Amounts.parseOrThrow(details.body.amount)}
- spec={config.currency_specification}
- />
- </dd>
- </div>
- {details.body.selected_reserve_pub !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Withdraw id</i18n.Translate>
- </dt>
- <dd
- class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0"
- title={details.body.selected_reserve_pub}
- >
- {details.body.selected_reserve_pub.substring(0, 16)}...
- </dd>
- </div>
- )}
- {details.body.selected_exchange_account !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>To account</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {details.body.selected_exchange_account}
- </dd>
- </div>
- )}
- </Fragment>
- );
-}
-
-function ShowCashoutDetails({
- request,
-}: {
- request: TalerCorebankApi.CashoutRequest;
-}): VNode {
- const { i18n } = useTranslationContext();
- const info = useConversionInfo();
- if (!info) {
- return <Loading />;
- }
-
- if (info instanceof TalerError) {
- return <ErrorLoadingWithDebug error={info} />;
- }
- if (info.type === "fail") {
- switch (info.case) {
- case HttpStatusCode.NotImplemented: {
- return (
- <Attention
- type="danger"
- title={i18n.str`Cashout are disabled`}
- >
- <i18n.Translate>Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.</i18n.Translate>
- </Attention>
- );
- }
- default:
- assertUnreachable(info.case);
- }
- }
-
- return (
- <Fragment>
- {request.subject !== undefined && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Subject</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {request.subject}
- </dd>
- </div>
- )}
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">Debit</dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- <RenderAmount
- value={Amounts.parseOrThrow(request.amount_credit)}
- spec={info.body.regional_currency_specification}
- />
- </dd>
- </div>
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">Credit</dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- <RenderAmount
- value={Amounts.parseOrThrow(request.amount_credit)}
- spec={info.body.fiat_currency_specification}
- />
- </dd>
- </div>
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
deleted file mode 100644
index 001d90fa1..000000000
--- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AmountJson,
- Amounts,
- HttpStatusCode,
- TranslatedString,
- assertUnreachable,
- parseWithdrawUri
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- LocalNotificationBanner,
- notifyError,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { VNode, h } from "preact";
-import { forwardRef } from "preact/compat";
-import { useState } from "preact/hooks";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useSessionState } from "../hooks/session.js";
-import { useBankState } from "../hooks/bank-state.js";
-import { usePreferences } from "../hooks/preferences.js";
-import { RouteDefinition } from "../route.js";
-import { undefinedIfEmpty } from "../utils.js";
-import { OperationState } from "./OperationState/index.js";
-import { InputAmount, doAutoFocus } from "./PaytoWireTransferForm.js";
-
-const RefAmount = forwardRef(InputAmount);
-
-function OldWithdrawalForm({
- onOperationCreated,
- limit,
- routeCancel,
- focus,
- routeOperationDetails,
-}: {
- limit: AmountJson;
- focus?: boolean;
- routeOperationDetails: RouteDefinition<{ wopid: string }>,
- onOperationCreated: (wopid: string) => void;
- routeCancel: RouteDefinition;
-}): VNode {
- const { i18n } = useTranslationContext();
- const [settings] = usePreferences();
-
- // const walletInegrationApi = useTalerWalletIntegrationAPI()
- // const { navigateTo } = useNavigationContext();
-
- const [bankState, updateBankState] = useBankState();
- const { bank: api } = useBankCoreApiContext();
-
- const { state: credentials } = useSessionState();
- const creds = credentials.status !== "loggedIn" ? undefined : credentials;
-
- const [amountStr, setAmountStr] = useState<string | undefined>(
- `${settings.maxWithdrawalAmount}`,
- );
- const [notification, notify, handleError] = useLocalNotification();
-
- if (bankState.currentWithdrawalOperationId) {
- // FIXME: doing the preventDefault is not optimal
-
- // const suri = stringifyWithdrawUri({
- // bankIntegrationApiBaseUrl: api.getIntegrationAPI().baseUrl,
- // withdrawalOperationId: bankState.currentWithdrawalOperationId,
- // });
- // const uri = parseWithdrawUri(suri)!
- const url = routeOperationDetails.url({
- wopid: bankState.currentWithdrawalOperationId,
- });
- return (
- <Attention type="warning" title={i18n.str`There is an operation already`} onClose={() => {
- updateBankState("currentWithdrawalOperationId", undefined);
- }}>
- <span ref={focus ? doAutoFocus : undefined} />
- <i18n.Translate>
- Complete the operation in
- </i18n.Translate>{" "}
- <a
- class="font-semibold text-yellow-700 hover:text-yellow-600"
- name="complete operation"
- href={url}
- // onClick={(e) => {
- // e.preventDefault()
- // walletInegrationApi.publishTalerAction(uri, () => {
- // navigateTo(url)
- // })
- // }}
- >
- <i18n.Translate>this page</i18n.Translate>
- </a>
- </Attention>
- );
- }
-
- const trimmedAmountStr = amountStr?.trim();
-
- const parsedAmount = trimmedAmountStr
- ? Amounts.parse(`${limit.currency}:${trimmedAmountStr}`)
- : undefined;
-
- const errors = undefinedIfEmpty({
- amount:
- trimmedAmountStr == null
- ? i18n.str`Required`
- : !parsedAmount
- ? i18n.str`Invalid`
- : Amounts.cmp(limit, parsedAmount) === -1
- ? i18n.str`Balance is not enough`
- : undefined,
- });
-
- async function doStart() {
- if (!parsedAmount || !creds) return;
- await handleError(async () => {
- const resp = await api.createWithdrawal(creds, {
- amount: Amounts.stringify(parsedAmount),
- });
- if (resp.type === "ok") {
- const uri = parseWithdrawUri(resp.body.taler_withdraw_uri);
- if (!uri) {
- return notifyError(
- i18n.str`Server responded with an invalid withdraw URI`,
- i18n.str`Withdraw URI: ${resp.body.taler_withdraw_uri}`,
- );
- } else {
- updateBankState(
- "currentWithdrawalOperationId",
- uri.withdrawalOperationId,
- );
- onOperationCreated(uri.withdrawalOperationId);
- }
- } else {
- switch (resp.case) {
- case HttpStatusCode.Conflict: {
- notify({
- type: "error",
- title: i18n.str`The operation was rejected due to insufficient funds`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- break;
- }
- case HttpStatusCode.Unauthorized: {
- notify({
- type: "error",
- title: i18n.str`The operation was rejected due to insufficient funds`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- break;
- }
- case HttpStatusCode.NotFound: {
- notify({
- type: "error",
- title: i18n.str`Account not found`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- break;
- }
- default:
- assertUnreachable(resp);
- }
- }
- });
- }
-
- return (
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2 mt-4"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <LocalNotificationBanner notification={notification} />
-
- <div class="px-4 py-6 ">
- <div class="grid max-w-xs grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label for="withdraw-amount">{i18n.str`Amount`}</label>
- <RefAmount
- currency={limit.currency}
- value={amountStr}
- name="withdraw-amount"
- onChange={(v) => {
- setAmountStr(v);
- }}
- error={errors?.amount}
- ref={focus ? doAutoFocus : undefined}
- />
- </div>
- </div>
- <div class="mt-4">
- <div class="sm:inline">
- <button
- type="button"
- name="set 50"
- class=" inline-flex px-6 py-4 text-sm items-center rounded-l-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
- onClick={(e) => {
- e.preventDefault();
- setAmountStr("50.00");
- }}
- >
- 50.00
- </button>
- <button
- type="button"
- name="set 25"
- class=" -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center rounded-r-md sm:rounded-none bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
- onClick={(e) => {
- e.preventDefault();
- setAmountStr("25.00");
- }}
- >
- 25.00
- </button>
- </div>
- <div class="mt-4 sm:inline">
- <button
- type="button"
- name="set 10"
- class=" -ml-px -mr-px inline-flex px-6 py-4 text-sm items-center rounded-l-md sm:rounded-none bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
- onClick={(e) => {
- e.preventDefault();
- setAmountStr("10.00");
- }}
- >
- 10.00
- </button>
- <button
- type="button"
- name="set 5"
- class=" inline-flex px-6 py-4 text-sm items-center rounded-r-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
- onClick={(e) => {
- e.preventDefault();
- setAmountStr("5.00");
- }}
- >
- 5.00
- </button>
- </div>
- </div>
- </div>
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <a
- href={routeCancel.url({})}
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="continue"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- // disabled={isRawPayto ? !!errorsPayto : !!errorsWire}
- onClick={(e) => {
- e.preventDefault();
- doStart();
- }}
- >
- <i18n.Translate>Continue</i18n.Translate>
- </button>
- </div>
- </form>
- );
-}
-
-export function WalletWithdrawForm({
- focus,
- limit,
- routeCancel,
- onAuthorizationRequired,
- onOperationCreated,
- onOperationAborted,
- routeOperationDetails,
-}: {
- limit: AmountJson;
- focus?: boolean;
- routeOperationDetails: RouteDefinition<{ wopid: string }>,
- onAuthorizationRequired: () => void;
- onOperationCreated: (wopid: string) => void;
- onOperationAborted: () => void;
- routeCancel: RouteDefinition;
-}): VNode {
- const { i18n } = useTranslationContext();
- const [settings, updateSettings] = usePreferences();
-
- return (
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <i18n.Translate>Prepare your Taler wallet</i18n.Translate>
- </h2>
- <p class="mt-1 text-sm text-gray-500">
- <i18n.Translate>
- After using your wallet you will need to confirm or cancel the
- operation on this site.
- </i18n.Translate>
- </p>
- </div>
-
- <div class="col-span-2">
- {settings.showInstallWallet && (
- <Attention
- title={i18n.str`You need a Taler wallet`}
- onClose={() => {
- updateSettings("showInstallWallet", false);
- }}
- >
- <i18n.Translate>
- If you don't have one yet you can follow the instruction in
- </i18n.Translate>{" "}
- <a
- target="_blank"
- name="wallet page"
- rel="noreferrer noopener"
- class="font-semibold text-blue-700 hover:text-blue-600"
- href="https://taler.net/en/wallet.html"
- >
- <i18n.Translate>this page</i18n.Translate>
- </a>
- </Attention>
- )}
-
- {!settings.fastWithdrawal ? (
- <OldWithdrawalForm
- focus={focus}
- routeOperationDetails={routeOperationDetails}
- limit={limit}
- routeCancel={routeCancel}
- onOperationCreated={onOperationCreated}
- />
- ) : (
- <OperationState
- currency={limit.currency}
- onAuthorizationRequired={onAuthorizationRequired}
- routeClose={routeCancel}
- routeHere={routeOperationDetails}
- onAbort={onOperationAborted}
- // route={routeCancel}
- />
- )}
- </div>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/pages/WireTransfer.tsx b/packages/demobank-ui/src/pages/WireTransfer.tsx
deleted file mode 100644
index 33f067e63..000000000
--- a/packages/demobank-ui/src/pages/WireTransfer.tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- Amounts,
- HttpStatusCode,
- TalerError,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- Loading,
- notifyInfo,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js";
-import { useAccountDetails } from "../hooks/account.js";
-import { useSessionState } from "../hooks/session.js";
-import { LoginForm } from "./LoginForm.js";
-import { PaytoWireTransferForm } from "./PaytoWireTransferForm.js";
-import { RouteDefinition } from "../route.js";
-
-export function WireTransfer({
- toAccount,
- withSubject,
- withAmount,
- onAuthorizationRequired,
- routeCancel,
- routeHere,
- onSuccess,
-}: {
- onSuccess?: () => void;
- routeHere: RouteDefinition<{
- account?: string,
- subject?: string,
- amount?: string,
- }>;
- toAccount?: string;
- withSubject?: string,
- withAmount?: string,
- routeCancel?: RouteDefinition;
- onAuthorizationRequired: () => void;
-}): VNode {
- const { i18n } = useTranslationContext();
- const r = useSessionState();
- const account = r.state.status !== "loggedOut" ? r.state.username : "admin";
- const result = useAccountDetails(account);
-
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <ErrorLoadingWithDebug error={result} />;
- }
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.Unauthorized:
- return <LoginForm currentUser={account} />;
- case HttpStatusCode.NotFound:
- return <LoginForm currentUser={account} />;
- default:
- assertUnreachable(result);
- }
- }
- const { body: data } = result;
-
- const balance = Amounts.parseOrThrow(data.balance.amount);
- const balanceIsDebit = data.balance.credit_debit_indicator == "debit";
-
- const debitThreshold = Amounts.parseOrThrow(data.debit_threshold);
- const limit = balanceIsDebit
- ? Amounts.sub(debitThreshold, balance).amount
- : Amounts.add(balance, debitThreshold).amount;
- if (!balance) return <Fragment />;
- return (
- <PaytoWireTransferForm
- title={i18n.str`Make a wire transfer`}
- withAccount={toAccount}
- withAmount={withAmount}
- withSubject={withSubject}
- routeHere={routeHere}
- limit={limit}
- onAuthorizationRequired={onAuthorizationRequired}
- onSuccess={() => {
- notifyInfo(i18n.str`Wire transfer created!`);
- if (onSuccess) onSuccess();
- }}
- routeCancel={routeCancel}
- />
- );
-}
diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
deleted file mode 100644
index 5925719c3..000000000
--- a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AbsoluteTime,
- AmountJson,
- HttpStatusCode,
- PaytoUri,
- PaytoUriIBAN,
- PaytoUriTalerBank,
- TalerErrorCode,
- TranslatedString,
- WithdrawUriResult,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- LocalNotificationBanner,
- notifyInfo,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { ComponentChildren, Fragment, VNode, h } from "preact";
-import { mutate } from "swr";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useBankState } from "../hooks/bank-state.js";
-import { usePreferences } from "../hooks/preferences.js";
-import { useSessionState } from "../hooks/session.js";
-import { RouteDefinition } from "../route.js";
-import { LoginForm } from "./LoginForm.js";
-import { RenderAmount } from "./PaytoWireTransferForm.js";
-
-interface Props {
- onAborted: () => void;
- withdrawUri: WithdrawUriResult;
- routeHere: RouteDefinition<{ wopid: string }>;
- details: {
- account: PaytoUri;
- reserve: string;
- username: string;
- amount: AmountJson;
- };
- onAuthorizationRequired: () => void;
-}
-/**
- * Additional authentication required to complete the operation.
- * Not providing a back button, only abort.
- */
-export function WithdrawalConfirmationQuestion({
- onAborted,
- details,
- onAuthorizationRequired,
- routeHere,
- withdrawUri,
-}: Props): VNode {
- const { i18n } = useTranslationContext();
- const [settings] = usePreferences();
- const { state: credentials } = useSessionState();
- const creds = credentials.status !== "loggedIn" ? undefined : credentials;
- const [, updateBankState] = useBankState();
-
- const [notification, notify, handleError] = useLocalNotification();
-
- const { config, bank: api } = useBankCoreApiContext();
-
- async function doTransfer() {
- await handleError(async () => {
- if (!creds) return;
- const resp = await api.confirmWithdrawalById(
- creds,
- withdrawUri.withdrawalOperationId,
- );
- if (resp.type === "ok") {
- mutate(() => true); // clean any info that we have
- if (!settings.showWithdrawalSuccess) {
- notifyInfo(i18n.str`Wire transfer completed!`);
- }
- } else {
- switch (resp.case) {
- case TalerErrorCode.BANK_CONFIRM_ABORT_CONFLICT:
- return notify({
- type: "error",
- title: i18n.str`The withdrawal has been aborted previously and can't be confirmed`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
- return notify({
- type: "error",
- title: i18n.str`The withdrawal operation can't be confirmed before a wallet accepted the transaction.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.BadRequest:
- return notify({
- type: "error",
- title: i18n.str`The operation id is invalid.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`The operation was not found.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_UNALLOWED_DEBIT:
- return notify({
- type: "error",
- title: i18n.str`Your balance is not enough for the operation.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Accepted: {
- updateBankState("currentChallenge", {
- operation: "confirm-withdrawal",
- id: String(resp.body.challenge_id),
- location: routeHere.url({ wopid: withdrawUri.withdrawalOperationId }),
- sent: AbsoluteTime.never(),
- request: withdrawUri.withdrawalOperationId,
- });
- return onAuthorizationRequired();
- }
- default:
- assertUnreachable(resp);
- }
- }
- });
- }
-
- async function doCancel() {
- await handleError(async () => {
- if (!creds) return;
- const resp = await api.abortWithdrawalById(
- creds,
- withdrawUri.withdrawalOperationId,
- );
- if (resp.type === "ok") {
- onAborted();
- } else {
- switch (resp.case) {
- case HttpStatusCode.Conflict:
- return notify({
- type: "error",
- title: i18n.str`The reserve operation has been confirmed previously and can't be aborted`,
- });
- case HttpStatusCode.BadRequest:
- return notify({
- type: "error",
- title: i18n.str`The operation id is invalid.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`The operation was not found.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- default: {
- assertUnreachable(resp);
- }
- }
- }
- });
- }
-
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} />
-
- <div class="bg-white shadow sm:rounded-lg">
- <div class="px-4 py-5 sm:p-6">
- <h3 class="text-base font-semibold text-gray-900">
- <i18n.Translate>Confirm the withdrawal operation</i18n.Translate>
- </h3>
- <div class="mt-3 text-sm leading-6">
- <ShouldBeSameUser username={details.username}>
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-2 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="px-4 mt-4">
- <div class="w-full">
- <div class="px-4 sm:px-0 text-sm">
- <p>
- <i18n.Translate>Wire transfer details</i18n.Translate>
- </p>
- </div>
- <div class="mt-6 border-t border-gray-100">
- <dl class="divide-y divide-gray-100">
- {((): VNode => {
- switch (details.account.targetType) {
- case "iban": {
- const p = details.account as PaytoUriIBAN;
- const name = p.params["receiver-name"];
- return (
- <Fragment>
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Payment provider's account number</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {p.iban}
- </dd>
- </div>
- {name && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Payment provider's name</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {name}
- </dd>
- </div>
- )}
- </Fragment>
- );
- }
- case "x-taler-bank": {
- const p = details.account as PaytoUriTalerBank;
- const name = p.params["receiver-name"];
- return (
- <Fragment>
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Payment provider's account id</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {p.account}
- </dd>
- </div>
- {name && (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Payment provider's name</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {name}
- </dd>
- </div>
- )}
- </Fragment>
- );
- }
- default:
- return (
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Payment provider's account</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- {details.account.targetPath}
- </dd>
- </div>
- );
- }
- })()}
- <div class="px-4 py-2 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
- <dt class="text-sm font-medium leading-6 text-gray-900">
- <i18n.Translate>Amount</i18n.Translate>
- </dt>
- <dd class="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
- <RenderAmount
- value={details.amount}
- spec={config.currency_specification}
- />
- </dd>
- </div>
- </dl>
- </div>
- </div>
- </div>
-
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <button
- type="button"
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- onClick={doCancel}
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </button>
- <button
- type="submit"
- name="transfer"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- onClick={(e) => {
- e.preventDefault();
- doTransfer();
- }}
- >
- <i18n.Translate>Transfer</i18n.Translate>
- </button>
- </div>
- </form>
- </div>
- </ShouldBeSameUser>
- </div>
- </div>
- </div>
- </Fragment>
- );
-}
-
-export function ShouldBeSameUser({
- username,
- children,
-}: {
- username: string;
- children: ComponentChildren;
-}): VNode {
- const { state: credentials } = useSessionState();
- const { i18n } = useTranslationContext();
- if (credentials.status === "loggedOut") {
- return (
- <Fragment>
- <Attention type="info" title={i18n.str`Authentication required`} />
- <LoginForm currentUser={username} fixedUser />
- </Fragment>
- );
- }
- if (credentials.username !== username) {
- return (
- <Fragment>
- <Attention
- type="warning"
- title={i18n.str`This operation was created with other username`}
- />
- <LoginForm currentUser={username} fixedUser />
- </Fragment>
- );
- }
- return <Fragment>{children}</Fragment>;
-}
diff --git a/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx b/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx
deleted file mode 100644
index 973a23011..000000000
--- a/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { parseWithdrawUri, stringifyWithdrawUri } from "@gnu-taler/taler-util";
-import { Attention, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { VNode, h } from "preact";
-import { useBankCoreApiContext } from "../context/config.js";
-import { useBankState } from "../hooks/bank-state.js";
-import { RouteDefinition } from "../route.js";
-import { WithdrawalQRCode } from "./WithdrawalQRCode.js";
-
-export function WithdrawalOperationPage({
- operationId,
- onAuthorizationRequired,
- onOperationAborted,
- routeClose,
- routeWithdrawalDetails,
-}: {
- onAuthorizationRequired: () => void;
- operationId: string;
- purpose: "after-creation" | "after-confirmation",
- onOperationAborted: () => void;
- routeClose: RouteDefinition;
- routeWithdrawalDetails: RouteDefinition<{ wopid: string }>;
-}): VNode {
- const { bank: api } = useBankCoreApiContext();
- const uri = stringifyWithdrawUri({
- bankIntegrationApiBaseUrl: api.getIntegrationAPI(),
- withdrawalOperationId: operationId,
- });
- const parsedUri = parseWithdrawUri(uri);
- const { i18n } = useTranslationContext();
- const [, updateBankState] = useBankState();
-
- if (!parsedUri) {
- return (
- <Attention
- type="danger"
- title={i18n.str`The Withdrawal URI is not valid`}
- >
- {uri}
- </Attention>
- );
- }
-
- return (
- <WithdrawalQRCode
- withdrawUri={parsedUri}
- routeWithdrawalDetails={routeWithdrawalDetails}
- onAuthorizationRequired={onAuthorizationRequired}
- onOperationAborted={() => {
- updateBankState("currentWithdrawalOperationId", undefined);
- onOperationAborted();
- }}
- routeClose={routeClose}
- />
- );
-}
diff --git a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
deleted file mode 100644
index 9765147d1..000000000
--- a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- Amounts,
- HttpStatusCode,
- TalerError,
- WithdrawUriResult,
- assertUnreachable,
- parsePaytoUri,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- Loading,
- notifyInfo,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { VNode, h } from "preact";
-import { ErrorLoadingWithDebug } from "../components/ErrorLoadingWithDebug.js";
-import { useWithdrawalDetails } from "../hooks/account.js";
-import { RouteDefinition } from "../route.js";
-import { QrCodeSection } from "./QrCodeSection.js";
-import { WithdrawalConfirmationQuestion } from "./WithdrawalConfirmationQuestion.js";
-
-interface Props {
- withdrawUri: WithdrawUriResult;
- onOperationAborted: () => void;
- routeClose: RouteDefinition;
- routeWithdrawalDetails: RouteDefinition<{ wopid: string }>;
- onAuthorizationRequired: () => void;
-}
-/**
- * Offer the QR code (and a clickable taler://-link) to
- * permit the passing of exchange and reserve details to
- * the bank. Poll the backend until such operation is done.
- */
-export function WithdrawalQRCode({
- withdrawUri,
- onOperationAborted,
- routeClose,
- routeWithdrawalDetails,
- onAuthorizationRequired,
-}: Props): VNode {
- const { i18n } = useTranslationContext();
- const result = useWithdrawalDetails(withdrawUri.withdrawalOperationId);
-
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <ErrorLoadingWithDebug error={result} />;
- }
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.BadRequest:
- case HttpStatusCode.NotFound:
- return <OperationNotFound routeClose={routeClose} />;
- default:
- assertUnreachable(result);
- }
- }
-
- const { body: data } = result;
-
- if (data.status === "aborted") {
- return (
- <div class="relative ml-auto mr-auto transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6">
- <div>
- <div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-yellow-100">
- <svg
- class="h-5 w-5 text-yellow-400"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a1 1 0 100-2 1 1 0 000 2z"
- clip-rule="evenodd"
- />
- </svg>
- </div>
- <div class="mt-3 text-center sm:mt-5">
- <h3
- class="text-base font-semibold leading-6 text-gray-900"
- id="modal-title"
- >
- <i18n.Translate>Operation aborted</i18n.Translate>
- </h3>
- <div class="mt-2">
- <p class="text-sm text-gray-500">
- <i18n.Translate>
- The wire transfer to the payment provider's account was
- aborted from somewhere else, your balance was not affected.
- </i18n.Translate>
- </p>
- </div>
- </div>
- </div>
- <div class="mt-5 sm:mt-6">
- <a
- href={routeClose.url({})}
- name="continue"
- class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Continue</i18n.Translate>
- </a>
- </div>
- </div>
- );
- }
-
- if (data.status === "confirmed") {
- return (
- <div class="relative ml-auto mr-auto transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6">
- <div>
- <div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
- <svg
- class="h-6 w-6 text-green-600"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- aria-hidden="true"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M4.5 12.75l6 6 9-13.5"
- />
- </svg>
- </div>
- <div class="mt-3 text-center sm:mt-5">
- <h3
- class="text-base font-semibold leading-6 text-gray-900"
- id="modal-title"
- >
- <i18n.Translate>Withdrawal confirmed</i18n.Translate>
- </h3>
- <div class="mt-2">
- <p class="text-sm text-gray-500">
- <i18n.Translate>
- The wire transfer to the Taler operator has been initiated.
- You will soon receive the requested amount in your Taler
- wallet.
- </i18n.Translate>
- </p>
- </div>
- </div>
- </div>
- <div class="mt-5 sm:mt-6">
- <a
- href={routeClose.url({})}
- name="done"
- class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Done</i18n.Translate>
- </a>
- </div>
- </div>
- );
- }
-
- if (data.status === "pending") {
- return (
- <QrCodeSection
- withdrawUri={withdrawUri}
- onAborted={() => {
- notifyInfo(i18n.str`Operation canceled`);
- onOperationAborted();
- }}
- />
- );
- }
-
- const account = !data.selected_exchange_account
- ? undefined
- : parsePaytoUri(data.selected_exchange_account);
-
- if (!data.selected_reserve_pub && account) {
- return (
- <Attention
- type="danger"
- title={i18n.str`The operation is marked as 'selected' but some step in the withdrawal failed`}
- >
- <i18n.Translate>
- The account is selected but no withdrawal identification found.
- </i18n.Translate>
- </Attention>
- );
- }
-
- if (!account && data.selected_reserve_pub) {
- return (
- <Attention
- type="danger"
- title={i18n.str`The operation is marked as 'selected' but some step in the withdrawal failed`}
- >
- <i18n.Translate>
- There is a withdrawal identification but no account has been selected
- or the selected account is invalid.
- </i18n.Translate>
- </Attention>
- );
- }
-
- if (!account || !data.selected_reserve_pub) {
- return (
- <Attention
- type="danger"
- title={i18n.str`The operation is marked as 'selected' but some step in the withdrawal failed`}
- >
- <i18n.Translate>
- No withdrawal ID found and no account has been selected or the
- selected account is invalid.
- </i18n.Translate>
- </Attention>
- );
- }
-
- return (
- <WithdrawalConfirmationQuestion
- withdrawUri={withdrawUri}
- routeHere={routeWithdrawalDetails}
- details={{
- username: data.username,
- account,
- reserve: data.selected_reserve_pub,
- amount: Amounts.parseOrThrow(data.amount),
- }}
- onAuthorizationRequired={onAuthorizationRequired}
- onAborted={() => {
- notifyInfo(i18n.str`Operation canceled`);
- onOperationAborted();
- }}
- />
- );
-}
-
-export function OperationNotFound({
- routeClose,
-}: {
- routeClose: RouteDefinition | undefined;
-}): VNode {
- const { i18n } = useTranslationContext();
- return (
- <div class="relative ml-auto mr-auto transform overflow-hidden rounded-lg bg-white px-4 pb-4 pt-5 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6">
- <div>
- <div class="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-red-100 ">
- <svg
- class="h-6 w-6 text-red-600"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- aria-hidden="true"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"
- />
- </svg>
- </div>
-
- <div class="mt-3 text-center sm:mt-5">
- <h3
- class="text-base font-semibold leading-6 text-gray-900"
- id="modal-title"
- >
- <i18n.Translate>Operation not found</i18n.Translate>
- </h3>
- <div class="mt-2">
- <p class="text-sm text-gray-500">
- <i18n.Translate>
- This operation is not known by the server. The operation id is
- wrong or the server deleted the operation information before
- reaching here.
- </i18n.Translate>
- </p>
- </div>
- </div>
- </div>
- {routeClose && (
- <div class="mt-5 sm:mt-6">
- <a
- href={routeClose.url({})}
- name="continue to dashboard"
- class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Cotinue to dashboard</i18n.Translate>
- </a>
- </div>
- )}
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx b/packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx
deleted file mode 100644
index 2216b96fc..000000000
--- a/packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { Cashouts } from "../../components/Cashouts/index.js";
-import { useSessionState } from "../../hooks/session.js";
-import { ProfileNavigation } from "../ProfileNavigation.js";
-import { CreateCashout } from "../regional/CreateCashout.js";
-import { RouteDefinition } from "../../route.js";
-
-interface Props {
- account: string;
- routeClose: RouteDefinition;
- onAuthorizationRequired: () => void;
- routeCashoutDetails: RouteDefinition<{ cid: string }>;
- routeMyAccountDetails: RouteDefinition;
- routeMyAccountDelete: RouteDefinition;
- routeMyAccountPassword: RouteDefinition;
- routeMyAccountCashout: RouteDefinition;
- routeCreateCashout: RouteDefinition;
- routeConversionConfig:RouteDefinition;
-}
-
-export function CashoutListForAccount({
- account,
- onAuthorizationRequired,
- routeCreateCashout,
- routeCashoutDetails,
- routeMyAccountCashout,
- routeMyAccountDelete,
- routeMyAccountDetails,
- routeConversionConfig,
- routeMyAccountPassword,
- routeClose,
-}: Props): VNode {
- const { i18n } = useTranslationContext();
-
- const { state: credentials } = useSessionState();
-
- const accountIsTheCurrentUser =
- credentials.status === "loggedIn"
- ? credentials.username === account
- : false;
-
- return (
- <Fragment>
- {accountIsTheCurrentUser ? (
- <ProfileNavigation current="cashouts"
- routeMyAccountCashout={routeMyAccountCashout}
- routeMyAccountDelete={routeMyAccountDelete}
- routeMyAccountDetails={routeMyAccountDetails}
- routeMyAccountPassword={routeMyAccountPassword}
- routeConversionConfig={routeConversionConfig}
- />
- ) : (
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Cashout for account {account}</i18n.Translate>
- </h1>
- )}
-
- <CreateCashout
- focus
- routeHere={routeCreateCashout}
- routeClose={routeClose}
- onAuthorizationRequired={onAuthorizationRequired}
- account={account}
- />
-
- <Cashouts account={account} routeCashoutDetails={routeCashoutDetails} />
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
deleted file mode 100644
index 62c8df7f8..000000000
--- a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- AbsoluteTime,
- HttpStatusCode,
- TalerCorebankApi,
- TalerError,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- Loading,
- LocalNotificationBanner,
- notifyInfo,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useAccountDetails } from "../../hooks/account.js";
-import { useSessionState } from "../../hooks/session.js";
-import { useBankState } from "../../hooks/bank-state.js";
-import { RouteDefinition } from "../../route.js";
-import { LoginForm } from "../LoginForm.js";
-import { ProfileNavigation } from "../ProfileNavigation.js";
-import { AccountForm } from "../admin/AccountForm.js";
-
-export function ShowAccountDetails({
- account,
- routeClose,
- onUpdateSuccess,
- onAuthorizationRequired,
- routeMyAccountCashout,
- routeMyAccountDelete,
- routeMyAccountDetails,
- routeHere,
- routeMyAccountPassword,
- routeConversionConfig,
-}: {
- routeClose: RouteDefinition;
- routeHere: RouteDefinition<{ account: string }>;
- routeMyAccountDetails: RouteDefinition;
- routeMyAccountDelete: RouteDefinition;
- routeMyAccountPassword: RouteDefinition;
- routeMyAccountCashout: RouteDefinition;
- routeConversionConfig: RouteDefinition;
- onUpdateSuccess: () => void;
- onAuthorizationRequired: () => void;
- account: string;
-}): VNode {
- const { i18n } = useTranslationContext();
- const { state: credentials } = useSessionState();
- const creds = credentials.status !== "loggedIn" ? undefined : credentials;
- const { bank: api } = useBankCoreApiContext();
- const accountIsTheCurrentUser =
- credentials.status === "loggedIn"
- ? credentials.username === account
- : false;
-
- const [submitAccount, setSubmitAccount] = useState<
- TalerCorebankApi.AccountReconfiguration | undefined
- >();
- const [notification, notify, handleError] = useLocalNotification();
- const [, updateBankState] = useBankState();
-
- const result = useAccountDetails(account);
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <ErrorLoadingWithDebug error={result} />;
- }
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.Unauthorized:
- case HttpStatusCode.NotFound:
- return <LoginForm currentUser={account} />;
- default:
- assertUnreachable(result);
- }
- }
-
- async function doUpdate() {
- if (!submitAccount || !creds) return;
- await handleError(async () => {
- const resp = await api.updateAccount(
- {
- token: creds.token,
- username: account,
- },
- submitAccount,
- );
-
- if (resp.type === "ok") {
- notifyInfo(i18n.str`Account updated`);
- onUpdateSuccess();
- } else {
- switch (resp.case) {
- case HttpStatusCode.Unauthorized:
- return notify({
- type: "error",
- title: i18n.str`The rights to change the account are not sufficient`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`The username was not found`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_LEGAL_NAME:
- return notify({
- type: "error",
- title: i18n.str`You can't change the legal name, please contact the your account administrator.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
- return notify({
- type: "error",
- title: i18n.str`You can't change the debt limit, please contact the your account administrator.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_CASHOUT:
- return notify({
- type: "error",
- title: i18n.str`You can't change the cashout address, please contact the your account administrator.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_MISSING_TAN_INFO:
- return notify({
- type: "error",
- title: i18n.str`No information for the selected authentication channel.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Accepted: {
- updateBankState("currentChallenge", {
- operation: "update-account",
- id: String(resp.body.challenge_id),
- location: routeHere.url({ account }),
- sent: AbsoluteTime.never(),
- request: submitAccount,
- });
- return onAuthorizationRequired();
- }
- case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED: {
- return notify({
- type: "error",
- title: i18n.str`Authentication channel is not supported.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- }
- default:
- assertUnreachable(resp);
- }
- }
- });
- }
-
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} showDebug={true} />
- {accountIsTheCurrentUser ? (
- <ProfileNavigation current="details"
- routeMyAccountCashout={routeMyAccountCashout}
- routeMyAccountDelete={routeMyAccountDelete}
- routeConversionConfig={routeConversionConfig}
- routeMyAccountDetails={routeMyAccountDetails}
- routeMyAccountPassword={routeMyAccountPassword}
- />
- ) : (
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Account "{account}"</i18n.Translate>
- </h1>
- )}
-
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-semibold leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Change details</i18n.Translate>
- </span>
- </span>
- </div>
- </h2>
- </div>
-
- <AccountForm
- focus={true}
- username={account}
- template={result.body}
- purpose="update"
- onChange={(a) => setSubmitAccount(a)}
- >
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <a
- href={routeClose.url({})}
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="update"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!submitAccount}
- onClick={doUpdate}
- >
- <i18n.Translate>Update</i18n.Translate>
- </button>
- </div>
- </AccountForm>
- </div>
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx
deleted file mode 100644
index e21ac2464..000000000
--- a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- AbsoluteTime,
- HttpStatusCode,
- TalerErrorCode,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- LocalNotificationBanner,
- ShowInputErrorLabel,
- notifyInfo,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useSessionState } from "../../hooks/session.js";
-import { useBankState } from "../../hooks/bank-state.js";
-import { RouteDefinition } from "../../route.js";
-import { undefinedIfEmpty } from "../../utils.js";
-import { doAutoFocus } from "../PaytoWireTransferForm.js";
-import { ProfileNavigation } from "../ProfileNavigation.js";
-
-export function UpdateAccountPassword({
- account: accountName,
- routeClose,
- onUpdateSuccess,
- onAuthorizationRequired,
- routeMyAccountCashout,
- routeMyAccountDelete,
- routeMyAccountDetails,
- routeMyAccountPassword,
- routeConversionConfig,
- focus,
- routeHere,
-}: {
- routeClose: RouteDefinition;
- routeHere: RouteDefinition<{ account: string }>;
- routeMyAccountDetails: RouteDefinition;
- routeMyAccountDelete: RouteDefinition;
- routeMyAccountPassword: RouteDefinition;
- routeMyAccountCashout: RouteDefinition;
- routeConversionConfig: RouteDefinition;
- focus?: boolean;
- onAuthorizationRequired: () => void;
- onUpdateSuccess: () => void;
- account: string;
-}): VNode {
- const { i18n } = useTranslationContext();
- const { state: credentials } = useSessionState();
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
- const { bank: api } = useBankCoreApiContext();
-
- const [current, setCurrent] = useState<string | undefined>();
- const [password, setPassword] = useState<string | undefined>();
- const [repeat, setRepeat] = useState<string | undefined>();
- const [, updateBankState] = useBankState();
-
- const accountIsTheCurrentUser =
- credentials.status === "loggedIn"
- ? credentials.username === accountName
- : false;
-
- const errors = undefinedIfEmpty({
- current: !accountIsTheCurrentUser
- ? undefined
- : !current
- ? i18n.str`Required`
- : undefined,
- password: !password ? i18n.str`Required` : undefined,
- repeat: !repeat
- ? i18n.str`Required`
- : password !== repeat
- ? i18n.str`Repeated password doesn't match`
- : undefined,
- });
- const [notification, notify, handleError] = useLocalNotification();
-
- async function doChangePassword() {
- if (!!errors || !password || !token) return;
- await handleError(async () => {
- const request = {
- old_password: current,
- new_password: password,
- };
- const resp = await api.updatePassword(
- { username: accountName, token },
- request,
- );
- if (resp.type === "ok") {
- notifyInfo(i18n.str`Password changed`);
- onUpdateSuccess();
- } else {
- switch (resp.case) {
- case HttpStatusCode.Unauthorized:
- return notify({
- type: "error",
- title: i18n.str`Not authorized to change the password, maybe the session is invalid.`,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`Account not found`,
- });
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_MISSING_OLD_PASSWORD:
- return notify({
- type: "error",
- title: i18n.str`You need to provide the old password. If you don't have it contact your account administrator.`,
- });
- case TalerErrorCode.BANK_PATCH_BAD_OLD_PASSWORD:
- return notify({
- type: "error",
- title: i18n.str`Your current password doesn't match, can't change to a new password.`,
- });
- case HttpStatusCode.Accepted: {
- updateBankState("currentChallenge", {
- operation: "update-password",
- id: String(resp.body.challenge_id),
- location: routeHere.url({ account: accountName }),
- sent: AbsoluteTime.never(),
- request,
- });
- return onAuthorizationRequired();
- }
- default:
- assertUnreachable(resp);
- }
- }
- });
- }
-
- return (
- <Fragment>
- <LocalNotificationBanner notification={notification} />
- {accountIsTheCurrentUser ? (
- <ProfileNavigation current="credentials"
- routeMyAccountCashout={routeMyAccountCashout}
- routeMyAccountDelete={routeMyAccountDelete}
- routeMyAccountDetails={routeMyAccountDetails}
- routeMyAccountPassword={routeMyAccountPassword}
- routeConversionConfig={routeConversionConfig}
- />
- ) : (
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Account "{accountName}"</i18n.Translate>
- </h1>
- )}
-
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <i18n.Translate>Update password</i18n.Translate>
- </h2>
- </div>
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="px-4 py-6 sm:p-8">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- {accountIsTheCurrentUser ? (
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="password"
- >
- {i18n.str`Current password`}
- </label>
- <div class="mt-2">
- <input
- type="password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="current"
- id="current-password"
- data-error={!!errors?.current && current !== undefined}
- value={current ?? ""}
- onChange={(e) => {
- setCurrent(e.currentTarget.value);
- }}
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.current}
- isDirty={current !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>
- Your current password, for security
- </i18n.Translate>
- </p>
- </div>
- ) : undefined}
-
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="password"
- >
- {i18n.str`New password`}
- </label>
- <div class="mt-2">
- <input
- ref={focus ? doAutoFocus : undefined}
- type="password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="password"
- id="password"
- data-error={!!errors?.password && password !== undefined}
- value={password ?? ""}
- onChange={(e) => {
- setPassword(e.currentTarget.value);
- }}
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.password}
- isDirty={password !== undefined}
- />
- </div>
- </div>
-
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="repeat"
- >
- {i18n.str`Type it again`}
- </label>
- <div class="mt-2">
- <input
- type="password"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="repeat"
- id="repeat"
- data-error={!!errors?.repeat && repeat !== undefined}
- value={repeat ?? ""}
- onChange={(e) => {
- setRepeat(e.currentTarget.value);
- }}
- // placeholder=""
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.repeat}
- isDirty={repeat !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Repeat the same password</i18n.Translate>
- </p>
- </div>
-
- </div>
- </div>
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <a
- href={routeClose.url({})}
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="change"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- onClick={(e) => {
- e.preventDefault();
- doChangePassword();
- }}
- >
- <i18n.Translate>Change</i18n.Translate>
- </button>
- </div>
- </form>
- </div>
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/admin/AccountForm.tsx b/packages/demobank-ui/src/pages/admin/AccountForm.tsx
deleted file mode 100644
index bce7afe11..000000000
--- a/packages/demobank-ui/src/pages/admin/AccountForm.tsx
+++ /dev/null
@@ -1,901 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- AmountString,
- Amounts,
- PaytoString,
- TalerCorebankApi,
- TranslatedString,
- assertUnreachable,
- buildPayto,
- parsePaytoUri,
- stringifyPaytoUri,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- CopyButton,
- ShowInputErrorLabel,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { ComponentChildren, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { VersionHint, useBankCoreApiContext } from "../../context/config.js";
-import { useSessionState } from "../../hooks/session.js";
-import {
- ErrorMessageMappingFor,
- TanChannel,
- undefinedIfEmpty,
- validateIBAN,
- validateTalerBank,
-} from "../../utils.js";
-import { InputAmount, TextField, doAutoFocus } from "../PaytoWireTransferForm.js";
-import { getRandomPassword } from "../rnd.js";
-
-const EMAIL_REGEX =
- /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
-const REGEX_JUST_NUMBERS_REGEX = /^\+[0-9 ]*$/;
-
-export type AccountFormData = {
- debit_threshold?: string;
- isExchange?: boolean;
- isPublic?: boolean;
- name?: string;
- username?: string;
- payto_uri?: string;
- cashout_payto_uri?: string;
- email?: string;
- phone?: string;
- tan_channel?: TanChannel | "remove";
-};
-
-type ChangeByPurposeType = {
- create: (a: TalerCorebankApi.RegisterAccountRequest | undefined) => void;
- update: (a: TalerCorebankApi.AccountReconfiguration | undefined) => void;
- show: undefined;
-};
-/**
- * FIXME:
- * is_public is missing on PATCH
- * account email/password should require 2FA
- *
- *
- * @param param0
- * @returns
- */
-export function AccountForm<PurposeType extends keyof ChangeByPurposeType>({
- template,
- username,
- purpose,
- onChange,
- focus,
- children,
-}: {
- focus?: boolean;
- children: ComponentChildren;
- username?: string;
- template: TalerCorebankApi.AccountData | undefined;
- onChange: ChangeByPurposeType[PurposeType];
- purpose: PurposeType;
-}): VNode {
- const { config, hints, url } = useBankCoreApiContext();
- const { i18n } = useTranslationContext();
- const { state: credentials } = useSessionState();
- const [form, setForm] = useState<AccountFormData>({});
-
- const [errors, setErrors] = useState<
- ErrorMessageMappingFor<typeof defaultValue> | undefined
- >(undefined);
-
- const paytoType = config.wire_type === "X_TALER_BANK" ? "x-taler-bank" as const : "iban" as const;
- const cashoutPaytoType: typeof paytoType = "iban" as const;
-
- const defaultValue: AccountFormData = {
- debit_threshold: Amounts.stringifyValue(
- template?.debit_threshold ?? config.default_debit_threshold,
- ),
- isExchange: template?.is_taler_exchange,
- isPublic: template?.is_public,
- name: template?.name ?? "",
- cashout_payto_uri:
- getAccountId(cashoutPaytoType, template?.cashout_payto_uri) ?? ("" as PaytoString),
- payto_uri: getAccountId(paytoType, template?.payto_uri) ?? ("" as PaytoString),
- email: template?.contact_data?.email ?? "",
- phone: template?.contact_data?.phone ?? "",
- username: username ?? "",
- tan_channel: template?.tan_channel,
- };
-
- const OLD_CASHOUT_API = hints.indexOf(VersionHint.CASHOUT_BEFORE_2FA) !== -1;
-
- const userIsAdmin =
- credentials.status !== "loggedIn" ? false : credentials.isUserAdministrator;
-
- const editableUsername = purpose === "create";
- const editableName =
- purpose === "create" ||
- (purpose === "update" && (config.allow_edit_name || userIsAdmin));
-
- const isCashoutEnabled = config.allow_conversion;
- const editableCashout =
- (purpose === "create" ||
- (purpose === "update" &&
- (config.allow_edit_cashout_payto_uri || userIsAdmin)));
- const editableThreshold =
- userIsAdmin && (purpose === "create" || purpose === "update");
- const editableAccount = purpose === "create" && userIsAdmin;
-
- const hasPhone = !!defaultValue.phone || !!form.phone;
- const hasEmail = !!defaultValue.email || !!form.email;
-
- function updateForm(newForm: typeof defaultValue): void {
-
- const trimmedAmountStr = newForm.debit_threshold?.trim();
- const parsedAmount = Amounts.parse(
- `${config.currency}:${trimmedAmountStr}`,
- );
-
- const errors = undefinedIfEmpty<
- ErrorMessageMappingFor<typeof defaultValue>
- >({
- cashout_payto_uri: !newForm.cashout_payto_uri
- ? undefined
- : !editableCashout
- ? undefined
- : !newForm.cashout_payto_uri ? undefined
- : cashoutPaytoType === "iban" ? validateIBAN(newForm.cashout_payto_uri, i18n) :
- cashoutPaytoType === "x-taler-bank" ? validateTalerBank(newForm.cashout_payto_uri, i18n) :
- undefined,
-
- payto_uri: !newForm.payto_uri
- ? undefined
- : !editableAccount
- ? undefined
- : !newForm.payto_uri ? undefined
- : paytoType === "iban" ? validateIBAN(newForm.payto_uri, i18n) :
- paytoType === "x-taler-bank" ? validateTalerBank(newForm.payto_uri, i18n) :
- undefined,
-
- email: !newForm.email
- ? undefined
- : !EMAIL_REGEX.test(newForm.email)
- ? i18n.str`Doesn't have the pattern of an email`
- : undefined,
- phone: !newForm.phone
- ? undefined
- : !newForm.phone.startsWith("+") // FIXME: better phone number check
- ? i18n.str`Should start with +`
- : !REGEX_JUST_NUMBERS_REGEX.test(newForm.phone)
- ? i18n.str`Phone number can't have other than numbers`
- : undefined,
- debit_threshold: !editableThreshold
- ? undefined
- : !trimmedAmountStr
- ? undefined
- : !parsedAmount
- ? i18n.str`Not valid`
- : undefined,
- name: !editableName
- ? undefined // disabled
- : !newForm.name
- ? i18n.str`Required`
- : undefined,
- username: !editableUsername
- ? undefined
- : !newForm.username
- ? i18n.str`Required`
- : undefined,
- });
- setErrors(errors);
-
- setForm(newForm);
- if (!onChange) return;
-
- if (errors) {
- onChange(undefined);
- } else {
- let cashout;
- if (newForm.cashout_payto_uri) switch (cashoutPaytoType) {
- case "x-taler-bank": {
- cashout = buildPayto("x-taler-bank", url.host, newForm.cashout_payto_uri);
- break;
- }
- case "iban": {
- cashout = buildPayto("iban", newForm.cashout_payto_uri, undefined);
- break;
- }
- default: assertUnreachable(cashoutPaytoType)
- }
- const cashoutURI = !cashout ? undefined : stringifyPaytoUri(cashout);
- let internal;
- if (newForm.payto_uri) switch (paytoType) {
- case "x-taler-bank": {
- internal = buildPayto("x-taler-bank", url.host, newForm.payto_uri);
- break;
- }
- case "iban": {
- internal = buildPayto("iban", newForm.payto_uri, undefined);
- break;
- }
- default: assertUnreachable(paytoType)
- }
- const internalURI = !internal ? undefined : stringifyPaytoUri(internal);
-
- const threshold = !parsedAmount
- ? undefined
- : Amounts.stringify(parsedAmount);
-
- switch (purpose) {
- case "create": {
- // typescript doesn't correctly narrow a generic type
- const callback = onChange as ChangeByPurposeType["create"];
- const result: TalerCorebankApi.RegisterAccountRequest = {
- name: newForm.name!,
- password: getRandomPassword(),
- username: newForm.username!,
- contact_data: undefinedIfEmpty({
- email: !newForm.email ? undefined : newForm.email,
- phone: !newForm.phone ? undefined :newForm.phone,
- }),
- debit_threshold: threshold ?? config.default_debit_threshold,
- cashout_payto_uri: cashoutURI,
- payto_uri: internalURI,
- is_public: newForm.isPublic,
- is_taler_exchange: newForm.isExchange,
- tan_channel:
- newForm.tan_channel === "remove"
- ? undefined
- : newForm.tan_channel,
- };
- callback(result);
- return;
- }
- case "update": {
- // typescript doesn't correctly narrow a generic type
- const callback = onChange as ChangeByPurposeType["update"];
-
- const result: TalerCorebankApi.AccountReconfiguration = {
- cashout_payto_uri: cashoutURI,
- contact_data: undefinedIfEmpty({
- email: !newForm.email ? undefined : newForm.email,
- phone: !newForm.phone ? undefined :newForm.phone,
- }),
- debit_threshold: threshold,
- is_public: newForm.isPublic,
- name: newForm.name,
- tan_channel:
- newForm.tan_channel === "remove" ? null : newForm.tan_channel,
- };
- callback(result);
- return;
- }
- case "show": {
- return;
- }
- default: {
- assertUnreachable(purpose);
- }
- }
- }
- }
- return (
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="px-4 py-6 sm:p-8">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="username"
- >
- {i18n.str`Login username`}
- {editableUsername && <b style={{ color: "red" }}> *</b>}
- </label>
- <div class="mt-2">
- <input
- ref={focus && purpose === "create" ? doAutoFocus : undefined}
- type="text"
- class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="username"
- id="username"
- data-error={!!errors?.username && form.username !== undefined}
- disabled={!editableUsername}
- value={form.username ?? defaultValue.username}
- onChange={(e) => {
- form.username = e.currentTarget.value;
- updateForm(structuredClone(form));
- }}
- // placeholder=""
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.username}
- isDirty={form.username !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Account id for authentication</i18n.Translate>
- </p>
- </div>
-
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="name"
- >
- {i18n.str`Full name`}
- {editableName && <b style={{ color: "red" }}> *</b>}
- </label>
- <div class="mt-2">
- <input
- type="text"
- class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="name"
- data-error={!!errors?.name && form.name !== undefined}
- id="name"
- disabled={!editableName}
- value={form.name ?? defaultValue.name}
- onChange={(e) => {
- form.name = e.currentTarget.value;
- updateForm(structuredClone(form));
- }}
- // placeholder=""
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.name}
- isDirty={form.name !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Name of the account holder</i18n.Translate>
- </p>
- </div>
-
- {purpose === "create" ? undefined :
- <TextField
- id="internal-account"
- label={i18n.str`Internal account`}
- help={
- purpose === "create"
- ? i18n.str`If empty a random account id will be assigned`
- : i18n.str`Share this id to receive bank transfers`
- }
-
- error={errors?.payto_uri}
- onChange={(e) => {
- form.payto_uri = e as PaytoString;
- updateForm(structuredClone(form));
- }}
- rightIcons={<CopyButton
- class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
- getContent={() => form.payto_uri ?? defaultValue.payto_uri ?? ""}
- />}
- value={(form.payto_uri ?? defaultValue.payto_uri) as PaytoString}
- disabled={!editableAccount}
- />
- }
-
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="email"
- >
- {i18n.str`Email`}
- </label>
- <div class="mt-2">
- <input
- type="email"
- class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="email"
- id="email"
- data-error={!!errors?.email && form.email !== undefined}
- disabled={purpose === "show"}
- value={form.email ?? defaultValue.email}
- onChange={(e) => {
- form.email = e.currentTarget.value;
- updateForm(structuredClone(form));
- }}
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.email}
- isDirty={form.email !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>To be used when second factor authentication is enabled</i18n.Translate>
- </p>
- </div>
-
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="phone"
- >
- {i18n.str`Phone`}
- </label>
- <div class="mt-2">
- <input
- type="text"
- class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="phone"
- id="phone"
- disabled={purpose === "show"}
- value={form.phone ?? defaultValue.phone}
- data-error={!!errors?.phone && form.phone !== undefined}
- onChange={(e) => {
- form.phone = e.currentTarget.value;
- updateForm(structuredClone(form));
- }}
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.phone}
- isDirty={form.phone !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>To be used when second factor authentication is enabled</i18n.Translate>
- </p>
- </div>
-
- {isCashoutEnabled && (
- <TextField
- id="cashout-account"
- label={i18n.str`Cashout account`}
- help={i18n.str`External account number where the money is going to be sent when doing cashouts`}
- error={errors?.cashout_payto_uri}
- onChange={(e) => {
- form.cashout_payto_uri = e as PaytoString;
- updateForm(structuredClone(form));
- }}
- value={(form.cashout_payto_uri ?? defaultValue.cashout_payto_uri) as PaytoString}
- disabled={!editableCashout}
- />
- )}
-
- {/* channel, not shown if old cashout api */}
- {OLD_CASHOUT_API ||
- config.supported_tan_channels.length === 0 ? undefined : (
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="channel"
- >
- {i18n.str`Enable second factor authentication`}
- </label>
- <div class="mt-2 max-w-xl text-sm text-gray-500">
- <div class="px-4 mt-4 grid grid-cols-1 gap-y-6">
- {config.supported_tan_channels.indexOf(TanChannel.EMAIL) ===
- -1 ? undefined : (
- <label
- onClick={(e) => {
- if (!hasEmail) return;
- if (form.tan_channel === TanChannel.EMAIL) {
- form.tan_channel = "remove";
- } else {
- form.tan_channel = TanChannel.EMAIL;
- }
- updateForm(structuredClone(form));
- e.preventDefault();
- }}
- data-disabled={purpose === "show" || !hasEmail}
- data-selected={
- (form.tan_channel ?? defaultValue.tan_channel) ===
- TanChannel.EMAIL
- }
- class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border bg-white data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="channel"
- value="Newsletter"
- class="sr-only"
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span
- id="project-type-0-label"
- class="block text-sm font-medium text-gray-900 "
- >
- <i18n.Translate>Using email</i18n.Translate>
- </span>
- {purpose !== "show" &&
- !hasEmail &&
- i18n.str`Add an email in your profile to enable this option`}
- </span>
- </span>
- <svg
- data-selected={
- (form.tan_channel ?? defaultValue.tan_channel) ===
- TanChannel.EMAIL
- }
- class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </label>
- )}
-
- {config.supported_tan_channels.indexOf(TanChannel.SMS) ===
- -1 ? undefined : (
- <label
- onClick={(e) => {
- if (!hasPhone) return;
- if (form.tan_channel === TanChannel.SMS) {
- form.tan_channel = "remove";
- } else {
- form.tan_channel = TanChannel.SMS;
- }
- updateForm(structuredClone(form));
- e.preventDefault();
- }}
- data-disabled={purpose === "show" || !hasPhone}
- data-selected={
- (form.tan_channel ?? defaultValue.tan_channel) ===
- TanChannel.SMS
- }
- class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="channel"
- value="Existing Customers"
- class="sr-only"
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span
- id="project-type-1-label"
- class="block text-sm font-medium text-gray-900"
- >
- <i18n.Translate>Using SMS</i18n.Translate>
- </span>
- {purpose !== "show" &&
- !hasPhone &&
- i18n.str`Add a phone number in your profile to enable this option`}
- </span>
- </span>
- <svg
- data-selected={
- (form.tan_channel ?? defaultValue.tan_channel) ===
- TanChannel.SMS
- }
- class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </label>
- )}
- </div>
- </div>
- </div>
- )}
-
- <div class="sm:col-span-5">
- <label
- for="debit"
- class="block text-sm font-medium leading-6 text-gray-900"
- >{i18n.str`Max debt`}</label>
- <InputAmount
- name="debit"
- left
- currency={config.currency}
- value={form.debit_threshold ?? defaultValue.debit_threshold}
- onChange={
- !editableThreshold
- ? undefined
- : (e) => {
- form.debit_threshold = e as AmountString;
- updateForm(structuredClone(form));
- }
- }
- />
- <ShowInputErrorLabel
- message={
- errors?.debit_threshold
- ? String(errors?.debit_threshold)
- : undefined
- }
- isDirty={form.debit_threshold !== undefined}
- />
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>How much the balance can go below zero.</i18n.Translate>
- </p>
- </div>
-
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Is this account public?</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name="is public"
- data-enabled={
- form.isPublic ?? defaultValue.isPublic ? "true" : "false"
- }
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- form.isPublic = !(form.isPublic ?? defaultValue.isPublic);
- updateForm(structuredClone(form));
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={
- form.isPublic ?? defaultValue.isPublic ? "true" : "false"
- }
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Public accounts have their balance publicly accessible</i18n.Translate>
- </p>
- </div>
-
- {purpose !== "create" || !userIsAdmin ? undefined : (
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Is this account a payment provider?</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name="is exchange"
- data-enabled={
- form.isExchange ?? defaultValue.isExchange
- ? "true"
- : "false"
- }
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- form.isExchange = !form.isExchange;
- updateForm(structuredClone(form));
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={
- form.isExchange ?? defaultValue.isExchange
- ? "true"
- : "false"
- }
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- )}
- </div>
- </div>
- {children}
- </form>
- );
-}
-
-function getAccountId(type: "iban" | "x-taler-bank", s: PaytoString | undefined): string | undefined {
- if (s === undefined) return undefined;
- const p = parsePaytoUri(s);
- if (p === undefined) return undefined;
- if (!p.isKnown) return "<unknown>";
- if (type === "iban" && p.targetType === "iban") return p.iban;
- if (type === "x-taler-bank" && p.targetType === "x-taler-bank") return p.account;
- return "<unsupported>";
-}
-
-{
- /* <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="cashout"
- >
- {}
- </label>
- <div class="mt-2">
- <input
- type="text"
- ref={focus && purpose === "update" ? doAutoFocus : undefined}
- data-error={!!errors?.cashout_payto_uri && form.cashout_payto_uri !== undefined}
- class="block w-full disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="cashout"
- id="cashout"
- disabled={purpose === "show"}
- value={form.cashout_payto_uri ?? defaultValue.cashout_payto_uri}
- onChange={(e) => {
- form.cashout_payto_uri = e.currentTarget.value as PaytoString;
- if (!form.cashout_payto_uri) {
- form.cashout_payto_uri = undefined
- }
- updateForm(structuredClone(form));
- }}
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.cashout_payto_uri}
- isDirty={form.cashout_payto_uri !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500" >
- <i18n.Translate></i18n.Translate>
- </p>
- </div> */
-}
-
-// function PaytoField({
-// name,
-// label,
-// help,
-// type,
-// value,
-// disabled,
-// onChange,
-// error,
-// }: {
-// error: TranslatedString | undefined;
-// name: string;
-// label: TranslatedString;
-// help: TranslatedString;
-// onChange: (s: string) => void;
-// type: "iban" | "x-taler-bank" | "bitcoin";
-// disabled?: boolean;
-// value: string | undefined;
-// }): VNode {
-// if (type === "iban") {
-// return (
-// <div class="sm:col-span-5">
-// <label
-// class="block text-sm font-medium leading-6 text-gray-900"
-// for={name}
-// >
-// {label}
-// </label>
-// <div class="mt-2">
-// <div class="flex justify-between">
-// <input
-// type="text"
-// class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
-// name={name}
-// id={name}
-// disabled={disabled}
-// value={value ?? ""}
-// onChange={(e) => {
-// onChange(e.currentTarget.value);
-// }}
-// />
-// <CopyButton
-// class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
-// getContent={() => value ?? ""}
-// />
-// </div>
-// <ShowInputErrorLabel message={error} isDirty={value !== undefined} />
-// </div>
-// <p class="mt-2 text-sm text-gray-500">{help}</p>
-// </div>
-// );
-// }
-// if (type === "x-taler-bank") {
-// return (
-// <div class="sm:col-span-5">
-// <label
-// class="block text-sm font-medium leading-6 text-gray-900"
-// for={name}
-// >
-// {label}
-// </label>
-// <div class="mt-2">
-// <div class="flex justify-between">
-// <input
-// type="text"
-// class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
-// name={name}
-// id={name}
-// disabled={disabled}
-// value={value ?? ""}
-// onChange={(e) => {
-// onChange(e.currentTarget.value);
-// }}
-// />
-// <CopyButton
-// class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
-// getContent={() => value ?? ""}
-// />
-// </div>
-// <ShowInputErrorLabel message={error} isDirty={value !== undefined} />
-// </div>
-// <p class="mt-2 text-sm text-gray-500">
-// {help}
-// </p>
-// </div>
-// );
-// }
-// if (type === "bitcoin") {
-// return (
-// <div class="sm:col-span-5">
-// <label
-// class="block text-sm font-medium leading-6 text-gray-900"
-// for={name}
-// >
-// {label}
-// </label>
-// <div class="mt-2">
-// <div class="flex justify-between">
-// <input
-// type="text"
-// class="mr-4 w-full block-inline disabled:bg-gray-100 rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
-// name={name}
-// id={name}
-// disabled={disabled}
-// value={value ?? ""}
-// />
-// <CopyButton
-// class="p-2 rounded-full text-black shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 "
-// getContent={() => value ?? ""}
-// />
-// <ShowInputErrorLabel
-// message={error}
-// isDirty={value !== undefined}
-// />
-// </div>
-// </div>
-// <p class="mt-2 text-sm text-gray-500">
-// {/* <i18n.Translate>bitcoin address</i18n.Translate> */}
-// {help}
-// </p>
-// </div>
-// );
-// }
-// assertUnreachable(type);
-// }
diff --git a/packages/demobank-ui/src/pages/admin/AccountList.tsx b/packages/demobank-ui/src/pages/admin/AccountList.tsx
deleted file mode 100644
index 4e465d4b5..000000000
--- a/packages/demobank-ui/src/pages/admin/AccountList.tsx
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- Amounts,
- HttpStatusCode,
- TalerError,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import { Loading, useTranslationContext } from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useBusinessAccounts } from "../../hooks/regional.js";
-import { RenderAmount } from "../PaytoWireTransferForm.js";
-import { RouteDefinition } from "../../route.js";
-
-interface Props {
- routeCreate: RouteDefinition;
-
- routeShowAccount: RouteDefinition<{ account: string }>;
- routeRemoveAccount: RouteDefinition<{ account: string }>;
- routeUpdatePasswordAccount: RouteDefinition<{ account: string }>;
- routeShowCashoutsAccount: RouteDefinition<{ account: string }>;
-}
-
-export function AccountList({
- routeCreate,
- routeRemoveAccount,
- routeShowAccount,
- routeShowCashoutsAccount,
- routeUpdatePasswordAccount,
-}: Props): VNode {
- const result = useBusinessAccounts();
- const { i18n } = useTranslationContext();
- const { config } = useBankCoreApiContext();
-
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <ErrorLoadingWithDebug error={result} />;
- }
- if (result.data.type === "fail") {
- switch (result.data.case) {
- case HttpStatusCode.Unauthorized:
- return <Fragment />;
- default:
- assertUnreachable(result.data.case);
- }
- }
-
- const onGoStart = result.isFirstPage ? undefined : result.loadFirst
- const onGoNext = result.isLastPage ? undefined : result.loadNext
-
- const accounts = result.result;
- return (
- <Fragment>
- <div class="px-4 sm:px-6 lg:px-8 mt-4">
- <div class="sm:flex sm:items-center">
- <div class="sm:flex-auto">
- <h1 class="text-base font-semibold leading-6 text-gray-900">
- <i18n.Translate>Accounts</i18n.Translate>
- </h1>
- <p class="mt-2 text-sm text-gray-700">
- <i18n.Translate>
- A list of all bank accounts.
- </i18n.Translate>
- </p>
- </div>
- <div class="mt-4 sm:ml-16 sm:mt-0 sm:flex-none">
- <a
- href={routeCreate.url({})}
- name="create account"
- type="button"
- class="block rounded-md bg-indigo-600 px-3 py-2 text-center text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Create account</i18n.Translate>
- </a>
- </div>
- </div>
- <div class="mt-8 flow-root">
- <div class="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
- <div class="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
- {!accounts.length ? (
- <div>
- {/* FIXME: ADD empty list */}
- </div>
- ) : (
- <table class="min-w-full divide-y divide-gray-300">
- <thead>
- <tr>
- <th
- scope="col"
- class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0"
- >{i18n.str`Username`}</th>
- <th
- scope="col"
- class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
- >{i18n.str`Name`}</th>
- <th
- scope="col"
- class="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
- >{i18n.str`Balance`}</th>
- <th scope="col" class="relative py-3.5 pl-3 pr-4 sm:pr-0">
- <span class="sr-only">{i18n.str`Actions`}</span>
- </th>
- </tr>
- </thead>
- <tbody class="divide-y divide-gray-200">
- {accounts.map((item, idx) => {
- const balance = !item.balance
- ? undefined
- : Amounts.parse(item.balance.amount);
- const noBalance = Amounts.isZero(item.balance.amount);
- const balanceIsDebit =
- item.balance &&
- item.balance.credit_debit_indicator == "debit";
-
- return (
- <tr key={idx}>
- <td class="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-0">
- <a
- name={`show account ${item.username}`}
- href={routeShowAccount.url({
- account: item.username,
- })}
- class="text-indigo-600 hover:text-indigo-900"
- >
- {item.username}
- </a>
- </td>
- <td class="whitespace-nowrap px-3 py-4 text-sm text-gray-500">
- {item.name}
- </td>
- <td
- data-negative={
- noBalance
- ? undefined
- : balanceIsDebit
- ? "true"
- : "false"
- }
- class="whitespace-nowrap px-3 py-4 text-sm text-gray-500 data-[negative=false]:text-green-600 data-[negative=true]:text-red-600 "
- >
- {!balance ? (
- i18n.str`Unknown`
- ) : (
- <span class="amount">
- <RenderAmount
- value={balance}
- negative={balanceIsDebit}
- spec={config.currency_specification}
- />
- </span>
- )}
- </td>
- <td class="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
- <a
- name={`update password ${item.username}`}
- href={routeUpdatePasswordAccount.url({
- account: item.username,
- })}
- class="text-indigo-600 hover:text-indigo-900"
- >
- <i18n.Translate>Change password</i18n.Translate>
- </a>
- <br />
- {/* {config.allow_conversion ?
- <Fragment>
-
- <a
- name={`show cashout ${item.username}`}
- href={routeShowCashoutsAccount.url({
- account: item.username,
- })}
- class="text-indigo-600 hover:text-indigo-900"
- >
- <i18n.Translate>Cashouts</i18n.Translate>
- </a>
- <br />
- </Fragment>
- : undefined} */}
- {noBalance ? (
- <a
- name={`remove account ${item.username}`}
- href={routeRemoveAccount.url({
- account: item.username,
- })}
- class="text-indigo-600 hover:text-indigo-900"
- >
- <i18n.Translate>Remove</i18n.Translate>
- </a>
- ) : undefined}
- </td>
- </tr>
- );
- })}
- </tbody>
- </table>
- )}
- </div>
- <nav
- class="flex items-center justify-between border-t border-gray-200 bg-white px-4 py-3 sm:px-6 rounded-lg"
- aria-label="Pagination"
- >
- <div class="flex flex-1 justify-between sm:justify-end">
- <button
- name="first page"
- class="relative disabled:bg-gray-100 disabled:text-gray-500 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
- disabled={!onGoStart}
- onClick={onGoStart}
- >
- <i18n.Translate>First page</i18n.Translate>
- </button>
- <button
- name="next page"
- class="relative disabled:bg-gray-100 disabled:text-gray-500 ml-3 inline-flex items-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus-visible:outline-offset-0"
- disabled={!onGoNext}
- onClick={onGoNext}
- >
- <i18n.Translate>Next</i18n.Translate>
- </button>
- </div>
- </nav>
-
- </div>
- </div>
- </div>
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/admin/AdminHome.tsx b/packages/demobank-ui/src/pages/admin/AdminHome.tsx
deleted file mode 100644
index 752d86aa6..000000000
--- a/packages/demobank-ui/src/pages/admin/AdminHome.tsx
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- AmountString,
- Amounts,
- CurrencySpecification,
- HttpStatusCode,
- TalerCorebankApi,
- TalerError,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import { Attention, useTranslationContext } from "@gnu-taler/web-util/browser";
-import {
- format,
- getDate,
- getHours,
- getMonth,
- getYear,
- setDate,
- setHours,
- setMonth,
- setYear,
- sub,
-} from "date-fns";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
-import { Transactions } from "../../components/Transactions/index.js";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useConversionInfo, useLastMonitorInfo } from "../../hooks/regional.js";
-import { RouteDefinition } from "../../route.js";
-import { RenderAmount } from "../PaytoWireTransferForm.js";
-import { WireTransfer } from "../WireTransfer.js";
-import { AccountList } from "./AccountList.js";
-
-/**
- * Query account information and show QR code if there is pending withdrawal
- */
-interface Props {
- routeCreate: RouteDefinition;
- routeDownloadStats: RouteDefinition;
- routeCreateWireTransfer: RouteDefinition<{
- account?: string,
- subject?: string,
- amount?: string,
- }>;
-
- routeShowAccount: RouteDefinition<{ account: string }>;
- routeRemoveAccount: RouteDefinition<{ account: string }>;
- routeUpdatePasswordAccount: RouteDefinition<{ account: string }>;
- routeShowCashoutsAccount: RouteDefinition<{ account: string }>;
- onAuthorizationRequired: () => void;
-}
-export function AdminHome({
- routeCreate,
- routeRemoveAccount,
- routeShowAccount,
- routeShowCashoutsAccount,
- routeUpdatePasswordAccount,
- routeDownloadStats,
- routeCreateWireTransfer,
- onAuthorizationRequired,
-}: Props): VNode {
- return (
- <Fragment>
- <Metrics routeDownloadStats={routeDownloadStats} />
- <WireTransfer routeHere={routeCreateWireTransfer} onAuthorizationRequired={onAuthorizationRequired} />
-
- <Transactions
- account="admin"
- routeCreateWireTransfer={routeCreateWireTransfer}
- />
- <AccountList
- routeCreate={routeCreate}
- routeRemoveAccount={routeRemoveAccount}
- routeShowAccount={routeShowAccount}
- routeShowCashoutsAccount={routeShowCashoutsAccount}
- routeUpdatePasswordAccount={routeUpdatePasswordAccount}
- />
- </Fragment>
- );
-}
-
-function getDateForTimeframe(
- which: number,
- timeframe: TalerCorebankApi.MonitorTimeframeParam,
- locale: Locale,
-): string {
- const time = Date.now();
- switch (timeframe) {
- case TalerCorebankApi.MonitorTimeframeParam.hour:
- return `${format(setHours(time, which), "HH", { locale })}hs`;
- case TalerCorebankApi.MonitorTimeframeParam.day:
- return format(setDate(time, which), "EEEE", { locale });
- case TalerCorebankApi.MonitorTimeframeParam.month:
- return format(setMonth(time, which), "MMMM", { locale });
- case TalerCorebankApi.MonitorTimeframeParam.year:
- return format(setYear(time, which), "yyyy", { locale });
- case TalerCorebankApi.MonitorTimeframeParam.decade:
- return format(setYear(time, which), "yyyy", { locale });
- }
- assertUnreachable(timeframe);
-}
-
-export function getTimeframesForDate(
- time: Date,
- timeframe: TalerCorebankApi.MonitorTimeframeParam,
-): { current: number; previous: number } {
- switch (timeframe) {
- case TalerCorebankApi.MonitorTimeframeParam.hour:
- return {
- current: getHours(sub(time, { hours: 1 })),
- previous: getHours(sub(time, { hours: 2 })),
- };
- case TalerCorebankApi.MonitorTimeframeParam.day:
- return {
- current: getDate(sub(time, { days: 1 })),
- previous: getDate(sub(time, { days: 2 })),
- };
- case TalerCorebankApi.MonitorTimeframeParam.month:
- return {
- current: getMonth(sub(time, { months: 1 })),
- previous: getMonth(sub(time, { months: 2 })),
- };
- case TalerCorebankApi.MonitorTimeframeParam.year:
- return {
- current: getYear(sub(time, { years: 1 })),
- previous: getYear(sub(time, { years: 2 })),
- };
- case TalerCorebankApi.MonitorTimeframeParam.decade:
- return {
- current: getYear(sub(time, { years: 10 })),
- previous: getYear(sub(time, { years: 20 })),
- };
- default:
- assertUnreachable(timeframe);
- }
-}
-
-function Metrics({
- routeDownloadStats,
-}: {
- routeDownloadStats: RouteDefinition;
-}): VNode {
- const { i18n, dateLocale } = useTranslationContext();
- const [metricType, setMetricType] =
- useState<TalerCorebankApi.MonitorTimeframeParam>(
- TalerCorebankApi.MonitorTimeframeParam.hour,
- );
- const { config } = useBankCoreApiContext();
- const respInfo = useConversionInfo();
- const params = getTimeframesForDate(new Date(), metricType);
-
- const resp = useLastMonitorInfo(params.current, params.previous, metricType);
- if (!resp) return <Fragment />;
- if (resp instanceof TalerError) {
- return <ErrorLoadingWithDebug error={resp} />;
- }
- if (!respInfo) return <Fragment />;
- if (respInfo instanceof TalerError) {
- return <ErrorLoadingWithDebug error={respInfo} />;
- }
- if (respInfo.type === "fail") {
- switch (respInfo.case) {
- case HttpStatusCode.NotImplemented: {
- return (
- <Attention type="danger" title={i18n.str`Cashout are disabled`}>
- <i18n.Translate>
- Cashout should be enable by configuration and the conversion rate
- should be initialized with fee, ratio and rounding mode.
- </i18n.Translate>
- </Attention>
- );
- }
- default:
- assertUnreachable(respInfo.case);
- }
- }
-
- if (resp.current.type !== "ok" || resp.previous.type !== "ok") {
- return <Fragment />;
- }
- return (
- <Fragment>
- <div class="sm:hidden">
- <label for="tabs" class="sr-only">
- <i18n.Translate>Select a section</i18n.Translate>
- </label>
- <select
- id="tabs"
- name="tabs"
- class="block w-full rounded-md border-gray-300 focus:border-indigo-500 focus:ring-indigo-500"
- onChange={(e) => {
- // const op = e.currentTarget.value as typeof metricType
- setMetricType(
- e.currentTarget
- .value as unknown as TalerCorebankApi.MonitorTimeframeParam,
- );
- }}
- >
- <option
- value={TalerCorebankApi.MonitorTimeframeParam.hour}
- selected={metricType == TalerCorebankApi.MonitorTimeframeParam.hour}
- >
- <i18n.Translate>Last hour</i18n.Translate>
- </option>
- <option
- value={TalerCorebankApi.MonitorTimeframeParam.day}
- selected={metricType == TalerCorebankApi.MonitorTimeframeParam.day}
- >
- <i18n.Translate>Previous day</i18n.Translate>
- </option>
- <option
- value={TalerCorebankApi.MonitorTimeframeParam.month}
- selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.month
- }
- >
- <i18n.Translate>Last month</i18n.Translate>
- </option>
- <option
- value={TalerCorebankApi.MonitorTimeframeParam.year}
- selected={metricType == TalerCorebankApi.MonitorTimeframeParam.year}
- >
- <i18n.Translate>Last year</i18n.Translate>
- </option>
- </select>
- </div>
- <div class="hidden sm:block">
- {/* FIXME: This should be LINKS */}
- <nav
- class="isolate flex divide-x divide-gray-200 rounded-lg shadow"
- aria-label="Tabs"
- >
- <button
- type="button"
- name="set last hour"
- onClick={(e) => {
- e.preventDefault();
- setMetricType(TalerCorebankApi.MonitorTimeframeParam.hour);
- }}
- data-selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.hour
- }
- class="rounded-l-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Last hour</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.hour
- }
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </button>
- <button
- type="button"
- name="set previous day"
- onClick={(e) => {
- e.preventDefault();
- setMetricType(TalerCorebankApi.MonitorTimeframeParam.day);
- }}
- data-selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.day
- }
- class=" text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Previous day</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.day
- }
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </button>
- <button
- type="button"
- name="set last month"
- onClick={(e) => {
- e.preventDefault();
- setMetricType(TalerCorebankApi.MonitorTimeframeParam.month);
- }}
- data-selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.month
- }
- class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Last month</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.month
- }
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </button>
- <button
- type="button"
- name="set last year"
- onClick={(e) => {
- e.preventDefault();
- setMetricType(TalerCorebankApi.MonitorTimeframeParam.year);
- }}
- data-selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.year
- }
- class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"
- >
- <span>
- <i18n.Translate>Last Year</i18n.Translate>
- </span>
- <span
- aria-hidden="true"
- data-selected={
- metricType == TalerCorebankApi.MonitorTimeframeParam.year
- }
- class="bg-transparent data-[selected=true]:bg-indigo-500 absolute inset-x-0 bottom-0 h-0.5"
- ></span>
- </button>
- </nav>
- </div>
-
- <div class="w-full flex justify-between">
- <h1 class="text-base font-semibold leading-7 text-gray-900 mt-5">
- {i18n.str`Trading volume on ${getDateForTimeframe(
- params.current,
- metricType,
- dateLocale,
- )} compared to ${getDateForTimeframe(
- params.previous,
- metricType,
- dateLocale,
- )}`}
- </h1>
- </div>
- <dl class="mt-5 grid grid-cols-1 md:grid-cols-2 divide-y divide-gray-200 overflow-hidden rounded-lg bg-white shadow-lg md:divide-x md:divide-y-0">
- {resp.current.body.type !== "with-conversions" ||
- resp.previous.body.type !== "with-conversions" ? undefined : (
- <Fragment>
- <div class="px-4 py-5 sm:p-6">
- <dt class="text-base font-normal text-gray-900">
- <i18n.Translate>Cashin</i18n.Translate>
- <div class="text-xs text-gray-500">
- <i18n.Translate>Transferred from an external account to an account in this bank.</i18n.Translate>
- </div>
- </dt>
- <MetricValue
- current={resp.current.body.cashinFiatVolume}
- previous={resp.previous.body.cashinFiatVolume}
- spec={respInfo.body.fiat_currency_specification}
- />
- </div>
- <div class="px-4 py-5 sm:p-6">
- <dt class="text-base font-normal text-gray-900">
- <i18n.Translate>Cashout</i18n.Translate>
- </dt>
- <div class="text-xs text-gray-500">
- <i18n.Translate>Transferred from an account in this bank to an external account.</i18n.Translate>
- </div>
- <MetricValue
- current={resp.current.body.cashoutFiatVolume}
- previous={resp.previous.body.cashoutFiatVolume}
- spec={respInfo.body.fiat_currency_specification}
- />
- </div>
- </Fragment>
- )}
- <div class="px-4 py-5 sm:p-6">
- <dt class="text-base font-normal text-gray-900">
- <i18n.Translate>Payin</i18n.Translate>
- <div class="text-xs text-gray-500">
- <i18n.Translate>Transferred from an account to a Taler exchange.</i18n.Translate>
- </div>
- </dt>
- <MetricValue
- current={resp.current.body.talerInVolume}
- previous={resp.previous.body.talerInVolume}
- spec={config.currency_specification}
- />
- </div>
- <div class="px-4 py-5 sm:p-6">
- <dt class="text-base font-normal text-gray-900">
- <i18n.Translate>Payout</i18n.Translate>
- <div class="text-xs text-gray-500">
- <i18n.Translate>Transferred from a Taler exchange to another account.</i18n.Translate>
- </div>
- </dt>
- <MetricValue
- current={resp.current.body.talerOutVolume}
- previous={resp.previous.body.talerOutVolume}
- spec={config.currency_specification}
- />
- </div>
- </dl>
- <div class="flex justify-end mt-2">
- <a
- href={routeDownloadStats.url({})}
- name="download stats"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Download stats as CSV</i18n.Translate>
- </a>
- </div>
- </Fragment>
- );
-}
-
-function MetricValue({
- current,
- previous,
- spec,
-}: {
- spec: CurrencySpecification;
- current: AmountString | undefined;
- previous: AmountString | undefined;
-}): VNode {
- const { i18n } = useTranslationContext();
- const cmp = current && previous ? Amounts.cmp(current, previous) : 0;
- const cv = !current ? undefined : Amounts.stringifyValue(current);
- const currAmount = !cv ? undefined : Number.parseFloat(cv);
- const prevAmount = !previous
- ? undefined
- : Number.parseFloat(Amounts.stringifyValue(previous));
-
- const rate =
- !currAmount ||
- Number.isNaN(currAmount) ||
- !prevAmount ||
- Number.isNaN(prevAmount)
- ? 0
- : cmp === -1
- ? 1 - Math.round(currAmount) / Math.round(prevAmount)
- : cmp === 1
- ? Math.round(currAmount) / Math.round(prevAmount) - 1
- : 0;
-
- const negative = cmp === 0 ? undefined : cmp === -1;
- const rateStr = `${(Math.abs(rate) * 100).toFixed(2)}%`;
- return (
- <Fragment>
- <dd class="mt-1 block ">
- <div class="flex justify-start text-2xl items-baseline font-semibold text-indigo-600">
- {!current ? (
- "-"
- ) : (
- <RenderAmount
- value={Amounts.parseOrThrow(current)}
- spec={spec}
- hideSmall
- />
- )}
- </div>
- <div class="flex flex-col">
- <div class="flex justify-end items-baseline text-2xl font-semibold text-indigo-600">
- <small class="ml-2 text-sm font-medium text-gray-500">
- <i18n.Translate>from</i18n.Translate>{" "}
- {!previous ? (
- "-"
- ) : (
- <RenderAmount
- value={Amounts.parseOrThrow(previous)}
- spec={spec}
- hideSmall
- />
- )}
- </small>
- </div>
- {!!rate && (
- <span
- data-negative={negative}
- class="flex items-center gap-x-1.5 w-fit rounded-md bg-green-100 text-green-800 data-[negative=true]:bg-red-100 px-2 py-1 text-xs font-medium data-[negative=true]:text-red-700 whitespace-pre"
- >
- {negative ? (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="w-6 h-6"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M12 4.5v15m0 0l6.75-6.75M12 19.5l-6.75-6.75"
- />
- </svg>
- ) : (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- fill="none"
- viewBox="0 0 24 24"
- stroke-width="1.5"
- stroke="currentColor"
- class="w-6 h-6"
- >
- <path
- stroke-linecap="round"
- stroke-linejoin="round"
- d="M12 19.5v-15m0 0l-6.75 6.75M12 4.5l6.75 6.75"
- />
- </svg>
- )}
-
- {negative ? (
- <span class="sr-only">
- <i18n.Translate>Decreased by</i18n.Translate>
- </span>
- ) : (
- <span class="sr-only">
- <i18n.Translate>Increased by</i18n.Translate>
- </span>
- )}
- {rateStr}
- </span>
- )}
- </div>
- </dd>
- </Fragment>
- );
-}
diff --git a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx b/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
deleted file mode 100644
index 38119735e..000000000
--- a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- HttpStatusCode,
- TalerCorebankApi,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- LocalNotificationBanner,
- notifyInfo,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useSessionState } from "../../hooks/session.js";
-import { RouteDefinition } from "../../route.js";
-import { AccountForm } from "./AccountForm.js";
-
-export function CreateNewAccount({
- routeCancel,
- onCreateSuccess,
-}: {
- routeCancel: RouteDefinition;
- onCreateSuccess: () => void;
-}): VNode {
- const { i18n } = useTranslationContext();
- const { state: credentials } = useSessionState();
- const token =
- credentials.status !== "loggedIn" ? undefined : credentials.token;
- const { bank: api } = useBankCoreApiContext();
-
- const [submitAccount, setSubmitAccount] = useState<
- TalerCorebankApi.RegisterAccountRequest | undefined
- >();
- const [notification, notify, handleError] = useLocalNotification();
-
- async function doCreate() {
- if (!submitAccount || !token) return;
- await handleError(async () => {
- const resp = await api.createAccount(token, submitAccount);
- if (resp.type === "ok") {
- notifyInfo(
- i18n.str`Account created with password "${submitAccount.password}".`,
- );
- onCreateSuccess();
- } else {
- switch (resp.case) {
- case HttpStatusCode.BadRequest:
- return notify({
- type: "error",
- title: i18n.str`Server replied that phone or email is invalid`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Unauthorized:
- return notify({
- type: "error",
- title: i18n.str`The rights to perform the operation are not sufficient`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_REGISTER_USERNAME_REUSE:
- return notify({
- type: "error",
- title: i18n.str`Account username is already taken`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_REGISTER_PAYTO_URI_REUSE:
- return notify({
- type: "error",
- title: i18n.str`Account id is already taken`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_UNALLOWED_DEBIT:
- return notify({
- type: "error",
- title: i18n.str`Bank ran out of bonus credit.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
- return notify({
- type: "error",
- title: i18n.str`Account username can't be used because is reserved`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_NON_ADMIN_PATCH_DEBT_LIMIT:
- return notify({
- type: "error",
- title: i18n.str`Only admin is allow to set debt limit.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_MISSING_TAN_INFO:
- return notify({
- type: "error",
- title: i18n.str`No information for the selected authentication channel.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_TAN_CHANNEL_NOT_SUPPORTED:
- return notify({
- type: "error",
- title: i18n.str`Authentication channel is not supported.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_NON_ADMIN_SET_TAN_CHANNEL:
- return notify({
- type: "error",
- title: i18n.str`Only admin can create accounts with second factor authentication.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- default:
- assertUnreachable(resp);
- }
- }
- });
- }
-
- if (!(credentials.status === "loggedIn" && credentials.isUserAdministrator)) {
- return (
- <Fragment>
- <Attention type="warning" title={i18n.str`Can't create accounts`}>
- <i18n.Translate>
- Only system admin can create accounts.
- </i18n.Translate>
- </Attention>
- <div class="mt-5 sm:mt-6">
- <a
- href={routeCancel.url({})}
- name="close"
- class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Close</i18n.Translate>
- </a>
- </div>
- </Fragment>
- );
- }
-
- return (
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <LocalNotificationBanner notification={notification} />
-
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <i18n.Translate>New bank account</i18n.Translate>
- </h2>
- </div>
- <AccountForm
- template={undefined}
- purpose="create"
- onChange={(a) => {
- setSubmitAccount(a);
- }}
- >
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <a
- href={routeCancel.url({})}
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="create"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!submitAccount}
- onClick={(e) => {
- e.preventDefault();
- doCreate();
- }}
- >
- <i18n.Translate>Create</i18n.Translate>
- </button>
- </div>
- </AccountForm>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/pages/admin/DownloadStats.tsx b/packages/demobank-ui/src/pages/admin/DownloadStats.tsx
deleted file mode 100644
index fba366676..000000000
--- a/packages/demobank-ui/src/pages/admin/DownloadStats.tsx
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AccessToken,
- AmountString,
- TalerCoreBankHttpClient,
- TalerCorebankApi,
- TalerError,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- LocalNotificationBanner,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useSessionState } from "../../hooks/session.js";
-import { EmptyObject, RouteDefinition } from "../../route.js";
-import { getTimeframesForDate } from "./AdminHome.js";
-
-interface Props {
- routeCancel: RouteDefinition;
-}
-
-type Options = {
- dayMetric: boolean;
- hourMetric: boolean;
- monthMetric: boolean;
- yearMetric: boolean;
- compareWithPrevious: boolean;
- endOnFirstFail: boolean;
- includeHeader: boolean;
-};
-
-/**
- * Show histories of public accounts.
- */
-export function DownloadStats({ routeCancel }: Props): VNode {
- const { i18n } = useTranslationContext();
-
- const { state: credentials } = useSessionState();
- const creds =
- credentials.status !== "loggedIn" || !credentials.isUserAdministrator
- ? undefined
- : credentials;
- const { bank: api } = useBankCoreApiContext();
-
- const [options, setOptions] = useState<Options>({
- compareWithPrevious: true,
- dayMetric: true,
- endOnFirstFail: false,
- hourMetric: true,
- includeHeader: true,
- monthMetric: true,
- yearMetric: true,
- });
- const [lastStep, setLastStep] = useState<{ step: number; total: number }>();
- const [downloaded, setDownloaded] = useState<string>();
- const referenceDates = [new Date()];
- const [notification, , handleError] = useLocalNotification();
-
- if (!creds) {
- return <div>only admin can download stats</div>;
- }
-
- return (
- <div>
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <LocalNotificationBanner notification={notification} />
-
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <i18n.Translate>Download bank stats</i18n.Translate>
- </h2>
- </div>
-
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="px-4 py-6 sm:p-8">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Include hour metric</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name={`hour switch`}
- data-enabled={options.hourMetric}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- setOptions({
- ...options,
- hourMetric: !options.hourMetric,
- });
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={options.hourMetric}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Include day metric</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name={`day switch`}
- data-enabled={!!options.dayMetric}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- setOptions({ ...options, dayMetric: !options.dayMetric });
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={options.dayMetric}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Include month metric</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name={`month switch`}
- data-enabled={!!options.monthMetric}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- setOptions({
- ...options,
- monthMetric: !options.monthMetric,
- });
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={options.monthMetric}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Include year metric</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name={`year switch`}
- data-enabled={!!options.yearMetric}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- setOptions({
- ...options,
- yearMetric: !options.yearMetric,
- });
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={options.yearMetric}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Include table header</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name={`header switch`}
- data-enabled={!!options.includeHeader}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- setOptions({
- ...options,
- includeHeader: !options.includeHeader,
- });
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={options.includeHeader}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>
- Add previous metric for compare
- </i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name={`compare switch`}
- data-enabled={!!options.compareWithPrevious}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- setOptions({
- ...options,
- compareWithPrevious: !options.compareWithPrevious,
- });
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={options.compareWithPrevious}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- <div class="sm:col-span-5">
- <div class="flex items-center justify-between">
- <span class="flex flex-grow flex-col">
- <span
- class="text-sm text-black font-medium leading-6 "
- id="availability-label"
- >
- <i18n.Translate>Fail on first error</i18n.Translate>
- </span>
- </span>
- <button
- type="button"
- name={`fail switch`}
- data-enabled={!!options.endOnFirstFail}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- setOptions({
- ...options,
- endOnFirstFail: !options.endOnFirstFail,
- });
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={options.endOnFirstFail}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button>
- </div>
- </div>
- </div>
- </div>
-
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <a name="cancel"
- href={routeCancel.url({})}
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="download"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={lastStep !== undefined}
- onClick={async () => {
- setDownloaded(undefined);
- await handleError(async () => {
- const csv = await fetchAllStatus(
- api,
- creds.token,
- options,
- referenceDates,
- (step, total) => {
- setLastStep({ step, total });
- },
- );
- setDownloaded(csv);
- });
- setLastStep(undefined);
- }}
- >
- <i18n.Translate>Download</i18n.Translate>
- </button>
- </div>
- </form>
- </div>
- {!lastStep || lastStep.step === lastStep.total ? (
- <div class="h-5 mb-5" />
- ) : (
- <div>
- <div class="relative mb-5 h-5 rounded-full bg-gray-200">
- <div
- class="h-full animate-pulse rounded-full bg-blue-500"
- style={{
- width: `${Math.round((lastStep.step / lastStep.total) * 100)}%`,
- }}
- >
- <span class="absolute inset-0 flex items-center justify-center text-xs font-semibold text-white">
- <i18n.Translate>
- downloading...{" "}
- {Math.round((lastStep.step / lastStep.total) * 100)}
- </i18n.Translate>
- </span>
- </div>
- </div>
- </div>
- )}
- {!downloaded ? (
- <div class="h-5 mb-5" />
- ) : (
- <a
- href={
- "data:text/plain;charset=utf-8," + encodeURIComponent(downloaded)
- }
- name="save file"
- download={"bank-stats.csv"}
- >
- <Attention title={i18n.str`Download completed`}>
- <i18n.Translate>
- Click here to save the file in your computer.
- </i18n.Translate>
- </Attention>
- </a>
- )}
- </div>
- );
-}
-
-async function fetchAllStatus(
- api: TalerCoreBankHttpClient,
- token: AccessToken,
- options: Options,
- references: Date[],
- progress: (current: number, total: number) => void,
-): Promise<string> {
- const allMetrics: TalerCorebankApi.MonitorTimeframeParam[] = [];
- if (options.hourMetric) {
- allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.hour);
- }
- if (options.dayMetric) {
- allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.day);
- }
- if (options.monthMetric) {
- allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.month);
- }
- if (options.yearMetric) {
- allMetrics.push(TalerCorebankApi.MonitorTimeframeParam.year);
- }
-
- /**
- * convert request into frames
- */
- const allFrames = allMetrics.flatMap((timeframe) =>
- references.map((reference) => ({
- reference,
- timeframe,
- moment: getTimeframesForDate(reference, timeframe),
- })),
- );
- const total = allFrames.length;
-
- /**
- * call API for info
- */
- const allInfo = await allFrames.reduce(
- async (prev, frame, index) => {
- const accumulatedMap = await prev;
- progress(index, total);
- // await delay()
- const previous = options.compareWithPrevious
- ? await api.getMonitor(token, {
- timeframe: frame.timeframe,
- which: frame.moment.previous,
- })
- : undefined;
-
- if (previous && previous.type === "fail" && options.endOnFirstFail) {
- throw TalerError.fromUncheckedDetail(previous.detail);
- }
-
- const current = await api.getMonitor(token, {
- timeframe: frame.timeframe,
- which: frame.moment.current,
- });
-
- if (current.type === "fail" && options.endOnFirstFail) {
- throw TalerError.fromUncheckedDetail(current.detail);
- }
-
- const metricName =
- TalerCorebankApi.MonitorTimeframeParam[allMetrics[index]];
- accumulatedMap[metricName] = {
- reference: frame.reference,
- current: current.type !== "ok" ? undefined : current.body,
- previous:
- !previous || previous.type !== "ok" ? undefined : previous.body,
- };
- return accumulatedMap;
- },
- Promise.resolve({} as Record<string, Data>),
- );
- progress(total, total);
-
- /**
- * convert into table format
- *
- */
- const table: Array<string[]> = [];
- if (options.includeHeader) {
- table.push([
- "date",
- "metric",
- "reference",
- "talerInCount",
- "talerInVolume",
- "talerOutCount",
- "talerOutVolume",
- "cashinCount",
- "cashinFiatVolume",
- "cashinRegionalVolume",
- "cashoutCount",
- "cashoutFiatVolume",
- "cashoutRegionalVolume",
- ]);
- }
- Object.entries(allInfo).forEach(([name, data]) => {
- if (data.current) {
- const row: TableRow = {
- date: data.reference.getTime(),
- metric: name,
- reference: "current",
- ...dataToRow(data.current),
- };
- table.push(Object.values(row) as string[]);
- }
-
- if (data.previous) {
- const row: TableRow = {
- date: data.reference.getTime(),
- metric: name,
- reference: "previous",
- ...dataToRow(data.previous),
- };
- table.push(Object.values(row) as string[]);
- }
- });
-
- const csv = table.reduce((acc, row) => {
- return acc + row.join(",") + "\n";
- }, "");
-
- return csv;
-}
-
-type JustData = Omit<Omit<Omit<TableRow, "metric">, "date">, "reference">;
-function dataToRow(info: TalerCorebankApi.MonitorResponse): JustData {
- return {
- talerInCount: info.talerInCount,
- talerInVolume: info.talerInVolume,
- talerOutCount: info.talerOutCount,
- talerOutVolume: info.talerOutVolume,
- cashinCount: info.type === "no-conversions" ? undefined : info.cashinCount,
- cashinFiatVolume:
- info.type === "no-conversions" ? undefined : info.cashinFiatVolume,
- cashinRegionalVolume:
- info.type === "no-conversions" ? undefined : info.cashinRegionalVolume,
- cashoutCount:
- info.type === "no-conversions" ? undefined : info.cashoutCount,
- cashoutFiatVolume:
- info.type === "no-conversions" ? undefined : info.cashoutFiatVolume,
- cashoutRegionalVolume:
- info.type === "no-conversions" ? undefined : info.cashoutRegionalVolume,
- };
-}
-
-type Data = {
- reference: Date;
- previous: TalerCorebankApi.MonitorResponse | undefined;
- current: TalerCorebankApi.MonitorResponse | undefined;
-};
-type TableRow = {
- date: number;
- metric: string;
- reference: "current" | "previous";
- cashinCount?: number;
- cashinRegionalVolume?: AmountString;
- cashinFiatVolume?: AmountString;
- cashoutCount?: number;
- cashoutRegionalVolume?: AmountString;
- cashoutFiatVolume?: AmountString;
- talerInCount: number;
- talerInVolume: AmountString;
- talerOutCount: number;
- talerOutVolume: AmountString;
-};
diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
deleted file mode 100644
index 61def9a95..000000000
--- a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- AbsoluteTime,
- Amounts,
- HttpStatusCode,
- TalerError,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- Loading,
- LocalNotificationBanner,
- ShowInputErrorLabel,
- notifyInfo,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useState } from "preact/hooks";
-import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useAccountDetails } from "../../hooks/account.js";
-import { useSessionState } from "../../hooks/session.js";
-import { undefinedIfEmpty } from "../../utils.js";
-import { LoginForm } from "../LoginForm.js";
-import { doAutoFocus } from "../PaytoWireTransferForm.js";
-import { useBankState } from "../../hooks/bank-state.js";
-import { RouteDefinition } from "../../route.js";
-
-export function RemoveAccount({
- account,
- routeCancel,
- onUpdateSuccess,
- onAuthorizationRequired,
- focus,
- routeHere,
-}: {
- focus?: boolean;
- routeHere: RouteDefinition<{ account: string }>;
- onAuthorizationRequired: () => void;
- routeCancel: RouteDefinition;
- onUpdateSuccess: () => void;
- account: string;
-}): VNode {
- const { i18n } = useTranslationContext();
- const result = useAccountDetails(account);
- const [accountName, setAccountName] = useState<string | undefined>();
-
- const { state } = useSessionState();
- const token = state.status !== "loggedIn" ? undefined : state.token;
- const { bank: api } = useBankCoreApiContext();
- const [notification, notify, handleError] = useLocalNotification();
- const [, updateBankState] = useBankState();
-
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <ErrorLoadingWithDebug error={result} />;
- }
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.Unauthorized:
- return <LoginForm currentUser={account} />;
- case HttpStatusCode.NotFound:
- return <LoginForm currentUser={account} />;
- default:
- assertUnreachable(result);
- }
- }
-
- const balance = Amounts.parse(result.body.balance.amount);
- if (!balance) {
- return <div>there was an error reading the balance</div>;
- }
- const isBalanceEmpty = Amounts.isZero(balance);
- if (!isBalanceEmpty) {
- return (
- <Fragment>
- <Attention type="warning" title={i18n.str`Can't delete the account`}>
- <i18n.Translate>
- The account can't be delete while still holding some balance. First
- make sure that the owner make a complete cashout.
- </i18n.Translate>
- </Attention>
- <div class="mt-5 sm:mt-6">
- <a
- href={routeCancel.url({})}
- name="close"
- class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Close</i18n.Translate>
- </a>
- </div>
- </Fragment>
- );
- }
-
- async function doRemove() {
- if (!token) return;
- await handleError(async () => {
- const resp = await api.deleteAccount({ username: account, token });
- if (resp.type === "ok") {
- notifyInfo(i18n.str`Account removed`);
- onUpdateSuccess();
- } else {
- switch (resp.case) {
- case HttpStatusCode.Unauthorized:
- return notify({
- type: "error",
- title: i18n.str`No enough permission to delete the account.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`The username was not found.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_RESERVED_USERNAME_CONFLICT:
- return notify({
- type: "error",
- title: i18n.str`Can't delete a reserved username.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_ACCOUNT_BALANCE_NOT_ZERO:
- return notify({
- type: "error",
- title: i18n.str`Can't delete an account with balance different than zero.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.Accepted: {
- updateBankState("currentChallenge", {
- operation: "delete-account",
- id: String(resp.body.challenge_id),
- sent: AbsoluteTime.never(),
- location: routeHere.url({ account }),
- request: account,
- });
- return onAuthorizationRequired();
- }
- default: {
- assertUnreachable(resp);
- }
- }
- }
- });
- }
-
- const errors = undefinedIfEmpty({
- accountName: !accountName
- ? i18n.str`Required`
- : account !== accountName
- ? i18n.str`Name doesn't match`
- : undefined,
- });
-
- return (
- <div>
- <LocalNotificationBanner notification={notification} />
-
- <Attention
- type="warning"
- title={i18n.str`You are going to remove the account`}
- >
- <i18n.Translate>This step can't be undone.</i18n.Translate>
- </Attention>
-
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <i18n.Translate>Deleting account "{account}"</i18n.Translate>
- </h2>
- </div>
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="px-4 py-6 sm:p-8">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="password"
- >
- {i18n.str`Verification`}
- </label>
- <div class="mt-2">
- <input
- ref={focus ? doAutoFocus : undefined}
- type="text"
- class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="password"
- id="password"
- data-error={
- !!errors?.accountName && accountName !== undefined
- }
- value={accountName ?? ""}
- onChange={(e) => {
- setAccountName(e.currentTarget.value);
- }}
- placeholder={account}
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.accountName}
- isDirty={accountName !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>
- Enter the account name that is going to be deleted
- </i18n.Translate>
- </p>
- </div>
- </div>
- </div>
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <a
- href={routeCancel.url({})}
- name="cancel"
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="delete"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-red-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-red-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600"
- disabled={!!errors}
- onClick={(e) => {
- e.preventDefault();
- doRemove();
- }}
- >
- <i18n.Translate>Delete</i18n.Translate>
- </button>
- </div>
- </form>
- </div>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/pages/index.stories.tsx b/packages/demobank-ui/src/pages/index.stories.tsx
deleted file mode 100644
index 823def5d7..000000000
--- a/packages/demobank-ui/src/pages/index.stories.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-export * as qr from "./QrCodeSection.stories.js";
-export * as po from "./PaymentOptions.stories.js";
-export * as ptf from "./PaytoWireTransferForm.stories.js";
-export * as frame from "./BankFrame.stories.js";
diff --git a/packages/demobank-ui/src/pages/regional/ConversionConfig.tsx b/packages/demobank-ui/src/pages/regional/ConversionConfig.tsx
deleted file mode 100644
index 8845ec9a0..000000000
--- a/packages/demobank-ui/src/pages/regional/ConversionConfig.tsx
+++ /dev/null
@@ -1,978 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AmountJson,
- Amounts,
- HttpStatusCode,
- TalerBankConversionApi,
- TalerError,
- TranslatedString,
- assertUnreachable
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- InternationalizationAPI,
- LocalNotificationBanner,
- ShowInputErrorLabel,
- useLocalNotification,
- useTranslationContext,
- utils
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useEffect, useState } from "preact/hooks";
-import { useBankCoreApiContext } from "../../context/config.js";
-import { useSessionState } from "../../hooks/session.js";
-import { TransferCalculation, useCashinEstimator, useCashoutEstimator, useConversionInfo } from "../../hooks/regional.js";
-import { RouteDefinition } from "../../route.js";
-import { undefinedIfEmpty } from "../../utils.js";
-import { InputAmount, RenderAmount } from "../PaytoWireTransferForm.js";
-import { ProfileNavigation } from "../ProfileNavigation.js";
-import { FormErrors, FormStatus, FormValues, RecursivePartial, UIField, useFormState } from "../../hooks/form.js";
-
-interface Props {
- routeMyAccountDetails: RouteDefinition;
- routeMyAccountDelete: RouteDefinition;
- routeMyAccountPassword: RouteDefinition;
- routeMyAccountCashout: RouteDefinition;
- routeConversionConfig: RouteDefinition;
- routeCancel: RouteDefinition;
- onUpdateSuccess: () => void;
-}
-
-type FormType = { amount: AmountJson, conv: TalerBankConversionApi.ConversionRate }
-
-
-function useComponentState({
- onUpdateSuccess,
- routeCancel,
- routeConversionConfig,
- routeMyAccountCashout,
- routeMyAccountDelete,
- routeMyAccountDetails,
- routeMyAccountPassword,
-}: Props): utils.RecursiveState<VNode> {
- const { i18n } = useTranslationContext();
-
- const result = useConversionInfo()
- const info = result && !(result instanceof TalerError) && result.type === "ok" ?
- result.body : undefined;
-
- const { state: credentials } = useSessionState();
- const creds =
- credentials.status !== "loggedIn" || !credentials.isUserAdministrator
- ? undefined
- : credentials;
-
- if (!info) {
- return <i18n.Translate>loading...</i18n.Translate>
- }
-
- if (!creds) {
- return <i18n.Translate>only admin can setup conversion</i18n.Translate>
- }
-
- return () => {
- const { i18n } = useTranslationContext();
-
- const { bank, conversion, config } = useBankCoreApiContext();
-
- const [notification, notify, handleError] = useLocalNotification();
-
- const initalState: FormValues<FormType> = {
- amount: "100",
- conv: {
- cashin_min_amount: info.conversion_rate.cashin_min_amount.split(":")[1],
- cashin_tiny_amount: info.conversion_rate.cashin_tiny_amount.split(":")[1],
- cashin_fee: info.conversion_rate.cashin_fee.split(":")[1],
- cashin_ratio: info.conversion_rate.cashin_ratio,
- cashin_rounding_mode: info.conversion_rate.cashin_rounding_mode,
- cashout_min_amount: info.conversion_rate.cashout_min_amount.split(":")[1],
- cashout_tiny_amount: info.conversion_rate.cashout_tiny_amount.split(":")[1],
- cashout_fee: info.conversion_rate.cashout_fee.split(":")[1],
- cashout_ratio: info.conversion_rate.cashout_ratio,
- cashout_rounding_mode: info.conversion_rate.cashout_rounding_mode,
- }
- }
-
- const [form, status] = useFormState<FormType>(
- initalState,
- createFormValidator(i18n, info.regional_currency, info.fiat_currency)
- )
-
- const {
- estimateByDebit: calculateCashoutFromDebit,
- } = useCashoutEstimator();
-
- const {
- estimateByDebit: calculateCashinFromDebit,
- } = useCashinEstimator();
-
- const [calculationResult, setCalc] = useState<{ cashin: TransferCalculation, cashout: TransferCalculation }>()
-
- useEffect(() => {
- async function doAsync() {
- await handleError(async () => {
- if (!info) return;
- if (!form.amount?.value || form.amount.error) return;
- const in_amount = Amounts.parseOrThrow(`${info.fiat_currency}:${form.amount.value}`)
- const in_fee = Amounts.parseOrThrow(info.conversion_rate.cashin_fee)
- const cashin = await calculateCashinFromDebit(in_amount, in_fee);
-
- if (cashin === "amount-is-too-small") {
- setCalc(undefined)
- return;
- }
- // const out_amount = Amounts.parseOrThrow(`${info.regional_currency}:${form.amount.value}`)
- const out_fee = Amounts.parseOrThrow(info.conversion_rate.cashout_fee)
- const cashout = await calculateCashoutFromDebit(cashin.credit, out_fee);
-
- setCalc({ cashin, cashout });
- });
- }
- doAsync();
- }, [form.amount?.value, form.conv?.cashin_fee?.value, form.conv?.cashout_fee?.value]);
-
- const [section, setSection] = useState<"detail" | "cashout" | "cashin">("detail")
- const cashinCalc = calculationResult?.cashin === "amount-is-too-small" ? undefined : calculationResult?.cashin
- const cashoutCalc = calculationResult?.cashout === "amount-is-too-small" ? undefined : calculationResult?.cashout
- async function doUpdate() {
- if (!creds) return
- await handleError(async () => {
- if (status.status === "fail") return;
- const resp = await conversion.updateConversionRate(creds.token, status.result.conv)
- if (resp.type === "ok") {
- setSection("detail")
- } else {
- switch (resp.case) {
- case HttpStatusCode.Unauthorized: {
- return notify({
- type: "error",
- title: i18n.str`Wrong credentials`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- }
- case HttpStatusCode.NotImplemented: {
- return notify({
- type: "error",
- title: i18n.str`Conversion is disabled`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- }
- default:
- assertUnreachable(resp);
- }
- }
- });
- }
-
- const in_ratio = Number.parseFloat(info.conversion_rate.cashin_ratio)
- const out_ratio = Number.parseFloat(info.conversion_rate.cashout_ratio)
-
- const both_high = in_ratio > 1 && out_ratio > 1;
- const both_low = in_ratio < 1 && out_ratio < 1;
-
-
- return (
- <div>
- <ProfileNavigation current="conversion"
- routeMyAccountCashout={routeMyAccountCashout}
- routeMyAccountDelete={routeMyAccountDelete}
- routeMyAccountDetails={routeMyAccountDetails}
- routeMyAccountPassword={routeMyAccountPassword}
- routeConversionConfig={routeConversionConfig}
- />
-
- <LocalNotificationBanner notification={notification} />
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
-
- <div class="px-4 sm:px-0">
- <h2 class="text-base font-semibold leading-7 text-gray-900">
- <i18n.Translate>Conversion</i18n.Translate>
- </h2>
- <div class="px-2 mt-2 grid grid-cols-1 gap-y-4 sm:gap-x-4">
- <label
- data-enabled={section === "detail"}
- class="relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none border-gray-300 data-[enabled=true]:border-indigo-600 data-[enabled=true]:ring-2 data-[enabled=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="project-type"
- value="Newsletter"
- class="sr-only"
- aria-labelledby="project-type-0-label"
- aria-describedby="project-type-0-description-0 project-type-0-description-1"
- onChange={() => {
- setSection("detail")
- }}
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span class="block text-sm font-medium text-gray-900">
- <i18n.Translate>Details</i18n.Translate>
- </span>
- </span>
- </span>
- </label>
-
- <label
- data-enabled={section === "cashout"}
- class="relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none border-gray-300 -- data-[enabled=true]:border-indigo-600 data-[enabled=true]:ring-2 data-[enabled=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="project-type"
- value="Existing Customers"
- class="sr-only"
- aria-labelledby="project-type-1-label"
- aria-describedby="project-type-1-description-0 project-type-1-description-1"
- onChange={() => {
- setSection("cashout")
- }}
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span class="block text-sm font-medium text-gray-900">
- <i18n.Translate>Config cashout</i18n.Translate>
- </span>
- </span>
- </span>
- </label>
- <label
- data-enabled={section === "cashin"}
- class="relative flex cursor-pointer rounded-lg border bg-white p-4 shadow-sm focus:outline-none border-gray-300 -- data-[enabled=true]:border-indigo-600 data-[enabled=true]:ring-2 data-[enabled=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="project-type"
- value="Existing Customers"
- class="sr-only"
- aria-labelledby="project-type-1-label"
- aria-describedby="project-type-1-description-0 project-type-1-description-1"
- onChange={() => {
- setSection("cashin")
- }}
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span class="block text-sm font-medium text-gray-900">
- <i18n.Translate>Config cashin</i18n.Translate>
- </span>
- </span>
- </span>
- </label>
- </div>
-
- </div>
-
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- {section == "cashin" &&
- <ConversionForm id="cashin"
- inputCurrency={info.fiat_currency}
- outputCurrency={info.regional_currency}
- fee={form?.conv?.cashin_fee}
- minimum={form?.conv?.cashin_min_amount}
- ratio={form?.conv?.cashin_ratio}
- rounding={form?.conv?.cashin_rounding_mode}
- tiny={form?.conv?.cashin_tiny_amount}
- />}
-
- {section == "cashout" && <Fragment>
- <ConversionForm id="cashout"
- inputCurrency={info.regional_currency}
- outputCurrency={info.fiat_currency}
- fee={form?.conv?.cashout_fee}
- minimum={form?.conv?.cashout_min_amount}
- ratio={form?.conv?.cashout_ratio}
- rounding={form?.conv?.cashout_rounding_mode}
- tiny={form?.conv?.cashout_tiny_amount}
- />
- </Fragment>}
-
- {section == "detail" && <Fragment>
- <div class="px-6 pt-6">
- <div class="justify-between items-center flex ">
- <dt class="text-sm text-gray-600">
- <i18n.Translate>Cashin ratio</i18n.Translate>
- </dt>
- <dd class="text-sm text-gray-900">
- {info.conversion_rate.cashin_ratio}
- </dd>
- </div>
- </div>
-
- <div class="px-6 pt-6">
- <div class="justify-between items-center flex ">
- <dt class="text-sm text-gray-600">
- <i18n.Translate>Cashout ratio</i18n.Translate>
- </dt>
- <dd class="text-sm text-gray-900">
- {info.conversion_rate.cashout_ratio}
- </dd>
- </div>
- </div>
-
- {both_low || both_high ? <div class="p-4">
- <Attention title={i18n.str`Bad ratios`} type="warning">
- <i18n.Translate>
- One of the ratios should be higher or equal than 1 an the other should be lower or equal than 1.
- </i18n.Translate>
- </Attention>
- </div> : undefined}
-
- <div class="px-6 pt-6">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label
- for="amount"
- class="block text-sm font-medium leading-6 text-gray-900"
- >{i18n.str`Initial amount`}</label>
- <InputAmount
- name="amount"
- left
- currency={info.fiat_currency}
- value={form.amount?.value ?? ""}
- onChange={form.amount?.onUpdate}
- />
- <ShowInputErrorLabel
- message={form.amount?.error}
- isDirty={form.amount?.value !== undefined}
- />
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Use it to test how the conversion will affect the amount.</i18n.Translate>
- </p>
- </div>
- </div>
- </div>
-
- {!cashoutCalc || !cashinCalc ? undefined : (
- <div class="px-6 pt-6">
- <div class="sm:col-span-5">
- <dl class="mt-4 space-y-4">
- <div class="justify-between items-center flex ">
- <dt class="text-sm text-gray-600">
- <i18n.Translate>Sending to this bank</i18n.Translate>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={cashinCalc.debit}
- negative
- withColor
- spec={info.regional_currency_specification}
- />
- </dd>
- </div>
-
- {Amounts.isZero(cashinCalc.beforeFee) ? undefined : (
- <div class="flex items-center justify-between afu ">
- <dt class="flex items-center text-sm text-gray-600">
- <span>
- <i18n.Translate>Converted</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={cashinCalc.beforeFee}
- spec={info.fiat_currency_specification}
- />
- </dd>
- </div>
- )}
- <div class="flex justify-between items-center border-t-2 afu pt-4">
- <dt class="text-lg text-gray-900 font-medium">
- <i18n.Translate>Cashin after fee</i18n.Translate>
- </dt>
- <dd class="text-lg text-gray-900 font-medium">
- <RenderAmount
- value={cashinCalc.credit}
- withColor
- spec={info.fiat_currency_specification}
- />
- </dd>
- </div>
- </dl>
- </div>
-
- <div class="sm:col-span-5">
- <dl class="mt-4 space-y-4">
- <div class="justify-between items-center flex ">
- <dt class="text-sm text-gray-600">
- <i18n.Translate>Sending from this bank</i18n.Translate>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={cashoutCalc.debit}
- negative
- withColor
- spec={info.fiat_currency_specification}
- />
- </dd>
- </div>
-
- {Amounts.isZero(cashoutCalc.beforeFee) ? undefined : (
- <div class="flex items-center justify-between afu">
- <dt class="flex items-center text-sm text-gray-600">
- <span>
- <i18n.Translate>Converted</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={cashoutCalc.beforeFee}
- spec={info.regional_currency_specification}
- />
- </dd>
- </div>
- )}
- <div class="flex justify-between items-center border-t-2 afu pt-4">
- <dt class="text-lg text-gray-900 font-medium">
- <i18n.Translate>Cashout after fee</i18n.Translate>
- </dt>
- <dd class="text-lg text-gray-900 font-medium">
- <RenderAmount
- value={cashoutCalc.credit}
- withColor
- spec={info.regional_currency_specification}
- />
- </dd>
- </div>
- </dl>
- </div>
-
- {cashoutCalc && status.status === "ok" && Amounts.cmp(status.result.amount, cashoutCalc.credit) < 0 ? <div class="p-4">
- <Attention title={i18n.str`Bad configuration`} type="warning">
- <i18n.Translate>
- This configuration allows users to cash out more of what has been cashed in.
- </i18n.Translate>
- </Attention>
- </div> : undefined}
- </div>
- )}
- </Fragment>}
-
-
- <div class="flex items-center justify-between mt-4 gap-x-6 border-t border-gray-900/10 px-4 py-4">
- <a name="cancel"
- href={routeCancel.url({})}
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- {section == "cashin" || section == "cashout" ? <Fragment>
- <button
- type="submit"
- name="update conversion"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- onClick={async () => {
- doUpdate()
- }}
- >
- <i18n.Translate>Update</i18n.Translate>
- </button>
- </Fragment> : <div />}
- </div>
-
-
- </form>
- </div>
- </div>
- );
-
- }
-}
-
-export const ConversionConfig = utils.recursive(useComponentState);
-
-/**
- *
- * @param i18n
- * @param regional
- * @param fiat
- * @returns form validator
- */
-function createFormValidator(i18n: InternationalizationAPI, regional: string, fiat: string) {
- return function check(state: FormValues<FormType>): FormStatus<FormType> {
-
- const cashin_min_amount = Amounts.parse(`${fiat}:${state.conv.cashin_min_amount}`)
- const cashin_tiny_amount = Amounts.parse(`${regional}:${state.conv.cashin_tiny_amount}`)
- const cashin_fee = Amounts.parse(`${regional}:${state.conv.cashin_fee}`)
-
- const cashout_min_amount = Amounts.parse(`${regional}:${state.conv.cashout_min_amount}`)
- const cashout_tiny_amount = Amounts.parse(`${fiat}:${state.conv.cashout_tiny_amount}`)
- const cashout_fee = Amounts.parse(`${fiat}:${state.conv.cashout_fee}`)
-
- const am = Amounts.parse(`${fiat}:${state.amount}`)
-
- const cashin_ratio = Number.parseFloat(state.conv.cashin_ratio ?? "")
- const cashout_ratio = Number.parseFloat(state.conv.cashout_ratio ?? "")
-
- const errors = undefinedIfEmpty<FormErrors<FormType>>({
- conv: undefinedIfEmpty<FormErrors<FormType["conv"]>>({
- cashin_min_amount: !state.conv.cashin_min_amount ? i18n.str`required` :
- !cashin_min_amount ? i18n.str`invalid` :
- undefined,
- cashin_tiny_amount: !state.conv.cashin_tiny_amount ? i18n.str`required` :
- !cashin_tiny_amount ? i18n.str`invalid` :
- undefined,
- cashin_fee: !state.conv.cashin_fee ? i18n.str`required` :
- !cashin_fee ? i18n.str`invalid` :
- undefined,
-
- cashout_min_amount: !state.conv.cashout_min_amount ? i18n.str`required` :
- !cashout_min_amount ? i18n.str`invalid` :
- undefined,
- cashout_tiny_amount: !state.conv.cashin_tiny_amount ? i18n.str`required` :
- !cashout_tiny_amount ? i18n.str`invalid` :
- undefined,
- cashout_fee: !state.conv.cashin_fee ? i18n.str`required` :
- !cashout_fee ? i18n.str`invalid` :
- undefined,
-
- cashin_rounding_mode: !state.conv.cashin_rounding_mode ? i18n.str`required` : undefined,
- cashout_rounding_mode: !state.conv.cashout_rounding_mode ? i18n.str`required` : undefined,
-
- cashin_ratio: !state.conv.cashin_ratio ? i18n.str`required` : Number.isNaN(cashin_ratio) ? i18n.str`invalid` : undefined,
- cashout_ratio: !state.conv.cashout_ratio ? i18n.str`required` : Number.isNaN(cashout_ratio) ? i18n.str`invalid` : undefined,
- }),
-
- amount: !state.amount ? i18n.str`required` :
- !am ? i18n.str`invalid` :
- undefined,
- })
-
- const result: RecursivePartial<FormType> = {
- amount: am,
- conv: {
- cashin_fee: !errors?.conv?.cashin_fee ? Amounts.stringify(cashin_fee!) : undefined,
- cashin_min_amount: !errors?.conv?.cashin_min_amount ? Amounts.stringify(cashin_min_amount!) : undefined,
- cashin_ratio: !errors?.conv?.cashin_ratio ? String(cashin_ratio!) : undefined,
- cashin_rounding_mode: !errors?.conv?.cashin_rounding_mode ? (state.conv.cashin_rounding_mode!) : undefined,
- cashin_tiny_amount: !errors?.conv?.cashin_tiny_amount ? Amounts.stringify(cashin_tiny_amount!) : undefined,
- cashout_fee: !errors?.conv?.cashout_fee ? Amounts.stringify(cashout_fee!) : undefined,
- cashout_min_amount: !errors?.conv?.cashout_min_amount ? Amounts.stringify(cashout_min_amount!) : undefined,
- cashout_ratio: !errors?.conv?.cashout_ratio ? String(cashout_ratio!) : undefined,
- cashout_rounding_mode: !errors?.conv?.cashout_rounding_mode ? (state.conv.cashout_rounding_mode!) : undefined,
- cashout_tiny_amount: !errors?.conv?.cashout_tiny_amount ? Amounts.stringify(cashout_tiny_amount!) : undefined,
- }
-
- }
- return errors === undefined ?
- { status: "ok", result: result as FormType, errors } :
- { status: "fail", result, errors }
- }
-}
-
-
-function ConversionForm({ id, inputCurrency, outputCurrency, fee, minimum, ratio, rounding, tiny }: {
- inputCurrency: string,
- outputCurrency: string,
- minimum: UIField | undefined,
- tiny: UIField | undefined,
- fee: UIField | undefined,
- rounding: UIField | undefined,
- ratio: UIField | undefined,
- id: string,
-}): VNode {
- const { i18n } = useTranslationContext();
- return <Fragment>
- <div class="px-6 pt-6">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label
- for="cashin_min_amount"
- class="block text-sm font-medium leading-6 text-gray-900"
- >{i18n.str`Minimum amount`}</label>
- <InputAmount
- name="cashin_min_amount"
- left
- currency={inputCurrency}
- value={minimum?.value ?? ""}
- onChange={minimum?.onUpdate}
- />
- <ShowInputErrorLabel
- message={minimum?.error}
- isDirty={minimum?.value !== undefined}
- />
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Only cashout operation above this threshold will be allowed</i18n.Translate>
- </p>
- </div>
- </div>
- </div>
-
- <div class="px-6 pt-6">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="password"
- >
- {i18n.str`Ratio`}
- </label>
- <div class="mt-2">
- <input
- type="number"
- class="block rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="current"
- id="cashin_ratio"
- data-error={!!ratio?.error && ratio?.value !== undefined}
- value={ratio?.value ?? ""}
- onChange={(e) => {
- ratio?.onUpdate(e.currentTarget.value);
- }}
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={ratio?.error}
- isDirty={ratio?.value !== undefined}
- />
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>
- Conversion ratio between currencies
- </i18n.Translate>
- </p>
- </div>
-
- <div class="px-6 pt-4">
- <Attention title={i18n.str`Example conversion`}>
- <i18n.Translate>1 {inputCurrency} will be converted into {ratio?.value} {outputCurrency}</i18n.Translate>
- </Attention>
- </div>
-
- <div class="px-6 pt-6">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label
- for="cashin_tiny_amount"
- class="block text-sm font-medium leading-6 text-gray-900"
- >{i18n.str`Rounding value`}</label>
- <InputAmount
- name="cashin_tiny_amount"
- left
- currency={outputCurrency}
- value={tiny?.value ?? ""}
- onChange={tiny?.onUpdate}
- />
- <ShowInputErrorLabel
- message={tiny?.error}
- isDirty={tiny?.value !== undefined}
- />
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Smallest difference between two amounts after the ratio is applied.</i18n.Translate>
- </p>
- </div>
- </div>
- </div>
-
- <div class="px-6 pt-6">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="channel"
- >
- {i18n.str`Rounding mode`}
- </label>
- <div class="mt-2 max-w-xl text-sm text-gray-500">
- <div class="px-4 mt-4 grid grid-cols-1 gap-y-6">
- <label
- onClick={(e) => {
- e.preventDefault();
- rounding?.onUpdate("zero")
- }}
- data-selected={rounding?.value === "zero"}
- class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border bg-white data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="channel"
- value="Newsletter"
- class="sr-only"
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span
- id="project-type-0-label"
- class="block text-sm font-medium text-gray-900 "
- >
- <i18n.Translate>Zero</i18n.Translate>
- </span>
- <i18n.Translate>Amount will be round below to the largest possible value smaller than the input.</i18n.Translate>
- </span>
- </span>
- <svg
- data-selected={rounding?.value === "zero"}
- class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </label>
-
- <label
- onClick={(e) => {
- e.preventDefault();
- rounding?.onUpdate("up")
- }}
- data-selected={rounding?.value === "up"}
- class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="channel"
- value="Existing Customers"
- class="sr-only"
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span
- id="project-type-0-label"
- class="block text-sm font-medium text-gray-900 "
- >
- <i18n.Translate>Up</i18n.Translate>
- </span>
- <i18n.Translate>Amount will be round up to the smallest possible value larger than the input.</i18n.Translate>
- </span>
- </span>
- <svg
- data-selected={rounding?.value === "up"}
- class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </label>
- <label
- onClick={(e) => {
- e.preventDefault();
- rounding?.onUpdate("nearest")
- }}
- data-selected={rounding?.value === "nearest"}
- class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="channel"
- value="Existing Customers"
- class="sr-only"
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span
- id="project-type-0-label"
- class="block text-sm font-medium text-gray-900 "
- >
- <i18n.Translate>Nearest</i18n.Translate>
- </span>
- <i18n.Translate>Amount will be round to the closest possible value.</i18n.Translate>
- </span>
- </span>
- <svg
- data-selected={rounding?.value === "nearest"}
- class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </label>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div class="px-6 pt-4">
- <Attention title={i18n.str`Examples`}>
- <section class="grid grid-cols-1 gap-y-3 text-gray-600">
- <details class="group text-sm">
- <summary class="flex cursor-pointer flex-row items-center justify-between ">
- <i18n.Translate>
- Rounding an amount of 1.24 with rounding value 0.1
- </i18n.Translate>
- <svg class="h-6 w-6 rotate-0 transform group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
- <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path>
- </svg>
- </summary>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- Given the rounding value of 0.1 the possible values closest to 1.24 are: 1.1, 1.2, 1.3, 1.4.
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "zero" mode the value will be rounded to 1.2
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "nearest" mode the value will be rounded to 1.2
- </i18n.Translate>
- </p>
- <p class="text-gray-900 mt-4">
- <i18n.Translate>
- With the "up" mode the value will be rounded to 1.3
- </i18n.Translate>
- </p>
- </details>
- <details class="group ">
- <summary class="flex cursor-pointer flex-row items-center justify-between ">
- <i18n.Translate>
- Rounding an amount of 1.26 with rounding value 0.1
- </i18n.Translate>
- <svg class="h-6 w-6 rotate-0 transform group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
- <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path>
- </svg>
- </summary>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- Given the rounding value of 0.1 the possible values closest to 1.24 are: 1.1, 1.2, 1.3, 1.4.
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "zero" mode the value will be rounded to 1.2
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "nearest" mode the value will be rounded to 1.3
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "up" mode the value will be rounded to 1.3
- </i18n.Translate>
- </p>
- </details>
- <details class="group ">
- <summary class="flex cursor-pointer flex-row items-center justify-between ">
- <i18n.Translate>
- Rounding an amount of 1.24 with rounding value 0.3
- </i18n.Translate>
- <svg class="h-6 w-6 rotate-0 transform group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
- <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path>
- </svg>
- </summary>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- Given the rounding value of 0.3 the possible values closest to 1.24 are: 0.9, 1.2, 1.5, 1.8.
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "zero" mode the value will be rounded to 1.2
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "nearest" mode the value will be rounded to 1.2
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "up" mode the value will be rounded to 1.5
- </i18n.Translate>
- </p>
- </details>
- <details class="group ">
- <summary class="flex cursor-pointer flex-row items-center justify-between ">
- <i18n.Translate>
- Rounding an amount of 1.26 with rounding value 0.3
- </i18n.Translate>
- <svg class="h-6 w-6 rotate-0 transform group-open:rotate-180" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" aria-hidden="true">
- <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"></path>
- </svg>
- </summary>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- Given the rounding value of 0.3 the possible values closest to 1.24 are: 0.9, 1.2, 1.5, 1.8.
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "zero" mode the value will be rounded to 1.2
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "nearest" mode the value will be rounded to 1.3
- </i18n.Translate>
- </p>
- <p class="text-gray-900 my-4">
- <i18n.Translate>
- With the "up" mode the value will be rounded to 1.3
- </i18n.Translate>
- </p>
- </details>
- </section>
- </Attention>
- </div>
-
-
-
- <div class="px-6 pt-6">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <label
- for="cashin_fee"
- class="block text-sm font-medium leading-6 text-gray-900"
- >{i18n.str`Fee`}</label>
- <InputAmount
- name="cashin_fee"
- left
- currency={outputCurrency}
- value={fee?.value ?? ""}
- onChange={fee?.onUpdate}
- />
- <ShowInputErrorLabel
- message={fee?.error}
- isDirty={fee?.value !== undefined}
- />
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>Amount to be deducted before amount is credited.</i18n.Translate>
- </p>
- </div>
- </div>
- </div>
-
- </Fragment>
-}
diff --git a/packages/demobank-ui/src/pages/regional/CreateCashout.tsx b/packages/demobank-ui/src/pages/regional/CreateCashout.tsx
deleted file mode 100644
index 2f15d16b4..000000000
--- a/packages/demobank-ui/src/pages/regional/CreateCashout.tsx
+++ /dev/null
@@ -1,809 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- AbsoluteTime,
- Amounts,
- HttpStatusCode,
- TalerError,
- TalerErrorCode,
- TranslatedString,
- assertUnreachable,
- encodeCrock,
- getRandomBytes,
- parsePaytoUri,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- Loading,
- LocalNotificationBanner,
- ShowInputErrorLabel,
- notifyInfo,
- useLocalNotification,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
-import { useEffect, useState } from "preact/hooks";
-import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
-import { VersionHint, useBankCoreApiContext } from "../../context/config.js";
-import { useAccountDetails } from "../../hooks/account.js";
-import { useSessionState } from "../../hooks/session.js";
-import { useBankState } from "../../hooks/bank-state.js";
-import { TransferCalculation, useCashoutEstimator, useConversionInfo, useEstimator } from "../../hooks/regional.js";
-import { RouteDefinition } from "../../route.js";
-import { TanChannel, undefinedIfEmpty } from "../../utils.js";
-import { LoginForm } from "../LoginForm.js";
-import {
- InputAmount,
- RenderAmount,
- doAutoFocus,
-} from "../PaytoWireTransferForm.js";
-
-interface Props {
- account: string;
- focus?: boolean;
- onAuthorizationRequired: () => void;
- routeClose: RouteDefinition;
- routeHere: RouteDefinition;
-}
-
-type FormType = {
- isDebit: boolean;
- amount: string;
- subject: string;
- channel: TanChannel;
-};
-type ErrorFrom<T> = {
- [P in keyof T]+?: string;
-};
-
-export function CreateCashout({
- account: accountName,
- onAuthorizationRequired,
- focus,
- routeHere,
- routeClose,
-}: Props): VNode {
- const { i18n } = useTranslationContext();
- const resultAccount = useAccountDetails(accountName);
- const {
- estimateByCredit: calculateFromCredit,
- estimateByDebit: calculateFromDebit,
- } = useCashoutEstimator();
- const { state: credentials } = useSessionState();
- const creds = credentials.status !== "loggedIn" ? undefined : credentials;
- const [, updateBankState] = useBankState();
-
- const { bank: api, config, hints } = useBankCoreApiContext();
- const [form, setForm] = useState<Partial<FormType>>({ isDebit: true });
- const [notification, notify, handleError] = useLocalNotification();
- const info = useConversionInfo();
-
- if (!config.allow_conversion) {
- return (
- <Fragment>
- <Attention type="warning" title={i18n.str`Unable to create a cashout`}>
- <i18n.Translate>
- The bank configuration does not support cashout operations.
- </i18n.Translate>
- </Attention>
- <div class="mt-5 sm:mt-6">
- <a
- href={routeClose.url({})}
- name="close"
- class="inline-flex w-full justify-center rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- >
- <i18n.Translate>Close</i18n.Translate>
- </a>
- </div>
- </Fragment>
- );
- }
-
- const OLD_CASHOUT_API = hints.indexOf(VersionHint.CASHOUT_BEFORE_2FA) !== -1;
-
- if (!resultAccount) {
- return <Loading />;
- }
- if (resultAccount instanceof TalerError) {
- return <ErrorLoadingWithDebug error={resultAccount} />;
- }
- if (resultAccount.type === "fail") {
- switch (resultAccount.case) {
- case HttpStatusCode.Unauthorized:
- return <LoginForm currentUser={accountName} />;
- case HttpStatusCode.NotFound:
- return <LoginForm currentUser={accountName} />;
- default:
- assertUnreachable(resultAccount);
- }
- }
- if (!info) {
- return <Loading />;
- }
-
- if (info instanceof TalerError) {
- return <ErrorLoadingWithDebug error={info} />;
- }
- if (info.type === "fail") {
- switch (info.case) {
- case HttpStatusCode.NotImplemented: {
- return (
- <Attention
- type="danger"
- title={i18n.str`Cashout are disabled`}
- >
- <i18n.Translate>Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.</i18n.Translate>
- </Attention>
- );
- }
- default:
- assertUnreachable(info.case);
- }
- }
-
- const conversionInfo = info.body.conversion_rate;
- if (!conversionInfo) {
- return (
- <div>conversion enabled but server replied without conversion_rate</div>
- );
- }
-
- const account = {
- balance: Amounts.parseOrThrow(resultAccount.body.balance.amount),
- balanceIsDebit:
- resultAccount.body.balance.credit_debit_indicator == "debit",
- debitThreshold: Amounts.parseOrThrow(resultAccount.body.debit_threshold),
- };
-
- const {
- fiat_currency,
- regional_currency,
- fiat_currency_specification,
- regional_currency_specification,
- } = info.body;
- const regionalZero = Amounts.zeroOfCurrency(regional_currency);
- const fiatZero = Amounts.zeroOfCurrency(fiat_currency);
- const limit = account.balanceIsDebit
- ? Amounts.sub(account.debitThreshold, account.balance).amount
- : Amounts.add(account.balance, account.debitThreshold).amount;
-
- const zeroCalc = {
- debit: regionalZero,
- credit: fiatZero,
- beforeFee: fiatZero,
- };
- const [calculationResult, setCalculation] = useState<TransferCalculation>(zeroCalc);
- const sellFee = Amounts.parseOrThrow(conversionInfo.cashout_fee);
- const sellRate = conversionInfo.cashout_ratio;
- /**
- * can be in regional currency or fiat currency
- * depending on the isDebit flag
- */
- const inputAmount = Amounts.parseOrThrow(
- `${form.isDebit ? regional_currency : fiat_currency}:${!form.amount ? "0" : form.amount
- }`,
- );
-
- useEffect(() => {
- async function doAsync() {
- await handleError(async () => {
- const higerThanMin = form.isDebit ?
- Amounts.cmp(inputAmount, conversionInfo.cashout_min_amount) === 1 : true;
- const notZero = Amounts.isNonZero(inputAmount)
- if (notZero && higerThanMin) {
- const resp = await (form.isDebit
- ? calculateFromDebit(inputAmount, sellFee)
- : calculateFromCredit(inputAmount, sellFee));
- setCalculation(resp);
- } else {
- setCalculation(zeroCalc)
- }
- });
- }
- doAsync();
- }, [form.amount, form.isDebit]);
-
- const calc = calculationResult === "amount-is-too-small" ? zeroCalc : calculationResult
-
- const balanceAfter = Amounts.sub(account.balance, calc.debit).amount;
-
- function updateForm(newForm: typeof form): void {
- setForm(newForm);
- }
- const errors = undefinedIfEmpty<ErrorFrom<typeof form>>({
- subject: !form.subject ? i18n.str`Required` : undefined,
- amount: !form.amount
- ? i18n.str`Required`
- : !inputAmount
- ? i18n.str`Invalid`
- : Amounts.cmp(limit, calc.debit) === -1
- ? i18n.str`Balance is not enough`
- : form.isDebit && Amounts.cmp(inputAmount, conversionInfo.cashout_min_amount) < 1
- ? i18n.str`Needs to be higher than ${Amounts.stringifyValueWithSpec(Amounts.parseOrThrow(conversionInfo.cashout_min_amount), regional_currency_specification).normal}`
- : calculationResult === "amount-is-too-small"
- ? i18n.str`Amount needs to be higher`
- : Amounts.isZero(calc.credit)
- ? i18n.str`The total transfer at destination will be zero`
- : undefined,
- channel: OLD_CASHOUT_API && !form.channel ? i18n.str`Required` : undefined,
- });
- const trimmedAmountStr = form.amount?.trim();
-
- async function createCashout() {
- const request_uid = encodeCrock(getRandomBytes(32));
- await handleError(async () => {
- // new cashout api doesn't require channel
- const validChannel =
- !OLD_CASHOUT_API ||
- config.supported_tan_channels.length === 0 ||
- form.channel;
-
- if (!creds || !form.subject || !validChannel) return;
- const request = {
- request_uid,
- amount_credit: Amounts.stringify(calc.credit),
- amount_debit: Amounts.stringify(calc.debit),
- subject: form.subject,
- tan_channel: form.channel,
- };
- const resp = await api.createCashout(creds, request);
- if (resp.type === "ok") {
- notifyInfo(i18n.str`Cashout created`);
- } else {
- switch (resp.case) {
- case HttpStatusCode.Accepted: {
- updateBankState("currentChallenge", {
- operation: "create-cashout",
- id: String(resp.body.challenge_id),
- sent: AbsoluteTime.never(),
- location: routeHere.url({}),
- request,
- });
- return onAuthorizationRequired();
- }
- case HttpStatusCode.NotFound:
- return notify({
- type: "error",
- title: i18n.str`Account not found`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_TRANSFER_REQUEST_UID_REUSED:
- return notify({
- type: "error",
- title: i18n.str`Duplicated request detected, check if the operation succeeded or try again.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_BAD_CONVERSION:
- return notify({
- type: "error",
- title: i18n.str`The conversion rate was incorrectly applied`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_UNALLOWED_DEBIT:
- return notify({
- type: "error",
- title: i18n.str`The account does not have sufficient funds`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case HttpStatusCode.NotImplemented:
- return notify({
- type: "error",
- title: i18n.str`Cashout are disabled`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_CONFIRM_INCOMPLETE:
- return notify({
- type: "error",
- title: i18n.str`Missing cashout URI in the profile`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
- return notify({
- type: "error",
- title: i18n.str`Sending the confirmation message failed, retry later or contact the administrator.`,
- description: resp.detail.hint as TranslatedString,
- debug: resp.detail,
- });
- }
- assertUnreachable(resp);
- }
- });
- }
- const cashoutDisabled =
- config.supported_tan_channels.length < 1 ||
- !resultAccount.body.cashout_payto_uri;
-
- const cashoutAccount = !resultAccount.body.cashout_payto_uri
- ? undefined
- : parsePaytoUri(resultAccount.body.cashout_payto_uri);
- const cashoutAccountName = !cashoutAccount
- ? undefined
- : cashoutAccount.targetPath;
-
- const cashoutLegalName = !cashoutAccount
- ? undefined
- : cashoutAccount.params["receiver-name"];
-
- return (
- <div>
- <LocalNotificationBanner notification={notification} />
-
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <section class="mt-4 rounded-sm px-4 py-6 p-8 ">
- <h2 id="summary-heading" class="font-medium text-lg">
- <i18n.Translate>Cashout</i18n.Translate>
- </h2>
-
- <dl class="mt-4 space-y-4">
- <div class="justify-between items-center flex">
- <dt class="text-sm text-gray-600">
- <i18n.Translate>Conversion rate</i18n.Translate>
- </dt>
- <dd class="text-sm text-gray-900">{sellRate}</dd>
- </div>
-
- <div class="flex items-center justify-between border-t-2 afu pt-4">
- <dt class="flex items-center text-sm text-gray-600">
- <span>
- <i18n.Translate>Balance</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={account.balance}
- spec={regional_currency_specification}
- />
- </dd>
- </div>
- <div class="flex items-center justify-between border-t-2 afu pt-4">
- <dt class="flex items-center text-sm text-gray-600">
- <span>
- <i18n.Translate>Fee</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={sellFee}
- spec={fiat_currency_specification}
- />
- </dd>
- </div>
- {cashoutAccountName && cashoutLegalName ? (
- <Fragment>
- <div class="flex items-center justify-between border-t-2 afu pt-4">
- <dt class="flex items-center text-sm text-gray-600">
- <span>
- <i18n.Translate>To account</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm text-gray-900">{cashoutAccountName}</dd>
- </div>
- <div class="flex items-center justify-between border-t-2 afu pt-4">
- <dt class="flex items-center text-sm text-gray-600">
- <span>
- <i18n.Translate>Legal name</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm text-gray-900">{cashoutLegalName}</dd>
- </div>
- <p class="mt-2 text-sm text-gray-500">
- <i18n.Translate>If this name doesn't match the account holder's name your transaction may fail.</i18n.Translate>
- </p>
- </Fragment>
- ) : (
- <div class="flex items-center justify-between border-t-2 afu pt-4">
- <Attention type="warning" title={i18n.str`No cashout account`}>
- <i18n.Translate>
- Before doing a cashout you need to complete your profile
- </i18n.Translate>
- </Attention>
- </div>
- )}
- </dl>
- </section>
- <form
- class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2"
- autoCapitalize="none"
- autoCorrect="off"
- onSubmit={(e) => {
- e.preventDefault();
- }}
- >
- <div class="px-4 py-6 sm:p-8">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- {/* subject */}
-
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="subject"
- >
- {i18n.str`Transfer subject`}
- <b style={{ color: "red" }}> *</b>
- </label>
- <div class="mt-2">
- <input
- ref={focus ? doAutoFocus : undefined}
- type="text"
- class="block w-full rounded-md disabled:bg-gray-200 border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 data-[error=true]:ring-red-500 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"
- name="subject"
- id="subject"
- disabled={cashoutDisabled}
- data-error={!!errors?.subject && form.subject !== undefined}
- value={form.subject ?? ""}
- onChange={(e) => {
- form.subject = e.currentTarget.value;
- updateForm(structuredClone(form));
- }}
- autocomplete="off"
- />
- <ShowInputErrorLabel
- message={errors?.subject}
- isDirty={form.subject !== undefined}
- />
- </div>
- </div>
-
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="subject"
- >
- {i18n.str`Currency`}
- </label>
-
- <div class="mt-2">
- <button
- type="button"
- name="set 50"
- class=" inline-flex p-4 text-sm items-center rounded-l-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
- onClick={(e) => {
- e.preventDefault();
- form.isDebit = true;
- updateForm(structuredClone(form));
- }}
- >
- {form.isDebit ?
- <svg
- class="self-center flex-none h-5 w-5 text-indigo-600"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
-
- :
- <svg fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
- <path d="M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
- </svg>
- }
-
- <i18n.Translate>Send {regional_currency}</i18n.Translate>
- </button>
- <button
- type="button"
- name="set 25"
- class=" -ml-px -mr-px inline-flex p-4 text-sm items-center rounded-r-md bg-white text-gray-900 ring-1 ring-inset ring-gray-300 hover:bg-gray-50 focus:z-10"
- onClick={(e) => {
- e.preventDefault();
- form.isDebit = false;
- updateForm(structuredClone(form));
- }}
- >
- {!form.isDebit ?
- <svg
- class="self-center flex-none h-5 w-5 text-indigo-600"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
-
- :
- <svg fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
- <path d="M15 12H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
- </svg>
- }
-
- <i18n.Translate>Receive {fiat_currency}</i18n.Translate>
- </button>
- </div>
- </div>
-
- {/* amount */}
- <div class="sm:col-span-5">
- <div class="flex justify-between">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="amount"
- >
- {i18n.str`Amount`}
- <b style={{ color: "red" }}> *</b>
- </label>
- {/* <button
- type="button"
- data-enabled={form.isDebit}
- class="bg-indigo-600 data-[enabled=false]:bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2"
- role="switch"
- aria-checked="false"
- aria-labelledby="availability-label"
- aria-describedby="availability-description"
- onClick={() => {
- form.isDebit = !form.isDebit;
- updateForm(structuredClone(form));
- }}
- >
- <span
- aria-hidden="true"
- data-enabled={form.isDebit}
- class="translate-x-5 data-[enabled=false]:translate-x-0 pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out"
- ></span>
- </button> */}
- </div>
- <div class="mt-2">
- <InputAmount
- name="amount"
- left
- currency={form.isDebit ? regional_currency : fiat_currency}
- value={trimmedAmountStr}
- onChange={
- cashoutDisabled
- ? undefined
- : (value) => {
- form.amount = value;
- updateForm(structuredClone(form));
- }
- }
- />
- <ShowInputErrorLabel
- message={errors?.amount}
- isDirty={form.amount !== undefined}
- />
- </div>
- </div>
-
- {Amounts.isZero(calc.credit) ? undefined : (
- <div class="sm:col-span-5">
- <dl class="mt-4 space-y-4">
- <div class="justify-between items-center flex ">
- <dt class="text-sm text-gray-600">
- <i18n.Translate>Total cost</i18n.Translate>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={calc.debit}
- negative
- withColor
- spec={regional_currency_specification}
- />
- </dd>
- </div>
-
- <div class="flex items-center justify-between border-t-2 afu pt-4">
- <dt class="flex items-center text-sm text-gray-600">
- <span>
- <i18n.Translate>Balance left</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={balanceAfter}
- spec={regional_currency_specification}
- />
- </dd>
- </div>
- {Amounts.isZero(sellFee) ||
- Amounts.isZero(calc.beforeFee) ? undefined : (
- <div class="flex items-center justify-between border-t-2 afu pt-4">
- <dt class="flex items-center text-sm text-gray-600">
- <span>
- <i18n.Translate>Before fee</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm text-gray-900">
- <RenderAmount
- value={calc.beforeFee}
- spec={fiat_currency_specification}
- />
- </dd>
- </div>
- )}
- <div class="flex justify-between items-center border-t-2 afu pt-4">
- <dt class="text-lg text-gray-900 font-medium">
- <i18n.Translate>Total cashout transfer</i18n.Translate>
- </dt>
- <dd class="text-lg text-gray-900 font-medium">
- <RenderAmount
- value={calc.credit}
- withColor
- spec={fiat_currency_specification}
- />
- </dd>
- </div>
- </dl>
- </div>
- )}
-
- {/* channel, not shown if new cashout api */}
- {!OLD_CASHOUT_API ? undefined : config.supported_tan_channels
- .length === 0 ? (
- <div class="sm:col-span-5">
- <Attention
- type="warning"
- title={i18n.str`No cashout channel available`}
- >
- <i18n.Translate>
- Before doing a cashout the server need to provide an
- second channel to confirm the operation
- </i18n.Translate>
- </Attention>
- </div>
- ) : (
- <div class="sm:col-span-5">
- <label
- class="block text-sm font-medium leading-6 text-gray-900"
- for="channel"
- >
- {i18n.str`Second factor authentication`}
- </label>
- <div class="mt-2 max-w-xl text-sm text-gray-500">
- <div class="px-4 mt-4 grid grid-cols-1 gap-y-6">
- {config.supported_tan_channels.indexOf(
- TanChannel.EMAIL,
- ) === -1 ? undefined : (
- <label
- onClick={() => {
- if (!resultAccount.body.contact_data?.email) return;
- form.channel = TanChannel.EMAIL;
- updateForm(structuredClone(form));
- }}
- data-disabled={
- !resultAccount.body.contact_data?.email
- }
- data-selected={form.channel === TanChannel.EMAIL}
- class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border bg-white data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="channel"
- value="Newsletter"
- class="sr-only"
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span
- id="project-type-0-label"
- class="block text-sm font-medium text-gray-900 "
- >
- <i18n.Translate>Email</i18n.Translate>
- </span>
- {!resultAccount.body.contact_data?.email &&
- i18n.str`Add a email in your profile to enable this option`}
- </span>
- </span>
- <svg
- data-selected={form.channel === TanChannel.EMAIL}
- class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </label>
- )}
-
- {config.supported_tan_channels.indexOf(TanChannel.SMS) ===
- -1 ? undefined : (
- <label
- onClick={() => {
- if (!resultAccount.body.contact_data?.phone) return;
- form.channel = TanChannel.SMS;
- updateForm(structuredClone(form));
- }}
- data-disabled={
- !resultAccount.body.contact_data?.phone
- }
- data-selected={form.channel === TanChannel.SMS}
- class="relative flex data-[disabled=false]:cursor-pointer rounded-lg border data-[disabled=true]:bg-gray-200 p-4 shadow-sm focus:outline-none border-gray-300 data-[selected=true]:ring-2 data-[selected=true]:ring-indigo-600"
- >
- <input
- type="radio"
- name="channel"
- value="Existing Customers"
- class="sr-only"
- />
- <span class="flex flex-1">
- <span class="flex flex-col">
- <span
- id="project-type-1-label"
- class="block text-sm font-medium text-gray-900"
- >
- <i18n.Translate>SMS</i18n.Translate>
- </span>
- {!resultAccount.body.contact_data?.phone &&
- i18n.str`Add a phone number in your profile to enable this option`}
- </span>
- </span>
- <svg
- data-selected={form.channel === TanChannel.SMS}
- class="h-5 w-5 text-indigo-600 data-[selected=false]:hidden"
- viewBox="0 0 20 20"
- fill="currentColor"
- aria-hidden="true"
- >
- <path
- fill-rule="evenodd"
- d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
- clip-rule="evenodd"
- />
- </svg>
- </label>
- )}
- </div>
- </div>
- </div>
- )}
- </div>
- </div>
-
- <div class="flex items-center justify-between gap-x-6 border-t border-gray-900/10 px-4 py-4 sm:px-8">
- <a
- href={routeClose.url({})}
- name="cancel"
- type="button"
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Cancel</i18n.Translate>
- </a>
- <button
- type="submit"
- name="cashout"
- class="disabled:opacity-50 disabled:cursor-default cursor-pointer rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600"
- disabled={!!errors}
- onClick={(e) => {
- e.preventDefault();
- createCashout();
- }}
- >
- <i18n.Translate>Cashout</i18n.Translate>
- </button>
- </div>
- </form>
- </div >
- </div >
- );
-}
diff --git a/packages/demobank-ui/src/pages/regional/ShowCashoutDetails.tsx b/packages/demobank-ui/src/pages/regional/ShowCashoutDetails.tsx
deleted file mode 100644
index 415f88868..000000000
--- a/packages/demobank-ui/src/pages/regional/ShowCashoutDetails.tsx
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import {
- AbsoluteTime,
- Amounts,
- Duration,
- HttpStatusCode,
- TalerError,
- assertUnreachable,
-} from "@gnu-taler/taler-util";
-import {
- Attention,
- Loading,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
-import { VNode, h } from "preact";
-import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js";
-import { useCashoutDetails, useConversionInfo } from "../../hooks/regional.js";
-import { RouteDefinition } from "../../route.js";
-import { RenderAmount } from "../PaytoWireTransferForm.js";
-import { Time } from "../../components/Time.js";
-
-interface Props {
- id: string;
- routeClose: RouteDefinition;
-}
-export function ShowCashoutDetails({ id, routeClose }: Props): VNode {
- const { i18n, dateLocale } = useTranslationContext();
- const cid = Number.parseInt(id, 10);
-
- const result = useCashoutDetails(Number.isNaN(cid) ? undefined : cid);
- const info = useConversionInfo();
-
- if (Number.isNaN(cid)) {
- return (
- <Attention
- type="danger"
- title={i18n.str`Cashout id should be a number`}
- />
- );
- }
- if (!result) {
- return <Loading />;
- }
- if (result instanceof TalerError) {
- return <ErrorLoadingWithDebug error={result} />;
- }
- if (result.type === "fail") {
- switch (result.case) {
- case HttpStatusCode.NotFound:
- return (
- <Attention
- type="warning"
- title={i18n.str`This cashout not found. Maybe already aborted.`}
- ></Attention>
- );
- case HttpStatusCode.NotImplemented:
- return (
- <Attention
- type="warning"
- title={i18n.str`Cashout are disabled`}
- >
- <i18n.Translate>Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.</i18n.Translate>
- </Attention>
- );
- default:
- assertUnreachable(result);
- }
- }
- if (!info) {
- return <Loading />;
- }
-
- if (info instanceof TalerError) {
- return <ErrorLoadingWithDebug error={info} />;
- }
- if (info.type === "fail") {
- switch (info.case) {
- case HttpStatusCode.NotImplemented: {
- return (
- <Attention type="danger"
- title={i18n.str`Cashout are disabled`}
- >
- <i18n.Translate>Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode.</i18n.Translate>
- </Attention>
- );
- }
- default:
- assertUnreachable(info.case);
- }
- }
-
- const { fiat_currency_specification, regional_currency_specification } =
- info.body;
-
- return (
- <div>
- <div class="grid grid-cols-1 gap-x-8 gap-y-8 pt-10 md:grid-cols-3 bg-gray-100 my-4 px-4 pb-4 rounded-lg">
- <section class="rounded-sm px-4">
- <h2 id="summary-heading" class="font-medium text-lg">
- <i18n.Translate>Cashout detail</i18n.Translate>
- </h2>
- <dl class="mt-8 space-y-4">
- <div class="justify-between items-center flex">
- <dt class="text-sm text-gray-600">
- <i18n.Translate>Subject</i18n.Translate>
- </dt>
- <dd class="text-sm ">{result.body.subject}</dd>
- </div>
- </dl>
- </section>
- <div class="bg-white shadow-sm ring-1 ring-gray-900/5 sm:rounded-xl md:col-span-2">
- <div class="px-4 py-6 sm:p-8">
- <div class="grid max-w-2xl grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
- <div class="sm:col-span-5">
- <dl class="space-y-4">
- {result.body.creation_time.t_s !== "never" ? (
- <div class="justify-between items-center flex ">
- <dt class=" text-gray-600">
- <i18n.Translate>Created</i18n.Translate>
- </dt>
- <dd class="text-sm ">
- <Time format="dd/MM/yyyy HH:mm:ss"
- timestamp={AbsoluteTime.fromProtocolTimestamp(result.body.creation_time)}
- // relative={Duration.fromSpec({ days: 1 })}
- />
- </dd>
- </div>
- ) : undefined}
-
- <div class="flex justify-between items-center border-t-2 afu pt-4">
- <dt class="text-gray-600">
- <i18n.Translate>Debited</i18n.Translate>
- </dt>
- <dd class=" font-medium">
- <RenderAmount
- value={Amounts.parseOrThrow(result.body.amount_debit)}
- negative
- withColor
- spec={regional_currency_specification}
- />
- </dd>
- </div>
-
- <div class="flex items-center justify-between border-t-2 afu pt-4">
- <dt class="flex items-center text-gray-600">
- <span>
- <i18n.Translate>Credited</i18n.Translate>
- </span>
- </dt>
- <dd class="text-sm ">
- <RenderAmount
- value={Amounts.parseOrThrow(result.body.amount_credit)}
- withColor
- spec={fiat_currency_specification}
- />
- </dd>
- </div>
- </dl>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <br />
- <div style={{ display: "flex", justifyContent: "space-between" }}>
- <a
- href={routeClose.url({})}
- name="close"
- class="text-sm font-semibold leading-6 text-gray-900"
- >
- <i18n.Translate>Close</i18n.Translate>
- </a>
- </div>
- </div>
- );
-}
diff --git a/packages/demobank-ui/src/pages/rnd.ts b/packages/demobank-ui/src/pages/rnd.ts
deleted file mode 100644
index d66fb005b..000000000
--- a/packages/demobank-ui/src/pages/rnd.ts
+++ /dev/null
@@ -1,2907 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
-
-const noun = [
- "people",
- "history",
- "way",
- "art",
- "world",
- "information",
- "map",
- "two",
- "family",
- "government",
- "health",
- "system",
- "computer",
- "meat",
- "year",
- "thanks",
- "music",
- "person",
- "reading",
- "method",
- "data",
- "food",
- "understanding",
- "theory",
- "law",
- "bird",
- "literature",
- "problem",
- "software",
- "control",
- "knowledge",
- "power",
- "ability",
- "economics",
- "love",
- "internet",
- "television",
- "science",
- "library",
- "nature",
- "fact",
- "product",
- "idea",
- "temperature",
- "investment",
- "area",
- "society",
- "activity",
- "story",
- "industry",
- "media",
- "thing",
- "oven",
- "community",
- "definition",
- "safety",
- "quality",
- "development",
- "language",
- "management",
- "player",
- "variety",
- "video",
- "week",
- "security",
- "country",
- "exam",
- "movie",
- "organization",
- "equipment",
- "physics",
- "analysis",
- "policy",
- "series",
- "thought",
- "basis",
- "boyfriend",
- "direction",
- "strategy",
- "technology",
- "army",
- "camera",
- "freedom",
- "paper",
- "environment",
- "child",
- "instance",
- "month",
- "truth",
- "marketing",
- "university",
- "writing",
- "article",
- "department",
- "difference",
- "goal",
- "news",
- "audience",
- "fishing",
- "growth",
- "income",
- "marriage",
- "user",
- "combination",
- "failure",
- "meaning",
- "medicine",
- "philosophy",
- "teacher",
- "communication",
- "night",
- "chemistry",
- "disease",
- "disk",
- "energy",
- "nation",
- "road",
- "role",
- "soup",
- "advertising",
- "location",
- "success",
- "addition",
- "apartment",
- "education",
- "math",
- "moment",
- "painting",
- "politics",
- "attention",
- "decision",
- "event",
- "property",
- "shopping",
- "student",
- "wood",
- "competition",
- "distribution",
- "entertainment",
- "office",
- "population",
- "president",
- "unit",
- "category",
- "cigarette",
- "context",
- "introduction",
- "opportunity",
- "performance",
- "driver",
- "flight",
- "length",
- "magazine",
- "newspaper",
- "relationship",
- "teaching",
- "cell",
- "dealer",
- "finding",
- "lake",
- "member",
- "message",
- "phone",
- "scene",
- "appearance",
- "association",
- "concept",
- "customer",
- "death",
- "discussion",
- "housing",
- "inflation",
- "insurance",
- "mood",
- "woman",
- "advice",
- "blood",
- "effort",
- "expression",
- "importance",
- "opinion",
- "payment",
- "reality",
- "responsibility",
- "situation",
- "skill",
- "statement",
- "wealth",
- "application",
- "city",
- "county",
- "depth",
- "estate",
- "foundation",
- "grandmother",
- "heart",
- "perspective",
- "photo",
- "recipe",
- "studio",
- "topic",
- "collection",
- "depression",
- "imagination",
- "passion",
- "percentage",
- "resource",
- "setting",
- "ad",
- "agency",
- "college",
- "connection",
- "criticism",
- "debt",
- "description",
- "memory",
- "patience",
- "secretary",
- "solution",
- "administration",
- "aspect",
- "attitude",
- "director",
- "personality",
- "psychology",
- "recommendation",
- "response",
- "selection",
- "storage",
- "version",
- "alcohol",
- "argument",
- "complaint",
- "contract",
- "emphasis",
- "highway",
- "loss",
- "membership",
- "possession",
- "preparation",
- "steak",
- "union",
- "agreement",
- "cancer",
- "currency",
- "employment",
- "engineering",
- "entry",
- "interaction",
- "mixture",
- "preference",
- "region",
- "republic",
- "tradition",
- "virus",
- "actor",
- "classroom",
- "delivery",
- "device",
- "difficulty",
- "drama",
- "election",
- "engine",
- "football",
- "guidance",
- "hotel",
- "owner",
- "priority",
- "protection",
- "suggestion",
- "tension",
- "variation",
- "anxiety",
- "atmosphere",
- "awareness",
- "bath",
- "bread",
- "candidate",
- "climate",
- "comparison",
- "confusion",
- "construction",
- "elevator",
- "emotion",
- "employee",
- "employer",
- "guest",
- "height",
- "leadership",
- "mall",
- "manager",
- "operation",
- "recording",
- "sample",
- "transportation",
- "charity",
- "cousin",
- "disaster",
- "editor",
- "efficiency",
- "excitement",
- "extent",
- "feedback",
- "guitar",
- "homework",
- "leader",
- "mom",
- "outcome",
- "permission",
- "presentation",
- "promotion",
- "reflection",
- "refrigerator",
- "resolution",
- "revenue",
- "session",
- "singer",
- "tennis",
- "basket",
- "bonus",
- "cabinet",
- "childhood",
- "church",
- "clothes",
- "coffee",
- "dinner",
- "drawing",
- "hair",
- "hearing",
- "initiative",
- "judgment",
- "lab",
- "measurement",
- "mode",
- "mud",
- "orange",
- "poetry",
- "police",
- "possibility",
- "procedure",
- "queen",
- "ratio",
- "relation",
- "restaurant",
- "satisfaction",
- "sector",
- "signature",
- "significance",
- "song",
- "tooth",
- "town",
- "vehicle",
- "volume",
- "wife",
- "accident",
- "airport",
- "appointment",
- "arrival",
- "assumption",
- "baseball",
- "chapter",
- "committee",
- "conversation",
- "database",
- "enthusiasm",
- "error",
- "explanation",
- "farmer",
- "gate",
- "girl",
- "hall",
- "historian",
- "hospital",
- "injury",
- "instruction",
- "maintenance",
- "manufacturer",
- "meal",
- "perception",
- "pie",
- "poem",
- "presence",
- "proposal",
- "reception",
- "replacement",
- "revolution",
- "river",
- "son",
- "speech",
- "tea",
- "village",
- "warning",
- "winner",
- "worker",
- "writer",
- "assistance",
- "breath",
- "buyer",
- "chest",
- "chocolate",
- "conclusion",
- "contribution",
- "cookie",
- "courage",
- "dad",
- "desk",
- "drawer",
- "establishment",
- "examination",
- "garbage",
- "grocery",
- "honey",
- "impression",
- "improvement",
- "independence",
- "insect",
- "inspection",
- "inspector",
- "king",
- "ladder",
- "menu",
- "penalty",
- "piano",
- "potato",
- "profession",
- "professor",
- "quantity",
- "reaction",
- "requirement",
- "salad",
- "sister",
- "supermarket",
- "tongue",
- "weakness",
- "wedding",
- "affair",
- "ambition",
- "analyst",
- "apple",
- "assignment",
- "assistant",
- "bathroom",
- "bedroom",
- "beer",
- "birthday",
- "celebration",
- "championship",
- "cheek",
- "client",
- "consequence",
- "departure",
- "diamond",
- "dirt",
- "ear",
- "fortune",
- "friendship",
- "funeral",
- "gene",
- "girlfriend",
- "hat",
- "indication",
- "intention",
- "lady",
- "midnight",
- "negotiation",
- "obligation",
- "passenger",
- "pizza",
- "platform",
- "poet",
- "pollution",
- "recognition",
- "reputation",
- "shirt",
- "sir",
- "speaker",
- "stranger",
- "surgery",
- "sympathy",
- "tale",
- "throat",
- "trainer",
- "uncle",
- "youth",
- "time",
- "work",
- "film",
- "water",
- "money",
- "example",
- "while",
- "business",
- "study",
- "game",
- "life",
- "form",
- "air",
- "day",
- "place",
- "number",
- "part",
- "field",
- "fish",
- "back",
- "process",
- "heat",
- "hand",
- "experience",
- "job",
- "book",
- "end",
- "point",
- "type",
- "home",
- "economy",
- "value",
- "body",
- "market",
- "guide",
- "interest",
- "state",
- "radio",
- "course",
- "company",
- "price",
- "size",
- "card",
- "list",
- "mind",
- "trade",
- "line",
- "care",
- "group",
- "risk",
- "word",
- "fat",
- "force",
- "key",
- "light",
- "training",
- "name",
- "school",
- "top",
- "amount",
- "level",
- "order",
- "practice",
- "research",
- "sense",
- "service",
- "piece",
- "web",
- "boss",
- "sport",
- "fun",
- "house",
- "page",
- "term",
- "test",
- "answer",
- "sound",
- "focus",
- "matter",
- "kind",
- "soil",
- "board",
- "oil",
- "picture",
- "access",
- "garden",
- "range",
- "rate",
- "reason",
- "future",
- "site",
- "demand",
- "exercise",
- "image",
- "case",
- "cause",
- "coast",
- "action",
- "age",
- "bad",
- "boat",
- "record",
- "result",
- "section",
- "building",
- "mouse",
- "cash",
- "class",
- "nothing",
- "period",
- "plan",
- "store",
- "tax",
- "side",
- "subject",
- "space",
- "rule",
- "stock",
- "weather",
- "chance",
- "figure",
- "man",
- "model",
- "source",
- "beginning",
- "earth",
- "program",
- "chicken",
- "design",
- "feature",
- "head",
- "material",
- "purpose",
- "question",
- "rock",
- "salt",
- "act",
- "birth",
- "car",
- "dog",
- "object",
- "scale",
- "sun",
- "note",
- "profit",
- "rent",
- "speed",
- "style",
- "war",
- "bank",
- "craft",
- "half",
- "inside",
- "outside",
- "standard",
- "bus",
- "exchange",
- "eye",
- "fire",
- "position",
- "pressure",
- "stress",
- "advantage",
- "benefit",
- "box",
- "frame",
- "issue",
- "step",
- "cycle",
- "face",
- "item",
- "metal",
- "paint",
- "review",
- "room",
- "screen",
- "structure",
- "view",
- "account",
- "ball",
- "discipline",
- "medium",
- "share",
- "balance",
- "bit",
- "black",
- "bottom",
- "choice",
- "gift",
- "impact",
- "machine",
- "shape",
- "tool",
- "wind",
- "address",
- "average",
- "career",
- "culture",
- "morning",
- "pot",
- "sign",
- "table",
- "task",
- "condition",
- "contact",
- "credit",
- "egg",
- "hope",
- "ice",
- "network",
- "north",
- "square",
- "attempt",
- "date",
- "effect",
- "link",
- "post",
- "star",
- "voice",
- "capital",
- "challenge",
- "friend",
- "self",
- "shot",
- "brush",
- "couple",
- "debate",
- "exit",
- "front",
- "function",
- "lack",
- "living",
- "plant",
- "plastic",
- "spot",
- "summer",
- "taste",
- "theme",
- "track",
- "wing",
- "brain",
- "button",
- "click",
- "desire",
- "foot",
- "gas",
- "influence",
- "notice",
- "rain",
- "wall",
- "base",
- "damage",
- "distance",
- "feeling",
- "pair",
- "savings",
- "staff",
- "sugar",
- "target",
- "text",
- "animal",
- "author",
- "budget",
- "discount",
- "file",
- "ground",
- "lesson",
- "minute",
- "officer",
- "phase",
- "reference",
- "register",
- "sky",
- "stage",
- "stick",
- "title",
- "trouble",
- "bowl",
- "bridge",
- "campaign",
- "character",
- "club",
- "edge",
- "evidence",
- "fan",
- "letter",
- "lock",
- "maximum",
- "novel",
- "option",
- "pack",
- "park",
- "plenty",
- "quarter",
- "skin",
- "sort",
- "weight",
- "baby",
- "background",
- "carry",
- "dish",
- "factor",
- "fruit",
- "glass",
- "joint",
- "master",
- "muscle",
- "red",
- "strength",
- "traffic",
- "trip",
- "vegetable",
- "appeal",
- "chart",
- "gear",
- "ideal",
- "kitchen",
- "land",
- "log",
- "mother",
- "net",
- "party",
- "principle",
- "relative",
- "sale",
- "season",
- "signal",
- "spirit",
- "street",
- "tree",
- "wave",
- "belt",
- "bench",
- "commission",
- "copy",
- "drop",
- "minimum",
- "path",
- "progress",
- "project",
- "sea",
- "south",
- "status",
- "stuff",
- "ticket",
- "tour",
- "angle",
- "blue",
- "breakfast",
- "confidence",
- "daughter",
- "degree",
- "doctor",
- "dot",
- "dream",
- "duty",
- "essay",
- "father",
- "fee",
- "finance",
- "hour",
- "juice",
- "limit",
- "luck",
- "milk",
- "mouth",
- "peace",
- "pipe",
- "seat",
- "stable",
- "storm",
- "substance",
- "team",
- "trick",
- "afternoon",
- "bat",
- "beach",
- "blank",
- "catch",
- "chain",
- "consideration",
- "cream",
- "crew",
- "detail",
- "gold",
- "interview",
- "kid",
- "mark",
- "match",
- "mission",
- "pain",
- "pleasure",
- "score",
- "screw",
- "sex",
- "shop",
- "shower",
- "suit",
- "tone",
- "window",
- "agent",
- "band",
- "block",
- "bone",
- "calendar",
- "cap",
- "coat",
- "contest",
- "corner",
- "court",
- "cup",
- "district",
- "door",
- "east",
- "finger",
- "garage",
- "guarantee",
- "hole",
- "hook",
- "implement",
- "layer",
- "lecture",
- "lie",
- "manner",
- "meeting",
- "nose",
- "parking",
- "partner",
- "profile",
- "respect",
- "rice",
- "routine",
- "schedule",
- "swimming",
- "telephone",
- "tip",
- "winter",
- "airline",
- "bag",
- "battle",
- "bed",
- "bill",
- "bother",
- "cake",
- "code",
- "curve",
- "designer",
- "dimension",
- "dress",
- "ease",
- "emergency",
- "evening",
- "extension",
- "farm",
- "fight",
- "gap",
- "grade",
- "holiday",
- "horror",
- "horse",
- "host",
- "husband",
- "loan",
- "mistake",
- "mountain",
- "nail",
- "noise",
- "occasion",
- "package",
- "patient",
- "pause",
- "phrase",
- "proof",
- "race",
- "relief",
- "sand",
- "sentence",
- "shoulder",
- "smoke",
- "stomach",
- "string",
- "tourist",
- "towel",
- "vacation",
- "west",
- "wheel",
- "wine",
- "arm",
- "aside",
- "associate",
- "bet",
- "blow",
- "border",
- "branch",
- "breast",
- "brother",
- "buddy",
- "bunch",
- "chip",
- "coach",
- "cross",
- "document",
- "draft",
- "dust",
- "expert",
- "floor",
- "god",
- "golf",
- "habit",
- "iron",
- "judge",
- "knife",
- "landscape",
- "league",
- "mail",
- "mess",
- "native",
- "opening",
- "parent",
- "pattern",
- "pin",
- "pool",
- "pound",
- "request",
- "salary",
- "shame",
- "shelter",
- "shoe",
- "silver",
- "tackle",
- "tank",
- "trust",
- "assist",
- "bake",
- "bar",
- "bell",
- "bike",
- "blame",
- "boy",
- "brick",
- "chair",
- "closet",
- "clue",
- "collar",
- "comment",
- "conference",
- "devil",
- "diet",
- "fear",
- "fuel",
- "glove",
- "jacket",
- "lunch",
- "monitor",
- "mortgage",
- "nurse",
- "pace",
- "panic",
- "peak",
- "plane",
- "reward",
- "row",
- "sandwich",
- "shock",
- "spite",
- "spray",
- "surprise",
- "till",
- "transition",
- "weekend",
- "welcome",
- "yard",
- "alarm",
- "bend",
- "bicycle",
- "bite",
- "blind",
- "bottle",
- "cable",
- "candle",
- "clerk",
- "cloud",
- "concert",
- "counter",
- "flower",
- "grandfather",
- "harm",
- "knee",
- "lawyer",
- "leather",
- "load",
- "mirror",
- "neck",
- "pension",
- "plate",
- "purple",
- "ruin",
- "ship",
- "skirt",
- "slice",
- "snow",
- "specialist",
- "stroke",
- "switch",
- "trash",
- "tune",
- "zone",
- "anger",
- "award",
- "bid",
- "bitter",
- "boot",
- "bug",
- "camp",
- "candy",
- "carpet",
- "cat",
- "champion",
- "channel",
- "clock",
- "comfort",
- "cow",
- "crack",
- "engineer",
- "entrance",
- "fault",
- "grass",
- "guy",
- "hell",
- "highlight",
- "incident",
- "island",
- "joke",
- "jury",
- "leg",
- "lip",
- "mate",
- "motor",
- "nerve",
- "passage",
- "pen",
- "pride",
- "priest",
- "prize",
- "promise",
- "resident",
- "resort",
- "ring",
- "roof",
- "rope",
- "sail",
- "scheme",
- "script",
- "sock",
- "station",
- "toe",
- "tower",
- "truck",
- "witness",
- "a",
- "you",
- "it",
- "can",
- "will",
- "if",
- "one",
- "many",
- "most",
- "other",
- "use",
- "make",
- "good",
- "look",
- "help",
- "go",
- "great",
- "being",
- "few",
- "might",
- "still",
- "public",
- "read",
- "keep",
- "start",
- "give",
- "human",
- "local",
- "general",
- "she",
- "specific",
- "long",
- "play",
- "feel",
- "high",
- "tonight",
- "put",
- "common",
- "set",
- "change",
- "simple",
- "past",
- "big",
- "possible",
- "particular",
- "today",
- "major",
- "personal",
- "current",
- "national",
- "cut",
- "natural",
- "physical",
- "show",
- "try",
- "check",
- "second",
- "call",
- "move",
- "pay",
- "let",
- "increase",
- "single",
- "individual",
- "turn",
- "ask",
- "buy",
- "guard",
- "hold",
- "main",
- "offer",
- "potential",
- "professional",
- "international",
- "travel",
- "cook",
- "alternative",
- "following",
- "special",
- "working",
- "whole",
- "dance",
- "excuse",
- "cold",
- "commercial",
- "low",
- "purchase",
- "deal",
- "primary",
- "worth",
- "fall",
- "necessary",
- "positive",
- "produce",
- "search",
- "present",
- "spend",
- "talk",
- "creative",
- "tell",
- "cost",
- "drive",
- "green",
- "support",
- "glad",
- "remove",
- "return",
- "run",
- "complex",
- "due",
- "effective",
- "middle",
- "regular",
- "reserve",
- "independent",
- "leave",
- "original",
- "reach",
- "rest",
- "serve",
- "watch",
- "beautiful",
- "charge",
- "active",
- "break",
- "negative",
- "safe",
- "stay",
- "visit",
- "visual",
- "affect",
- "cover",
- "report",
- "rise",
- "walk",
- "white",
- "beyond",
- "junior",
- "pick",
- "unique",
- "anything",
- "classic",
- "final",
- "lift",
- "mix",
- "private",
- "stop",
- "teach",
- "western",
- "concern",
- "familiar",
- "fly",
- "official",
- "broad",
- "comfortable",
- "gain",
- "maybe",
- "rich",
- "save",
- "stand",
- "young",
- "fail",
- "heavy",
- "hello",
- "lead",
- "listen",
- "valuable",
- "worry",
- "handle",
- "leading",
- "meet",
- "release",
- "sell",
- "finish",
- "normal",
- "press",
- "ride",
- "secret",
- "spread",
- "spring",
- "tough",
- "wait",
- "brown",
- "deep",
- "display",
- "flow",
- "hit",
- "objective",
- "shoot",
- "touch",
- "cancel",
- "chemical",
- "cry",
- "dump",
- "extreme",
- "push",
- "conflict",
- "eat",
- "fill",
- "formal",
- "jump",
- "kick",
- "opposite",
- "pass",
- "pitch",
- "remote",
- "total",
- "treat",
- "vast",
- "abuse",
- "beat",
- "burn",
- "deposit",
- "print",
- "raise",
- "sleep",
- "somewhere",
- "advance",
- "anywhere",
- "consist",
- "dark",
- "double",
- "draw",
- "equal",
- "fix",
- "hire",
- "internal",
- "join",
- "kill",
- "sensitive",
- "tap",
- "win",
- "attack",
- "claim",
- "constant",
- "drag",
- "drink",
- "guess",
- "minor",
- "pull",
- "raw",
- "soft",
- "solid",
- "wear",
- "weird",
- "wonder",
- "annual",
- "count",
- "dead",
- "doubt",
- "feed",
- "forever",
- "impress",
- "nobody",
- "repeat",
- "round",
- "sing",
- "slide",
- "strip",
- "whereas",
- "wish",
- "combine",
- "command",
- "dig",
- "divide",
- "equivalent",
- "hang",
- "hunt",
- "initial",
- "march",
- "mention",
- "smell",
- "spiritual",
- "survey",
- "tie",
- "adult",
- "brief",
- "crazy",
- "escape",
- "gather",
- "hate",
- "prior",
- "repair",
- "rough",
- "sad",
- "scratch",
- "sick",
- "strike",
- "employ",
- "external",
- "hurt",
- "illegal",
- "laugh",
- "lay",
- "mobile",
- "nasty",
- "ordinary",
- "respond",
- "royal",
- "senior",
- "split",
- "strain",
- "struggle",
- "swim",
- "train",
- "upper",
- "wash",
- "yellow",
- "convert",
- "crash",
- "dependent",
- "fold",
- "funny",
- "grab",
- "hide",
- "miss",
- "permit",
- "quote",
- "recover",
- "resolve",
- "roll",
- "sink",
- "slip",
- "spare",
- "suspect",
- "sweet",
- "swing",
- "twist",
- "upstairs",
- "usual",
- "abroad",
- "brave",
- "calm",
- "concentrate",
- "estimate",
- "grand",
- "male",
- "mine",
- "prompt",
- "quiet",
- "refuse",
- "regret",
- "reveal",
- "rush",
- "shake",
- "shift",
- "shine",
- "steal",
- "suck",
- "surround",
- "anybody",
- "bear",
- "brilliant",
- "dare",
- "dear",
- "delay",
- "drunk",
- "female",
- "hurry",
- "inevitable",
- "invite",
- "kiss",
- "neat",
- "pop",
- "punch",
- "quit",
- "reply",
- "representative",
- "resist",
- "rip",
- "rub",
- "silly",
- "smile",
- "spell",
- "stretch",
- "stupid",
- "tear",
- "temporary",
- "tomorrow",
- "wake",
- "wrap",
- "yesterday",
-];
-
-const adj = [
- "abandoned",
- "able",
- "absolute",
- "adorable",
- "adventurous",
- "academic",
- "acceptable",
- "acclaimed",
- "accomplished",
- "accurate",
- "aching",
- "acidic",
- "acrobatic",
- "active",
- "actual",
- "adept",
- "admirable",
- "admired",
- "adolescent",
- "adorable",
- "adored",
- "advanced",
- "afraid",
- "affectionate",
- "aged",
- "aggravating",
- "aggressive",
- "agile",
- "agitated",
- "agonizing",
- "agreeable",
- "ajar",
- "alarmed",
- "alarming",
- "alert",
- "alienated",
- "alive",
- "all",
- "altruistic",
- "amazing",
- "ambitious",
- "ample",
- "amused",
- "amusing",
- "anchored",
- "ancient",
- "angelic",
- "angry",
- "anguished",
- "animated",
- "annual",
- "another",
- "antique",
- "anxious",
- "any",
- "apprehensive",
- "appropriate",
- "apt",
- "arctic",
- "arid",
- "aromatic",
- "artistic",
- "ashamed",
- "assured",
- "astonishing",
- "athletic",
- "attached",
- "attentive",
- "attractive",
- "austere",
- "authentic",
- "authorized",
- "automatic",
- "avaricious",
- "average",
- "aware",
- "awesome",
- "awful",
- "awkward",
- "babyish",
- "bad",
- "back",
- "baggy",
- "bare",
- "barren",
- "basic",
- "beautiful",
- "belated",
- "beloved",
- "beneficial",
- "better",
- "best",
- "bewitched",
- "big",
- "big-hearted",
- "biodegradable",
- "bite-sized",
- "bitter",
- "black",
- "black-and-white",
- "bland",
- "blank",
- "blaring",
- "bleak",
- "blind",
- "blissful",
- "blond",
- "blue",
- "blushing",
- "bogus",
- "boiling",
- "bold",
- "bony",
- "boring",
- "bossy",
- "both",
- "bouncy",
- "bountiful",
- "bowed",
- "brave",
- "breakable",
- "brief",
- "bright",
- "brilliant",
- "brisk",
- "broken",
- "bronze",
- "brown",
- "bruised",
- "bubbly",
- "bulky",
- "bumpy",
- "buoyant",
- "burdensome",
- "burly",
- "bustling",
- "busy",
- "buttery",
- "buzzing",
- "calculating",
- "calm",
- "candid",
- "canine",
- "capital",
- "carefree",
- "careful",
- "careless",
- "caring",
- "cautious",
- "cavernous",
- "celebrated",
- "charming",
- "cheap",
- "cheerful",
- "cheery",
- "chief",
- "chilly",
- "chubby",
- "circular",
- "classic",
- "clean",
- "clear",
- "clear-cut",
- "clever",
- "close",
- "closed",
- "cloudy",
- "clueless",
- "clumsy",
- "cluttered",
- "coarse",
- "cold",
- "colorful",
- "colorless",
- "colossal",
- "comfortable",
- "common",
- "compassionate",
- "competent",
- "complete",
- "complex",
- "complicated",
- "composed",
- "concerned",
- "concrete",
- "confused",
- "conscious",
- "considerate",
- "constant",
- "content",
- "conventional",
- "cooked",
- "cool",
- "cooperative",
- "coordinated",
- "corny",
- "corrupt",
- "costly",
- "courageous",
- "courteous",
- "crafty",
- "crazy",
- "creamy",
- "creative",
- "creepy",
- "criminal",
- "crisp",
- "critical",
- "crooked",
- "crowded",
- "cruel",
- "crushing",
- "cuddly",
- "cultivated",
- "cultured",
- "cumbersome",
- "curly",
- "curvy",
- "cute",
- "cylindrical",
- "damaged",
- "damp",
- "dangerous",
- "dapper",
- "daring",
- "darling",
- "dark",
- "dazzling",
- "dead",
- "deadly",
- "deafening",
- "dear",
- "dearest",
- "decent",
- "decimal",
- "decisive",
- "deep",
- "defenseless",
- "defensive",
- "defiant",
- "deficient",
- "definite",
- "definitive",
- "delayed",
- "delectable",
- "delicious",
- "delightful",
- "delirious",
- "demanding",
- "dense",
- "dental",
- "dependable",
- "dependent",
- "descriptive",
- "deserted",
- "detailed",
- "determined",
- "devoted",
- "different",
- "difficult",
- "digital",
- "diligent",
- "dim",
- "dimpled",
- "dimwitted",
- "direct",
- "disastrous",
- "discrete",
- "disfigured",
- "disgusting",
- "disloyal",
- "dismal",
- "distant",
- "downright",
- "dreary",
- "dirty",
- "disguised",
- "dishonest",
- "dismal",
- "distant",
- "distinct",
- "distorted",
- "dizzy",
- "dopey",
- "doting",
- "double",
- "downright",
- "drab",
- "drafty",
- "dramatic",
- "dreary",
- "droopy",
- "dry",
- "dual",
- "dull",
- "dutiful",
- "each",
- "eager",
- "earnest",
- "early",
- "easy",
- "easy-going",
- "ecstatic",
- "edible",
- "educated",
- "elaborate",
- "elastic",
- "elated",
- "elderly",
- "electric",
- "elegant",
- "elementary",
- "elliptical",
- "embarrassed",
- "embellished",
- "eminent",
- "emotional",
- "empty",
- "enchanted",
- "enchanting",
- "energetic",
- "enlightened",
- "enormous",
- "enraged",
- "entire",
- "envious",
- "equal",
- "equatorial",
- "essential",
- "esteemed",
- "ethical",
- "euphoric",
- "even",
- "evergreen",
- "everlasting",
- "every",
- "evil",
- "exalted",
- "excellent",
- "exemplary",
- "exhausted",
- "excitable",
- "excited",
- "exciting",
- "exotic",
- "expensive",
- "experienced",
- "expert",
- "extraneous",
- "extroverted",
- "extra-large",
- "extra-small",
- "fabulous",
- "failing",
- "faint",
- "fair",
- "faithful",
- "fake",
- "false",
- "familiar",
- "famous",
- "fancy",
- "fantastic",
- "far",
- "faraway",
- "far-flung",
- "far-off",
- "fast",
- "fat",
- "fatal",
- "fatherly",
- "favorable",
- "favorite",
- "fearful",
- "fearless",
- "feisty",
- "feline",
- "female",
- "feminine",
- "few",
- "fickle",
- "filthy",
- "fine",
- "finished",
- "firm",
- "first",
- "firsthand",
- "fitting",
- "fixed",
- "flaky",
- "flamboyant",
- "flashy",
- "flat",
- "flawed",
- "flawless",
- "flickering",
- "flimsy",
- "flippant",
- "flowery",
- "fluffy",
- "fluid",
- "flustered",
- "focused",
- "fond",
- "foolhardy",
- "foolish",
- "forceful",
- "forked",
- "formal",
- "forsaken",
- "forthright",
- "fortunate",
- "fragrant",
- "frail",
- "frank",
- "frayed",
- "free",
- "French",
- "fresh",
- "frequent",
- "friendly",
- "frightened",
- "frightening",
- "frigid",
- "frilly",
- "frizzy",
- "frivolous",
- "front",
- "frosty",
- "frozen",
- "frugal",
- "fruitful",
- "full",
- "fumbling",
- "functional",
- "funny",
- "fussy",
- "fuzzy",
- "gargantuan",
- "gaseous",
- "general",
- "generous",
- "gentle",
- "genuine",
- "giant",
- "giddy",
- "gigantic",
- "gifted",
- "giving",
- "glamorous",
- "glaring",
- "glass",
- "gleaming",
- "gleeful",
- "glistening",
- "glittering",
- "gloomy",
- "glorious",
- "glossy",
- "glum",
- "golden",
- "good",
- "good-natured",
- "gorgeous",
- "graceful",
- "gracious",
- "grand",
- "grandiose",
- "granular",
- "grateful",
- "grave",
- "gray",
- "great",
- "greedy",
- "green",
- "gregarious",
- "grim",
- "grimy",
- "gripping",
- "grizzled",
- "gross",
- "grotesque",
- "grouchy",
- "grounded",
- "growing",
- "growling",
- "grown",
- "grubby",
- "gruesome",
- "grumpy",
- "guilty",
- "gullible",
- "gummy",
- "hairy",
- "half",
- "handmade",
- "handsome",
- "handy",
- "happy",
- "happy-go-lucky",
- "hard",
- "hard-to-find",
- "harmful",
- "harmless",
- "harmonious",
- "harsh",
- "hasty",
- "hateful",
- "haunting",
- "healthy",
- "heartfelt",
- "hearty",
- "heavenly",
- "heavy",
- "hefty",
- "helpful",
- "helpless",
- "hidden",
- "hideous",
- "high",
- "high-level",
- "hilarious",
- "hoarse",
- "hollow",
- "homely",
- "honest",
- "honorable",
- "honored",
- "hopeful",
- "horrible",
- "hospitable",
- "hot",
- "huge",
- "humble",
- "humiliating",
- "humming",
- "humongous",
- "hungry",
- "hurtful",
- "husky",
- "icky",
- "icy",
- "ideal",
- "idealistic",
- "identical",
- "idle",
- "idiotic",
- "idolized",
- "ignorant",
- "ill",
- "illegal",
- "ill-fated",
- "ill-informed",
- "illiterate",
- "illustrious",
- "imaginary",
- "imaginative",
- "immaculate",
- "immaterial",
- "immediate",
- "immense",
- "impassioned",
- "impeccable",
- "impartial",
- "imperfect",
- "imperturbable",
- "impish",
- "impolite",
- "important",
- "impossible",
- "impractical",
- "impressionable",
- "impressive",
- "improbable",
- "impure",
- "inborn",
- "incomparable",
- "incompatible",
- "incomplete",
- "inconsequential",
- "incredible",
- "indelible",
- "inexperienced",
- "indolent",
- "infamous",
- "infantile",
- "infatuated",
- "inferior",
- "infinite",
- "informal",
- "innocent",
- "insecure",
- "insidious",
- "insignificant",
- "insistent",
- "instructive",
- "insubstantial",
- "intelligent",
- "intent",
- "intentional",
- "interesting",
- "internal",
- "international",
- "intrepid",
- "ironclad",
- "irresponsible",
- "irritating",
- "itchy",
- "jaded",
- "jagged",
- "jam-packed",
- "jaunty",
- "jealous",
- "jittery",
- "joint",
- "jolly",
- "jovial",
- "joyful",
- "joyous",
- "jubilant",
- "judicious",
- "juicy",
- "jumbo",
- "junior",
- "jumpy",
- "juvenile",
- "kaleidoscopic",
- "keen",
- "key",
- "kind",
- "kindhearted",
- "kindly",
- "klutzy",
- "knobby",
- "knotty",
- "knowledgeable",
- "knowing",
- "known",
- "kooky",
- "kosher",
- "lame",
- "lanky",
- "large",
- "last",
- "lasting",
- "late",
- "lavish",
- "lawful",
- "lazy",
- "leading",
- "lean",
- "leafy",
- "left",
- "legal",
- "legitimate",
- "light",
- "lighthearted",
- "likable",
- "likely",
- "limited",
- "limp",
- "limping",
- "linear",
- "lined",
- "liquid",
- "little",
- "live",
- "lively",
- "livid",
- "loathsome",
- "lone",
- "lonely",
- "long",
- "long-term",
- "loose",
- "lopsided",
- "lost",
- "loud",
- "lovable",
- "lovely",
- "loving",
- "low",
- "loyal",
- "lucky",
- "lumbering",
- "luminous",
- "lumpy",
- "lustrous",
- "luxurious",
- "mad",
- "made-up",
- "magnificent",
- "majestic",
- "major",
- "male",
- "mammoth",
- "married",
- "marvelous",
- "masculine",
- "massive",
- "mature",
- "meager",
- "mealy",
- "mean",
- "measly",
- "meaty",
- "medical",
- "mediocre",
- "medium",
- "meek",
- "mellow",
- "melodic",
- "memorable",
- "menacing",
- "merry",
- "messy",
- "metallic",
- "mild",
- "milky",
- "mindless",
- "miniature",
- "minor",
- "minty",
- "miserable",
- "miserly",
- "misguided",
- "misty",
- "mixed",
- "modern",
- "modest",
- "moist",
- "monstrous",
- "monthly",
- "monumental",
- "moral",
- "mortified",
- "motherly",
- "motionless",
- "mountainous",
- "muddy",
- "muffled",
- "multicolored",
- "mundane",
- "murky",
- "mushy",
- "musty",
- "muted",
- "mysterious",
- "naive",
- "narrow",
- "nasty",
- "natural",
- "naughty",
- "nautical",
- "near",
- "neat",
- "necessary",
- "needy",
- "negative",
- "neglected",
- "negligible",
- "neighboring",
- "nervous",
- "new",
- "next",
- "nice",
- "nifty",
- "nimble",
- "nippy",
- "nocturnal",
- "noisy",
- "nonstop",
- "normal",
- "notable",
- "noted",
- "noteworthy",
- "novel",
- "noxious",
- "numb",
- "nutritious",
- "nutty",
- "obedient",
- "obese",
- "oblong",
- "oily",
- "oblong",
- "obvious",
- "occasional",
- "odd",
- "oddball",
- "offbeat",
- "offensive",
- "official",
- "old",
- "old-fashioned",
- "only",
- "open",
- "optimal",
- "optimistic",
- "opulent",
- "orange",
- "orderly",
- "organic",
- "ornate",
- "ornery",
- "ordinary",
- "original",
- "other",
- "our",
- "outlying",
- "outgoing",
- "outlandish",
- "outrageous",
- "outstanding",
- "oval",
- "overcooked",
- "overdue",
- "overjoyed",
- "overlooked",
- "palatable",
- "pale",
- "paltry",
- "parallel",
- "parched",
- "partial",
- "passionate",
- "past",
- "pastel",
- "peaceful",
- "peppery",
- "perfect",
- "perfumed",
- "periodic",
- "perky",
- "personal",
- "pertinent",
- "pesky",
- "pessimistic",
- "petty",
- "phony",
- "physical",
- "piercing",
- "pink",
- "pitiful",
- "plain",
- "plaintive",
- "plastic",
- "playful",
- "pleasant",
- "pleased",
- "pleasing",
- "plump",
- "plush",
- "polished",
- "polite",
- "political",
- "pointed",
- "pointless",
- "poised",
- "poor",
- "popular",
- "portly",
- "posh",
- "positive",
- "possible",
- "potable",
- "powerful",
- "powerless",
- "practical",
- "precious",
- "present",
- "prestigious",
- "pretty",
- "precious",
- "previous",
- "pricey",
- "prickly",
- "primary",
- "prime",
- "pristine",
- "private",
- "prize",
- "probable",
- "productive",
- "profitable",
- "profuse",
- "proper",
- "proud",
- "prudent",
- "punctual",
- "pungent",
- "puny",
- "pure",
- "purple",
- "pushy",
- "putrid",
- "puzzled",
- "puzzling",
- "quaint",
- "qualified",
- "quarrelsome",
- "quarterly",
- "queasy",
- "querulous",
- "questionable",
- "quick",
- "quick-witted",
- "quiet",
- "quintessential",
- "quirky",
- "quixotic",
- "quizzical",
- "radiant",
- "ragged",
- "rapid",
- "rare",
- "rash",
- "raw",
- "recent",
- "reckless",
- "rectangular",
- "ready",
- "real",
- "realistic",
- "reasonable",
- "red",
- "reflecting",
- "regal",
- "regular",
- "reliable",
- "relieved",
- "remarkable",
- "remorseful",
- "remote",
- "repentant",
- "required",
- "respectful",
- "responsible",
- "repulsive",
- "revolving",
- "rewarding",
- "rich",
- "rigid",
- "right",
- "ringed",
- "ripe",
- "roasted",
- "robust",
- "rosy",
- "rotating",
- "rotten",
- "rough",
- "round",
- "rowdy",
- "royal",
- "rubbery",
- "rundown",
- "ruddy",
- "rude",
- "runny",
- "rural",
- "rusty",
- "sad",
- "safe",
- "salty",
- "same",
- "sandy",
- "sane",
- "sarcastic",
- "sardonic",
- "satisfied",
- "scaly",
- "scarce",
- "scared",
- "scary",
- "scented",
- "scholarly",
- "scientific",
- "scornful",
- "scratchy",
- "scrawny",
- "second",
- "secondary",
- "second-hand",
- "secret",
- "self-assured",
- "self-reliant",
- "selfish",
- "sentimental",
- "separate",
- "serene",
- "serious",
- "serpentine",
- "several",
- "severe",
- "shabby",
- "shadowy",
- "shady",
- "shallow",
- "shameful",
- "shameless",
- "sharp",
- "shimmering",
- "shiny",
- "shocked",
- "shocking",
- "shoddy",
- "short",
- "short-term",
- "showy",
- "shrill",
- "shy",
- "sick",
- "silent",
- "silky",
- "silly",
- "silver",
- "similar",
- "simple",
- "simplistic",
- "sinful",
- "single",
- "sizzling",
- "skeletal",
- "skinny",
- "sleepy",
- "slight",
- "slim",
- "slimy",
- "slippery",
- "slow",
- "slushy",
- "small",
- "smart",
- "smoggy",
- "smooth",
- "smug",
- "snappy",
- "snarling",
- "sneaky",
- "sniveling",
- "snoopy",
- "sociable",
- "soft",
- "soggy",
- "solid",
- "somber",
- "some",
- "spherical",
- "sophisticated",
- "sore",
- "sorrowful",
- "soulful",
- "soupy",
- "sour",
- "Spanish",
- "sparkling",
- "sparse",
- "specific",
- "spectacular",
- "speedy",
- "spicy",
- "spiffy",
- "spirited",
- "spiteful",
- "splendid",
- "spotless",
- "spotted",
- "spry",
- "square",
- "squeaky",
- "squiggly",
- "stable",
- "staid",
- "stained",
- "stale",
- "standard",
- "starchy",
- "stark",
- "starry",
- "steep",
- "sticky",
- "stiff",
- "stimulating",
- "stingy",
- "stormy",
- "straight",
- "strange",
- "steel",
- "strict",
- "strident",
- "striking",
- "striped",
- "strong",
- "studious",
- "stunning",
- "stupendous",
- "stupid",
- "sturdy",
- "stylish",
- "subdued",
- "submissive",
- "substantial",
- "subtle",
- "suburban",
- "sudden",
- "sugary",
- "sunny",
- "super",
- "superb",
- "superficial",
- "superior",
- "supportive",
- "sure-footed",
- "surprised",
- "suspicious",
- "svelte",
- "sweaty",
- "sweet",
- "sweltering",
- "swift",
- "sympathetic",
- "tall",
- "talkative",
- "tame",
- "tan",
- "tangible",
- "tart",
- "tasty",
- "tattered",
- "taut",
- "tedious",
- "teeming",
- "tempting",
- "tender",
- "tense",
- "tepid",
- "terrible",
- "terrific",
- "testy",
- "thankful",
- "that",
- "these",
- "thick",
- "thin",
- "third",
- "thirsty",
- "this",
- "thorough",
- "thorny",
- "those",
- "thoughtful",
- "threadbare",
- "thrifty",
- "thunderous",
- "tidy",
- "tight",
- "timely",
- "tinted",
- "tiny",
- "tired",
- "torn",
- "total",
- "tough",
- "traumatic",
- "treasured",
- "tremendous",
- "tragic",
- "trained",
- "tremendous",
- "triangular",
- "tricky",
- "trifling",
- "trim",
- "trivial",
- "troubled",
- "true",
- "trusting",
- "trustworthy",
- "trusty",
- "truthful",
- "tubby",
- "turbulent",
- "twin",
- "ugly",
- "ultimate",
- "unacceptable",
- "unaware",
- "uncomfortable",
- "uncommon",
- "unconscious",
- "understated",
- "unequaled",
- "uneven",
- "unfinished",
- "unfit",
- "unfolded",
- "unfortunate",
- "unhappy",
- "unhealthy",
- "uniform",
- "unimportant",
- "unique",
- "united",
- "unkempt",
- "unknown",
- "unlawful",
- "unlined",
- "unlucky",
- "unnatural",
- "unpleasant",
- "unrealistic",
- "unripe",
- "unruly",
- "unselfish",
- "unsightly",
- "unsteady",
- "unsung",
- "untidy",
- "untimely",
- "untried",
- "untrue",
- "unused",
- "unusual",
- "unwelcome",
- "unwieldy",
- "unwilling",
- "unwitting",
- "unwritten",
- "upbeat",
- "upright",
- "upset",
- "urban",
- "usable",
- "used",
- "useful",
- "useless",
- "utilized",
- "utter",
- "vacant",
- "vague",
- "vain",
- "valid",
- "valuable",
- "vapid",
- "variable",
- "vast",
- "velvety",
- "venerated",
- "vengeful",
- "verifiable",
- "vibrant",
- "vicious",
- "victorious",
- "vigilant",
- "vigorous",
- "villainous",
- "violet",
- "violent",
- "virtual",
- "virtuous",
- "visible",
- "vital",
- "vivacious",
- "vivid",
- "voluminous",
- "wan",
- "warlike",
- "warm",
- "warmhearted",
- "warped",
- "wary",
- "wasteful",
- "watchful",
- "waterlogged",
- "watery",
- "wavy",
- "wealthy",
- "weak",
- "weary",
- "webbed",
- "weed",
- "weekly",
- "weepy",
- "weighty",
- "weird",
- "welcome",
- "well-documented",
- "well-groomed",
- "well-informed",
- "well-lit",
- "well-made",
- "well-off",
- "well-to-do",
- "well-worn",
- "wet",
- "which",
- "whimsical",
- "whirlwind",
- "whispered",
- "white",
- "whole",
- "whopping",
- "wicked",
- "wide",
- "wide-eyed",
- "wiggly",
- "wild",
- "willing",
- "wilted",
- "winding",
- "windy",
- "winged",
- "wiry",
- "wise",
- "witty",
- "wobbly",
- "woeful",
- "wonderful",
- "wooden",
- "woozy",
- "wordy",
- "worldly",
- "worn",
- "worried",
- "worrisome",
- "worse",
- "worst",
- "worthless",
- "worthwhile",
- "worthy",
- "wrathful",
- "wretched",
- "writhing",
- "wrong",
- "wry",
- "yawning",
- "yearly",
- "yellow",
- "yellowish",
- "young",
- "youthful",
- "yummy",
- "zany",
- "zealous",
- "zesty",
- "zigzag",
-];
-
-export function getRandomUsername(): { first: string; second: string } {
- const n = Math.floor(Math.random() * noun.length);
- const a = Math.floor(Math.random() * adj.length);
- return {
- first: adj[a],
- second: noun[n],
- };
-}
-
-export function getRandomPassword(): string {
- return encodeCrock(getRandomBytes(16));
-}
diff --git a/packages/demobank-ui/src/route.ts b/packages/demobank-ui/src/route.ts
deleted file mode 100644
index 1f85ce54e..000000000
--- a/packages/demobank-ui/src/route.ts
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-import { useNavigationContext } from "./context/navigation.js";
-
-declare const __location: unique symbol;
-/**
- * special string that defined a location in the application
- *
- * this help to prevent wrong path
- */
-export type AppLocation = string & {
- [__location]: true;
-};
-export type EmptyObject = Record<string, never>;
-
-export function urlPattern<
- T extends Record<string, string | undefined> = EmptyObject,
->(pattern: RegExp, reverse: (p: T) => string): RouteDefinition<T> {
- const url = reverse as ((p: T) => AppLocation)
- return {
- pattern: new RegExp(pattern),
- url,
- };
-}
-
-/**
- * defines a location in the app
- *
- * pattern: how a string will trigger this location
- * url(): how a state serialize to a location
- */
-
-export type ObjectOf<T> = Record<string, T> | EmptyObject;
-
-export type RouteDefinition<T extends ObjectOf<string | undefined> = EmptyObject> = {
- pattern: RegExp;
- url: (p: T) => AppLocation;
-};
-
-const nullRountDef = {
- pattern: new RegExp(/.*/),
- url: () => "" as AppLocation,
-};
-export function buildNullRoutDefinition<T extends ObjectOf<string>>(): RouteDefinition<T> {
- return nullRountDef;
-}
-
-/**
- * Search path in the pageList
- * get the values from the path found
- * add params from searchParams
- *
- * @param path
- * @param params
- */
-function findMatch<T extends ObjectOf<RouteDefinition>>(
- pagesMap: T,
- pageList: Array<keyof T>,
- path: string,
- params: Record<string, string>,
-): Location<T> | undefined {
- for (let idx = 0; idx < pageList.length; idx++) {
- const name = pageList[idx];
- const found = pagesMap[name].pattern.exec(path);
- if (found !== null) {
- const values = {} as Record<string, any>
-
- Object.entries(params).forEach(([key, value]) => {
- values[key] = value;
- });
-
- if (found.groups !== undefined) {
- Object.entries(found.groups).forEach(([key, value]) => {
- values[key] = value;
- });
- }
-
- // @ts-expect-error values is a map string which is equivalent to the RouteParamsType
- return { name, parent: pagesMap, values };
- }
- }
- return undefined;
-}
-
-/**
- * get the type of the params of a location
- *
- */
-type RouteParamsType<
- RouteType,
- Key extends keyof RouteType,
-> = RouteType[Key] extends RouteDefinition<infer ParamType> ? ParamType : never;
-
-/**
- * Helps to create a map of a type with the key
- */
-type MapKeyValue<Type> = {
- [Key in keyof Type]: Key extends string ? {
- parent: Type,
- name: Key,
- values: RouteParamsType<Type, Key>;
- } : never;
-}
-
-/**
- * create a enumeration of value of a mapped type
- */
-type EnumerationOf<T> = T[keyof T]
-
-type Location<T> = EnumerationOf<MapKeyValue<T>>
-
-export function useCurrentLocation<T extends ObjectOf<RouteDefinition<any>>>(pagesMap: T): Location<T> | undefined {
- const pageList = Object.keys(pagesMap as object) as Array<keyof T>;
- const { path, params } = useNavigationContext();
-
- return findMatch(pagesMap, pageList, path, params);
-}
diff --git a/packages/demobank-ui/src/scss/main.css b/packages/demobank-ui/src/scss/main.css
deleted file mode 100644
index b5c61c956..000000000
--- a/packages/demobank-ui/src/scss/main.css
+++ /dev/null
@@ -1,3 +0,0 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
diff --git a/packages/demobank-ui/src/settings.json b/packages/demobank-ui/src/settings.json
deleted file mode 100644
index df5fe75ce..000000000
--- a/packages/demobank-ui/src/settings.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "backendBaseURL": "http://bank.taler.test:1180/",
- "simplePasswordForRandomAccounts": true,
- "allowRandomAccountCreation": true,
- "bankName": "Taler DEVELOPMENT Bank",
- "topNavSites": {
- "Exchange": "http://Exchnage.taler.test:1180/",
- "Bank": "http://bank-ui.taler.test:1180/",
- "Merchant": "http://merchant.taler.test:1180/"
- }
-}
diff --git a/packages/demobank-ui/src/settings.ts b/packages/demobank-ui/src/settings.ts
deleted file mode 100644
index 91790d10d..000000000
--- a/packages/demobank-ui/src/settings.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- Codec,
- buildCodecForObject,
- codecForBoolean,
- codecForMap,
- codecForString,
- codecOptional,
-} from "@gnu-taler/taler-util";
-
-export interface BankUiSettings {
- // Where libeufin backend is localted
- // default: window.origin without "webui/"
- backendBaseURL?: string;
- // Shows a button "create random account" in the registration form
- // Useful for testing
- // default: false
- allowRandomAccountCreation?: boolean;
- // Create all random accounts with password "123"
- // Useful for testing
- // default: false
- simplePasswordForRandomAccounts?: boolean;
- // Bank name shown in the header
- // default: "Taler Bank"
- bankName?: string;
- // URL where the user is going to be redirected after
- // clicking in Taler Logo
- // default: home page
- iconLinkURL?: string;
- // Mapping for every link shown in the top navitation bar
- // - key: link label, what the user will read
- // - value: link target, where the user is going to be redirected
- // default: empty list
- topNavSites?: Record<string, string>;
-}
-
-/**
- * Global settings for the bank UI.
- */
-const defaultSettings: BankUiSettings = {
- backendBaseURL: buildDefaultBackendBaseURL(),
- iconLinkURL: undefined,
- bankName: "Taler Bank",
- simplePasswordForRandomAccounts: false,
- allowRandomAccountCreation: false,
- topNavSites: {},
-};
-
-const codecForBankUISettings = (): Codec<BankUiSettings> =>
- buildCodecForObject<BankUiSettings>()
- .property("backendBaseURL", codecOptional(codecForString()))
- .property("allowRandomAccountCreation", codecOptional(codecForBoolean()))
- .property(
- "simplePasswordForRandomAccounts",
- codecOptional(codecForBoolean()),
- )
- .property("bankName", codecOptional(codecForString()))
- .property("iconLinkURL", codecOptional(codecForString()))
- .property("topNavSites", codecOptional(codecForMap(codecForString())))
- .build("BankUiSettings");
-
-function removeUndefineField<T extends object>(obj: T): T {
- const keys = Object.keys(obj) as Array<keyof T>;
- return keys.reduce((prev, cur) => {
- if (typeof prev[cur] === "undefined") {
- delete prev[cur];
- }
- return prev;
- }, obj);
-}
-
-export function fetchSettings(listener: (s: BankUiSettings) => void): void {
- fetch("./settings.json")
- .then((resp) => resp.json())
- .then((json) => codecForBankUISettings().decode(json))
- .then((result) =>
- listener({
- ...defaultSettings,
- ...removeUndefineField(result),
- }),
- )
- .catch((e) => {
- console.log("failed to fetch settings", e);
- listener(defaultSettings);
- });
-}
-
-function buildDefaultBackendBaseURL(): string | undefined {
- if (typeof window !== "undefined") {
- const currentLocation = new URL(
- window.location.pathname,
- window.location.origin,
- ).href;
- return currentLocation.replace("/webui", "");
- }
- return undefined;
-}
diff --git a/packages/demobank-ui/src/stories.test.ts b/packages/demobank-ui/src/stories.test.ts
deleted file mode 100644
index 8171c6d8f..000000000
--- a/packages/demobank-ui/src/stories.test.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-import {
- AccessToken,
- AmountString,
- TalerCorebankApi,
- setupI18n,
-} from "@gnu-taler/taler-util";
-import { parseGroupImport } from "@gnu-taler/web-util/browser";
-import * as tests from "@gnu-taler/web-util/testing";
-import * as components from "./components/index.examples.js";
-import * as pages from "./pages/index.stories.js";
-
-import { ComponentChildren, VNode, h as create } from "preact";
-import { BankCoreApiProviderTesting } from "./context/config.js";
-
-setupI18n("en", { en: {} });
-
-describe("All the examples:", () => {
- const cms = parseGroupImport({ pages, components });
- cms.forEach((group) => {
- describe(`Example for group "${group.title}:"`, () => {
- group.list.forEach((component) => {
- describe(`Component ${component.name}:`, () => {
- component.examples.forEach((example) => {
- it(`should render example: ${example.name}`, () => {
- tests.renderUI(example.render, DefaultTestingContext);
- });
- });
- });
- });
- });
- });
-});
-
-function DefaultTestingContext({
- children,
-}: {
- children: ComponentChildren;
-}): VNode {
- const cfg: TalerCorebankApi.Config = {
- name: "libeufin-bank",
- allow_deletions: true,
- supported_tan_channels: [],
- allow_registrations: true,
- allow_conversion: true,
- allow_edit_cashout_payto_uri: false,
- allow_edit_name: false,
- currency: "ASR",
- currency_specification: {
- name: "ARS",
- alt_unit_names: {},
- num_fractional_input_digits: 2,
- num_fractional_normal_digits: 2,
- num_fractional_trailing_zero_digits: 2,
- },
- default_debit_threshold: "ARS:10" as AmountString,
- version: "1:0:0",
- };
- const ctx2 = create(BankCoreApiProviderTesting, {
- children: [],
- state: cfg,
- url: "http://localhost",
- });
- return ctx2;
-}
diff --git a/packages/demobank-ui/src/stories.tsx b/packages/demobank-ui/src/stories.tsx
deleted file mode 100644
index 8342a8434..000000000
--- a/packages/demobank-ui/src/stories.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-/**
- *
- * @author Sebastian Javier Marchano (sebasjm)
- */
-import { strings } from "./i18n/strings.js";
-
-import * as pages from "./pages/index.stories.js";
-import * as components from "./components/index.examples.js";
-
-import { renderStories } from "@gnu-taler/web-util/browser";
-
-function main(): void {
- renderStories(
- { pages, components },
- {
- strings,
- },
- );
-}
-
-if (document.readyState === "loading") {
- document.addEventListener("DOMContentLoaded", main);
-} else {
- main();
-}
diff --git a/packages/demobank-ui/src/utils.ts b/packages/demobank-ui/src/utils.ts
deleted file mode 100644
index 8b0febe42..000000000
--- a/packages/demobank-ui/src/utils.ts
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import {
- AmountString,
- PaytoString,
- TalerError,
- TalerErrorCode,
- TranslatedString,
-} from "@gnu-taler/taler-util";
-import {
- ErrorNotification,
- InternationalizationAPI,
- notify,
- notifyError,
- useTranslationContext,
-} from "@gnu-taler/web-util/browser";
-
-/**
- * Validate (the number part of) an amount. If needed,
- * replace comma with a dot. Returns 'false' whenever
- * the input is invalid, the valid amount otherwise.
- */
-const amountRegex = /^[0-9]+(.[0-9]+)?$/;
-export function validateAmount(
- maybeAmount: string | undefined,
-): string | undefined {
- if (!maybeAmount || !amountRegex.test(maybeAmount)) {
- return;
- }
- return maybeAmount;
-}
-
-/**
- * Extract IBAN from a Payto URI.
- */
-export function getIbanFromPayto(url: string): string {
- const pathSplit = new URL(url).pathname.split("/");
- let lastIndex = pathSplit.length - 1;
- // Happens if the path ends with "/".
- if (pathSplit[lastIndex] === "") lastIndex--;
- const iban = pathSplit[lastIndex];
- return iban;
-}
-
-export function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
- return Object.keys(obj).some(
- (k) => (obj as Record<string, T>)[k] !== undefined,
- )
- ? obj
- : undefined;
-}
-
-export type PartialButDefined<T> = {
- [P in keyof T]: T[P] | undefined;
-};
-
-/**
- * every non-map field can be undefined
- */
-export type WithIntermediate<Type> = {
- [prop in keyof Type]: Type[prop] extends PaytoString
- ? Type[prop] | undefined
- : Type[prop] extends AmountString
- ? Type[prop] | undefined
- : Type[prop] extends TranslatedString
- ? Type[prop] | undefined
- : Type[prop] extends object
- ? WithIntermediate<Type[prop]>
- : Type[prop] | undefined;
-};
-export type RecursivePartial<Type> = {
- [P in keyof Type]?: Type[P] extends (infer U)[]
- ? RecursivePartial<U>[]
- : Type[P] extends object
- ? RecursivePartial<Type[P]>
- : Type[P];
-};
-export type ErrorMessageMappingFor<Type> = {
- [prop in keyof Type]+?: Exclude<Type[prop], undefined> extends PaytoString // enumerate known object
- ? TranslatedString
- : Exclude<Type[prop], undefined> extends AmountString
- ? TranslatedString
- : Exclude<Type[prop], undefined> extends TranslatedString
- ? TranslatedString
- : // arrays: every element
- Exclude<Type[prop], undefined> extends (infer U)[]
- ? ErrorMessageMappingFor<U>[]
- : // map: every field
- Exclude<Type[prop], undefined> extends object
- ? ErrorMessageMappingFor<Type[prop]>
- : TranslatedString;
-};
-
-export enum TanChannel {
- SMS = "sms",
- EMAIL = "email",
-}
-export enum CashoutStatus {
- // The payment was initiated after a valid
- // TAN was received by the bank.
- CONFIRMED = "confirmed",
-
- // The cashout was created and now waits
- // for the TAN by the author.
- PENDING = "pending",
-}
-
-export const PAGE_SIZE = 5;
-
-type Translator = ReturnType<typeof useTranslationContext>["i18n"];
-
-export async function withRuntimeErrorHandling<T>(
- i18n: Translator,
- cb: () => Promise<T>,
-): Promise<void> {
- try {
- await cb();
- } catch (error: unknown) {
- if (error instanceof TalerError) {
- notify(buildRequestErrorMessage(i18n, error));
- } else {
- notifyError(
- i18n.str`Operation failed, please report`,
- (error instanceof Error
- ? error.message
- : JSON.stringify(error)) as TranslatedString,
- );
- }
- }
-}
-
-export function buildRequestErrorMessage(
- i18n: Translator,
- cause: TalerError,
-): ErrorNotification {
- let result: ErrorNotification;
- switch (cause.errorDetail.code) {
- case TalerErrorCode.WALLET_HTTP_REQUEST_GENERIC_TIMEOUT: {
- result = {
- type: "error",
- title: i18n.str`Request timeout`,
- description: cause.message as TranslatedString,
- debug: JSON.stringify(cause.errorDetail, undefined, 2),
- };
- break;
- }
- case TalerErrorCode.WALLET_HTTP_REQUEST_THROTTLED: {
- result = {
- type: "error",
- title: i18n.str`Request throttled`,
- description: cause.message as TranslatedString,
- debug: JSON.stringify(cause.errorDetail, undefined, 2),
- };
- break;
- }
- case TalerErrorCode.WALLET_RECEIVED_MALFORMED_RESPONSE: {
- result = {
- type: "error",
- title: i18n.str`Malformed response`,
- description: cause.message as TranslatedString,
- debug: JSON.stringify(cause.errorDetail, undefined, 2),
- };
- break;
- }
- case TalerErrorCode.WALLET_NETWORK_ERROR: {
- result = {
- type: "error",
- title: i18n.str`Network error`,
- description: cause.message as TranslatedString,
- debug: JSON.stringify(cause.errorDetail, undefined, 2),
- };
- break;
- }
- case TalerErrorCode.WALLET_UNEXPECTED_REQUEST_ERROR: {
- result = {
- type: "error",
- title: i18n.str`Unexpected request error`,
- description: cause.message as TranslatedString,
- debug: JSON.stringify(cause.errorDetail, undefined, 2),
- };
- break;
- }
- default: {
- result = {
- type: "error",
- title: i18n.str`Unexpected error`,
- description: cause.message as TranslatedString,
- debug: JSON.stringify(cause.errorDetail, undefined, 2),
- };
- break;
- }
- }
- return result;
-}
-
-export const COUNTRY_TABLE = {
- AE: "U.A.E.",
- AF: "Afghanistan",
- AL: "Albania",
- AM: "Armenia",
- AN: "Netherlands Antilles",
- AR: "Argentina",
- AT: "Austria",
- AU: "Australia",
- AZ: "Azerbaijan",
- BA: "Bosnia and Herzegovina",
- BD: "Bangladesh",
- BE: "Belgium",
- BG: "Bulgaria",
- BH: "Bahrain",
- BN: "Brunei Darussalam",
- BO: "Bolivia",
- BR: "Brazil",
- BT: "Bhutan",
- BY: "Belarus",
- BZ: "Belize",
- CA: "Canada",
- CG: "Congo",
- CH: "Switzerland",
- CI: "Cote d'Ivoire",
- CL: "Chile",
- CM: "Cameroon",
- CN: "People's Republic of China",
- CO: "Colombia",
- CR: "Costa Rica",
- CS: "Serbia and Montenegro",
- CZ: "Czech Republic",
- DE: "Germany",
- DK: "Denmark",
- DO: "Dominican Republic",
- DZ: "Algeria",
- EC: "Ecuador",
- EE: "Estonia",
- EG: "Egypt",
- ER: "Eritrea",
- ES: "Spain",
- ET: "Ethiopia",
- FI: "Finland",
- FO: "Faroe Islands",
- FR: "France",
- GB: "United Kingdom",
- GD: "Caribbean",
- GE: "Georgia",
- GL: "Greenland",
- GR: "Greece",
- GT: "Guatemala",
- HK: "Hong Kong",
- // HK: "Hong Kong S.A.R.",
- HN: "Honduras",
- HR: "Croatia",
- HT: "Haiti",
- HU: "Hungary",
- ID: "Indonesia",
- IE: "Ireland",
- IL: "Israel",
- IN: "India",
- IQ: "Iraq",
- IR: "Iran",
- IS: "Iceland",
- IT: "Italy",
- JM: "Jamaica",
- JO: "Jordan",
- JP: "Japan",
- KE: "Kenya",
- KG: "Kyrgyzstan",
- KH: "Cambodia",
- KR: "South Korea",
- KW: "Kuwait",
- KZ: "Kazakhstan",
- LA: "Laos",
- LB: "Lebanon",
- LI: "Liechtenstein",
- LK: "Sri Lanka",
- LT: "Lithuania",
- LU: "Luxembourg",
- LV: "Latvia",
- LY: "Libya",
- MA: "Morocco",
- MC: "Principality of Monaco",
- MD: "Moldava",
- // MD: "Moldova",
- ME: "Montenegro",
- MK: "Former Yugoslav Republic of Macedonia",
- ML: "Mali",
- MM: "Myanmar",
- MN: "Mongolia",
- MO: "Macau S.A.R.",
- MT: "Malta",
- MV: "Maldives",
- MX: "Mexico",
- MY: "Malaysia",
- NG: "Nigeria",
- NI: "Nicaragua",
- NL: "Netherlands",
- NO: "Norway",
- NP: "Nepal",
- NZ: "New Zealand",
- OM: "Oman",
- PA: "Panama",
- PE: "Peru",
- PH: "Philippines",
- PK: "Islamic Republic of Pakistan",
- PL: "Poland",
- PR: "Puerto Rico",
- PT: "Portugal",
- PY: "Paraguay",
- QA: "Qatar",
- RE: "Reunion",
- RO: "Romania",
- RS: "Serbia",
- RU: "Russia",
- RW: "Rwanda",
- SA: "Saudi Arabia",
- SE: "Sweden",
- SG: "Singapore",
- SI: "Slovenia",
- SK: "Slovak",
- SN: "Senegal",
- SO: "Somalia",
- SR: "Suriname",
- SV: "El Salvador",
- SY: "Syria",
- TH: "Thailand",
- TJ: "Tajikistan",
- TM: "Turkmenistan",
- TN: "Tunisia",
- TR: "Turkey",
- TT: "Trinidad and Tobago",
- TW: "Taiwan",
- TZ: "Tanzania",
- UA: "Ukraine",
- US: "United States",
- UY: "Uruguay",
- VA: "Vatican",
- VE: "Venezuela",
- VN: "Viet Nam",
- YE: "Yemen",
- ZA: "South Africa",
- ZW: "Zimbabwe",
-};
-
-/**
- * An IBAN is validated by converting it into an integer and performing a
- * basic mod-97 operation (as described in ISO 7064) on it.
- * If the IBAN is valid, the remainder equals 1.
- *
- * The algorithm of IBAN validation is as follows:
- * 1.- Check that the total IBAN length is correct as per the country. If not, the IBAN is invalid
- * 2.- Move the four initial characters to the end of the string
- * 3.- Replace each letter in the string with two digits, thereby expanding the string, where A = 10, B = 11, ..., Z = 35
- * 4.- Interpret the string as a decimal integer and compute the remainder of that number on division by 97
- *
- * If the remainder is 1, the check digit test is passed and the IBAN might be valid.
- *
- */
-const IBAN_REGEX = /^[A-Z][A-Z0-9]*$/;
-export function validateIBAN(
- account: string,
- i18n: InternationalizationAPI,
-): TranslatedString | undefined {
- if (!IBAN_REGEX.test(account)) {
- return i18n.str`IBAN only have uppercased letters and numbers`
- }
- // Check total length
- if (account.length < 4)
- return i18n.str`IBAN numbers have more that 4 digits`;
- if (account.length > 34)
- return i18n.str`IBAN numbers have less that 34 digits`;
-
- const A_code = "A".charCodeAt(0);
- const Z_code = "Z".charCodeAt(0);
- const IBAN = account.toUpperCase();
- // check supported country
- const code = IBAN.substring(0, 2);
- const found = code in COUNTRY_TABLE;
- if (!found) return i18n.str`IBAN country code not found`;
-
- // 2.- Move the four initial characters to the end of the string
- const step2 = IBAN.substring(4) + account.substring(0, 4);
- const step3 = Array.from(step2)
- .map((letter) => {
- const code = letter.charCodeAt(0);
- if (code < A_code || code > Z_code) return letter;
- return `${letter.charCodeAt(0) - "A".charCodeAt(0) + 10}`;
- })
- .join("");
-
- const checksum = calculate_iban_checksum(step3);
- if (checksum !== 1)
- return i18n.str`IBAN number is not valid, checksum is wrong`;
- return undefined;
-}
-
-function calculate_iban_checksum(str: string): number {
- const numberStr = str.substring(0, 5);
- const rest = str.substring(5);
- const number = parseInt(numberStr, 10);
- const result = number % 97;
- if (rest.length > 0) {
- return calculate_iban_checksum(`${result}${rest}`);
- }
- return result;
-}
-
-const USERNAME_REGEX = /^[A-Za-z][A-Za-z0-9]*$/;
-
-export function validateTalerBank(
- account: string,
- i18n: InternationalizationAPI,
-): TranslatedString | undefined {
- if (!USERNAME_REGEX.test(account)) {
- return i18n.str`Account only have letters and numbers`
- }
- return undefined
-}
-
-export function validateRawIBAN(
- payto: string,
- i18n: InternationalizationAPI,
-): TranslatedString | undefined {
- return undefined
-}
-
-
-
-export function validateRawTalerBank(
- payto: string,
- currentHost: string,
- i18n: InternationalizationAPI,
-): TranslatedString | undefined {
- return undefined
-}
-
diff --git a/packages/demobank-ui/tailwind.config.js b/packages/demobank-ui/tailwind.config.js
deleted file mode 100644
index ec51dfbb8..000000000
--- a/packages/demobank-ui/tailwind.config.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/** @type {import('tailwindcss').Config} */
-export default {
- content: {
- relative: true,
- files: [
- "./src/**/*.{html,tsx}",
- "./node_modules/@gnu-taler/web-util/src/**/*.{html,tsx}"
- ],
- },
- theme: {
- extend: {},
- },
- plugins: [require("@tailwindcss/typography"), require("@tailwindcss/forms")],
-};
diff --git a/packages/demobank-ui/test.mjs b/packages/demobank-ui/test.mjs
deleted file mode 100755
index baaaaa3ef..000000000
--- a/packages/demobank-ui/test.mjs
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/usr/bin/env node
-/*
- This file is part of GNU Taler
- (C) 2022-2024 Taler Systems S.A.
-
- GNU Taler is free software; you can redistribute it and/or modify it under the
- terms of the GNU General Public License as published by the Free Software
- Foundation; either version 3, or (at your option) any later version.
-
- GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along with
- GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- */
-
-import { build } from "@gnu-taler/web-util/build";
-import { getFilesInDirectory } from "@gnu-taler/web-util/build";
-
-const allTestFiles = getFilesInDirectory("src", /.test.tsx?$/);
-
-await build({
- type: "test",
- source: {
- js: allTestFiles.files,
- assets: [{ base: "src", files: ["src/index.html"] }],
-
- },
- destination: "./dist/test",
- css: "sass",
-});
diff --git a/packages/demobank-ui/tsconfig.json b/packages/demobank-ui/tsconfig.json
deleted file mode 100644
index 9826fac07..000000000
--- a/packages/demobank-ui/tsconfig.json
+++ /dev/null
@@ -1,46 +0,0 @@
-{
- "compilerOptions": {
- /* Basic Options */
- "target": "ES2020",
- "module": "Node16",
- "lib": ["DOM", "ES2020"],
- "allowJs": true /* Allow javascript files to be compiled. */,
- // "checkJs": true, /* Report errors in .js files. */
- "jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
- "jsxFactory": "h",
- "jsxFragmentFactory": "Fragment",
- "noEmit": true /* Do not emit outputs. */,
- // "importHelpers": true, /* Import emit helpers from 'tslib'. */
- // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
- // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
- /* Strict Type-Checking Options */
- "strict": true /* Enable all strict type-checking options. */,
- "noImplicitAny": true /* Raise error on expressions and declarations with an implied 'any' type. */,
- /* Additional Checks */
- // "noUnusedLocals": true, /* Report errors on unused locals. */
- // "noUnusedParameters": true, /* Report errors on unused parameters. */
- // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
- // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
- /* Module Resolution Options */
- "moduleResolution": "Node16" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */,
- "esModuleInterop": true /* */,
- // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
- // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
- // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
- // "typeRoots": [], /* List of folders to include type definitions from. */
- // "types": [], /* Type declaration files to be included in compilation. */
- "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */,
- // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
- /* Source Map Options */
- // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
- // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */
- // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
- // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
- /* Experimental Options */
- // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
- // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
- /* Advanced Options */
- "skipLibCheck": true /* Skip type checking of declaration files. */
- },
- "include": ["src/**/*"]
-}