gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] 03/03: exchange selection for invoices and some fixe


From: gnunet
Subject: [taler-wallet-core] 03/03: exchange selection for invoices and some fixes
Date: Wed, 21 Sep 2022 01:27:02 +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 859991a40c4a7757d874f9ae6e6db7b76145a3c3
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue Sep 20 20:26:41 2022 -0300

    exchange selection for invoices and some fixes
---
 .../src/cta/InvoiceCreate/index.ts                 |  20 +++-
 .../src/cta/InvoiceCreate/state.ts                 | 120 +++++++++++----------
 .../src/cta/Withdraw/index.ts                      |  22 ++--
 .../src/cta/Withdraw/state.ts                      |  16 +--
 .../src/cta/Withdraw/views.tsx                     |  10 --
 .../src/hooks/useSelectedExchange.ts               |  13 ++-
 .../src/wallet/ExchangeSelection/index.ts          |  12 +--
 .../src/wallet/ExchangeSelection/state.ts          |   7 +-
 .../src/wallet/ExchangeSelection/views.tsx         |  16 ++-
 9 files changed, 123 insertions(+), 113 deletions(-)

diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
index 2bee51669..61f286d1f 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/index.ts
@@ -14,14 +14,19 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
+import {
+  State as SelectExchangeState
+} from "../../hooks/useSelectedExchange.js";
+import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
-import { LoadingUriView, ReadyView } from "./views.js";
+import { ExchangeSelectionPage } from 
"../../wallet/ExchangeSelection/index.js";
+import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
 import * as wxApi from "../../wxApi.js";
 import { useComponentState } from "./state.js";
