aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-05-04 16:25:53 -0300
committerSebastian <sebasjm@gmail.com>2022-05-04 16:26:53 -0300
commit7a2fe8018faa4666ff681072682f16f8fb1bfc13 (patch)
treed82afd97a4748f64a794475db60df58b1baec776 /packages/taler-wallet-webextension
parent4491118494c332c9ce0a0c4533804744d63701f2 (diff)
add age restriction option to withdraw cta
Diffstat (limited to 'packages/taler-wallet-webextension')
-rw-r--r--packages/taler-wallet-webextension/src/components/Checkbox.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/components/SelectList.tsx7
-rw-r--r--packages/taler-wallet-webextension/src/cta/Pay.stories.tsx36
-rw-r--r--packages/taler-wallet-webextension/src/cta/Pay.tsx27
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx53
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw.tsx38
-rw-r--r--packages/taler-wallet-webextension/src/mui/handlers.ts2
-rw-r--r--packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts4
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DepositPage.test.ts2
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx15
-rw-r--r--packages/taler-wallet-webextension/src/wxApi.ts4
11 files changed, 167 insertions, 25 deletions
diff --git a/packages/taler-wallet-webextension/src/components/Checkbox.tsx b/packages/taler-wallet-webextension/src/components/Checkbox.tsx
index 0eb087b07..2e14f3367 100644
--- a/packages/taler-wallet-webextension/src/components/Checkbox.tsx
+++ b/packages/taler-wallet-webextension/src/components/Checkbox.tsx
@@ -17,8 +17,8 @@
import { h, VNode } from "preact";
interface Props {
- enabled: boolean;
- onToggle: () => void;
+ enabled?: boolean;
+ onToggle?: () => void;
label: VNode;
name: string;
description?: VNode;
diff --git a/packages/taler-wallet-webextension/src/components/SelectList.tsx b/packages/taler-wallet-webextension/src/components/SelectList.tsx
index aa17d82b8..9271240f0 100644
--- a/packages/taler-wallet-webextension/src/components/SelectList.tsx
+++ b/packages/taler-wallet-webextension/src/components/SelectList.tsx
@@ -20,7 +20,7 @@ import { NiceSelect } from "./styled/index.js";
interface Props {
value?: string;
- onChange: (s: string) => void;
+ onChange?: (s: string) => void;
label: VNode;
list: {
[label: string]: string;
@@ -28,6 +28,7 @@ interface Props {
name: string;
description?: string;
canBeNull?: boolean;
+ maxWidth?: boolean;
}
export function SelectList({
@@ -36,6 +37,7 @@ export function SelectList({
list,
onChange,
label,
+ maxWidth,
description,
canBeNull,
}: Props): VNode {
@@ -53,8 +55,9 @@ export function SelectList({
<select
name={name}
value={value}
+ style={maxWidth ? { width: "100%" } : undefined}
onChange={(e) => {
- onChange(e.currentTarget.value);
+ if (onChange) onChange(e.currentTarget.value);
}}
>
{value === undefined ||
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx
index 3656bbbd4..76bfa3ab3 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx
@@ -101,6 +101,42 @@ export const NoEnoughBalance = createExample(TestedComponent, {
goToWalletManualWithdraw: () => null,
});
+export const EnoughBalanceButRestricted = createExample(TestedComponent, {
+ state: {
+ status: "ready",
+ hook: undefined,
+ amount: Amounts.parseOrThrow("USD:10"),
+ balance: {
+ currency: "USD",
+ fraction: 40000000,
+ value: 19,
+ },
+ payHandler: {
+ onClick: async () => {
+ null;
+ },
+ },
+ totalFees: Amounts.parseOrThrow("USD:0"),
+ payResult: undefined,
+ uri: "",
+ payStatus: {
+ status: PreparePayResultType.InsufficientBalance,
+ noncePriv: "",
+ proposalId: "proposal1234",
+ contractTerms: {
+ merchant: {
+ name: "someone",
+ },
+ summary: "some beers",
+ amount: "USD:10",
+ } as Partial<ContractTerms> as any,
+ amountRaw: "USD:10",
+ },
+ },
+ goBack: () => null,
+ goToWalletManualWithdraw: () => null,
+});
+
export const PaymentPossible = createExample(TestedComponent, {
state: {
status: "ready",
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx
index 0e2530149..4f44ebab2 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx
@@ -542,23 +542,22 @@ function ButtonsSection({
);
}
if (payStatus.status === PreparePayResultType.InsufficientBalance) {
+ let BalanceMessage = "";
+ if (!state.balance) {
+ BalanceMessage = i18n.str`You have no balance for this currency. Withdraw digital cash first.`;
+ } else {
+ const balanceShouldBeEnough =
+ Amounts.cmp(state.balance, state.amount) !== -1;
+ if (balanceShouldBeEnough) {
+ BalanceMessage = i18n.str`Could not find enough coins to pay this order. Even if you have enough ${state.balance.currency} some restriction may apply.`;
+ } else {
+ BalanceMessage = i18n.str`Your current balance is not enough for this order.`;
+ }
+ }
return (
<Fragment>
<section>
- {state.balance ? (
- <WarningBox>
- <i18n.Translate>
- Your balance of {<Amount value={state.balance} />} is not
- enough to pay for this purchase
- </i18n.Translate>
- </WarningBox>
- ) : (
- <WarningBox>
- <i18n.Translate>
- Your balance is not enough to pay for this purchase.
- </i18n.Translate>
- </WarningBox>
- )}
+ <WarningBox>{BalanceMessage}</WarningBox>
</section>
<section>
<ButtonSuccess
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
index b77e98a10..79f9c220d 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
@@ -50,12 +50,24 @@ const normalTosState = {
reviewing: false,
};
+const ageRestrictionOptions: Record<string, string> = "6:12:18"
+ .split(":")
+ .reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {});
+
+ageRestrictionOptions["0"] = "Not restricted";
+
+const ageRestrictionSelectField = {
+ list: ageRestrictionOptions,
+ value: "0",
+};
+
export const TermsOfServiceNotYetLoaded = createExample(TestedComponent, {
state: {
hook: undefined,
status: "success",
cancelEditExchange: nullHandler,
confirmEditExchange: nullHandler,
+ ageRestriction: ageRestrictionSelectField,
chosenAmount: {
currency: "USD",
value: 2,
@@ -91,6 +103,7 @@ export const WithSomeFee = createExample(TestedComponent, {
status: "success",
cancelEditExchange: nullHandler,
confirmEditExchange: nullHandler,
+ ageRestriction: ageRestrictionSelectField,
chosenAmount: {
currency: "USD",
value: 2,
@@ -127,6 +140,7 @@ export const WithoutFee = createExample(TestedComponent, {
status: "success",
cancelEditExchange: nullHandler,
confirmEditExchange: nullHandler,
+ ageRestriction: ageRestrictionSelectField,
chosenAmount: {
currency: "USD",
value: 2,
@@ -163,6 +177,7 @@ export const EditExchangeUntouched = createExample(TestedComponent, {
status: "success",
cancelEditExchange: nullHandler,
confirmEditExchange: nullHandler,
+ ageRestriction: ageRestrictionSelectField,
chosenAmount: {
currency: "USD",
value: 2,
@@ -199,6 +214,7 @@ export const EditExchangeModified = createExample(TestedComponent, {
status: "success",
cancelEditExchange: nullHandler,
confirmEditExchange: nullHandler,
+ ageRestriction: ageRestrictionSelectField,
chosenAmount: {
currency: "USD",
value: 2,
@@ -236,3 +252,40 @@ export const CompletedWithoutBankURL = createExample(TestedComponent, {
hook: undefined,
},
});
+
+export const WithAgeRestrictionSelected = createExample(TestedComponent, {
+ state: {
+ hook: undefined,
+ status: "success",
+ cancelEditExchange: nullHandler,
+ confirmEditExchange: nullHandler,
+ ageRestriction: ageRestrictionSelectField,
+ chosenAmount: {
+ currency: "USD",
+ value: 2,
+ fraction: 10000000,
+ },
+ doWithdrawal: nullHandler,
+ editExchange: nullHandler,
+ exchange: {
+ list: exchangeList,
+ value: "exchange.demo.taler.net",
+ onChange: async () => {
+ null;
+ },
+ },
+ showExchangeSelection: false,
+ mustAcceptFirst: false,
+ withdrawalFee: {
+ currency: "USD",
+ fraction: 0,
+ value: 0,
+ },
+ toBeReceived: {
+ currency: "USD",
+ fraction: 0,
+ value: 2,
+ },
+ tosProps: normalTosState,
+ },
+});
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
index cd0ba2cc3..c4bc3457a 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
@@ -35,6 +35,7 @@ import { SelectList } from "../components/SelectList.js";
import {
ButtonSuccess,
ButtonWarning,
+ Input,
LinkSuccess,
SubTitle,
SuccessBox,
@@ -43,12 +44,18 @@ import {
import { useTranslationContext } from "../context/translation.js";
import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
import { buildTermsOfServiceState } from "../utils/index.js";
-import { ButtonHandler, SelectFieldHandler } from "../mui/handlers.js";
+import {
+ ButtonHandler,
+ SelectFieldHandler,
+ ToggleHandler,
+} from "../mui/handlers.js";
import * as wxApi from "../wxApi.js";
import {
Props as TermsOfServiceSectionProps,
TermsOfServiceSection,
} from "./TermsOfServiceSection.js";
+import { startOfWeekYear } from "date-fns/esm";
+import { Checkbox } from "../components/Checkbox.js";
interface Props {
talerWithdrawUri?: string;
@@ -97,6 +104,8 @@ type Success = {
doWithdrawal: ButtonHandler;
tosProps?: TermsOfServiceSectionProps;
mustAcceptFirst: boolean;
+
+ ageRestriction: SelectFieldHandler;
};
export function useComponentState(
@@ -106,6 +115,7 @@ export function useComponentState(
const [customExchange, setCustomExchange] = useState<string | undefined>(
undefined,
);
+ const [ageRestricted, setAgeRestricted] = useState(0);
/**
* Ask the wallet about the withdraw URI
@@ -228,6 +238,7 @@ export function useComponentState(
const res = await api.acceptWithdrawal(
talerWithdrawUri,
selectedExchange,
+ !ageRestricted ? undefined : ageRestricted,
);
if (res.confirmTransferUrl) {
document.location.href = res.confirmTransferUrl;
@@ -320,6 +331,14 @@ export function useComponentState(
termsState !== undefined &&
(termsState.status === "changed" || termsState.status === "new");
+ const ageRestrictionOptions: Record<string, string> | undefined = "6:12:18"
+ .split(":")
+ .reduce((p, c) => ({ ...p, [c]: `under ${c}` }), {});
+
+ if (ageRestrictionOptions) {
+ ageRestrictionOptions["0"] = "Not restricted";
+ }
+
return {
status: "success",
hook: undefined,
@@ -331,6 +350,11 @@ export function useComponentState(
toBeReceived,
withdrawalFee,
chosenAmount: amount,
+ ageRestriction: {
+ list: ageRestrictionOptions,
+ value: String(ageRestricted),
+ onChange: async (v) => setAgeRestricted(parseInt(v, 10)),
+ },
doWithdrawal: {
onClick:
doingWithdraw || (mustAcceptFirst && !reviewed)
@@ -486,6 +510,18 @@ export function View({ state }: { state: State }): VNode {
</LinkSuccess>
)}
</section>
+ <section>
+ <Input>
+ <SelectList
+ label={<i18n.Translate>Age restriction</i18n.Translate>}
+ list={state.ageRestriction.list}
+ name="age"
+ maxWidth
+ value={state.ageRestriction.value}
+ onChange={state.ageRestriction.onChange}
+ />
+ </Input>
+ </section>
{state.tosProps && <TermsOfServiceSection {...state.tosProps} />}
{state.tosProps ? (
<section>
diff --git a/packages/taler-wallet-webextension/src/mui/handlers.ts b/packages/taler-wallet-webextension/src/mui/handlers.ts
index 60cfee421..646bdcf17 100644
--- a/packages/taler-wallet-webextension/src/mui/handlers.ts
+++ b/packages/taler-wallet-webextension/src/mui/handlers.ts
@@ -17,7 +17,7 @@ export interface ToggleHandler {
}
export interface SelectFieldHandler {
- onChange: (value: string) => Promise<void>;
+ onChange?: (value: string) => Promise<void>;
error?: string;
value: string;
isDirty?: boolean;
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts
index a4b333f02..7a9a5314b 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.test.ts
@@ -87,7 +87,7 @@ describe("CreateManualWithdraw states", () => {
const { exchange, currency } = getLastResultOrThrow()
expect(exchange.value).equal("url2")
-
+ if (currency.onChange === undefined) expect.fail();
currency.onChange("USD")
}
@@ -111,6 +111,7 @@ describe("CreateManualWithdraw states", () => {
expect(exchange.value).equal("url2")
expect(currency.value).equal("ARS")
+ if (exchange.onChange === undefined) expect.fail();
exchange.onChange("url1")
}
@@ -205,6 +206,7 @@ async function defaultTestForInputSelect(awaiter: () => Promise<void>, getField:
throw new Error('no enough values')
}
nextValue = keys[nextIdx]
+ if (field.onChange === undefined) expect.fail();
field.onChange(nextValue)
}
diff --git a/packages/taler-wallet-webextension/src/wallet/DepositPage.test.ts b/packages/taler-wallet-webextension/src/wallet/DepositPage.test.ts
index c863b27d5..5fc55934d 100644
--- a/packages/taler-wallet-webextension/src/wallet/DepositPage.test.ts
+++ b/packages/taler-wallet-webextension/src/wallet/DepositPage.test.ts
@@ -258,6 +258,7 @@ describe("DepositPage states", () => {
expect(r.depositHandler.onClick).undefined;
expect(r.totalFee).deep.eq(Amounts.parseOrThrow(`${currency}:0`))
+ if (r.account.onChange === undefined) expect.fail();
r.account.onChange("1")
}
@@ -290,6 +291,7 @@ describe("DepositPage states", () => {
expect(r.totalToDeposit).deep.eq(Amounts.parseOrThrow(`${currency}:7`))
expect(r.depositHandler.onClick).undefined;
+ if (r.account.onChange === undefined) expect.fail();
r.account.onChange("0")
}
diff --git a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
index 829e60b44..c4725a8d7 100644
--- a/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DeveloperPage.tsx
@@ -81,6 +81,7 @@ export function DeveloperPage(): VNode {
type CoinsInfo = CoinDumpJson["coins"];
type CalculatedCoinfInfo = {
+ ageKeysCount: number | undefined;
denom_value: number;
remain_value: number;
status: string;
@@ -132,11 +133,13 @@ export function View({
const money_by_exchange = coins.reduce(
(prev, cur) => {
const denom = Amounts.parseOrThrow(cur.denom_value);
+ console.log(cur);
if (!prev[cur.exchange_base_url]) {
prev[cur.exchange_base_url] = [];
currencies[cur.exchange_base_url] = denom.currency;
}
prev[cur.exchange_base_url].push({
+ ageKeysCount: cur.ageCommitmentProof?.proof.privateKeys.length,
denom_value: parseFloat(Amounts.stringifyValue(denom)),
remain_value: parseFloat(
Amounts.stringifyValue(Amounts.parseOrThrow(cur.remaining_value)),
@@ -305,7 +308,7 @@ function ShowAllCoins({
<p>
<b>{ex}</b>: {total} {currencies[ex]}
</p>
- <p>
+ <p onClick={() => setCollapsedUnspent(true)}>
<b>
<i18n.Translate>usable coins</i18n.Translate>
</b>
@@ -313,7 +316,7 @@ function ShowAllCoins({
{collapsedUnspent ? (
<div onClick={() => setCollapsedUnspent(false)}>click to show</div>
) : (
- <table onClick={() => setCollapsedUnspent(true)}>
+ <table>
<tr>
<td>
<i18n.Translate>id</i18n.Translate>
@@ -330,6 +333,9 @@ function ShowAllCoins({
<td>
<i18n.Translate>from refresh?</i18n.Translate>
</td>
+ <td>
+ <i18n.Translate>age key count</i18n.Translate>
+ </td>
</tr>
{coins.usable.map((c, idx) => {
return (
@@ -339,12 +345,13 @@ function ShowAllCoins({
<td>{c.remain_value}</td>
<td>{c.status}</td>
<td>{c.from_refresh ? "true" : "false"}</td>
+ <td>{String(c.ageKeysCount)}</td>
</tr>
);
})}
</table>
)}
- <p>
+ <p onClick={() => setCollapsedSpent(true)}>
<i18n.Translate>spent coins</i18n.Translate>
</p>
{collapsedSpent ? (
@@ -352,7 +359,7 @@ function ShowAllCoins({
<i18n.Translate>click to show</i18n.Translate>
</div>
) : (
- <table onClick={() => setCollapsedSpent(true)}>
+ <table>
<tr>
<td>
<i18n.Translate>id</i18n.Translate>
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts
index b48826645..dd4eb2cf4 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -324,10 +324,12 @@ export function preparePay(talerPayUri: string): Promise<PreparePayResult> {
export function acceptWithdrawal(
talerWithdrawUri: string,
selectedExchange: string,
+ restrictAge?: number,
): Promise<AcceptWithdrawalResponse> {
return callBackend("acceptBankIntegratedWithdrawal", {
talerWithdrawUri,
exchangeBaseUrl: selectedExchange,
+ restrictAge
});
}
@@ -340,10 +342,12 @@ export function acceptWithdrawal(
export function acceptManualWithdrawal(
exchangeBaseUrl: string,
amount: string,
+ restrictAge?: number,
): Promise<AcceptManualWithdrawalResult> {
return callBackend("acceptManualWithdrawal", {
amount,
exchangeBaseUrl,
+ restrictAge
});
}