gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated (7f3ce304 -> 6a294361)


From: gnunet
Subject: [taler-wallet-core] branch master updated (7f3ce304 -> 6a294361)
Date: Mon, 21 Jun 2021 01:52:49 +0200

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

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

    from 7f3ce304 missing globalThis Polyfill, remove duplicate url util
     new 956fc35a wallet transaction detail view
     new 6a294361 fix height, wallet popup should stay at 400x320

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../.storybook/preview.js                          |   5 +-
 packages/taler-wallet-webextension/package.json    |   1 +
 .../taler-wallet-webextension/rollup.config.js     |   2 +
 .../{.storybook/.babelrc => src/custom.d.ts}       |  23 +-
 .../src/popup/History.stories.tsx                  | 256 +++++++++++++++++
 .../src/popup/History.tsx                          |  34 ++-
 .../src/popup/Transaction.stories.tsx              |  76 +++--
 .../src/popup/Transaction.tsx                      | 308 ++++++++-------------
 .../src/popupEntryPoint.tsx                        |   2 +-
 .../taler-wallet-webextension/static/img/empty.png | Bin 0 -> 2785 bytes
 .../static/style/popup.css                         |  33 ++-
 pnpm-lock.yaml                                     |  18 ++
 12 files changed, 516 insertions(+), 242 deletions(-)
 copy packages/taler-wallet-webextension/{.storybook/.babelrc => 
src/custom.d.ts} (75%)
 create mode 100644 
packages/taler-wallet-webextension/src/popup/History.stories.tsx
 create mode 100644 packages/taler-wallet-webextension/static/img/empty.png

diff --git a/packages/taler-wallet-webextension/.storybook/preview.js 
b/packages/taler-wallet-webextension/.storybook/preview.js
index e669398d..6a7c8e86 100644
--- a/packages/taler-wallet-webextension/.storybook/preview.js
+++ b/packages/taler-wallet-webextension/.storybook/preview.js
@@ -15,7 +15,10 @@
  */
 
 import { setupI18n } from "@gnu-taler/taler-util"
-import { strings } from '../src/i18n'
+import { strings } from '../src/i18n/strings.ts'
+import '../static/style/pure.css'
+import '../static/style/popup.css'
+import '../static/style/wallet.css'
 
 const mockConfig = {
   backendURL: 'http://demo.taler.net',
diff --git a/packages/taler-wallet-webextension/package.json 
b/packages/taler-wallet-webextension/package.json
index 60a2ea5d..206ce8c1 100644
--- a/packages/taler-wallet-webextension/package.json
+++ b/packages/taler-wallet-webextension/package.json
@@ -28,6 +28,7 @@
     "@babel/plugin-transform-react-jsx-source": "^7.12.13",
     "@babel/preset-typescript": "^7.13.0",
     "@rollup/plugin-commonjs": "^17.0.0",
+    "@rollup/plugin-image": "^2.0.6",
     "@rollup/plugin-json": "^4.1.0",
     "@rollup/plugin-node-resolve": "^11.1.0",
     "@rollup/plugin-replace": "^2.3.4",
diff --git a/packages/taler-wallet-webextension/rollup.config.js 
b/packages/taler-wallet-webextension/rollup.config.js
index c5bb936c..80b4f6ee 100644
--- a/packages/taler-wallet-webextension/rollup.config.js
+++ b/packages/taler-wallet-webextension/rollup.config.js
@@ -5,6 +5,7 @@ import json from "@rollup/plugin-json";
 import builtins from "builtin-modules";
 import replace from "@rollup/plugin-replace";
 import ignore from "rollup-plugin-ignore"
+import image from '@rollup/plugin-image';
 
 const makePlugins = () => [
     ignore(["module", "os"]),
@@ -29,6 +30,7 @@ const makePlugins = () => [
     }),
 
     json(),
+    image(),
 ];
 
 
diff --git a/packages/taler-wallet-webextension/.storybook/.babelrc 
b/packages/taler-wallet-webextension/src/custom.d.ts
similarity index 75%
copy from packages/taler-wallet-webextension/.storybook/.babelrc
copy to packages/taler-wallet-webextension/src/custom.d.ts
index 39829d50..1981067d 100644
--- a/packages/taler-wallet-webextension/.storybook/.babelrc
+++ b/packages/taler-wallet-webextension/src/custom.d.ts
@@ -13,14 +13,15 @@
  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)
