diff options
Diffstat (limited to 'packages')
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    });  } | 
