From 4ca38113abee2c0ca17b26aa55cf6a0ecafe49c9 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Thu, 18 Aug 2022 16:00:01 -0300 Subject: first iteration of exchange selection: added information in the exchangeDetails response from core --- .../src/NavigationBar.tsx | 1 + .../src/cta/Withdraw/test.ts | 12 + .../src/wallet/Application.tsx | 2 + .../src/wallet/ExchangeSelection.stories.tsx | 85 +++++++ .../src/wallet/ExchangeSelection.tsx | 282 +++++++++++++++++++++ .../src/wallet/Settings.stories.tsx | 4 +- .../src/wallet/index.stories.tsx | 2 + 7 files changed, 386 insertions(+), 2 deletions(-) create mode 100644 packages/taler-wallet-webextension/src/wallet/ExchangeSelection.stories.tsx create mode 100644 packages/taler-wallet-webextension/src/wallet/ExchangeSelection.tsx (limited to 'packages/taler-wallet-webextension') diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index 70fb7bdcb..42a365f8c 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -98,6 +98,7 @@ export const Pages = { receiveCash: pageDefinition<{ amount?: string }>("/destination/get/:amount?"), dev: "/dev", + exchanges: "/exchanges", backup: "/backup", backupProviderDetail: pageDefinition<{ pid: string }>( "/backup/provider/:pid", diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts index 5917be092..dd3f6c9c7 100644 --- a/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts +++ b/packages/taler-wallet-webextension/src/cta/Withdraw/test.ts @@ -37,6 +37,18 @@ const exchanges: ExchangeListItem[] = [ tos: { acceptedVersion: "", }, + auditors: [ + { + auditor_pub: "pubpubpubpubpub", + auditor_url: "https://audotor.taler.net", + denomination_keys: [], + }, + ], + denominations: [{} as any], + wireInfo: { + accounts: [], + feesForType: {}, + }, }, ]; diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx index 6c08ecb71..1f375a82e 100644 --- a/packages/taler-wallet-webextension/src/wallet/Application.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx @@ -58,6 +58,7 @@ import { DestinationSelectionSendCash, } from "./DestinationSelection.js"; import { Amounts } from "@gnu-taler/taler-util"; +import { ExchangeSelection } from "./ExchangeSelection.js"; export function Application(): VNode { const [globalNotification, setGlobalNotification] = useState< @@ -141,6 +142,7 @@ export function Application(): VNode { ) } /> + + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { TalerProtocolTimestamp } from "@gnu-taler/taler-util"; +import { createExample } from "../test-utils.js"; +import { ExchangeSelectionView } from "./ExchangeSelection.js"; + +export default { + title: "wallet/select exchange", +}; + +const exchangeList = [ + { + currency: "KUDOS", + exchangeBaseUrl: "https://exchange.demo.taler.net", + paytoUris: [], + tos: {}, + auditors: [ + { + auditor_pub: "pubpubpubpubpub", + auditor_url: "https://audotor.taler.net", + denomination_keys: [], + }, + ], + denominations: [ + { + stampStart: TalerProtocolTimestamp.never(), + stampExpireWithdraw: TalerProtocolTimestamp.never(), + stampExpireLegal: TalerProtocolTimestamp.never(), + stampExpireDeposit: TalerProtocolTimestamp.never(), + }, + ], + wireInfo: { + accounts: [], + feesForType: {}, + }, + }, + { + currency: "ARS", + exchangeBaseUrl: "https://exchange.taler.ar", + paytoUris: [], + tos: {}, + auditors: [ + { + auditor_pub: "pubpubpubpubpub", + auditor_url: "https://audotor.taler.net", + denomination_keys: [], + }, + ], + denominations: [ + { + stampStart: TalerProtocolTimestamp.never(), + stampExpireWithdraw: TalerProtocolTimestamp.never(), + stampExpireLegal: TalerProtocolTimestamp.never(), + stampExpireDeposit: TalerProtocolTimestamp.never(), + } as any, + ], + wireInfo: { + accounts: [], + feesForType: {}, + }, + }, +]; + +export const Listing = createExample(ExchangeSelectionView, { + exchanges: exchangeList, +}); diff --git a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.tsx b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.tsx new file mode 100644 index 000000000..1fa921429 --- /dev/null +++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.tsx @@ -0,0 +1,282 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { + AbsoluteTime, + ExchangeListItem, + TalerProtocolTimestamp, +} from "@gnu-taler/taler-util"; +import { styled } from "@linaria/react"; +import { Fragment, h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { Loading } from "../components/Loading.js"; +import { LoadingError } from "../components/LoadingError.js"; +import { SelectList } from "../components/SelectList.js"; +import { Input, LinkPrimary } from "../components/styled/index.js"; +import { Time } from "../components/Time.js"; +import { useTranslationContext } from "../context/translation.js"; +import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { Button } from "../mui/Button.js"; +import * as wxApi from "../wxApi.js"; + +const Container = styled.div` + display: flex; + flex-direction: column; + & > * { + margin-bottom: 20px; + } +`; + +interface Props { + initialValue?: number; + exchanges: ExchangeListItem[]; + onSelected: (exchange: string) => void; +} + +const ButtonGroup = styled.div` + & > button { + margin-left: 8px; + margin-right: 8px; + } +`; + +export function ExchangeSelection(): VNode { + const hook = useAsyncAsHook(wxApi.listExchanges); + const { i18n } = useTranslationContext(); + if (!hook) { + return ; + } + if (hook.hasError) { + return ( + Could not load list of exchange} + /> + ); + } + return ( + alert(`ok, selected: ${exchange}`)} + /> + ); +} + +export function ExchangeSelectionView({ + initialValue, + exchanges, + onSelected, +}: Props): VNode { + const list: Record = {}; + exchanges.forEach((e, i) => (list[String(i)] = e.exchangeBaseUrl)); + + const [value, setValue] = useState(String(initialValue || 0)); + const { i18n } = useTranslationContext(); + + if (!exchanges.length) { + return
no exchanges for listing, please add one
; + } + + const current = exchanges[Number(value)]; + + const hasChange = value !== current.exchangeBaseUrl; + + function nearestTimestamp( + first: TalerProtocolTimestamp, + second: TalerProtocolTimestamp, + ): TalerProtocolTimestamp { + const f = AbsoluteTime.fromTimestamp(first); + const s = AbsoluteTime.fromTimestamp(second); + const a = AbsoluteTime.min(f, s); + return AbsoluteTime.toTimestamp(a); + } + + let nextFeeUpdate = TalerProtocolTimestamp.never(); + + nextFeeUpdate = Object.values(current.wireInfo.feesForType).reduce( + (prev, cur) => { + return cur.reduce((p, c) => nearestTimestamp(p, c.endStamp), prev); + }, + nextFeeUpdate, + ); + + nextFeeUpdate = current.denominations.reduce((prev, cur) => { + return [ + cur.stampExpireWithdraw, + cur.stampExpireLegal, + cur.stampExpireDeposit, + ].reduce(nearestTimestamp, prev); + }, nextFeeUpdate); + + return ( + +

+ Service fee description +

+ +
+
+

+ + Known exchanges} + list={list} + name="lang" + value={value} + onChange={(v) => setValue(v)} + /> + +

+ {hasChange ? ( + + + + + ) : ( + + )} +
+
+
+
+
Auditors
+ {current.auditors.map((a) => { +
{a.auditor_url}
; + })} +
+ + + + + + + + + +
currency{current.currency}
next fee update + { +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
Denomination operationsCurrent fee
deposit (i)
* 100.1
* 50.05
* 10.01
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Wallet operationsCurrent fee
history(i) 0.1
kyc (i) 0.1
account (i) 0.1
purse (i) 0.1
wire SEPA (i) 0.1
closing SEPA(i) 0.1
wad SEPA (i) 0.1
+
+
+ + Privacy policy + Terms of service + +
+
+ ); +} diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx index 6a500a48e..5c01b1132 100644 --- a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx @@ -57,7 +57,7 @@ export const WithOneExchange = createExample(TestedComponent, { contentType: "text/plain", }, paytoUris: ["payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator"], - }, + } as any, //TODO: complete with auditors, wireInfo and denominations ], }); @@ -87,7 +87,7 @@ export const WithExchangeInDifferentState = createExample(TestedComponent, { contentType: "text/plain", }, paytoUris: ["payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator"], - }, + } as any, //TODO: complete with auditors, wireInfo and denominations { currency: "USD", exchangeBaseUrl: "http://exchange3.taler", diff --git a/packages/taler-wallet-webextension/src/wallet/index.stories.tsx b/packages/taler-wallet-webextension/src/wallet/index.stories.tsx index 25537691d..11f1fb422 100644 --- a/packages/taler-wallet-webextension/src/wallet/index.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/index.stories.tsx @@ -36,6 +36,7 @@ import * as a15 from "./AddNewActionView.stories.js"; import * as a16 from "./DeveloperPage.stories.js"; import * as a17 from "./QrReader.stories.js"; import * as a18 from "./DestinationSelection.stories.js"; +import * as a19 from "./ExchangeSelection.stories.js"; export default [ a1, @@ -55,4 +56,5 @@ export default [ a16, a17, a18, + a19, ]; -- cgit v1.2.3