aboutsummaryrefslogtreecommitdiff
path: root/packages/bank-ui
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-05-07 12:09:48 -0300
committerSebastian <sebasjm@gmail.com>2024-05-07 12:09:48 -0300
commit7b78c1350cfe49e06ce31ed076f69aa9dfac3490 (patch)
tree9c0a037d8ad232873d49452f38330e7122e16abb /packages/bank-ui
parentb84fc8b580a7dbb00d2ec4bd463966e546b9b47f (diff)
downloadwallet-core-7b78c1350cfe49e06ce31ed076f69aa9dfac3490.tar.xz
fix #8781: min cashout ui
Diffstat (limited to 'packages/bank-ui')
-rw-r--r--packages/bank-ui/src/Routing.tsx10
-rw-r--r--packages/bank-ui/src/pages/LoginForm.tsx4
-rw-r--r--packages/bank-ui/src/pages/account/CashoutListForAccount.tsx3
-rw-r--r--packages/bank-ui/src/pages/admin/AccountForm.tsx1
-rw-r--r--packages/bank-ui/src/pages/admin/AdminHome.tsx5
-rw-r--r--packages/bank-ui/src/pages/regional/CreateCashout.tsx53
6 files changed, 51 insertions, 25 deletions
diff --git a/packages/bank-ui/src/Routing.tsx b/packages/bank-ui/src/Routing.tsx
index 23635d4cd..380b267a2 100644
--- a/packages/bank-ui/src/Routing.tsx
+++ b/packages/bank-ui/src/Routing.tsx
@@ -31,6 +31,7 @@ import {
HttpStatusCode,
TranslatedString,
assertUnreachable,
+ createRFC8959AccessTokenEncoded
} from "@gnu-taler/taler-util";
import { useEffect } from "preact/hooks";
import { useSessionState } from "./hooks/session.js";
@@ -121,7 +122,7 @@ function PublicRounting({
refreshable: true,
});
if (resp.type === "ok") {
- onLoggedUser(username, resp.body.access_token);
+ onLoggedUser(username, createRFC8959AccessTokenEncoded(resp.body.access_token));
} else {
switch (resp.case) {
case HttpStatusCode.Unauthorized:
@@ -394,6 +395,9 @@ function PrivateRouting({
routeMyAccountDetails={privatePages.myAccountDetails}
routeMyAccountPassword={privatePages.myAccountPassword}
routeConversionConfig={privatePages.conversionConfig}
+ onCashout={() =>
+ navigateTo(privatePages.home.url({}))
+ }
onAuthorizationRequired={() =>
navigateTo(privatePages.solveSecondFactor.url({}))
}
@@ -461,6 +465,9 @@ function PrivateRouting({
routeMyAccountDetails={privatePages.myAccountDetails}
routeMyAccountPassword={privatePages.myAccountPassword}
routeConversionConfig={privatePages.conversionConfig}
+ onCashout={() =>
+ navigateTo(privatePages.home.url({}))
+ }
onAuthorizationRequired={() =>
navigateTo(privatePages.solveSecondFactor.url({}))
}
@@ -515,6 +522,7 @@ function PrivateRouting({
onAuthorizationRequired={() =>
navigateTo(privatePages.solveSecondFactor.url({}))
}
+ onCashout={() => navigateTo(privatePages.home.url({}))}
routeClose={privatePages.home}
/>
);
diff --git a/packages/bank-ui/src/pages/LoginForm.tsx b/packages/bank-ui/src/pages/LoginForm.tsx
index 2f967895c..600025400 100644
--- a/packages/bank-ui/src/pages/LoginForm.tsx
+++ b/packages/bank-ui/src/pages/LoginForm.tsx
@@ -14,7 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { HttpStatusCode } from "@gnu-taler/taler-util";
+import { HttpStatusCode, createRFC8959AccessTokenEncoded, createRFC8959AccessTokenPlain } from "@gnu-taler/taler-util";
import {
Button,
LocalNotificationBanner,
@@ -87,7 +87,7 @@ export function LoginForm({
refreshable: true,
}),
(result) => {
- session.logIn({ username, token: result.body.access_token });
+ session.logIn({ username, token: createRFC8959AccessTokenEncoded(result.body.access_token) });
},
(fail) => {
switch (fail.case) {
diff --git a/packages/bank-ui/src/pages/account/CashoutListForAccount.tsx b/packages/bank-ui/src/pages/account/CashoutListForAccount.tsx
index 301978eaa..fd6379895 100644
--- a/packages/bank-ui/src/pages/account/CashoutListForAccount.tsx
+++ b/packages/bank-ui/src/pages/account/CashoutListForAccount.tsx
@@ -25,6 +25,7 @@ interface Props {
account: string;
routeClose: RouteDefinition;
onAuthorizationRequired: () => void;
+ onCashout: () => void;
routeCashoutDetails: RouteDefinition<{ cid: string }>;
routeMyAccountDetails: RouteDefinition;
routeMyAccountDelete: RouteDefinition;
@@ -37,6 +38,7 @@ interface Props {
export function CashoutListForAccount({
account,
onAuthorizationRequired,
+ onCashout,
routeCreateCashout,
routeCashoutDetails,
routeMyAccountCashout,
@@ -76,6 +78,7 @@ export function CashoutListForAccount({
focus
routeHere={routeCreateCashout}
routeClose={routeClose}
+ onCashout={onCashout}
onAuthorizationRequired={onAuthorizationRequired}
account={account}
/>
diff --git a/packages/bank-ui/src/pages/admin/AccountForm.tsx b/packages/bank-ui/src/pages/admin/AccountForm.tsx
index 21e3e6588..ba5da609f 100644
--- a/packages/bank-ui/src/pages/admin/AccountForm.tsx
+++ b/packages/bank-ui/src/pages/admin/AccountForm.tsx
@@ -213,6 +213,7 @@ export function AccountForm<PurposeType extends keyof ChangeByPurposeType>({
: undefined,
name: !editableName
? undefined // disabled
+ : purpose === "update" && newForm.name === undefined ? undefined // the field hasn't been changed
: !newForm.name
? i18n.str`Required`
: undefined,
diff --git a/packages/bank-ui/src/pages/admin/AdminHome.tsx b/packages/bank-ui/src/pages/admin/AdminHome.tsx
index acae09b40..34c121235 100644
--- a/packages/bank-ui/src/pages/admin/AdminHome.tsx
+++ b/packages/bank-ui/src/pages/admin/AdminHome.tsx
@@ -276,10 +276,9 @@ function Metrics({
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,
+ parseInt(e.currentTarget
+ .value, 10) as TalerCorebankApi.MonitorTimeframeParam,
);
}}
>
diff --git a/packages/bank-ui/src/pages/regional/CreateCashout.tsx b/packages/bank-ui/src/pages/regional/CreateCashout.tsx
index 8e54bbd4e..c51b96b8b 100644
--- a/packages/bank-ui/src/pages/regional/CreateCashout.tsx
+++ b/packages/bank-ui/src/pages/regional/CreateCashout.tsx
@@ -59,6 +59,7 @@ interface Props {
account: string;
focus?: boolean;
onAuthorizationRequired: () => void;
+ onCashout: () => void;
routeClose: RouteDefinition;
routeHere: RouteDefinition;
}
@@ -76,6 +77,7 @@ type ErrorFrom<T> = {
export function CreateCashout({
account: accountName,
onAuthorizationRequired,
+ onCashout,
focus,
routeHere,
routeClose,
@@ -93,7 +95,6 @@ export function CreateCashout({
const {
lib: { bank: api },
config,
- hints,
} = useBankCoreApiContext();
const [form, setForm] = useState<Partial<FormType>>({ isDebit: true });
const [notification, notify, handleError] = useLocalNotification();
@@ -167,13 +168,6 @@ export function CreateCashout({
);
}
- 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,
@@ -182,6 +176,15 @@ export function CreateCashout({
} = info.body;
const regionalZero = Amounts.zeroOfCurrency(regional_currency);
const fiatZero = Amounts.zeroOfCurrency(fiat_currency);
+
+ const account = {
+ balance: Amounts.parseOrThrow(resultAccount.body.balance.amount),
+ balanceIsDebit:
+ resultAccount.body.balance.credit_debit_indicator == "debit",
+ debitThreshold: Amounts.parseOrThrow(resultAccount.body.debit_threshold),
+ minCashout: resultAccount.body.min_cashout === undefined ? regionalZero : Amounts.parseOrThrow(resultAccount.body.min_cashout)
+ };
+
const limit = account.balanceIsDebit
? Amounts.sub(account.debitThreshold, account.balance).amount
: Amounts.add(account.balance, account.debitThreshold).amount;
@@ -241,16 +244,23 @@ export function CreateCashout({
? 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 ${
+ : calculationResult === "amount-is-too-small"
+ ? i18n.str`Amount needs to be higher`
+ : Amounts.cmp(calc.debit, conversionInfo.cashout_min_amount) < 0
+ ? i18n.str`No account can't cashout less 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.cmp(calc.debit, account.minCashout) < 0
+ ? i18n.str`Your account can't cashout less than ${
+ Amounts.stringifyValueWithSpec(
+ Amounts.parseOrThrow(account.minCashout),
+ regional_currency_specification,
+ ).normal
+ }`
+
: Amounts.isZero(calc.credit)
? i18n.str`The total transfer at destination will be zero`
: undefined,
@@ -260,21 +270,17 @@ export function CreateCashout({
async function createCashout() {
const request_uid = encodeCrock(getRandomBytes(32));
await handleError(async () => {
- // new cashout api doesn't require channel
- const validChannel =
- config.supported_tan_channels.length === 0 || form.channel;
-
- if (!creds || !form.subject || !validChannel) return;
+ if (!creds || !form.subject) 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`);
+ onCashout();
} else {
switch (resp.case) {
case HttpStatusCode.Accepted: {
@@ -335,6 +341,15 @@ export function CreateCashout({
debug: resp.detail,
when: AbsoluteTime.now(),
});
+ case TalerErrorCode.BANK_CONVERSION_AMOUNT_TO_SMALL:
+ return notify({
+ type: "error",
+ title: i18n.str`The amount is less than the minimum allowed.`,
+ description: resp.detail.hint as TranslatedString,
+ debug: resp.detail,
+ when: AbsoluteTime.now(),
+ });
+
case TalerErrorCode.BANK_TAN_CHANNEL_SCRIPT_FAILED:
return notify({
type: "error",