- */
-{
-    //FIXME: check if we can remove this preset and just use default storybook 
presets
-    "presets": [
-        "preact-cli/babel"
-    ]
-}
\ No newline at end of file
+declare module "*.jpeg" {
+  const content: any;
+  export default content;
+}
+declare module "*.png" {
+  const content: any;
+  export default content;
+}
+declare module '*.svg' {
+  const content: any;
+  export default content;
+}
diff --git a/packages/taler-wallet-webextension/src/popup/History.stories.tsx 
b/packages/taler-wallet-webextension/src/popup/History.stories.tsx
new file mode 100644
index 00000000..a73b7ea3
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/popup/History.stories.tsx
@@ -0,0 +1,256 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 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 {
+  PaymentStatus,
+  TransactionCommon, TransactionDeposit, TransactionPayment,
+  TransactionRefresh, TransactionRefund, TransactionTip, TransactionType,
+  TransactionWithdrawal,
+  WithdrawalType
+} from '@gnu-taler/taler-util';
+import { FunctionalComponent } from 'preact';
+import { HistoryView as TestedComponent } from './History';
+
+export default {
+  title: 'popup/transaction/list',
+  component: TestedComponent,
+  decorators: [
+    (Story: any) => <div>
+      <link key="1" rel="stylesheet" type="text/css" href="/style/pure.css" />
+      <link key="2" rel="stylesheet" type="text/css" href="/style/popup.css" />
+      <link key="3" rel="stylesheet" type="text/css" href="/style/wallet.css" 
/>
+      <div style={{ margin: "1em", width: 400, display: 'flex', padding: 
'0.5em', height: 'calc(20rem - 34px)', border: 'black solid 1px' }}>
+        <Story />
+      </div>
+    </div>
+  ],
+};
+
+const commonTransaction = {
+  amountRaw: 'USD:10',
+  amountEffective: 'USD:9',
+  pending: false,
+  timestamp: {
+    t_ms: new Date().getTime()
+  },
+  transactionId: '12',
+} as TransactionCommon
+
+const exampleData = {
+  withdraw: {
+    ...commonTransaction,
+    type: TransactionType.Withdrawal,
+    exchangeBaseUrl: 'http://exchange.taler',
+    withdrawalDetails: {
+      confirmed: false,
+      exchangePaytoUris: ['payto://x-taler-bank/bank/account'],
+      type: WithdrawalType.ManualTransfer,
+    }
+  } as TransactionWithdrawal,
+  payment: {
+    ...commonTransaction,
+    amountEffective: 'USD:11',
+    type: TransactionType.Payment,
+    info: {
+      contractTermsHash: 'ASDZXCASD',
+      merchant: {
+        name: 'the merchant',
+      },
+      orderId: '2021.167-03NPY6MCYMVGT',
+      products: [],
+      summary: 'the summary',
+      fulfillmentMessage: '',
+    },
+    proposalId: '1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+    status: PaymentStatus.Accepted,
+  } as TransactionPayment,
+  deposit: {
+    ...commonTransaction,
+    type: TransactionType.Deposit,
+    depositGroupId: '#groupId',
+    targetPaytoUri: 'payto://x-taler-bank/bank/account',
+  } as TransactionDeposit,
+  refresh: {
+    ...commonTransaction,
+    type: TransactionType.Refresh,
+    exchangeBaseUrl: 'http://exchange.taler',
+  } as TransactionRefresh,
+  tip: {
+    ...commonTransaction,
+    type: TransactionType.Tip,
+    merchantBaseUrl: 'http://merchant.taler',
+  } as TransactionTip,
+  refund: {
+    ...commonTransaction,
+    type: TransactionType.Refund,
+    refundedTransactionId: 
'payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+    info: {
+      contractTermsHash: 'ASDZXCASD',
+      merchant: {
+        name: 'the merchant',
+      },
+      orderId: '2021.167-03NPY6MCYMVGT',
+      products: [],
+      summary: 'the summary',
+      fulfillmentMessage: '',
+    },
+  } as TransactionRefund,
+}
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const Empty = createExample(TestedComponent, {
+  list: []
+});
+
+
+export const One = createExample(TestedComponent, {
+  list: [exampleData.withdraw]
+});
+
+export const Several = createExample(TestedComponent, {
+  list: [
+    exampleData.withdraw,
+    exampleData.payment,
+    exampleData.withdraw,
+    exampleData.payment,
+    exampleData.refresh,
+    exampleData.refund,
+    exampleData.tip,
+    exampleData.deposit,
+  ]
+});
+
+// export const WithdrawPending = createExample(TestedComponent, {
+//   transaction: { ...exampleData.withdraw, pending: true },
+// });
+
+
+// export const Payment = createExample(TestedComponent, {
+//   transaction: exampleData.payment
+// });
+
+// export const PaymentWithoutFee = createExample(TestedComponent, {
+//   transaction: {
+//     ...exampleData.payment,
+//     amountRaw: 'USD:11',
+
+//   }
+// });
+
+// export const PaymentPending = createExample(TestedComponent, {
+//   transaction: { ...exampleData.payment, pending: true },
+// });
+
+// export const PaymentWithProducts = createExample(TestedComponent, {
+//   transaction: {
+//     ...exampleData.payment,
+//     info: {
+//       ...exampleData.payment.info,
+//       summary: 'this order has 5 products',
+//       products: [{
+//         description: 't-shirt',
+//         unit: 'shirts',
+//         quantity: 1,
+//       }, {
+//         description: 't-shirt',
+//         unit: 'shirts',
+//         quantity: 1,
+//       }, {
+//         description: 'e-book',
+//       }, {
+//         description: 'beer',
+//         unit: 'pint',
+//         quantity: 15,
+//       }, {
+//         description: 'beer',
+//         unit: 'pint',
+//         quantity: 15,
+//       }]
+//     }
+//   } as TransactionPayment,
+// });
+
+// export const PaymentWithLongSummary = createExample(TestedComponent, {
+//   transaction: {
+//     ...exampleData.payment,
+//     info: {
+//       ...exampleData.payment.info,
+//       summary: 'this is a very long summary that will occupy severals 
lines, this is a very long summary that will occupy severals lines, this is a 
very long summary that will occupy severals lines, this is a very long summary 
that will occupy severals lines, ',
+//       products: [{
+//         description: 'an xl sized t-shirt with some drawings on it, color 
pink',
+//         unit: 'shirts',
+//         quantity: 1,
+//       }, {
+//         description: 'beer',
+//         unit: 'pint',
+//         quantity: 15,
+//       }]
+//     }
+//   } as TransactionPayment,
+// });
+
+
+// export const Deposit = createExample(TestedComponent, {
+//   transaction: exampleData.deposit
+// });
+
+// export const DepositPending = createExample(TestedComponent, {
+//   transaction: { ...exampleData.deposit, pending: true }
+// });
+
+// export const Refresh = createExample(TestedComponent, {
+//   transaction: exampleData.refresh
+// });
+
+// export const Tip = createExample(TestedComponent, {
+//   transaction: exampleData.tip
+// });
+
+// export const TipPending = createExample(TestedComponent, {
+//   transaction: { ...exampleData.tip, pending: true }
+// });
+
+// export const Refund = createExample(TestedComponent, {
+//   transaction: exampleData.refund
+// });
+
+// export const RefundPending = createExample(TestedComponent, {
+//   transaction: { ...exampleData.refund, pending: true }
+// });
+
+// export const RefundWithProducts = createExample(TestedComponent, {
+//   transaction: {
+//     ...exampleData.refund,
+//     info: {
+//       ...exampleData.refund.info,
+//       products: [{
+//         description: 't-shirt',
+//       }, {
+//         description: 'beer',
+//       }]
+//     }
+//   } as TransactionRefund,
+// });
diff --git a/packages/taler-wallet-webextension/src/popup/History.tsx 
b/packages/taler-wallet-webextension/src/popup/History.tsx
index ffcec5e4..f055f6cb 100644
--- a/packages/taler-wallet-webextension/src/popup/History.tsx
+++ b/packages/taler-wallet-webextension/src/popup/History.tsx
@@ -38,17 +38,23 @@ export function HistoryPage(props: any): JSX.Element {
     return <div>Loading ...</div>;
   }
 
