gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: fix #8735


From: gnunet
Subject: [taler-wallet-core] branch master updated: fix #8735
Date: Tue, 16 Apr 2024 18:04:36 +0200

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

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

The following commit(s) were added to refs/heads/master by this push:
     new 80fee4ee6 fix #8735
80fee4ee6 is described below

commit 80fee4ee613ccfcbf951636eaac7ef61957d312d
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue Apr 16 13:04:31 2024 -0300

    fix #8735
---
 packages/taler-wallet-core/src/wallet.ts           |   6 +-
 .../src/NavigationBar.tsx                          |  33 ++-
 .../src/svg/search_24px.inline.svg                 |   4 +
 .../src/wallet/Application.tsx                     |  43 +++-
 .../src/wallet/History.stories.tsx                 | 257 +++++++++++----------
 .../src/wallet/History.tsx                         | 151 +++++++++---
 6 files changed, 324 insertions(+), 170 deletions(-)

diff --git a/packages/taler-wallet-core/src/wallet.ts 
b/packages/taler-wallet-core/src/wallet.ts
index fb5a93693..d1234d39f 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -1468,7 +1468,7 @@ export function getObservedWalletExecutionContext(
   ws: InternalWalletState,
   cancellationToken: CancellationToken,
   oc: ObservabilityContext,
-) {
+): WalletExecutionContext {
   const wex: WalletExecutionContext = {
     ws,
     cancellationToken,
@@ -1485,7 +1485,7 @@ export function getNormalWalletExecutionContext(
   ws: InternalWalletState,
   cancellationToken: CancellationToken,
   oc: ObservabilityContext,
-) {
+): WalletExecutionContext {
   const wex: WalletExecutionContext = {
     ws,
     cancellationToken,
@@ -1893,7 +1893,7 @@ export class InternalWalletState {
     } finally {
       for (const token of tokens) {
         this.resourceLocks.delete(token);
-        let waiter = (this.resourceWaiters[token] ?? []).shift();
+        const waiter = (this.resourceWaiters[token] ?? []).shift();
         if (waiter) {
           waiter.resolve();
         }
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx 
b/packages/taler-wallet-webextension/src/NavigationBar.tsx
index 527600c96..fe348f7fb 100644
--- a/packages/taler-wallet-webextension/src/NavigationBar.tsx
+++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx
@@ -34,6 +34,7 @@ import {
 } from "./components/styled/index.js";
 import { useBackendContext } from "./context/backend.js";
 import { useAsyncAsHook } from "./hooks/useAsyncAsHook.js";
+import searchIcon from "./svg/search_24px.inline.svg";
 import qrIcon from "./svg/qr_code_24px.inline.svg";
 import settingsIcon from "./svg/settings_black_24dp.inline.svg";
 import warningIcon from "./svg/warning_24px.inline.svg";
@@ -55,7 +56,7 @@ type PageLocation<DynamicPart extends object> = {
 function replaceAll(
   pattern: string,
   vars: Record<string, string>,
-  values: Record<string, any>,
+  values: Record<string, string>,
 ): string {
   let result = pattern;
   for (const v in vars) {
@@ -75,16 +76,20 @@ function pageDefinition<T extends object>(pattern: string): 
PageLocation<T> {
       `page definition pattern ${pattern} doesn't have any parameter`,
     );
 
-  const vars = patternParams.reduce((prev, cur) => {
-    const pName = cur.match(/(\w+)/g);
+  const vars = patternParams.reduce(
+    (prev, cur) => {
+      const pName = cur.match(/(\w+)/g);
 
-    //skip things like :? in the path pattern
-    if (!pName || !pName[0]) return prev;
-    const name = pName[0];
-    return { ...prev, [name]: cur };
-  }, {} as Record<string, string>);
+      //skip things like :? in the path pattern
+      if (!pName || !pName[0]) return prev;
+      const name = pName[0];
+      return { ...prev, [name]: cur };
+    },
+    {} as Record<string, string>,
+  );
 
-  const f = (values: T): string => replaceAll(pattern, vars, values ?? {});
+  const f = (values: T): string =>
+    replaceAll(pattern, vars, (values ?? {}) as Record<string, string>);
   f.pattern = pattern;
   return f;
 }
@@ -95,6 +100,9 @@ export const Pages = {
   balanceHistory: pageDefinition<{ currency?: string }>(
     "/balance/history/:currency?",
   ),
+  searchHistory: pageDefinition<{ currency?: string }>(
+    "/search/history/:currency?",
+  ),
   balanceDeposit: pageDefinition<{ amount: string }>(
     "/balance/deposit/:amount",
   ),
@@ -268,6 +276,13 @@ export function WalletNavBar({ path }: { path?: 
WalletNavBarOptions }): VNode {
         <div
           style={{ display: "flex", paddingTop: 4, justifyContent: "right" }}
         >
+          <a href={Pages.searchHistory({})}>
+            <SvgIcon
+              title={i18n.str`Search transactions`}
+              dangerouslySetInnerHTML={{ __html: searchIcon }}
+              color="white"
+            />
+          </a>
           <a href={Pages.qr}>
             <SvgIcon
               title={i18n.str`QR Reader and Taler URI`}
diff --git a/packages/taler-wallet-webextension/src/svg/search_24px.inline.svg 
b/packages/taler-wallet-webextension/src/svg/search_24px.inline.svg
new file mode 100644
index 000000000..d880cbf0f
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/svg/search_24px.inline.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg"; enable-background="new 0 0 24 24" 
viewBox="0 0 24 24" height="24"  width="24">
+  <path fill-rule="evenodd" d="M10.5 3.75a6.75 6.75 0 1 0 0 13.5 6.75 6.75 0 0 
0 0-13.5ZM2.25 10.5a8.25 8.25 0 1 1 14.59 5.28l4.69 4.69a.75.75 0 1 1-1.06 
1.06l-4.69-4.69A8.25 8.25 0 0 1 2.25 10.5Z" clip-rule="evenodd" />
+</svg>
+
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx 
b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index 5c31701e2..884c2eab7 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -157,7 +157,7 @@ export function Application(): VNode {
             )}
           />
 
-          <Route
+<Route
             path={Pages.balanceHistory.pattern}
             component={({ currency }: { currency?: string }) => (
               <WalletTemplate path="balance" 
goToTransaction={redirectToTxInfo} goToURL={redirectToURL}>
@@ -177,6 +177,27 @@ export function Application(): VNode {
               </WalletTemplate>
             )}
           />
+          <Route
+            path={Pages.searchHistory.pattern}
+            component={({ currency }: { currency?: string }) => (
+              <WalletTemplate path="balance" 
goToTransaction={redirectToTxInfo} goToURL={redirectToURL}>
+                <HistoryPage
+                  currency={currency}
+                  search
+                  goToWalletDeposit={(currency: string) =>
+                    redirectTo(Pages.sendCash({ amount: `${currency}:0` }))
+                  }
+                  goToWalletManualWithdraw={(currency?: string) =>
+                    redirectTo(
+                      Pages.receiveCash({
+                        amount: !currency ? undefined : `${currency}:0`,
+                      }),
+                    )
+                  }
+                />
+              </WalletTemplate>
+            )}
+          />
           <Route
             path={Pages.sendCash.pattern}
             component={({ amount }: { amount?: string }) => (
@@ -568,17 +589,17 @@ function Redirect({ to }: { to: string }): null {
   return null;
 }
 
-function matchesRoute(url: string, route: string): boolean {
-  type MatcherFunc = (
-    url: string,
-    route: string,
-    opts: any,
-  ) => Record<string, string> | false;
+// function matchesRoute(url: string, route: string): boolean {
+//   type MatcherFunc = (
+//     url: string,
+//     route: string,
+//     opts: any,
+//   ) => Record<string, string> | false;
 
-  const internalPreactMatcher: MatcherFunc = (Router as any).exec;
-  const result = internalPreactMatcher(url, route, {});
-  return !result ? false : true;
-}
+//   const internalPreactMatcher: MatcherFunc = (Router as any).exec;
+//   const result = internalPreactMatcher(url, route, {});
+//   return !result ? false : true;
+// }
 
 function CallToActionTemplate({
   title,
diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
index c28e4188f..482b8d698 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
@@ -49,17 +49,17 @@ export default {
 
 let count = 0;
 const commonTransaction = (): TransactionCommon =>
-({
-  amountRaw: "USD:10",
-  amountEffective: "USD:9",
-  txState: {
-    major: TransactionMajorState.Done,
-  },
-  timestamp: TalerProtocolTimestamp.fromSeconds(
-    new Date().getTime() / 1000 - count++ * 60 * 60 * 7,
-  ),
-  transactionId: String(count),
-} as TransactionCommon);
+  ({
+    amountRaw: "USD:10",
+    amountEffective: "USD:9",
+    txState: {
+      major: TransactionMajorState.Done,
+    },
+    timestamp: TalerProtocolTimestamp.fromSeconds(
+      new Date().getTime() / 1000 - count++ * 60 * 60 * 7,
+    ),
+    transactionId: String(count),
+  }) as TransactionCommon;
 
 const exampleData = {
   withdraw: {
@@ -165,7 +165,9 @@ const exampleData = {
 export const SomeBalanceWithNoTransactions = tests.createExample(
   TestedComponent,
   {
-    transactions: [],
+    transactionsByDate: {
+      "11/11/11": [],
+    },
     balances: [
       {
         available: "TESTKUDOS:10" as AmountString,
@@ -186,7 +188,9 @@ export const SomeBalanceWithNoTransactions = 
tests.createExample(
 );
 
 export const OneSimpleTransaction = tests.createExample(TestedComponent, {
-  transactions: [exampleData.withdraw],
+  transactionsByDate: {
+    "11/11/11": [exampleData.withdraw],
+  },
   balances: [
     {
       flags: [],
@@ -203,13 +207,14 @@ export const OneSimpleTransaction = 
tests.createExample(TestedComponent, {
     },
   ],
   balanceIndex: 0,
-
 });
 
 export const TwoTransactionsAndZeroBalance = tests.createExample(
   TestedComponent,
   {
-    transactions: [exampleData.withdraw, exampleData.deposit],
+    transactionsByDate: {
+      "11/11/11": [exampleData.withdraw, exampleData.deposit],
+    },
     balances: [
       {
         flags: [],
@@ -230,14 +235,16 @@ export const TwoTransactionsAndZeroBalance = 
tests.createExample(
 );
 
 export const OneTransactionPending = tests.createExample(TestedComponent, {
-  transactions: [
-    {
-      ...exampleData.withdraw,
-      txState: {
-        major: TransactionMajorState.Pending,
+  transactionsByDate: {
+    "11/11/11": [
+      {
+        ...exampleData.withdraw,
+        txState: {
+          major: TransactionMajorState.Pending,
+        },
       },
-    },
-  ],
+    ],
+  },
   balances: [
     {
       flags: [],
@@ -257,22 +264,24 @@ export const OneTransactionPending = 
tests.createExample(TestedComponent, {
 });
 
 export const SomeTransactions = tests.createExample(TestedComponent, {
-  transactions: [
-    exampleData.withdraw,
-    exampleData.payment,
-    exampleData.withdraw,
-    exampleData.payment,
-    {
-      ...exampleData.payment,
-      info: {
-        ...exampleData.payment.info,
-        summary:
-          "this is a long summary that may be cropped because its too long",
+  transactionsByDate: {
+    "11/11/11": [
+      exampleData.withdraw,
+      exampleData.payment,
+      exampleData.withdraw,
+      exampleData.payment,
+      {
+        ...exampleData.payment,
+        info: {
+          ...exampleData.payment.info,
+          summary:
+            "this is a long summary that may be cropped because its too long",
+        },
       },
-    },
-    exampleData.refund,
-    exampleData.deposit,
-  ],
+      exampleData.refund,
+      exampleData.deposit,
+    ],
+  },
   balances: [
     {
       flags: [],
@@ -294,79 +303,81 @@ export const SomeTransactions = 
tests.createExample(TestedComponent, {
 export const SomeTransactionsInDifferentStates = tests.createExample(
   TestedComponent,
   {
-    transactions: [
-      exampleData.withdraw,
-      {
-        ...exampleData.withdraw,
-        exchangeBaseUrl: "https://aborted/withdrawal";,
-        txState: {
-          major: TransactionMajorState.Aborted,
+    transactionsByDate: {
+      "11/11/11": [
+        exampleData.withdraw,
+        {
+          ...exampleData.withdraw,
+          exchangeBaseUrl: "https://aborted/withdrawal";,
+          txState: {
+            major: TransactionMajorState.Aborted,
+          },
         },
-      },
-      {
-        ...exampleData.withdraw,
-        exchangeBaseUrl: "https://pending/withdrawal";,
-        txState: {
-          major: TransactionMajorState.Pending,
+        {
+          ...exampleData.withdraw,
+          exchangeBaseUrl: "https://pending/withdrawal";,
+          txState: {
+            major: TransactionMajorState.Pending,
+          },
         },
-      },
-      {
-        ...exampleData.withdraw,
-        exchangeBaseUrl: "https://failed/withdrawal";,
-        txState: {
-          major: TransactionMajorState.Failed,
+        {
+          ...exampleData.withdraw,
+          exchangeBaseUrl: "https://failed/withdrawal";,
+          txState: {
+            major: TransactionMajorState.Failed,
+          },
         },
-      },
-      {
-        ...exampleData.payment,
-        info: {
-          ...exampleData.payment.info,
-          summary: "normal payment",
-        },
-      },
-      {
-        ...exampleData.payment,
-        info: {
-          ...exampleData.payment.info,
-          summary: "aborting in progress",
-        },
-        txState: {
-          major: TransactionMajorState.Aborting,
-        },
-      },
-      {
-        ...exampleData.payment,
-        info: {
-          ...exampleData.payment.info,
-          summary: "aborted payment",
+        {
+          ...exampleData.payment,
+          info: {
+            ...exampleData.payment.info,
+            summary: "normal payment",
+          },
         },
-        txState: {
-          major: TransactionMajorState.Aborted,
-        },
-      },
-      {
-        ...exampleData.payment,
-        info: {
-          ...exampleData.payment.info,
-          summary: "pending payment",
+        {
+          ...exampleData.payment,
+          info: {
+            ...exampleData.payment.info,
+            summary: "aborting in progress",
+          },
+          txState: {
+            major: TransactionMajorState.Aborting,
+          },
         },
-        txState: {
-          major: TransactionMajorState.Pending,
+        {
+          ...exampleData.payment,
+          info: {
+            ...exampleData.payment.info,
+            summary: "aborted payment",
+          },
+          txState: {
+            major: TransactionMajorState.Aborted,
+          },
         },
-      },
-      {
-        ...exampleData.payment,
-        info: {
-          ...exampleData.payment.info,
-          summary: "failed payment",
+        {
+          ...exampleData.payment,
+          info: {
+            ...exampleData.payment.info,
+            summary: "pending payment",
+          },
+          txState: {
+            major: TransactionMajorState.Pending,
+          },
         },
-        txState: {
-          major: TransactionMajorState.Failed,
+        {
+          ...exampleData.payment,
+          info: {
+            ...exampleData.payment.info,
+            summary: "failed payment",
+          },
+          txState: {
+            major: TransactionMajorState.Failed,
+          },
         },
-      },
-      exampleData.refund,
-      exampleData.deposit,
-    ],
+        exampleData.refund,
+        exampleData.deposit,
+      ],
+    },
     balances: [
       {
         flags: [],
@@ -389,15 +400,17 @@ export const SomeTransactionsInDifferentStates = 
tests.createExample(
 export const SomeTransactionsWithTwoCurrencies = tests.createExample(
   TestedComponent,
   {
-    transactions: [
-      exampleData.withdraw,
-      exampleData.payment,
-      exampleData.withdraw,
-      exampleData.payment,
-      exampleData.refresh,
-      exampleData.refund,
-      exampleData.deposit,
-    ],
+    transactionsByDate: {
+      "11/11/11": [
+        exampleData.withdraw,
+        exampleData.payment,
+        exampleData.withdraw,
+        exampleData.payment,
+        exampleData.refresh,
+        exampleData.refund,
+        exampleData.deposit,
+      ],
+    },
     balances: [
       {
         flags: [],
@@ -431,7 +444,9 @@ export const SomeTransactionsWithTwoCurrencies = 
tests.createExample(
 );
 
 export const FiveOfficialCurrencies = tests.createExample(TestedComponent, {
-  transactions: [exampleData.withdraw],
+  transactionsByDate: {
+    "11/11/11": [exampleData.withdraw],
+  },
   balances: [
     {
       flags: [],
@@ -505,7 +520,9 @@ export const FiveOfficialCurrencies = 
tests.createExample(TestedComponent, {
 export const FiveOfficialCurrenciesWithHighValue = tests.createExample(
   TestedComponent,
   {
-    transactions: [exampleData.withdraw],
+    transactionsByDate: {
+      "11/11/11": [exampleData.withdraw],
+    },
     balances: [
       {
         flags: [],
@@ -578,12 +595,14 @@ export const FiveOfficialCurrenciesWithHighValue = 
tests.createExample(
 );
 
 export const PeerToPeer = tests.createExample(TestedComponent, {
-  transactions: [
-    exampleData.pull_credit,
-    exampleData.pull_debit,
-    exampleData.push_credit,
-    exampleData.push_debit,
-  ],
+  transactionsByDate: {
+    "11/11/11": [
+      exampleData.pull_credit,
+      exampleData.pull_debit,
+      exampleData.push_credit,
+      exampleData.push_debit,
+    ],
+  },
   balances: [
     {
       flags: [],
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx 
b/packages/taler-wallet-webextension/src/wallet/History.tsx
index fcd21a5ee..6006ce5e7 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -35,7 +35,7 @@ import {
   CenteredBoldText,
   CenteredText,
   DateSeparator,
-  NiceSelect
+  NiceSelect,
 } from "../components/styled/index.js";
 import { alertFromError, useAlertContext } from "../context/alert.js";
 import { useBackendContext } from "../context/backend.js";
@@ -45,32 +45,39 @@ import { Button } from "../mui/Button.js";
 import { NoBalanceHelp } from "../popup/NoBalanceHelp.js";
 import DownloadIcon from "../svg/download_24px.inline.svg";
 import UploadIcon from "../svg/upload_24px.inline.svg";
+import { TextField } from "../mui/TextField.js";
+import { TextFieldHandler } from "../mui/handlers.js";
 
 interface Props {
   currency?: string;
+  search?: boolean;
   goToWalletDeposit: (currency: string) => Promise<void>;
   goToWalletManualWithdraw: (currency?: string) => Promise<void>;
 }
 export function HistoryPage({
   currency: _c,
+  search: showSearch,
   goToWalletManualWithdraw,
   goToWalletDeposit,
 }: Props): VNode {
   const { i18n } = useTranslationContext();
   const api = useBackendContext();
   const [balanceIndex, setBalanceIndex] = useState<number>(0);
+  const [search, setSearch] = useState<string>();
+
   const [settings] = useSettings();
   const state = useAsyncAsHook(async () => {
     const b = await api.wallet.call(WalletApiOperation.GetBalances, {});
     const balance =
       b.balances.length > 0 ? b.balances[balanceIndex] : undefined;
     const tx = await api.wallet.call(WalletApiOperation.GetTransactions, {
-      scopeInfo: balance?.scopeInfo,
+      scopeInfo: showSearch ? undefined : balance?.scopeInfo,
       sort: "descending",
       includeRefreshes: settings.showRefeshTransactions,
+      search,
     });
     return { b, tx };
-  }, [balanceIndex]);
+  }, [balanceIndex, search]);
 
   useEffect(() => {
     return api.listener.onUpdateNotification(
@@ -105,6 +112,41 @@ export function HistoryPage({
       />
     );
   }
+
+  const byDate = state.response.tx.transactions.reduce(
+    (rv, x) => {
+      const startDay =
+        x.timestamp.t_s === "never"
+          ? 0
+          : startOfDay(x.timestamp.t_s * 1000).getTime();
+      if (startDay) {
+        if (!rv[startDay]) {
+          rv[startDay] = [];
+          // datesWithTransaction.push(String(startDay));
+        }
+        rv[startDay].push(x);
+      }
+
+      return rv;
+    },
+    {} as { [x: string]: Transaction[] },
+  );
+
+  if (showSearch) {
+    return (
+      <FilteredHistoryView
+        balance={state.response.b.balances[balanceIndex]}
+        search={{
+          value: search ?? "",
+          onInput: pushAlertOnError(async (d: string) => {
+            setSearch(d);
+          }),
+        }}
+        transactionsByDate={byDate}
+      />
+    );
+  }
+
   return (
     <HistoryView
       balanceIndex={balanceIndex}
@@ -112,7 +154,7 @@ export function HistoryPage({
       balances={state.response.b.balances}
       goToWalletManualWithdraw={goToWalletManualWithdraw}
       goToWalletDeposit={goToWalletDeposit}
-      transactions={state.response.tx.transactions}
+      transactionsByDate={byDate}
     />
   );
 }
@@ -121,7 +163,7 @@ export function HistoryView({
   balances,
   balanceIndex,
   changeBalanceIndex,
-  transactions,
+  transactionsByDate,
   goToWalletManualWithdraw,
   goToWalletDeposit,
 }: {
@@ -129,7 +171,7 @@ export function HistoryView({
   changeBalanceIndex: (s: number) => void;
   goToWalletDeposit: (currency: string) => Promise<void>;
   goToWalletManualWithdraw: (currency?: string) => Promise<void>;
-  transactions: Transaction[];
+  transactionsByDate: Record<string, Transaction[]>;
   balances: WalletBalance[];
 }): VNode {
   const { i18n } = useTranslationContext();
@@ -140,25 +182,7 @@ export function HistoryView({
     ? Amounts.jsonifyAmount(balance.available)
     : undefined;
 
-  const datesWithTransaction: string[] = [];
-  const byDate = transactions.reduce(
-    (rv, x) => {
-      const startDay =
-        x.timestamp.t_s === "never"
-          ? 0
-          : startOfDay(x.timestamp.t_s * 1000).getTime();
-      if (startDay) {
-        if (!rv[startDay]) {
-          rv[startDay] = [];
-          datesWithTransaction.push(String(startDay));
-        }
-        rv[startDay].push(x);
-      }
-
-      return rv;
-    },
-    {} as { [x: string]: Transaction[] },
-  );
+  const datesWithTransaction: string[] = Object.keys(transactionsByDate);
 
   return (
     <Fragment>
@@ -195,8 +219,8 @@ export function HistoryView({
               </Button>
             )}
           </div>
-          <div style={{display:"flex", flexDirection:"column"}}>
-            <h3 style={{marginBottom: 0}}>Balance</h3>
+          <div style={{ display: "flex", flexDirection: "column" }}>
+            <h3 style={{ marginBottom: 0 }}>Balance</h3>
             <div
               style={{
                 width: "fit-content",
@@ -270,7 +294,78 @@ export function HistoryView({
                     format="dd MMMM yyyy"
                   />
                 </DateSeparator>
-                {byDate[d].map((tx, i) => (
+                {transactionsByDate[d].map((tx, i) => (
+                  <HistoryItem key={i} tx={tx} />
+                ))}
+              </Fragment>
+            );
+          })}
+        </section>
+      )}
+    </Fragment>
+  );
+}
+
+export function FilteredHistoryView({
+  balance,
+  search,
+  transactionsByDate,
+}: {
+  balance: WalletBalance;
+  search: TextFieldHandler;
+  transactionsByDate: Record<string, Transaction[]>;
+}): VNode {
+  const { i18n } = useTranslationContext();
+
+  const available = balance
+    ? Amounts.jsonifyAmount(balance.available)
+    : undefined;
+
+  const datesWithTransaction: string[] = Object.keys(transactionsByDate);
+
+  return (
+    <Fragment>
+      <section>
+        <div
+          style={{
+            display: "flex",
+            flexWrap: "wrap",
+            alignItems: "center",
+            justifyContent: "space-between",
+            marginRight: 20,
+          }}
+        >
+          <TextField
+            label="Search"
+            variant="filled"
+            error={search.error}
+            required
+            fullWidth
+            value={search.value}
+            onChange={search.onInput}
+          />
+        </div>
+      </section>
+      {datesWithTransaction.length === 0 ? (
+        <section>
+          <i18n.Translate>
+            Your transaction history is empty for this currency.
+          </i18n.Translate>
+        </section>
+      ) : (
+        <section>
+          {datesWithTransaction.map((d, i) => {
+            return (
+              <Fragment key={i}>
+                <DateSeparator>
+                  <Time
+                    timestamp={AbsoluteTime.fromMilliseconds(
+                      Number.parseInt(d, 10),
+                    )}
+                    format="dd MMMM yyyy"
+                  />
+                </DateSeparator>
+                {transactionsByDate[d].map((tx, i) => (
                   <HistoryItem key={i} tx={tx} />
                 ))}
               </Fragment>

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