-import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
-import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
+import { LoadingUriView, ReadyView } from "./views.js";
 
 export interface Props {
   amount: string;
@@ -29,7 +34,12 @@ export interface Props {
   onSuccess: (tx: string) => Promise<void>;
 }
 
-export type State = State.Loading | State.LoadingUriError | State.Ready;
+export type State = State.Loading
+  | State.LoadingUriError
+  | State.Ready
+  | SelectExchangeState.Selecting
+  | SelectExchangeState.NoExchange
+  ;
 
 export namespace State {
   export interface Loading {
@@ -63,6 +73,8 @@ export namespace State {
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
   "loading-uri": LoadingUriView,
+  "no-exchange": NoExchangesView,
+  "selecting-exchange": ExchangeSelectionPage,
   ready: ReadyView,
 };
 
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts 
b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
index 9b67b4414..4f75e982d 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/state.ts
@@ -14,26 +14,24 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
+/* eslint-disable react-hooks/rules-of-hooks */
 import { Amounts, TalerErrorDetail } from "@gnu-taler/taler-util";
 import { TalerError } from "@gnu-taler/taler-wallet-core";
 import { useState } from "preact/hooks";
 import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
+import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
 import * as wxApi from "../../wxApi.js";
 import { Props, State } from "./index.js";
 
+type RecursiveState<S extends object> = S | (() => RecursiveState<S>)
+
 export function useComponentState(
   { amount: amountStr, onClose, onSuccess }: Props,
   api: typeof wxApi,
-): State {
+): RecursiveState<State> {
   const amount = Amounts.parseOrThrow(amountStr);
 
-  const [subject, setSubject] = useState("");
-
   const hook = useAsyncAsHook(api.listExchanges);
-  const [exchangeIdx, setExchangeIdx] = useState("0");
-  const [operationError, setOperationError] = useState<
-    TalerErrorDetail | undefined
-  >(undefined);
 
   if (!hook) {
     return {
@@ -48,56 +46,68 @@ export function useComponentState(
     };
   }
 
-  const exchanges = hook.response.exchanges.filter(
-    (e) => e.currency === amount.currency,
-  );
-  const exchangeMap = exchanges.reduce(
-    (prev, cur, idx) => ({ ...prev, [String(idx)]: cur.exchangeBaseUrl }),
-    {} as Record<string, string>,
-  );
-  const selected = exchanges[Number(exchangeIdx)];
-
-  async function accept(): Promise<void> {
-    try {
-      const resp = await api.initiatePeerPullPayment({
-        amount: Amounts.stringify(amount),
-        exchangeBaseUrl: selected.exchangeBaseUrl,
-        partialContractTerms: {
-          summary: subject,
-        },
-      });
-
-      onSuccess(resp.transactionId);
-    } catch (e) {
-      if (e instanceof TalerError) {
-        setOperationError(e.errorDetail);
+  const exchangeList = hook.response.exchanges
+
+  return () => {
+    const [subject, setSubject] = useState("");
+
+    const [operationError, setOperationError] = useState<
+      TalerErrorDetail | undefined
+    >(undefined);
+
+
+    const selectedExchange = useSelectedExchange({ currency: amount.currency, 
defaultExchange: undefined, list: exchangeList })
+
+    if (selectedExchange.status !== 'ready') {
+      return selectedExchange
+    }
+
+    const exchange = selectedExchange.selected
+
+    async function accept(): Promise<void> {
+      try {
+        const resp = await api.initiatePeerPullPayment({
+          amount: Amounts.stringify(amount),
+          exchangeBaseUrl: exchange.exchangeBaseUrl,
+          partialContractTerms: {
+            summary: subject,
+          },
+        });
+
+        onSuccess(resp.transactionId);
+      } catch (e) {
+        if (e instanceof TalerError) {
+          setOperationError(e.errorDetail);
+        }
+        console.error(e);
+        throw Error("error trying to accept");
       }
-      console.error(e);
-      throw Error("error trying to accept");
     }
+
+    return {
+      status: "ready",
+      subject: {
+        error: !subject ? "cant be empty" : undefined,
+        value: subject,
+        onInput: async (e) => setSubject(e),
+      },
+      doSelectExchange: selectedExchange.doSelect,
+      invalid: !subject || Amounts.isZero(amount),
+      exchangeUrl: exchange.exchangeBaseUrl,
+      create: {
+        onClick: accept,
+      },
+      cancel: {
+        onClick: onClose,
+      },
+      chosenAmount: amount,
+      toBeReceived: amount,
+      error: undefined,
+      operationError,
+    };
   }
 
-  return {
-    status: "ready",
-    subject: {
-      error: !subject ? "cant be empty" : undefined,
-      value: subject,
-      onInput: async (e) => setSubject(e),
-    },
-    doSelectExchange: {
-      //FIX
-    },
-    invalid: !subject || Amounts.isZero(amount),
-    exchangeUrl: selected.exchangeBaseUrl,
-    create: {
-      onClick: accept,
-    },
-    cancel: {
-      onClick: onClose,
-    },
-    chosenAmount: amount,
-    toBeReceived: amount,
-    error: undefined,
-    operationError,
-  };
+
+
+
 }
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
index d38c27a2f..9de9c693a 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/index.ts
@@ -17,25 +17,25 @@
 import { AmountJson } from "@gnu-taler/taler-util";
 import { Loading } from "../../components/Loading.js";
 import { HookError } from "../../hooks/useAsyncAsHook.js";
+import {
+  State as SelectExchangeState
+} from "../../hooks/useSelectedExchange.js";
 import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
 import { compose, StateViewMap } from "../../utils/index.js";
 import * as wxApi from "../../wxApi.js";
 import { Props as TermsOfServiceSectionProps } from 
"../TermsOfServiceSection.js";
 import {
   useComponentStateFromParams,
-  useComponentStateFromURI,
+  useComponentStateFromURI
 } from "./state.js";
-import {
-  State as SelectExchangeState
-} from "../../hooks/useSelectedExchange.js";
 
+import { ExchangeSelectionPage } from 
"../../wallet/ExchangeSelection/index.js";
 import {
-  LoadingExchangeView,
   LoadingInfoView,
   LoadingUriView,
-  SuccessView,
+  SuccessView
 } from "./views.js";
-import { ExchangeSelectionPage } from 
"../../wallet/ExchangeSelection/index.js";
+import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
 
 export interface PropsFromURI {
   talerWithdrawUri: string | undefined;
@@ -52,8 +52,8 @@ export interface PropsFromParams {
 export type State =
   | State.Loading
   | State.LoadingUriError
-  | State.LoadingExchangeError
   | State.LoadingInfoError
+  | SelectExchangeState.NoExchange
   | SelectExchangeState.Selecting
   | State.Success;
 
@@ -66,10 +66,6 @@ export namespace State {
     status: "loading-error";
     error: HookError;
   }
-  export interface LoadingExchangeError {
-    status: "no-exchange";
-    error: undefined,
-  }
   export interface LoadingInfoError {
     status: "loading-info";
     error: HookError;
@@ -100,8 +96,8 @@ export namespace State {
 const viewMapping: StateViewMap<State> = {
   loading: Loading,
   "loading-error": LoadingUriView,
-  "no-exchange": LoadingExchangeView,
   "loading-info": LoadingInfoView,
+  "no-exchange": NoExchangesView,
   "selecting-exchange": ExchangeSelectionPage,
   success: SuccessView,
 };
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts 
b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
index 2e68d056e..5b5c11182 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/state.ts
@@ -36,8 +36,6 @@ export function useComponentStateFromParams(
     return { amount: Amounts.parseOrThrow(amount), exchanges };
   });
 
-  console.log("uri info", uriInfoHook)
-
   if (!uriInfoHook) return { status: "loading", error: undefined };
 
   if (uriInfoHook.hasError) {
@@ -80,7 +78,6 @@ export function useComponentStateFromURI(
     return { talerWithdrawUri, amount: Amounts.parseOrThrow(amount), 
thisExchange: defaultExchangeBaseUrl, exchanges };
   });
 
-  console.log("uri info", uriInfoHook)
   if (!uriInfoHook) return { status: "loading", error: undefined };
 
   if (uriInfoHook.hasError) {
@@ -111,20 +108,11 @@ type ManualOrManagedWithdrawFunction = (exchange: string, 
ageRestricted: number
 
 function exchangeSelectionState(doWithdraw: ManualOrManagedWithdrawFunction, 
cancel: () => Promise<void>, onSuccess: (txid: string) => Promise<void>, 
talerWithdrawUri: string | undefined, chosenAmount: AmountJson, exchangeList: 
ExchangeListItem[], defaultExchange: string | undefined, api: typeof wxApi,): 
RecursiveState<State> {
 
-  //FIXME: use substates here
   const selectedExchange = useSelectedExchange({ currency: 
chosenAmount.currency, defaultExchange, list: exchangeList })
 
-  if (selectedExchange.status === 'no-exchange') {
-    return {
-      status: "no-exchange",
-      error: undefined,
-    }
-  }
-
-  if (selectedExchange.status === 'selecting-exchange') {
+  if (selectedExchange.status !== 'ready') {
     return selectedExchange
   }
-  console.log("exchange selected", selectedExchange.selected)
 
   return () => {
 
@@ -142,7 +130,7 @@ function exchangeSelectionState(doWithdraw: 
ManualOrManagedWithdrawFunction, can
 
       return { state };
     }, []);
-    console.log("terms", terms)
+
     /**
      * With the exchange and amount, ask the wallet the information
      * about the withdrawal
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx 
b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
index 82d6090e5..1e8284739 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw/views.tsx
@@ -53,16 +53,6 @@ export function LoadingUriView({ error }: 
State.LoadingUriError): VNode {
   );
 }
 
-export function LoadingExchangeView(p: State.LoadingExchangeError): VNode {
-  const { i18n } = useTranslationContext();
-
-  return (
-    <ErrorMessage 
-      title={<i18n.Translate>Could not get a default exchange, please check 
configuration</i18n.Translate>}
-    />
-  );
-}
-
 export function LoadingInfoView({ error }: State.LoadingInfoError): VNode {
   const { i18n } = useTranslationContext();
 
diff --git 
a/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts 
b/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts
index d9085153e..7219c30d2 100644
--- a/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useSelectedExchange.ts
@@ -24,6 +24,7 @@ export namespace State {
   export interface NoExchange {
     status: "no-exchange"
     error: undefined;
+    currency: string | undefined;
   }
   export interface Ready {
     status: "ready",
@@ -59,25 +60,27 @@ export function useSelectedExchange({ currency, 
defaultExchange, list }: Props):
     return {
       status: "no-exchange",
       error: undefined,
+      currency: undefined,
     }
   }
 
-  const firstByCurrency = list.find((e) => e.currency === currency)
-  if (!firstByCurrency) {
+  const listCurrency = list.filter((e) => e.currency === currency)
+  if (!listCurrency.length) {
     // there should be at least one exchange for this currency
     return {
       status: "no-exchange",
       error: undefined,
+      currency,
     }
   }
 
 
   if (isSelecting) {
-    const currentExchange = selectedExchange ?? defaultExchange ?? 
firstByCurrency.exchangeBaseUrl;
+    const currentExchange = selectedExchange ?? defaultExchange ?? 
listCurrency[0].exchangeBaseUrl;
     return {
       status: "selecting-exchange",
       error: undefined,
-      list,
+      list: listCurrency,
       currency,
       currentExchange: currentExchange,
       onSelection: async (exchangeBaseUrl: string) => {
@@ -120,6 +123,6 @@ export function useSelectedExchange({ currency, 
defaultExchange, list }: Props):
     doSelect: {
       onClick: async () => setIsSelecting(true)
     },
-    selected: firstByCurrency
+    selected: listCurrency[0]
   }
 }
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
index 2834028c6..4b28904fb 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/index.ts
@@ -41,13 +41,16 @@ export interface Props {
   onCancel: () => Promise<void>;
   onSelection: (exchange: string) => Promise<void>;
 }
+import {
+  State as SelectExchangeState
+} from "../../hooks/useSelectedExchange.js";
 
 export type State =
   | State.Loading
   | State.LoadingUriError
   | State.Ready
   | State.Comparing
-  | State.NoExchanges;
+  | SelectExchangeState.NoExchange;
 
 export namespace State {
   export interface Loading {
@@ -66,11 +69,6 @@ export namespace State {
     error: undefined;
   }
 
-  export interface NoExchanges {
-    status: "no-exchanges";
-    error: undefined;
-  }
-
   export interface Ready extends BaseInfo {
     status: "ready";
     timeline: OperationMap<FeeDescription[]>;
@@ -89,7 +87,7 @@ const viewMapping: StateViewMap<State> = {
   loading: Loading,
   "error-loading": ErrorLoadingView,
   comparing: ComparingView,
-  "no-exchanges": NoExchangesView,
+  "no-exchange": NoExchangesView,
   ready: ReadyView,
 };
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
index db6138f8e..0279f6514 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/state.ts
@@ -47,7 +47,7 @@ export function useComponentState(
       ? undefined
       : await api.getExchangeDetailedInfo(initialExchange.exchangeBaseUrl);
     return { exchanges, selected, original };
-  });
+  }, [value]);
 
   if (!hook) {
     return {
@@ -67,13 +67,14 @@ export function useComponentState(
   if (!selected) {
     //!selected <=> exchanges.length === 0
     return {
-      status: "no-exchanges",
+      status: "no-exchange",
       error: undefined,
+      currency: undefined,
     };
   }
 
   const exchangeMap = exchanges.reduce(
-    (prev, cur, idx) => ({ ...prev, [cur.exchangeBaseUrl]: String(idx) }),
+    (prev, cur, idx) => ({ ...prev, [String(idx)]: cur.exchangeBaseUrl }),
     {} as Record<string, string>,
   );
 
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx 
b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
index dd85dff46..47554bfcd 100644
--- a/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ExchangeSelection/views.tsx
@@ -31,6 +31,9 @@ import { useTranslationContext } from 
"../../context/translation.js";
 import { Button } from "../../mui/Button.js";
 import arrowDown from "../../svg/chevron-down.svg";
 import { State } from "./index.js";
+import {
+  State as SelectExchangeState
+} from "../../hooks/useSelectedExchange.js";
 
 const ButtonGroup = styled.div`
   & > button {
@@ -112,11 +115,20 @@ export function ErrorLoadingView({ error }: 
State.LoadingUriError): VNode {
   );
 }
 
-export function NoExchangesView(state: State.NoExchanges): VNode {
+
+
+export function NoExchangesView({currency}: SelectExchangeState.NoExchange): 
VNode {
   const { i18n } = useTranslationContext();
+  if (!currency) {
+    return (
+      <div>
+        <i18n.Translate>could not find any exchange</i18n.Translate>
+      </div>
+    );  
+  }
   return (
     <div>
-      <i18n.Translate>no exchanges</i18n.Translate>
+      <i18n.Translate>could not find any exchange for the currency 
{currency}</i18n.Translate>
     </div>
   );
 }

-- 
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]