-  const txs = [...transactions.transactions].reverse();
+  return <HistoryView list={[...transactions.transactions].reverse()} />;
+}
 
-  return (
-    <div>
-      {txs.map((tx, i) => (
-        <TransactionItem key={i} tx={tx} />
-      ))}
-    </div>
-  );
+export function HistoryView({ list }: { list: Transaction[] }) {
+  return <div style={{ height: 'calc(320px - 34px - 2em)', overflow: 'auto', 
width: '100%' }}>
+    {list.map((tx, i) => (
+      <TransactionItem key={i} tx={tx} />
+    ))}
+  </div>
 }
 
+import imageBank from '../../static/img/ri-bank-line.svg';
+import imageShoppingCart from '../../static/img/ri-shopping-cart-line.svg';
+import imageRefund from '../../static/img/ri-refund-2-line.svg';
+import imageHandHeart from '../../static/img/ri-hand-heart-line.svg';
+import imageRefresh from '../../static/img/ri-refresh-line.svg';
+
 function TransactionItem(props: { tx: Transaction }): JSX.Element {
   const tx = props.tx;
   switch (tx.type) {
@@ -61,7 +67,7 @@ function TransactionItem(props: { tx: Transaction }): 
JSX.Element {
           title="Withdrawal"
           subtitle={`via ${tx.exchangeBaseUrl}`}
           timestamp={tx.timestamp}
-          iconPath="/static/img/ri-bank-line.svg"
+          iconPath={imageBank}
           pending={tx.pending}
         ></TransactionLayout>
       );
@@ -74,7 +80,7 @@ function TransactionItem(props: { tx: Transaction }): 
JSX.Element {
           title="Payment"
           subtitle={tx.info.summary}
           timestamp={tx.timestamp}
-          iconPath="/static/img/ri-shopping-cart-line.svg"
+          iconPath={imageShoppingCart}
           pending={tx.pending}
         ></TransactionLayout>
       );
@@ -87,7 +93,7 @@ function TransactionItem(props: { tx: Transaction }): 
JSX.Element {
           title="Refund"
           subtitle={tx.info.summary}
           timestamp={tx.timestamp}
-          iconPath="/static/img/ri-refund-2-line.svg"
+          iconPath={imageRefund}
           pending={tx.pending}
         ></TransactionLayout>
       );
@@ -100,7 +106,7 @@ function TransactionItem(props: { tx: Transaction }): 
JSX.Element {
           title="Tip"
           subtitle={`from ${new URL(tx.merchantBaseUrl).hostname}`}
           timestamp={tx.timestamp}
-          iconPath="/static/img/ri-hand-heart-line.svg"
+          iconPath={imageHandHeart}
           pending={tx.pending}
         ></TransactionLayout>
       );
@@ -113,7 +119,7 @@ function TransactionItem(props: { tx: Transaction }): 
JSX.Element {
           title="Refresh"
           subtitle={`via exchange ${tx.exchangeBaseUrl}`}
           timestamp={tx.timestamp}
-          iconPath="/static/img/ri-refresh-line.svg"
+          iconPath={imageRefresh}
           pending={tx.pending}
         ></TransactionLayout>
       );
@@ -126,7 +132,7 @@ function TransactionItem(props: { tx: Transaction }): 
JSX.Element {
           title="Refresh"
           subtitle={`to ${tx.targetPaytoUri}`}
           timestamp={tx.timestamp}
-          iconPath="/static/img/ri-refresh-line.svg"
+          iconPath={imageRefresh}
           pending={tx.pending}
         ></TransactionLayout>
       );
diff --git 
a/packages/taler-wallet-webextension/src/popup/Transaction.stories.tsx 
b/packages/taler-wallet-webextension/src/popup/Transaction.stories.tsx
index 3df2687f..bf090cad 100644
--- a/packages/taler-wallet-webextension/src/popup/Transaction.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Transaction.stories.tsx
@@ -37,7 +37,7 @@ export default {
       <link key="1" rel="stylesheet" type="text/css" href="/style/pure.css" />
       <link key="2" rel="stylesheet" type="text/css" href="/style/popup.css" />
       <link key="3" rel="stylesheet" type="text/css" href="/style/wallet.css" 
/>
-      <div style={{ margin: "1em", width: 400 }}>
+      <div style={{ margin: "1em", width: 400, display: 'flex', padding: 
'0.5em', height: 'calc(20rem - 34px)', border: 'black solid 1px' }}>
         <Story />
       </div>
     </div>
@@ -74,7 +74,7 @@ const exampleData = {
       merchant: {
         name: 'the merchant',
       },
-      orderId: '#12345',
+      orderId: '2021.167-03NPY6MCYMVGT',
       products: [],
       summary: 'the summary',
       fulfillmentMessage: '',
@@ -107,7 +107,7 @@ const exampleData = {
       merchant: {
         name: 'the merchant',
       },
-      orderId: '#12345',
+      orderId: '2021.167-03NPY6MCYMVGT',
       products: [],
       summary: 'the summary',
       fulfillmentMessage: '',
@@ -121,69 +121,111 @@ function createExample<Props>(Component: 
FunctionalComponent<Props>, props: Part
   return r
 }
 
-export const NotYetLoaded = createExample(TestedComponent,{});
+export const NotYetLoaded = createExample(TestedComponent, {});
 
-export const Withdraw = createExample(TestedComponent,{
+export const Withdraw = createExample(TestedComponent, {
   transaction: exampleData.withdraw
 });
 
-export const WithdrawPending = createExample(TestedComponent,{
+export const WithdrawPending = createExample(TestedComponent, {
   transaction: { ...exampleData.withdraw, pending: true },
 });
 
 
-export const Payment = createExample(TestedComponent,{
+export const Payment = createExample(TestedComponent, {
   transaction: exampleData.payment
 });
 
-export const PaymentPending = createExample(TestedComponent,{
+export const PaymentWithoutFee = createExample(TestedComponent, {
+  transaction: {
+    ...exampleData.payment,
+    amountRaw: 'USD:11',
+
+  }
+});
+
+export const PaymentPending = createExample(TestedComponent, {
   transaction: { ...exampleData.payment, pending: true },
 });
 
-export const PaymentWithProducts = createExample(TestedComponent,{
+export const PaymentWithProducts = createExample(TestedComponent, {
   transaction: {
     ...exampleData.payment,
     info: {
       ...exampleData.payment.info,
+      summary: 'this order has 5 products',
       products: [{
         description: 't-shirt',
+        unit: 'shirts',
+        quantity: 1,
+      }, {
+        description: 't-shirt',
+        unit: 'shirts',
+        quantity: 1,
+      }, {
+        description: 'e-book',
+      }, {
+        description: 'beer',
+        unit: 'pint',
+        quantity: 15,
+      }, {
+        description: 'beer',
+        unit: 'pint',
+        quantity: 15,
+      }]
+    }
+  } as TransactionPayment,
+});
+
+export const PaymentWithLongSummary = createExample(TestedComponent, {
+  transaction: {
+    ...exampleData.payment,
+    info: {
+      ...exampleData.payment.info,
+      summary: 'this is a very long summary that will occupy severals lines, 
this is a very long summary that will occupy severals lines, this is a very 
long summary that will occupy severals lines, this is a very long summary that 
will occupy severals lines, ',
+      products: [{
+        description: 'an xl sized t-shirt with some drawings on it, color 
pink',
+        unit: 'shirts',
+        quantity: 1,
       }, {
         description: 'beer',
+        unit: 'pint',
+        quantity: 15,
       }]
     }
   } as TransactionPayment,
 });
 
 
-export const Deposit = createExample(TestedComponent,{
+export const Deposit = createExample(TestedComponent, {
   transaction: exampleData.deposit
 });
 
-export const DepositPending = createExample(TestedComponent,{
+export const DepositPending = createExample(TestedComponent, {
   transaction: { ...exampleData.deposit, pending: true }
 });
 
-export const Refresh = createExample(TestedComponent,{
+export const Refresh = createExample(TestedComponent, {
   transaction: exampleData.refresh
 });
 
-export const Tip = createExample(TestedComponent,{
+export const Tip = createExample(TestedComponent, {
   transaction: exampleData.tip
 });
 
-export const TipPending = createExample(TestedComponent,{
+export const TipPending = createExample(TestedComponent, {
   transaction: { ...exampleData.tip, pending: true }
 });
 
-export const Refund = createExample(TestedComponent,{
+export const Refund = createExample(TestedComponent, {
   transaction: exampleData.refund
 });
 
-export const RefundPending = createExample(TestedComponent,{
+export const RefundPending = createExample(TestedComponent, {
   transaction: { ...exampleData.refund, pending: true }
 });
 
-export const RefundWithProducts = createExample(TestedComponent,{
+export const RefundWithProducts = createExample(TestedComponent, {
   transaction: {
     ...exampleData.refund,
     info: {
diff --git a/packages/taler-wallet-webextension/src/popup/Transaction.tsx 
b/packages/taler-wallet-webextension/src/popup/Transaction.tsx
index b1179228..2db4cc1a 100644
--- a/packages/taler-wallet-webextension/src/popup/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Transaction.tsx
@@ -14,14 +14,14 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { Amounts, i18n, Transaction, TransactionType } from 
"@gnu-taler/taler-util";
+import { AmountJson, Amounts, i18n, Transaction, TransactionType } from 
"@gnu-taler/taler-util";
 import { format } from "date-fns";
-import { JSX } from "preact";
+import { Fragment, JSX } from "preact";
 import { route } from 'preact-router';
 import { useEffect, useState } from "preact/hooks";
 import * as wxApi from "../wxApi";
 import { Pages } from "./popup";
-
+import emptyImg from "../../static/img/empty.png"
 
 export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
   const [transaction, setTransaction] = useState<
@@ -59,11 +59,10 @@ export function TransactionView({ transaction, onDelete, 
onBack }: WalletTransac
   }
 
   function Footer() {
-    return <footer style={{ marginTop: 'auto', display: 'flex' }}>
+    return <footer style={{ marginTop: 'auto', display: 'flex', flexShrink: 0 
}}>
       <button onClick={onBack}><i18n.Translate>back</i18n.Translate></button>
       <div style={{ width: '100%', flexDirection: 'row', justifyContent: 
'flex-end', display: 'flex' }}>
-        <button 
onClick={onDelete}><i18n.Translate>remove</i18n.Translate></button>
-
+        <button class="pure-button button-destructive" 
onClick={onDelete}><i18n.Translate>forget</i18n.Translate></button>
       </div>
 
     </footer>
@@ -74,91 +73,66 @@ export function TransactionView({ transaction, onDelete, 
onBack }: WalletTransac
     return <span style={{ fontWeight: 'normal', fontSize: 16, color: 'gray' 
}}>(pending...)</span>
   }
 
+  const Fee = ({ value }: { value: AmountJson }) => Amounts.isNonZero(value) ?
+    <span style="font-size: 16px;font-weight: normal;color: gray;">(fee 
{Amounts.stringify(value)})</span> : null
+
   if (transaction.type === TransactionType.Withdrawal) {
+    const fee = Amounts.sub(
+      Amounts.parseOrThrow(transaction.amountRaw),
+      Amounts.parseOrThrow(transaction.amountEffective),
+    ).amount
     return (
-      <div style={{ display: 'flex', flexDirection: 'column', flex: 1, 
minHeight: '20rem' }} >
-        <section>
-          <h1>Withdrawal <Pending /></h1>
-          <p>
+      <div style={{ display: 'flex', flexDirection: 'column', width: '100%' }} 
>
+        <section style={{ color: transaction.pending ? 'gray' : '', flex: '1 0 
auto', height: 'calc(320px - 34px - 45px - 2em)', overflow: 'auto' }}>
+          <span style="flat: left; font-size:small; 
color:gray">{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</span>
+          <span style="float: right; font-size:small; color:gray">
             From <b>{transaction.exchangeBaseUrl}</b>
-          </p>
-          <table class={transaction.pending ? "detailsTable pending" : 
"detailsTable"}>
-            <tr>
-              <td>Amount subtracted</td>
-              <td>{transaction.amountRaw}</td>
-            </tr>
-            <tr>
-              <td>Amount received</td>
-              <td>{transaction.amountEffective}</td>
-            </tr>
-            <tr>
-              <td>Exchange fee</td>
-              <td>{Amounts.stringify(
-                Amounts.sub(
-                  Amounts.parseOrThrow(transaction.amountRaw),
-                  Amounts.parseOrThrow(transaction.amountEffective),
-                ).amount
-              )}</td>
-            </tr>
-            <tr>
-              <td>When</td>
-              <td>{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</td>
-            </tr>
-          </table>
+          </span>
+          <h3>Withdraw <Pending /></h3>
+          <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
         </section>
         <Footer />
       </div>
     );
   }
 
+  const showLargePic = () => {
+
+  }
+
   if (transaction.type === TransactionType.Payment) {
+    const fee = Amounts.sub(
+      Amounts.parseOrThrow(transaction.amountEffective),
+      Amounts.parseOrThrow(transaction.amountRaw),
+    ).amount
+
     return (
-      <div style={{ display: 'flex', flexDirection: 'column', flex: 1, 
minHeight: '20rem' }} >
-        <section>
-          <h1>Payment ({transaction.proposalId.substring(0, 10)}...) <Pending 
/></h1>
-          <p>
+      <div style={{ display: 'flex', flexDirection: 'column', width: '100%' }} 
>
+        <section style={{ color: transaction.pending ? 'gray' : '', flex: '1 0 
auto', height: 'calc(320px - 34px - 45px - 2em)', overflow: 'auto' }}>
+          <span style="flat: left; font-size:small; 
color:gray">{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</span>
+          <span style="float: right; font-size:small; color:gray">
             To <b>{transaction.info.merchant.name}</b>
+          </span>
+          <h3>Payment <Pending /></h3>
+          <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
+          <span style="font-size:small; 
color:gray">#{transaction.info.orderId}</span>
+          <p>
+            {transaction.info.summary}
           </p>
-          <table class={transaction.pending ? "detailsTable pending" : 
"detailsTable"}>
-            <tr>
-              <td>Order id</td>
-              <td>{transaction.info.orderId}</td>
-            </tr>
-            <tr>
-              <td>Summary</td>
-              <td>{transaction.info.summary}</td>
-            </tr>
-            {transaction.info.products && transaction.info.products.length > 0 
&&
-              <tr>
-                <td>Products</td>
-                <td><ol style={{ margin: 0, textAlign: 'left' }}>
-                  {transaction.info.products.map(p =>
-                    <li>{p.description}</li>
-                  )}</ol></td>
-              </tr>
+          <div>
+            {transaction.info.products && transaction.info.products.length > 0 
&& <div>
+              {transaction.info.products.map(p => <div style="display: flex; 
flex-direction: row; border: 1px solid gray; border-radius: 0.5em; margin: 
0.5em 0px; justify-content: left; padding: 0.5em;">
+                <a href="#" onClick={showLargePic}>
+                  <img class="pure-img" style="display:inline-block" 
src={p.image ? p.image : emptyImg} width="32" height="32" />
+                </a>
+                <div style="display: block; margin-left: 1em;">
+                  {p.quantity && p.quantity > 0 && <div style="font-size: 
small; color: gray;">x {p.quantity} {p.unit}</div>}
+                  <div style={{ textOverflow: 'ellipsis', overflow: 'hidden', 
width: 'calc(20rem - 32px - 32px - 8px - 1em)', whiteSpace: 'nowrap' 
}}>{p.description}</div>
+                </div>
+              </div>)}
+            </div>
             }
-            <tr>
-              <td>Order amount</td>
-              <td>{transaction.amountRaw}</td>
-            </tr>
-            <tr>
-              <td>Order amount and fees</td>
-              <td>{transaction.amountEffective}</td>
-            </tr>
-            <tr>
-              <td>Exchange fee</td>
-              <td>{Amounts.stringify(
-                Amounts.sub(
-                  Amounts.parseOrThrow(transaction.amountEffective),
-                  Amounts.parseOrThrow(transaction.amountRaw),
-                ).amount
-              )}</td>
-            </tr>
-            <tr>
-              <td>When</td>
-              <td>{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</td>
-            </tr>
-          </table>
+          </div>
         </section>
         <Footer />
       </div>
@@ -166,36 +140,19 @@ export function TransactionView({ transaction, onDelete, 
onBack }: WalletTransac
   }
 
   if (transaction.type === TransactionType.Deposit) {
+    const fee = Amounts.sub(
+      Amounts.parseOrThrow(transaction.amountRaw),
+      Amounts.parseOrThrow(transaction.amountEffective),
+    ).amount
     return (
-      <div style={{ display: 'flex', flexDirection: 'column', flex: 1, 
minHeight: '20rem' }} >
-        <section>
-          <h1>Deposit ({transaction.depositGroupId}) <Pending /></h1>
-          <p>
+      <div style={{ display: 'flex', flexDirection: 'column', width: '100%' }} 
>
+        <section style={{ color: transaction.pending ? 'gray' : '', flex: '1 0 
auto', height: 'calc(320px - 34px - 45px - 2em)', overflow: 'auto' }}>
+          <span style="flat: left; font-size:small; 
color:gray">{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</span>
+          <span style="float: right; font-size:small; color:gray">
             To <b>{transaction.targetPaytoUri}</b>
-          </p>
-          <table class={transaction.pending ? "detailsTable pending" : 
"detailsTable"}>
-            <tr>
-              <td>Amount deposit</td>
-              <td>{transaction.amountRaw}</td>
-            </tr>
-            <tr>
-              <td>Amount deposit and fees</td>
-              <td>{transaction.amountEffective}</td>
-            </tr>
-            <tr>
-              <td>Exchange fee</td>
-              <td>{Amounts.stringify(
-                Amounts.sub(
-                  Amounts.parseOrThrow(transaction.amountEffective),
-                  Amounts.parseOrThrow(transaction.amountRaw),
-                ).amount
-              )}</td>
-            </tr>
-            <tr>
-              <td>When</td>
-              <td>{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</td>
-            </tr>
-          </table>
+          </span>
+          <h3>Deposit <Pending /></h3>
+          <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
         </section>
         <Footer />
       </div>
@@ -203,27 +160,19 @@ export function TransactionView({ transaction, onDelete, 
onBack }: WalletTransac
   }
 
   if (transaction.type === TransactionType.Refresh) {
+    const fee = Amounts.sub(
+      Amounts.parseOrThrow(transaction.amountRaw),
+      Amounts.parseOrThrow(transaction.amountEffective),
+    ).amount
     return (
-      <div style={{ display: 'flex', flexDirection: 'column', flex: 1, 
minHeight: '20rem' }} >
-        <section>
-          <h1>Refresh <Pending /></h1>
-          <p>
+      <div style={{ display: 'flex', flexDirection: 'column', width: '100%' }} 
>
+        <section style={{ color: transaction.pending ? 'gray' : '', flex: '1 0 
auto', height: 'calc(320px - 34px - 45px - 2em)', overflow: 'auto' }}>
+          <span style="flat: left; font-size:small; 
color:gray">{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</span>
+          <span style="float: right; font-size:small; color:gray">
             From <b>{transaction.exchangeBaseUrl}</b>
-          </p>
-          <table class={transaction.pending ? "detailsTable pending" : 
"detailsTable"}>
-            <tr>
-              <td>Amount refreshed</td>
-              <td>{transaction.amountRaw}</td>
-            </tr>
-            <tr>
-              <td>Fees</td>
-              <td>{transaction.amountEffective}</td>
-            </tr>
-            <tr>
-              <td>When</td>
-              <td>{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</td>
-            </tr>
-          </table>
+          </span>
+          <h3>Refresh <Pending /></h3>
+          <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
         </section>
         <Footer />
       </div>
@@ -231,91 +180,58 @@ export function TransactionView({ transaction, onDelete, 
onBack }: WalletTransac
   }
 
   if (transaction.type === TransactionType.Tip) {
+    const fee = Amounts.sub(
+      Amounts.parseOrThrow(transaction.amountRaw),
+      Amounts.parseOrThrow(transaction.amountEffective),
+    ).amount
     return (
-      <div style={{ display: 'flex', flexDirection: 'column', flex: 1, 
minHeight: '20rem' }} >
-        <section>
-          <h1>Tip <Pending /></h1>
-          <p>
+      <div style={{ display: 'flex', flexDirection: 'column', width: '100%' }} 
>
+        <section style={{ color: transaction.pending ? 'gray' : '', flex: '1 0 
auto', height: 'calc(320px - 34px - 45px - 2em)', overflow: 'auto' }}>
+          <span style="flat: left; font-size:small; 
color:gray">{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</span>
+          <span style="float: right; font-size:small; color:gray">
             From <b>{transaction.merchantBaseUrl}</b>
-          </p>
-          <table class={transaction.pending ? "detailsTable pending" : 
"detailsTable"}>
-            <tr>
-              <td>Amount deduce</td>
-              <td>{transaction.amountRaw}</td>
-            </tr>
-            <tr>
-              <td>Amount received</td>
-              <td>{transaction.amountEffective}</td>
-            </tr>
-            <tr>
-              <td>Exchange fee</td>
-              <td>{Amounts.stringify(
-                Amounts.sub(
-                  Amounts.parseOrThrow(transaction.amountRaw),
-                  Amounts.parseOrThrow(transaction.amountEffective),
-                ).amount
-              )}</td>
-            </tr>
-            <tr>
-              <td>When</td>
-              <td>{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</td>
-            </tr>
-          </table>
+          </span>
+          <h3>Tip <Pending /></h3>
+          <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
         </section>
         <Footer />
       </div>
     );
   }
 
-  const TRANSACTION_FROM_REFUND = /[a-z]*:([\w]{10}).*/
   if (transaction.type === TransactionType.Refund) {
+    const fee = Amounts.sub(
+      Amounts.parseOrThrow(transaction.amountRaw),
+      Amounts.parseOrThrow(transaction.amountEffective),
+    ).amount
     return (
-      <div style={{ display: 'flex', flexDirection: 'column', flex: 1, 
minHeight: '20rem' }} >
-        <section>
-          <h1>Refund 
({TRANSACTION_FROM_REFUND.exec(transaction.refundedTransactionId)![1]}...) 
<Pending /></h1>
-          <p>
+      <div style={{ display: 'flex', flexDirection: 'column', width: '100%' }} 
>
+        <section style={{ color: transaction.pending ? 'gray' : '', flex: '1 0 
auto', height: 'calc(320px - 34px - 45px - 2em)', overflow: 'auto' }}>
+          <span style="flat: left; font-size:small; 
color:gray">{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</span>
+          <span style="float: right; font-size:small; color:gray">
             From <b>{transaction.info.merchant.name}</b>
+          </span>
+          <h3>Refund <Pending /></h3>
+          <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
+          <span style="font-size:small; 
color:gray">#{transaction.info.orderId}</span>
+          <p>
+            {transaction.info.summary}
           </p>
-          <table class={transaction.pending ? "detailsTable pending" : 
"detailsTable"}>
-            <tr>
-              <td>Order id</td>
-              <td>{transaction.info.orderId}</td>
-            </tr>
-            <tr>
-              <td>Summary</td>
-              <td>{transaction.info.summary}</td>
-            </tr>
-            {transaction.info.products && transaction.info.products.length > 0 
&&
-              <tr>
-                <td>Products</td>
-                <td><ol>
-                  {transaction.info.products.map(p =>
-                    <li>{p.description}</li>
-                  )}</ol></td>
-              </tr>
+          <div>
+            {transaction.info.products && transaction.info.products.length > 0 
&& <div>
+              {transaction.info.products.map(p => <div style="display: flex; 
flex-direction: row; border: 1px solid gray; border-radius: 0.5em; margin: 
0.5em 0px; justify-content: left; padding: 0.5em;">
+                <a href="#" onClick={showLargePic}>
+                  <img class="pure-img" style="display:inline-block" 
src={p.image ? p.image : emptyImg} width="32" height="32" />
+                </a>
+                <div style="display: block; margin-left: 1em;">
+                  {p.quantity && p.quantity > 0 && <div style="font-size: 
small; color: gray;">x {p.quantity} {p.unit}</div>}
+                  <div style={{ textOverflow: 'ellipsis', overflow: 'hidden', 
width: 'calc(20rem - 32px - 32px - 8px - 1em)', whiteSpace: 'nowrap' 
}}>{p.description}</div>
+                </div>
+              </div>)}
+            </div>
             }
-            <tr>
-              <td>Amount deduce</td>
-              <td>{transaction.amountRaw}</td>
-            </tr>
-            <tr>
-              <td>Amount received</td>
-              <td>{transaction.amountEffective}</td>
-            </tr>
-            <tr>
-              <td>Exchange fee</td>
-              <td>{Amounts.stringify(
-                Amounts.sub(
-                  Amounts.parseOrThrow(transaction.amountRaw),
-                  Amounts.parseOrThrow(transaction.amountEffective),
-                ).amount
-              )}</td>
-            </tr>
-            <tr>
-              <td>When</td>
-              <td>{transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}</td>
-            </tr>
-          </table>
+          </div>
+
         </section>
         <Footer />
       </div>
diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx 
b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
index 6cc781aa..05c5cca9 100644
--- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
@@ -88,7 +88,7 @@ function Application() {
   return (
     <div>
       <Match>{({ path }: any) => <WalletNavBar current={path} />}</Match >
-      <div style={{ margin: "1em", width: 400 }}>
+      <div style={{ padding: "1em", width: 'calc(400px - 2em)', height: 
'calc(320px - 34px - 2em)' }}>
         <Router>
           <Route path={Pages.balance} component={BalancePage} />
           <Route path={Pages.settings} component={SettingsPage} />
diff --git a/packages/taler-wallet-webextension/static/img/empty.png 
b/packages/taler-wallet-webextension/static/img/empty.png
new file mode 100644
index 00000000..5120d313
Binary files /dev/null and 
b/packages/taler-wallet-webextension/static/img/empty.png differ
diff --git a/packages/taler-wallet-webextension/static/style/popup.css 
b/packages/taler-wallet-webextension/static/style/popup.css
index a234f2a2..50440047 100644
--- a/packages/taler-wallet-webextension/static/style/popup.css
+++ b/packages/taler-wallet-webextension/static/style/popup.css
@@ -5,11 +5,11 @@
  */
 
 body {
-  min-height: 20em;
+  /* min-height: 20em; */
   /* width: 30em; */
   margin: 0;
   padding: 0;
-  max-height: 800px;
+  /* max-height: 800px; */
   overflow: hidden;
   background-color: #f8faf7;
   font-family: Arial, Helvetica, sans-serif;
@@ -259,4 +259,33 @@ table.detailsTable {
 
 table.detailsTable.pending {
   color: gray;
+}
+
+.overflow {
+  text-align: justify;
+  position: relative;
+  max-height: calc(1.2em * 2);
+  overflow: hidden;
+  padding-right: 1rem; /* space for ellipsis */
+}
+.overflow::before {
+  position: absolute;
+  content: "...";
+/*   inset-block-end: 0;
+  inset-inline-end: 0; */
+  bottom: 0;
+  right: 0;
+}
+.overflow::after {
+  content: "";
+  position: absolute;
+/*   inset-inline-end: 0; */
+  right: 0;
+  width: 1rem;
+  height: 1rem;
+  background: white;
+}
+
+button.danger {
+  background-color: 'red';
 }
\ No newline at end of file
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 14219b2f..ca93291b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -211,6 +211,7 @@ importers:
       '@gnu-taler/taler-util': workspace:*
       '@gnu-taler/taler-wallet-core': workspace:*
       '@rollup/plugin-commonjs': ^17.0.0
+      '@rollup/plugin-image': ^2.0.6
       '@rollup/plugin-json': ^4.1.0
       '@rollup/plugin-node-resolve': ^11.1.0
       '@rollup/plugin-replace': ^2.3.4
@@ -253,6 +254,7 @@ importers:
       '@babel/plugin-transform-react-jsx-source': 7.12.13_@babel+core@7.14.0
       '@babel/preset-typescript': 7.13.0_@babel+core@7.14.0
       '@rollup/plugin-commonjs': 17.0.0_rollup@2.37.1
+      '@rollup/plugin-image': 2.0.6_rollup@2.37.1
       '@rollup/plugin-json': 4.1.0_rollup@2.37.1
       '@rollup/plugin-node-resolve': 11.1.0_rollup@2.37.1
       '@rollup/plugin-replace': 2.3.4_rollup@2.37.1
@@ -3280,6 +3282,17 @@ packages:
       rollup: 2.37.1
     dev: true
 
+  /@rollup/plugin-image/2.0.6_rollup@2.37.1:
+    resolution: {integrity: 
sha512-bB+spXogbPiFjhBS7i8ajUOgOnVwWK3bnJ6VroxKey/q8/EPRkoSh+4O1qPCw97qMIDspF4TlzXVBhZ7nojIPw==}
+    engines: {node: '>= 8.0.0'}
+    peerDependencies:
+      rollup: ^1.20.0 || ^2.0.0
+    dependencies:
+      '@rollup/pluginutils': 3.1.0_rollup@2.37.1
+      mini-svg-data-uri: 1.3.3
+      rollup: 2.37.1
+    dev: true
+
   /@rollup/plugin-json/4.1.0_rollup@2.37.1:
     resolution: {integrity: 
sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==}
     peerDependencies:
@@ -12933,6 +12946,11 @@ packages:
       webpack-sources: 1.4.3
     dev: true
 
+  /mini-svg-data-uri/1.3.3:
+    resolution: {integrity: 
sha512-+fA2oRcR1dJI/7ITmeQJDrYWks0wodlOz0pAEhKYJ2IVc1z0AnwJUsKY2fzFmPAM3Jo9J0rBx8JAA9QQSJ5PuA==}
+    hasBin: true
+    dev: true
+
   /minimalistic-assert/1.0.1:
     resolution: {integrity: 
sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
     dev: true

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