gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 02/02: first iteration of exchange selection: added


From: gnunet
Subject: [taler-wallet-core] 02/02: first iteration of exchange selection: added information in the exchangeDetails response from core
Date: Thu, 18 Aug 2022 21:02:27 +0200

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

commit 4ca38113abee2c0ca17b26aa55cf6a0ecafe49c9
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Aug 18 16:00:01 2022 -0300

    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(-)

diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx 
b/packages/taler-wallet-webextension/src/NavigationBar.tsx
index 70fb7bdc..42a365f8 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 5917be09..dd3f6c9c 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 6c08ecb7..1f375a82 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 {
                   )
                 }
               />
+              <Route path={Pages.exchanges} component={ExchangeSelection} />
               <Route
                 path={Pages.sendCash.pattern}
                 component={DestinationSelectionSendCash}
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.stories.tsx
new file mode 100644
index 00000000..b99c6c01
--- /dev/null
+++ 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection.stories.tsx
@@ -0,0 +1,85 @@
+/*
+ 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 <http://www.gnu.org/licenses/>
+ */
+
+/**
+ *
+ * @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 00000000..1fa92142
--- /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 <http://www.gnu.org/licenses/>
+ */
+
+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 <Loading />;
+  }
+  if (hook.hasError) {
+    return (
+      <LoadingError
+        error={hook}
+        title={<i18n.Translate>Could not load list of 
exchange</i18n.Translate>}
+      />
+    );
+  }
+  return (
+    <ExchangeSelectionView
+      exchanges={hook.response.exchanges}
+      onSelected={(exchange) => alert(`ok, selected: ${exchange}`)}
+    />
+  );
+}
+
+export function ExchangeSelectionView({
+  initialValue,
+  exchanges,
+  onSelected,
+}: Props): VNode {
+  const list: Record<string, string> = {};
+  exchanges.forEach((e, i) => (list[String(i)] = e.exchangeBaseUrl));
+
+  const [value, setValue] = useState(String(initialValue || 0));
+  const { i18n } = useTranslationContext();
+
+  if (!exchanges.length) {
+    return <div>no exchanges for listing, please add one</div>;
+  }
+
+  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 (
+    <Container>
+      <h2>
+        <i18n.Translate>Service fee description</i18n.Translate>
+      </h2>
+
+      <section>
+        <div
+          style={{
+            display: "flex",
+            flexWrap: "wrap",
+            alignItems: "center",
+            justifyContent: "space-between",
+          }}
+        >
+          <p>
+            <Input>
+              <SelectList
+                label={<i18n.Translate>Known exchanges</i18n.Translate>}
+                list={list}
+                name="lang"
+                value={value}
+                onChange={(v) => setValue(v)}
+              />
+            </Input>
+          </p>
+          {hasChange ? (
+            <ButtonGroup>
+              <Button
+                variant="outlined"
+                onClick={async () => {
+                  setValue(current.exchangeBaseUrl);
+                }}
+              >
+                Reset
+              </Button>
+              <Button
+                variant="contained"
+                onClick={async () => {
+                  onSelected(value);
+                }}
+              >
+                Use this exchange
+              </Button>
+            </ButtonGroup>
+          ) : (
+            <Button
+              variant="outlined"
+              onClick={async () => {
+                null;
+              }}
+            >
+              Close
+            </Button>
+          )}
+        </div>
+      </section>
+      <section>
+        <dl>
+          <dt>Auditors</dt>
+          {current.auditors.map((a) => {
+            <dd>{a.auditor_url}</dd>;
+          })}
+        </dl>
+        <table>
+          <tr>
+            <td>currency</td>
+            <td>{current.currency}</td>
+          </tr>
+          <tr>
+            <td>next fee update</td>
+            <td>
+              {
+                <Time
+                  timestamp={AbsoluteTime.fromTimestamp(nextFeeUpdate)}
+                  format="dd MMMM yyyy, HH:mm"
+                />
+              }
+            </td>
+          </tr>
+        </table>
+      </section>
+      <section>
+        <table>
+          <thead>
+            <tr>
+              <td>Denomination operations</td>
+              <td>Current fee</td>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td colSpan={2}>deposit (i)</td>
+            </tr>
+
+            <tr>
+              <td>* 10</td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>* 5</td>
+              <td>0.05</td>
+            </tr>
+            <tr>
+              <td>* 1</td>
+              <td>0.01</td>
+            </tr>
+          </tbody>
+        </table>
+      </section>
+      <section>
+        <table>
+          <thead>
+            <tr>
+              <td>Wallet operations</td>
+              <td>Current fee</td>
+            </tr>
+          </thead>
+          <tbody>
+            <tr>
+              <td>history(i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>kyc (i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>account (i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>purse (i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>wire SEPA (i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>closing SEPA(i) </td>
+              <td>0.1</td>
+            </tr>
+            <tr>
+              <td>wad SEPA (i) </td>
+              <td>0.1</td>
+            </tr>
+          </tbody>
+        </table>
+      </section>
+      <section>
+        <ButtonGroup>
+          <LinkPrimary>Privacy policy</LinkPrimary>
+          <LinkPrimary>Terms of service</LinkPrimary>
+        </ButtonGroup>
+      </section>
+    </Container>
+  );
+}
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
index 6a500a48..5c01b113 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 25537691..11f1fb42 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,
 ];

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]