aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-02-23 08:30:43 -0300
committerSebastian <sebasjm@gmail.com>2024-02-23 08:30:43 -0300
commit73e36c99037cef1ccc43bb80b67b19e0f44326fd (patch)
treec076b0084a3fb5004b8f3ffa32cc09a9b1a42d22 /packages
parent271488f041890391e1c6d946fd1aef00c2113fd0 (diff)
return to form after 2fa cancelled
Diffstat (limited to 'packages')
-rw-r--r--packages/demobank-ui/src/Routing.tsx92
-rw-r--r--packages/demobank-ui/src/components/Transactions/index.ts12
-rw-r--r--packages/demobank-ui/src/components/Transactions/views.tsx4
-rw-r--r--packages/demobank-ui/src/context/navigation.ts3
-rw-r--r--packages/demobank-ui/src/hooks/bank-state.ts10
-rw-r--r--packages/demobank-ui/src/pages/AccountPage/index.ts42
-rw-r--r--packages/demobank-ui/src/pages/AccountPage/views.tsx4
-rw-r--r--packages/demobank-ui/src/pages/BankFrame.tsx6
-rw-r--r--packages/demobank-ui/src/pages/DownloadStats.tsx4
-rw-r--r--packages/demobank-ui/src/pages/LoginForm.tsx4
-rw-r--r--packages/demobank-ui/src/pages/OperationState/index.ts26
-rw-r--r--packages/demobank-ui/src/pages/OperationState/state.ts8
-rw-r--r--packages/demobank-ui/src/pages/OperationState/views.tsx5
-rw-r--r--packages/demobank-ui/src/pages/PaymentOptions.tsx13
-rw-r--r--packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx43
-rw-r--r--packages/demobank-ui/src/pages/ProfileNavigation.tsx10
-rw-r--r--packages/demobank-ui/src/pages/RegistrationPage.tsx6
-rw-r--r--packages/demobank-ui/src/pages/SolveChallengePage.tsx11
-rw-r--r--packages/demobank-ui/src/pages/WalletWithdrawForm.tsx5
-rw-r--r--packages/demobank-ui/src/pages/WireTransfer.tsx17
-rw-r--r--packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx4
-rw-r--r--packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx5
-rw-r--r--packages/demobank-ui/src/pages/WithdrawalQRCode.tsx7
-rw-r--r--packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx13
-rw-r--r--packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx13
-rw-r--r--packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx17
-rw-r--r--packages/demobank-ui/src/pages/admin/AccountList.tsx2
-rw-r--r--packages/demobank-ui/src/pages/admin/AdminHome.tsx22
-rw-r--r--packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx2
-rw-r--r--packages/demobank-ui/src/pages/admin/RemoveAccount.tsx5
-rw-r--r--packages/demobank-ui/src/pages/business/CreateCashout.tsx5
-rw-r--r--packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx2
-rw-r--r--packages/demobank-ui/src/route.ts100
33 files changed, 324 insertions, 198 deletions
diff --git a/packages/demobank-ui/src/Routing.tsx b/packages/demobank-ui/src/Routing.tsx
index 096b6039b..14df5a274 100644
--- a/packages/demobank-ui/src/Routing.tsx
+++ b/packages/demobank-ui/src/Routing.tsx
@@ -47,7 +47,7 @@ import { CreateNewAccount } from "./pages/admin/CreateNewAccount.js";
import { RemoveAccount } from "./pages/admin/RemoveAccount.js";
import { CreateCashout } from "./pages/business/CreateCashout.js";
import { ShowCashoutDetails } from "./pages/business/ShowCashoutDetails.js";
-import { RouteParamsType, urlPattern, useCurrentLocation } from "./route.js";
+import { urlPattern, useCurrentLocation } from "./route.js";
import { useNavigationContext } from "./context/navigation.js";
import { useEffect } from "preact/hooks";
@@ -155,14 +155,10 @@ function PublicRounting({
return <PublicHistoriesPage />;
}
case "operationDetails": {
- const { wopid } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
-
return (
<WithdrawalOperationPage
- operationId={wopid}
+ operationId={location.values.wopid}
+ routeWithdrawalDetails={publicPages.operationDetails}
purpose="after-confirmation"
onOperationAborted={() => navigateTo(publicPages.login.url({}))}
routeClose={publicPages.login}
@@ -192,7 +188,7 @@ function PublicRounting({
);
}
default:
- assertUnreachable(location.name);
+ assertUnreachable(location);
}
}
@@ -201,7 +197,11 @@ export const privatePages = {
/\/account\/charge-wallet/,
() => "#/account/charge-wallet",
),
- homeWireTransfer: urlPattern(
+ homeWireTransfer: urlPattern<{
+ account?: string,
+ subject?: string,
+ amount?: string,
+ }>(
/\/account\/wire-transfer/,
() => "#/account/wire-transfer",
),
@@ -212,9 +212,13 @@ export const privatePages = {
/\/cashout\/(?<cid>[a-zA-Z0-9]+)/,
({ cid }) => `#/cashout/${cid}`,
),
- wireTranserCreate: urlPattern<{ destination: string }>(
- /\/wire-transfer\/(?<destination>[a-zA-Z0-9]+)/,
- ({ destination }) => `#/wire-transfer/${destination}`,
+ 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"),
@@ -273,14 +277,11 @@ function PrivateRouting({
switch (location.name) {
case "operationDetails": {
- const { wopid } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
return (
<WithdrawalOperationPage
- operationId={wopid}
+ operationId={location.values.wopid}
+ routeWithdrawalDetails={privatePages.operationDetails}
purpose="after-confirmation"
onOperationAborted={() => navigateTo(privatePages.home.url({}))}
routeClose={privatePages.home}
@@ -291,14 +292,11 @@ function PrivateRouting({
);
}
case "startOperation": {
- const { wopid } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
return (
<WithdrawalOperationPage
- operationId={wopid}
+ operationId={location.values.wopid}
+ routeWithdrawalDetails={privatePages.operationDetails}
purpose="after-creation"
onOperationAborted={() => navigateTo(privatePages.home.url({}))}
routeClose={privatePages.home}
@@ -331,14 +329,11 @@ function PrivateRouting({
);
}
case "accountDetails": {
- const { account } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
return (
<ShowAccountDetails
- account={account}
+ account={location.values.account}
onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
+ routeHere={privatePages.accountDetails}
routeMyAccountCashout={privatePages.myAccountCashouts}
routeMyAccountDelete={privatePages.myAccountDelete}
routeMyAccountDetails={privatePages.myAccountDetails}
@@ -351,14 +346,11 @@ function PrivateRouting({
);
}
case "accountChangePassword": {
- const { account } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
return (
<UpdateAccountPassword
focus
- account={account}
+ account={location.values.account}
+ routeHere={privatePages.accountChangePassword}
onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
routeMyAccountCashout={privatePages.myAccountCashouts}
routeMyAccountDelete={privatePages.myAccountDelete}
@@ -372,13 +364,10 @@ function PrivateRouting({
);
}
case "accountDelete": {
- const { account } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
return (
<RemoveAccount
- account={account}
+ account={location.values.account}
+ routeHere={privatePages.accountDelete}
onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
onAuthorizationRequired={() =>
navigateTo(privatePages.solveSecondFactor.url({}))
@@ -388,13 +377,10 @@ function PrivateRouting({
);
}
case "accountCashouts": {
- const { account } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
return (
<CashoutListForAccount
- account={account}
+ account={location.values.account}
+ routeCreateCashout={privatePages.cashoutCreate}
routeCashoutDetails={privatePages.cashoutDetails}
routeClose={privatePages.home}
routeMyAccountCashout={privatePages.myAccountCashouts}
@@ -411,6 +397,7 @@ function PrivateRouting({
return (
<RemoveAccount
account={username}
+ routeHere={privatePages.accountDelete}
onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
onAuthorizationRequired={() =>
navigateTo(privatePages.solveSecondFactor.url({}))
@@ -423,6 +410,7 @@ function PrivateRouting({
return (
<ShowAccountDetails
account={username}
+ routeHere={privatePages.accountDetails}
onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
routeMyAccountCashout={privatePages.myAccountCashouts}
routeMyAccountDelete={privatePages.myAccountDelete}
@@ -440,6 +428,7 @@ function PrivateRouting({
<UpdateAccountPassword
focus
account={username}
+ routeHere={privatePages.accountChangePassword}
onUpdateSuccess={() => navigateTo(privatePages.home.url({}))}
routeMyAccountCashout={privatePages.myAccountCashouts}
routeMyAccountDelete={privatePages.myAccountDelete}
@@ -457,6 +446,7 @@ function PrivateRouting({
<CashoutListForAccount
account={username}
routeCashoutDetails={privatePages.cashoutDetails}
+ routeCreateCashout={privatePages.cashoutCreate}
routeMyAccountCashout={privatePages.myAccountCashouts}
routeMyAccountDelete={privatePages.myAccountDelete}
routeMyAccountDetails={privatePages.myAccountDetails}
@@ -510,6 +500,7 @@ function PrivateRouting({
return (
<CreateCashout
account={username}
+ routeHere={privatePages.cashoutCreate}
onAuthorizationRequired={() =>
navigateTo(privatePages.solveSecondFactor.url({}))
}
@@ -518,25 +509,20 @@ function PrivateRouting({
);
}
case "cashoutDetails": {
- const { cid } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
return (
<ShowCashoutDetails
- id={cid}
+ id={location.values.cid}
routeClose={privatePages.myAccountCashouts}
/>
);
}
case "wireTranserCreate": {
- const { destination } = location.values as RouteParamsType<
- typeof location.parent,
- typeof location.name
- >;
return (
<WireTransfer
- toAccount={destination}
+ toAccount={location.values.account}
+ withAmount={location.values.amount}
+ withSubject={location.values.subject}
+ routeHere={privatePages.wireTranserCreate}
onAuthorizationRequired={() =>
navigateTo(privatePages.solveSecondFactor.url({}))
}
@@ -590,6 +576,6 @@ function PrivateRouting({
);
}
default:
- assertUnreachable(location.name);
+ assertUnreachable(location);
}
}
diff --git a/packages/demobank-ui/src/components/Transactions/index.ts b/packages/demobank-ui/src/components/Transactions/index.ts
index f4e799839..42b12ac65 100644
--- a/packages/demobank-ui/src/components/Transactions/index.ts
+++ b/packages/demobank-ui/src/components/Transactions/index.ts
@@ -23,7 +23,11 @@ import { RouteDefinition } from "../../route.js";
export interface Props {
account: string;
- routeCreateWireTransfer: RouteDefinition<{ destination: string }> | undefined;
+ routeCreateWireTransfer: RouteDefinition<{
+ account?: string,
+ subject?: string,
+ amount?: string,
+ }> | undefined;
}
export type State = State.Loading | State.LoadingUriError | State.Ready;
@@ -45,7 +49,11 @@ export namespace State {
export interface Ready extends BaseInfo {
status: "ready";
error: undefined;
- routeCreateWireTransfer: RouteDefinition<{ destination: string }> | undefined;
+ routeCreateWireTransfer: RouteDefinition<{
+ account?: string,
+ subject?: string,
+ amount?: string,
+ }> | undefined;
transactions: Transaction[];
onPrev?: () => void;
onNext?: () => void;
diff --git a/packages/demobank-ui/src/components/Transactions/views.tsx b/packages/demobank-ui/src/components/Transactions/views.tsx
index a1ec0fa00..321a6ff3a 100644
--- a/packages/demobank-ui/src/components/Transactions/views.tsx
+++ b/packages/demobank-ui/src/components/Transactions/views.tsx
@@ -154,7 +154,7 @@ export function ReadyView({
<a
name={`transfer to ${item.counterpart}`}
href={routeCreateWireTransfer.url({
- destination: item.counterpart,
+ account: item.counterpart,
})}
class="text-indigo-600 hover:text-indigo-900"
>
@@ -191,7 +191,7 @@ export function ReadyView({
<a
name={`wire transfer to ${item.counterpart}`}
href={routeCreateWireTransfer.url({
- destination: item.counterpart,
+ account: item.counterpart,
})}
class="text-indigo-600 hover:text-indigo-900"
>
diff --git a/packages/demobank-ui/src/context/navigation.ts b/packages/demobank-ui/src/context/navigation.ts
index 27fdf4649..9552bf899 100644
--- a/packages/demobank-ui/src/context/navigation.ts
+++ b/packages/demobank-ui/src/context/navigation.ts
@@ -16,6 +16,7 @@
import { ComponentChildren, createContext, h, VNode } from "preact";
import { useContext, useEffect, useState } from "preact/hooks";
+import { AppLocation } from "../route.js";
/**
*
@@ -25,7 +26,7 @@ import { useContext, useEffect, useState } from "preact/hooks";
export type Type = {
path: string;
params: Record<string, string>;
- navigateTo: (path: string) => void;
+ navigateTo: (path: AppLocation) => void;
// addNavigationListener: (listener: (path: string, params: Record<string, string>) => void) => (() => void);
};
diff --git a/packages/demobank-ui/src/hooks/bank-state.ts b/packages/demobank-ui/src/hooks/bank-state.ts
index 87f7a49f0..15daf9180 100644
--- a/packages/demobank-ui/src/hooks/bank-state.ts
+++ b/packages/demobank-ui/src/hooks/bank-state.ts
@@ -28,6 +28,7 @@ import {
codecOptional,
} from "@gnu-taler/taler-util";
import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
+import { AppLocation } from "../route.js";
export type ChallengeInProgess =
| DeleteAccountChallenge
@@ -41,6 +42,7 @@ type BaseChallenge<OpType extends string, ReqType> = {
id: string;
operation: OpType;
sent: AbsoluteTime;
+ location: AppLocation;
info?: TalerCorebankApi.TanTransmission;
request: ReqType;
};
@@ -68,6 +70,7 @@ 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())
@@ -77,6 +80,7 @@ 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()))
@@ -86,6 +90,7 @@ 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())
@@ -96,6 +101,7 @@ const codecForChallengeCreateTransaction =
buildCodecForObject<CreateTransactionChallenge>()
.property("operation", codecForConstString("create-transaction"))
.property("id", codecForString())
+ .property("location", codecForAppLocation())
.property("sent", codecForAbsoluteTime)
.property("info", codecOptional(codecForTanTransmission()))
.property("request", codecForAny())
@@ -106,15 +112,19 @@ const codecForChallengeConfirmWithdrawal =
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())
diff --git a/packages/demobank-ui/src/pages/AccountPage/index.ts b/packages/demobank-ui/src/pages/AccountPage/index.ts
index 6c67f6d90..7a85f59fe 100644
--- a/packages/demobank-ui/src/pages/AccountPage/index.ts
+++ b/packages/demobank-ui/src/pages/AccountPage/index.ts
@@ -33,13 +33,21 @@ export interface Props {
onOperationCreated: (wopid: string) => void;
onClose: () => void;
tab: "charge-wallet" | "wire-transfer" | undefined;
- routeClose: RouteDefinition<Record<string, never>>;
- routeChargeWallet: RouteDefinition<Record<string, never>>;
- routeWireTransfer: RouteDefinition<Record<string, never>>;
- routePublicAccounts: RouteDefinition<Record<string, never>>;
- routeCreateWireTransfer: RouteDefinition<{ destination: string }>;
+ routeClose: 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<Record<string, never>>;
+ routeSolveSecondFactor: RouteDefinition;
}
export type State =
@@ -73,13 +81,21 @@ export namespace State {
onAuthorizationRequired: () => void;
onOperationCreated: (wopid: string) => void;
onClose: () => void;
- routeClose: RouteDefinition<Record<string, never>>;
- routeChargeWallet: RouteDefinition<Record<string, never>>;
- routeWireTransfer: RouteDefinition<Record<string, never>>;
- routePublicAccounts: RouteDefinition<Record<string, never>>;
- routeCreateWireTransfer: RouteDefinition<{ destination: string }>;
+ routeClose: 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<Record<string, never>>;
+ routeSolveSecondFactor: RouteDefinition;
}
export interface InvalidIban {
@@ -90,7 +106,7 @@ export namespace State {
export interface UserNotFound {
status: "login";
reason: "not-found" | "forbidden";
- routeRegister?: RouteDefinition<Record<string, never>>;
+ routeRegister?: RouteDefinition;
}
}
diff --git a/packages/demobank-ui/src/pages/AccountPage/views.tsx b/packages/demobank-ui/src/pages/AccountPage/views.tsx
index 4f411940f..cb98c5f2a 100644
--- a/packages/demobank-ui/src/pages/AccountPage/views.tsx
+++ b/packages/demobank-ui/src/pages/AccountPage/views.tsx
@@ -33,7 +33,7 @@ export function InvalidIbanView({ error }: State.InvalidIban) {
const IS_PUBLIC_ACCOUNT_ENABLED = false;
function ShowDemoInfo({ routePublicAccounts }: {
- routePublicAccounts: RouteDefinition<Record<string, never>>;
+ routePublicAccounts: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const [settings, updateSettings] = usePreferences();
@@ -63,7 +63,7 @@ function ShowDemoInfo({ routePublicAccounts }: {
}
function ShowPedingOperation({ routeSolveSecondFactor }: {
- routeSolveSecondFactor: RouteDefinition<Record<string, never>>;
+ routeSolveSecondFactor: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const [bankState, updateBankState] = useBankState();
diff --git a/packages/demobank-ui/src/pages/BankFrame.tsx b/packages/demobank-ui/src/pages/BankFrame.tsx
index 266eab636..436076ba4 100644
--- a/packages/demobank-ui/src/pages/BankFrame.tsx
+++ b/packages/demobank-ui/src/pages/BankFrame.tsx
@@ -36,8 +36,8 @@ import {
getLabelForPreferences,
usePreferences,
} from "../hooks/preferences.js";
-import { RenderAmount } from "./PaytoWireTransferForm.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;
@@ -48,7 +48,7 @@ export function BankFrame({
routeAccountDetails,
}: {
account?: string;
- routeAccountDetails?: RouteDefinition<Record<string, never>>;
+ routeAccountDetails?: RouteDefinition;
children: ComponentChildren;
}): VNode {
const { i18n } = useTranslationContext();
@@ -179,7 +179,7 @@ export function BankFrame({
function WelcomeAccount({ account, routeAccountDetails }: {
account: string,
- routeAccountDetails: RouteDefinition<Record<string, never>>;
+ routeAccountDetails: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const result = useAccountDetails(account);
diff --git a/packages/demobank-ui/src/pages/DownloadStats.tsx b/packages/demobank-ui/src/pages/DownloadStats.tsx
index 9bdc04123..353238c13 100644
--- a/packages/demobank-ui/src/pages/DownloadStats.tsx
+++ b/packages/demobank-ui/src/pages/DownloadStats.tsx
@@ -31,11 +31,11 @@ import { VNode, h } from "preact";
import { useState } from "preact/hooks";
import { useBankCoreApiContext } from "../context/config.js";
import { useBackendState } from "../hooks/backend.js";
-import { RouteDefinition } from "../route.js";
+import { EmptyObject, RouteDefinition } from "../route.js";
import { getTimeframesForDate } from "./admin/AdminHome.js";
interface Props {
- routeCancel: RouteDefinition<Record<string, never>>;
+ routeCancel: RouteDefinition;
}
type Options = {
diff --git a/packages/demobank-ui/src/pages/LoginForm.tsx b/packages/demobank-ui/src/pages/LoginForm.tsx
index 6d732f5e8..f90b985e6 100644
--- a/packages/demobank-ui/src/pages/LoginForm.tsx
+++ b/packages/demobank-ui/src/pages/LoginForm.tsx
@@ -31,7 +31,7 @@ import { useBankCoreApiContext } from "../context/config.js";
import { useBackendState } from "../hooks/backend.js";
import { undefinedIfEmpty } from "../utils.js";
import { doAutoFocus } from "./PaytoWireTransferForm.js";
-import { RouteDefinition } from "../route.js";
+import { EmptyObject, RouteDefinition } from "../route.js";
/**
* Collect and submit login data.
@@ -43,7 +43,7 @@ export function LoginForm({
}: {
fixedUser?: boolean;
currentUser?: string;
- routeRegister?: RouteDefinition<Record<string, never>>;
+ routeRegister?: RouteDefinition;
}): VNode {
const backend = useBackendState();
diff --git a/packages/demobank-ui/src/pages/OperationState/index.ts b/packages/demobank-ui/src/pages/OperationState/index.ts
index 20cb1760f..e4d9d45e3 100644
--- a/packages/demobank-ui/src/pages/OperationState/index.ts
+++ b/packages/demobank-ui/src/pages/OperationState/index.ts
@@ -39,8 +39,9 @@ import { RouteDefinition } from "../../route.js";
export interface Props {
currency: string;
onAuthorizationRequired: () => void;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
onAbort: () => void;
+ routeHere: RouteDefinition<{ wopid: string }>;
}
export type State =
@@ -81,7 +82,7 @@ export namespace State {
onAbort: () => Promise<
TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined
>;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
}
export interface InvalidPayto {
@@ -103,28 +104,29 @@ export namespace State {
status: "need-confirmation";
onAuthorizationRequired: () => void;
account: string;
+ routeHere: RouteDefinition<{ wopid: string }>;
onAbort:
- | undefined
- | (() => Promise<
- TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined
- >);
+ | undefined
+ | (() => Promise<
+ TalerCoreBankErrorsByMethod<"abortWithdrawalById"> | undefined
+ >);
onConfirm:
- | undefined
- | (() => Promise<
- TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined
- >);
+ | undefined
+ | (() => Promise<
+ TalerCoreBankErrorsByMethod<"confirmWithdrawalById"> | undefined
+ >);
error: undefined;
id: string;
}
export interface Aborted {
status: "aborted";
error: undefined;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
}
export interface Confirmed {
status: "confirmed";
error: undefined;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
}
}
diff --git a/packages/demobank-ui/src/pages/OperationState/state.ts b/packages/demobank-ui/src/pages/OperationState/state.ts
index 20d66bbb1..ad2d91ee4 100644
--- a/packages/demobank-ui/src/pages/OperationState/state.ts
+++ b/packages/demobank-ui/src/pages/OperationState/state.ts
@@ -38,6 +38,7 @@ export function useComponentState({
currency,
routeClose,
onAbort,
+ routeHere,
onAuthorizationRequired,
}: Props): utils.RecursiveState<State> {
const [settings] = usePreferences();
@@ -190,9 +191,9 @@ export function useComponentState({
routeClose,
onAbort: !creds
? async () => {
- onAbort();
- return undefined;
- }
+ onAbort();
+ return undefined;
+ }
: doAbort,
};
}
@@ -220,6 +221,7 @@ export function useComponentState({
return {
status: "need-confirmation",
error: undefined,
+ routeHere,
onAuthorizationRequired,
account: data.username,
id: withdrawalOperationId,
diff --git a/packages/demobank-ui/src/pages/OperationState/views.tsx b/packages/demobank-ui/src/pages/OperationState/views.tsx
index d086c3dd1..6eee6daa9 100644
--- a/packages/demobank-ui/src/pages/OperationState/views.tsx
+++ b/packages/demobank-ui/src/pages/OperationState/views.tsx
@@ -51,6 +51,7 @@ export function InvalidReserveView({ reserve }: State.InvalidReserve) {
export function NeedConfirmationView({
onAbort: doAbort,
onConfirm: doConfirm,
+ routeHere,
account,
id,
onAuthorizationRequired,
@@ -144,7 +145,9 @@ export function NeedConfirmationView({
operation: "confirm-withdrawal",
id: String(resp.body.challenge_id),
sent: AbsoluteTime.never(),
+ location: routeHere.url({ wopid: id }),
request: id,
+
});
return onAuthorizationRequired();
}
@@ -331,7 +334,7 @@ export function ConfirmedView({ routeClose }: State.Confirmed) {
export function ReadyView({
uri,
onAbort: doAbort,
-}: State.Ready): VNode<Record<string, never>> {
+}: State.Ready): VNode {
const { i18n } = useTranslationContext();
const walletInegrationApi = useTalerWalletIntegrationAPI();
const [notification, notify, errorHandler] = useLocalNotification();
diff --git a/packages/demobank-ui/src/pages/PaymentOptions.tsx b/packages/demobank-ui/src/pages/PaymentOptions.tsx
index 10be1245f..b13f7539f 100644
--- a/packages/demobank-ui/src/pages/PaymentOptions.tsx
+++ b/packages/demobank-ui/src/pages/PaymentOptions.tsx
@@ -19,7 +19,7 @@ import { Fragment, VNode, h } from "preact";
import { useBankState } from "../hooks/bank-state.js";
import { PaytoWireTransferForm } from "./PaytoWireTransferForm.js";
import { WalletWithdrawForm } from "./WalletWithdrawForm.js";
-import { RouteDefinition } from "../route.js";
+import { EmptyObject, RouteDefinition } from "../route.js";
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { useWithdrawalDetails } from "../hooks/access.js";
import { useEffect } from "preact/hooks";
@@ -85,9 +85,13 @@ export function PaymentOptions({
onClose: () => void;
routeOperationDetails: RouteDefinition<{ wopid: string }>;
- routeClose: RouteDefinition<Record<string, never>>;
- routeChargeWallet: RouteDefinition<Record<string, never>>;
- routeWireTransfer: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
+ routeChargeWallet: RouteDefinition;
+ routeWireTransfer: RouteDefinition<{
+ account?: string,
+ subject?: string,
+ amount?: string,
+ }>;
}): VNode {
const { i18n } = useTranslationContext();
const [bankState, updateBankState] = useBankState();
@@ -213,6 +217,7 @@ export function PaymentOptions({
<PaytoWireTransferForm
focus
title={i18n.str`Transfer details`}
+ routeHere={routeWireTransfer}
limit={limit}
onAuthorizationRequired={onAuthorizationRequired}
onSuccess={onClose}
diff --git a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
index 9fe3453a5..00b6767ac 100644
--- a/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
+++ b/packages/demobank-ui/src/pages/PaytoWireTransferForm.tsx
@@ -45,35 +45,47 @@ import { mutate } from "swr";
import { useBankCoreApiContext } from "../context/config.js";
import { useBackendState } from "../hooks/backend.js";
import { useBankState } from "../hooks/bank-state.js";
-import { RouteDefinition } from "../route.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;
+ routeHere: RouteDefinition<{
+ account?: string,
+ subject?: string,
+ amount?: string,
+ }>;
+ limit: AmountJson;
+}
+
export function PaytoWireTransferForm({
focus,
title,
- toAccount,
+ withAccount,
+ withSubject,
+ withAmount,
onSuccess,
routeCancel,
+ routeHere,
onAuthorizationRequired,
limit,
-}: {
- title: TranslatedString;
- focus?: boolean;
- toAccount?: string;
- onSuccess: () => void;
- onAuthorizationRequired: () => void;
- routeCancel?: RouteDefinition<Record<string, never>>;
- limit: AmountJson;
-}): VNode {
+}: Props): VNode {
const [isRawPayto, setIsRawPayto] = useState(false);
const { state: credentials } = useBackendState();
const { api, config, url } = useBankCoreApiContext();
- const sendingToFixedAccount = toAccount !== undefined;
+ const sendingToFixedAccount = withAccount !== undefined;
- const [account, setAccount] = useState<string | undefined>(toAccount);
- const [subject, setSubject] = useState<string | undefined>();
- const [amount, setAmount] = useState<string | 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>(
@@ -200,6 +212,7 @@ export function PaytoWireTransferForm({
updateBankState("currentChallenge", {
operation: "create-transaction",
id: String(resp.body.challenge_id),
+ location: routeHere.url({ account: account ?? "", amount, subject }),
sent: AbsoluteTime.never(),
request,
});
diff --git a/packages/demobank-ui/src/pages/ProfileNavigation.tsx b/packages/demobank-ui/src/pages/ProfileNavigation.tsx
index 7c52f4eaa..ba02d07b9 100644
--- a/packages/demobank-ui/src/pages/ProfileNavigation.tsx
+++ b/packages/demobank-ui/src/pages/ProfileNavigation.tsx
@@ -19,7 +19,7 @@ import { useBankCoreApiContext } from "../context/config.js";
import { useBackendState } from "../hooks/backend.js";
import { assertUnreachable } from "@gnu-taler/taler-util";
import { useNavigationContext } from "../context/navigation.js";
-import { RouteDefinition } from "../route.js";
+import { EmptyObject, RouteDefinition } from "../route.js";
export function ProfileNavigation({
current,
@@ -29,10 +29,10 @@ export function ProfileNavigation({
routeMyAccountPassword,
}: {
current: "details" | "delete" | "credentials" | "cashouts",
- routeMyAccountDetails: RouteDefinition<Record<string, never>>;
- routeMyAccountDelete: RouteDefinition<Record<string, never>>;
- routeMyAccountPassword: RouteDefinition<Record<string, never>>;
- routeMyAccountCashout: RouteDefinition<Record<string, never>>;
+ routeMyAccountDetails: RouteDefinition;
+ routeMyAccountDelete: RouteDefinition;
+ routeMyAccountPassword: RouteDefinition;
+ routeMyAccountCashout: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const { config } = useBankCoreApiContext();
diff --git a/packages/demobank-ui/src/pages/RegistrationPage.tsx b/packages/demobank-ui/src/pages/RegistrationPage.tsx
index 29e71413c..87e284411 100644
--- a/packages/demobank-ui/src/pages/RegistrationPage.tsx
+++ b/packages/demobank-ui/src/pages/RegistrationPage.tsx
@@ -30,7 +30,7 @@ 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 { EmptyObject, RouteDefinition } from "../route.js";
import { undefinedIfEmpty } from "../utils.js";
import { getRandomPassword, getRandomUsername } from "./rnd.js";
@@ -39,7 +39,7 @@ export function RegistrationPage({
routeCancel,
}: {
onRegistrationSuccesful: (user: string, password: string) => void;
- routeCancel: RouteDefinition<Record<string, never>>;
+ routeCancel: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const { config } = useBankCoreApiContext();
@@ -68,7 +68,7 @@ function RegistrationForm({
routeCancel,
}: {
onRegistrationSuccesful: (user: string, password: string) => void;
- routeCancel: RouteDefinition<Record<string, never>>;
+ routeCancel: RouteDefinition;
}): VNode {
const [username, setUsername] = useState<string | undefined>();
const [name, setName] = useState<string | undefined>();
diff --git a/packages/demobank-ui/src/pages/SolveChallengePage.tsx b/packages/demobank-ui/src/pages/SolveChallengePage.tsx
index 5ac622795..b7fc82a94 100644
--- a/packages/demobank-ui/src/pages/SolveChallengePage.tsx
+++ b/packages/demobank-ui/src/pages/SolveChallengePage.tsx
@@ -46,13 +46,14 @@ 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";
export function SolveChallengePage({
onChallengeCompleted,
routeClose,
}: {
onChallengeCompleted: () => void;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
}): VNode {
const { api } = useBankCoreApiContext();
const { i18n } = useTranslationContext();
@@ -61,6 +62,7 @@ export function SolveChallengePage({
const [notification, notify, handleError] = useLocalNotification();
const { state } = useBackendState();
const creds = state.status !== "loggedIn" ? undefined : state;
+ const { navigateTo } = useNavigationContext();
if (!bankState.currentChallenge) {
return (
@@ -209,6 +211,7 @@ export function SolveChallengePage({
updateBankState("currentChallenge", {
operation: ch.operation,
id: String(resp.body.challenge_id),
+ location: ch.location,
sent: AbsoluteTime.never(),
request: ch.request,
});
@@ -262,7 +265,7 @@ export function SolveChallengePage({
onStart={startChallenge}
onCancel={() => {
updateBankState("currentChallenge", undefined);
- onChallengeCompleted();
+ navigateTo(ch.location)
}}
/>
{ch.info && (
@@ -304,7 +307,7 @@ export function SolveChallengePage({
</div>
</div>
<div class="flex items-center justify-between border-gray-900/10 px-4 py-4 ">
- <div />
+ <div />
<button
type="submit"
name="confirm"
@@ -344,7 +347,7 @@ function ChallengeDetails({
if (firstTime) {
onStart()
}
- },[])
+ }, [])
return (
<div class="px-4 mt-4 ">
<div class="w-full">
diff --git a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
index ecb3eb4fc..078f4e5f5 100644
--- a/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
+++ b/packages/demobank-ui/src/pages/WalletWithdrawForm.tsx
@@ -54,7 +54,7 @@ function OldWithdrawalForm({
focus?: boolean;
routeOperationDetails: RouteDefinition<{ wopid: string }>,
onOperationCreated: (wopid: string) => void;
- routeCancel: RouteDefinition<Record<string, never>>;
+ routeCancel: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const [settings] = usePreferences();
@@ -300,7 +300,7 @@ export function WalletWithdrawForm({
onAuthorizationRequired: () => void;
onOperationCreated: (wopid: string) => void;
onOperationAborted: () => void;
- routeCancel: RouteDefinition<Record<string, never>>;
+ routeCancel: RouteDefinition;
}): VNode {
const { i18n } = useTranslationContext();
const [settings, updateSettings] = usePreferences();
@@ -355,6 +355,7 @@ export function WalletWithdrawForm({
currency={limit.currency}
onAuthorizationRequired={onAuthorizationRequired}
routeClose={routeCancel}
+ routeHere={routeOperationDetails}
onAbort={onOperationAborted}
// route={routeCancel}
/>
diff --git a/packages/demobank-ui/src/pages/WireTransfer.tsx b/packages/demobank-ui/src/pages/WireTransfer.tsx
index 190afd66e..927968304 100644
--- a/packages/demobank-ui/src/pages/WireTransfer.tsx
+++ b/packages/demobank-ui/src/pages/WireTransfer.tsx
@@ -34,13 +34,23 @@ 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;
- routeCancel?: RouteDefinition<Record<string, never>>;
+ withSubject?: string,
+ withAmount?: string,
+ routeCancel?: RouteDefinition;
onAuthorizationRequired: () => void;
}): VNode {
const { i18n } = useTranslationContext();
@@ -77,7 +87,10 @@ export function WireTransfer({
return (
<PaytoWireTransferForm
title={i18n.str`Make a wire transfer`}
- toAccount={toAccount}
+ withAccount={toAccount}
+ withAmount={withAmount}
+ withSubject={withSubject}
+ routeHere={routeHere}
limit={limit}
onAuthorizationRequired={onAuthorizationRequired}
onSuccess={() => {
diff --git a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
index e4631fcc8..39b94b349 100644
--- a/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalConfirmationQuestion.tsx
@@ -39,12 +39,14 @@ import { useBankCoreApiContext } from "../context/config.js";
import { useBackendState } from "../hooks/backend.js";
import { useBankState } from "../hooks/bank-state.js";
import { usePreferences } from "../hooks/preferences.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;
@@ -61,6 +63,7 @@ export function WithdrawalConfirmationQuestion({
onAborted,
details,
onAuthorizationRequired,
+ routeHere,
withdrawUri,
}: Props): VNode {
const { i18n } = useTranslationContext();
@@ -126,6 +129,7 @@ export function WithdrawalConfirmationQuestion({
updateBankState("currentChallenge", {
operation: "confirm-withdrawal",
id: String(resp.body.challenge_id),
+ location: routeHere.url({ wopid: withdrawUri.withdrawalOperationId }),
sent: AbsoluteTime.never(),
request: withdrawUri.withdrawalOperationId,
});
diff --git a/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx b/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx
index 87999a722..7075c34c6 100644
--- a/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalOperationPage.tsx
@@ -27,12 +27,14 @@ export function WithdrawalOperationPage({
onAuthorizationRequired,
onOperationAborted,
routeClose,
+ routeWithdrawalDetails,
}: {
onAuthorizationRequired: () => void;
operationId: string;
purpose: "after-creation" | "after-confirmation",
onOperationAborted: () => void;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
+ routeWithdrawalDetails: RouteDefinition<{ wopid: string }>;
}): VNode {
const { api } = useBankCoreApiContext();
const uri = stringifyWithdrawUri({
@@ -57,6 +59,7 @@ export function WithdrawalOperationPage({
return (
<WithdrawalQRCode
withdrawUri={parsedUri}
+ routeWithdrawalDetails={routeWithdrawalDetails}
onAuthorizationRequired={onAuthorizationRequired}
onOperationAborted={() => {
updateBankState("currentWithdrawalOperationId", undefined);
diff --git a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
index e6323631c..b128bd99f 100644
--- a/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
+++ b/packages/demobank-ui/src/pages/WithdrawalQRCode.tsx
@@ -38,7 +38,8 @@ import { WithdrawalConfirmationQuestion } from "./WithdrawalConfirmationQuestion
interface Props {
withdrawUri: WithdrawUriResult;
onOperationAborted: () => void;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
+ routeWithdrawalDetails: RouteDefinition<{ wopid: string }>;
onAuthorizationRequired: () => void;
}
/**
@@ -50,6 +51,7 @@ export function WithdrawalQRCode({
withdrawUri,
onOperationAborted,
routeClose,
+ routeWithdrawalDetails,
onAuthorizationRequired,
}: Props): VNode {
const { i18n } = useTranslationContext();
@@ -232,6 +234,7 @@ export function WithdrawalQRCode({
return (
<WithdrawalConfirmationQuestion
withdrawUri={withdrawUri}
+ routeHere={routeWithdrawalDetails}
details={{
username: data.username,
account,
@@ -250,7 +253,7 @@ export function WithdrawalQRCode({
export function OperationNotFound({
routeClose,
}: {
- routeClose: RouteDefinition<Record<string, never>> | undefined;
+ routeClose: RouteDefinition | undefined;
}): VNode {
const { i18n } = useTranslationContext();
return (
diff --git a/packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx b/packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx
index 656c2a52a..14f4acdb8 100644
--- a/packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx
+++ b/packages/demobank-ui/src/pages/account/CashoutListForAccount.tsx
@@ -23,18 +23,20 @@ import { RouteDefinition } from "../../route.js";
interface Props {
account: string;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
onAuthorizationRequired: () => void;
routeCashoutDetails: RouteDefinition<{ cid: string }>;
- routeMyAccountDetails: RouteDefinition<Record<string, never>>;
- routeMyAccountDelete: RouteDefinition<Record<string, never>>;
- routeMyAccountPassword: RouteDefinition<Record<string, never>>;
- routeMyAccountCashout: RouteDefinition<Record<string, never>>;
+ routeMyAccountDetails: RouteDefinition;
+ routeMyAccountDelete: RouteDefinition;
+ routeMyAccountPassword: RouteDefinition;
+ routeMyAccountCashout: RouteDefinition;
+ routeCreateCashout: RouteDefinition;
}
export function CashoutListForAccount({
account,
onAuthorizationRequired,
+ routeCreateCashout,
routeCashoutDetails,
routeMyAccountCashout,
routeMyAccountDelete,
@@ -68,6 +70,7 @@ export function CashoutListForAccount({
<CreateCashout
focus
+ routeHere={routeCreateCashout}
routeClose={routeClose}
onAuthorizationRequired={onAuthorizationRequired}
account={account}
diff --git a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
index 8cd758c75..db76e83d9 100644
--- a/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
+++ b/packages/demobank-ui/src/pages/account/ShowAccountDetails.tsx
@@ -49,13 +49,15 @@ export function ShowAccountDetails({
routeMyAccountCashout,
routeMyAccountDelete,
routeMyAccountDetails,
+ routeHere,
routeMyAccountPassword,
}: {
- routeClose: RouteDefinition<Record<string, never>>;
- routeMyAccountDetails: RouteDefinition<Record<string, never>>;
- routeMyAccountDelete: RouteDefinition<Record<string, never>>;
- routeMyAccountPassword: RouteDefinition<Record<string, never>>;
- routeMyAccountCashout: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
+ routeHere: RouteDefinition<{ account: string }>;
+ routeMyAccountDetails: RouteDefinition;
+ routeMyAccountDelete: RouteDefinition;
+ routeMyAccountPassword: RouteDefinition;
+ routeMyAccountCashout: RouteDefinition;
onUpdateSuccess: () => void;
onAuthorizationRequired: () => void;
account: string;
@@ -154,6 +156,7 @@ export function ShowAccountDetails({
updateBankState("currentChallenge", {
operation: "update-account",
id: String(resp.body.challenge_id),
+ location: routeHere.url({ account }),
sent: AbsoluteTime.never(),
request: submitAccount,
});
diff --git a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx
index d15420b84..dfa0adf17 100644
--- a/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx
+++ b/packages/demobank-ui/src/pages/account/UpdateAccountPassword.tsx
@@ -46,12 +46,14 @@ export function UpdateAccountPassword({
routeMyAccountDetails,
routeMyAccountPassword,
focus,
+ routeHere,
}: {
- routeClose: RouteDefinition<Record<string, never>>;
- routeMyAccountDetails: RouteDefinition<Record<string, never>>;
- routeMyAccountDelete: RouteDefinition<Record<string, never>>;
- routeMyAccountPassword: RouteDefinition<Record<string, never>>;
- routeMyAccountCashout: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
+ routeHere: RouteDefinition<{ account: string }>;
+ routeMyAccountDetails: RouteDefinition;
+ routeMyAccountDelete: RouteDefinition;
+ routeMyAccountPassword: RouteDefinition;
+ routeMyAccountCashout: RouteDefinition;
focus?: boolean;
onAuthorizationRequired: () => void;
onUpdateSuccess: () => void;
@@ -128,6 +130,7 @@ export function UpdateAccountPassword({
updateBankState("currentChallenge", {
operation: "update-password",
id: String(resp.body.challenge_id),
+ location: routeHere.url({ account: accountName }),
sent: AbsoluteTime.never(),
request,
});
@@ -172,7 +175,7 @@ export function UpdateAccountPassword({
>
<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 ? (
+ {accountIsTheCurrentUser ? (
<div class="sm:col-span-5">
<label
class="block text-sm font-medium leading-6 text-gray-900"
@@ -205,7 +208,7 @@ export function UpdateAccountPassword({
</p>
</div>
) : undefined}
-
+
<div class="sm:col-span-5">
<label
class="block text-sm font-medium leading-6 text-gray-900"
diff --git a/packages/demobank-ui/src/pages/admin/AccountList.tsx b/packages/demobank-ui/src/pages/admin/AccountList.tsx
index 36e417171..d8c129507 100644
--- a/packages/demobank-ui/src/pages/admin/AccountList.tsx
+++ b/packages/demobank-ui/src/pages/admin/AccountList.tsx
@@ -28,7 +28,7 @@ import { RenderAmount } from "../PaytoWireTransferForm.js";
import { RouteDefinition } from "../../route.js";
interface Props {
- routeCreate: RouteDefinition<Record<string, never>>;
+ routeCreate: RouteDefinition;
routeShowAccount: RouteDefinition<{ account: string }>;
routeRemoveAccount: RouteDefinition<{ account: string }>;
diff --git a/packages/demobank-ui/src/pages/admin/AdminHome.tsx b/packages/demobank-ui/src/pages/admin/AdminHome.tsx
index 1803f1b9c..4695d35cf 100644
--- a/packages/demobank-ui/src/pages/admin/AdminHome.tsx
+++ b/packages/demobank-ui/src/pages/admin/AdminHome.tsx
@@ -50,9 +50,13 @@ import { AccountList } from "./AccountList.js";
* Query account information and show QR code if there is pending withdrawal
*/
interface Props {
- routeCreate: RouteDefinition<Record<string, never>>;
- routeDownloadStats: RouteDefinition<Record<string, never>>;
- routeCreateWireTransfer: RouteDefinition<{ destination: string }>;
+ routeCreate: RouteDefinition;
+ routeDownloadStats: RouteDefinition;
+ routeCreateWireTransfer: RouteDefinition<{
+ account?: string,
+ subject?: string,
+ amount?: string,
+ }>;
routeShowAccount: RouteDefinition<{ account: string }>;
routeRemoveAccount: RouteDefinition<{ account: string }>;
@@ -73,7 +77,7 @@ export function AdminHome({
return (
<Fragment>
<Metrics routeDownloadStats={routeDownloadStats} />
- <WireTransfer onAuthorizationRequired={onAuthorizationRequired} />
+ <WireTransfer routeHere={routeCreateWireTransfer} onAuthorizationRequired={onAuthorizationRequired} />
<Transactions
account="admin"
@@ -149,7 +153,7 @@ export function getTimeframesForDate(
function Metrics({
routeDownloadStats,
}: {
- routeDownloadStats: RouteDefinition<Record<string, never>>;
+ routeDownloadStats: RouteDefinition;
}): VNode {
const { i18n, dateLocale } = useTranslationContext();
const [metricType, setMetricType] =
@@ -351,7 +355,7 @@ function Metrics({
</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 : (
+ 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">
@@ -428,9 +432,9 @@ function MetricValue({
const rate =
!currAmount ||
- Number.isNaN(currAmount) ||
- !prevAmount ||
- Number.isNaN(prevAmount)
+ Number.isNaN(currAmount) ||
+ !prevAmount ||
+ Number.isNaN(prevAmount)
? 0
: cmp === -1
? 1 - Math.round(currAmount) / Math.round(prevAmount)
diff --git a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx b/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
index 6b4307417..8e353b5e7 100644
--- a/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/CreateNewAccount.tsx
@@ -38,7 +38,7 @@ export function CreateNewAccount({
routeCancel,
onCreateSuccess,
}: {
- routeCancel: RouteDefinition<Record<string, never>>;
+ routeCancel: RouteDefinition;
onCreateSuccess: () => void;
}): VNode {
const { i18n } = useTranslationContext();
diff --git a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
index 7fc5961cb..6f02eae8f 100644
--- a/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
+++ b/packages/demobank-ui/src/pages/admin/RemoveAccount.tsx
@@ -49,10 +49,12 @@ export function RemoveAccount({
onUpdateSuccess,
onAuthorizationRequired,
focus,
+ routeHere,
}: {
focus?: boolean;
+ routeHere: RouteDefinition<{ account: string }>;
onAuthorizationRequired: () => void;
- routeCancel: RouteDefinition<Record<string, never>>;
+ routeCancel: RouteDefinition;
onUpdateSuccess: () => void;
account: string;
}): VNode {
@@ -152,6 +154,7 @@ export function RemoveAccount({
operation: "delete-account",
id: String(resp.body.challenge_id),
sent: AbsoluteTime.never(),
+ location: routeHere.url({ account }),
request: account,
});
return onAuthorizationRequired();
diff --git a/packages/demobank-ui/src/pages/business/CreateCashout.tsx b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
index 8dcdf5296..1b51e3222 100644
--- a/packages/demobank-ui/src/pages/business/CreateCashout.tsx
+++ b/packages/demobank-ui/src/pages/business/CreateCashout.tsx
@@ -55,7 +55,8 @@ interface Props {
account: string;
focus?: boolean;
onAuthorizationRequired: () => void;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
+ routeHere: RouteDefinition;
}
type FormType = {
@@ -72,6 +73,7 @@ export function CreateCashout({
account: accountName,
onAuthorizationRequired,
focus,
+ routeHere,
routeClose,
}: Props): VNode {
const { i18n } = useTranslationContext();
@@ -258,6 +260,7 @@ export function CreateCashout({
operation: "create-cashout",
id: String(resp.body.challenge_id),
sent: AbsoluteTime.never(),
+ location: routeHere.url({}),
request,
});
return onAuthorizationRequired();
diff --git a/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx b/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
index d841ae319..f4b2130a9 100644
--- a/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
+++ b/packages/demobank-ui/src/pages/business/ShowCashoutDetails.tsx
@@ -33,7 +33,7 @@ import { RenderAmount } from "../PaytoWireTransferForm.js";
interface Props {
id: string;
- routeClose: RouteDefinition<Record<string, never>>;
+ routeClose: RouteDefinition;
}
export function ShowCashoutDetails({ id, routeClose }: Props): VNode {
const { i18n, dateLocale } = useTranslationContext();
diff --git a/packages/demobank-ui/src/route.ts b/packages/demobank-ui/src/route.ts
index 4b021d762..72c7802fb 100644
--- a/packages/demobank-ui/src/route.ts
+++ b/packages/demobank-ui/src/route.ts
@@ -15,43 +15,49 @@
*/
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> = Record<string, never>,
+ 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: reverse,
+ url,
};
}
-export type RouteDefinition<T> = {
+/**
+ * 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) => string;
+ url: (p: T) => AppLocation;
};
const nullRountDef = {
pattern: new RegExp(/.*/),
- url: () => "",
+ url: () => "" as AppLocation,
};
-export function buildNullRoutDefinition<T>(): RouteDefinition<T> {
+export function buildNullRoutDefinition<T extends ObjectOf<string>>(): RouteDefinition<T> {
return nullRountDef;
}
-export type RouteMap<T> = {
- [n in keyof T]: RouteDefinition<T[n]>;
-};
-
-export type RouteParamsType<
- P,
- T extends keyof P,
-> = P[T] extends RouteDefinition<infer ASD> ? ASD : never;
-
-type Location<E, T extends RouteMap<E>, NAME extends keyof T> = {
- parent: T;
- name: NAME;
- values: RouteParamsType<T, NAME>;
-};
-
/**
* Search path in the pageList
* get the values from the path found
@@ -60,23 +66,28 @@ type Location<E, T extends RouteMap<E>, NAME extends keyof T> = {
* @param path
* @param params
*/
-function findMatch<DEF, RM extends RouteMap<DEF>, ROUTES extends keyof RM>(
- pagesMap: RM,
- pageList: Array<ROUTES>,
+function findMatch<T extends ObjectOf<RouteDefinition>>(
+ pagesMap: T,
+ pageList: Array<keyof T>,
path: string,
params: Record<string, string>,
-): Location<DEF, RM, ROUTES> | undefined {
+): 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 =
- found.groups === undefined ? {} : structuredClone(found.groups);
+ 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 };
}
@@ -84,12 +95,35 @@ function findMatch<DEF, RM extends RouteMap<DEF>, ROUTES extends keyof RM>(
return undefined;
}
-export function useCurrentLocation<
- DEF,
- RM extends RouteMap<DEF>,
- ROUTES extends keyof RM,
->(pagesMap: RM) {
- const pageList = Object.keys(pagesMap) as Array<ROUTES>;
+/**
+ * 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 enumaration 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);