gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] 02/02: transaction details new ui


From: gnunet
Subject: [taler-wallet-core] 02/02: transaction details new ui
Date: Tue, 24 Aug 2021 20:16:44 +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 e22bdd52f7dc878738d1b1306a15ae0f573c30a2
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue Aug 24 15:16:11 2021 -0300

    transaction details new ui
---
 packages/taler-util/src/amounts.ts                 |   9 +-
 .../.storybook/preview.js                          |   2 -
 .../src/components/styled/index.tsx                |  48 ++++++++-
 .../src/popup/ProviderDetailPage.tsx               |   4 +-
 .../src/wallet/ProviderDetailPage.tsx              |   4 +-
 .../src/wallet/Transaction.stories.tsx             |   8 +-
 .../src/wallet/Transaction.tsx                     | 117 +++++++++++++--------
 7 files changed, 135 insertions(+), 57 deletions(-)

diff --git a/packages/taler-util/src/amounts.ts 
b/packages/taler-util/src/amounts.ts
index e472de50..f0434be0 100644
--- a/packages/taler-util/src/amounts.ts
+++ b/packages/taler-util/src/amounts.ts
@@ -402,6 +402,12 @@ export class Amounts {
    */
   static stringify(a: AmountLike): string {
     a = Amounts.jsonifyAmount(a);
+    const s = this.stringifyValue(a)
+
+    return `${a.currency}:${s}`;
+  }
+
+  static stringifyValue(a: AmountJson): string {
     const av = a.value + Math.floor(a.fraction / amountFractionalBase);
     const af = a.fraction % amountFractionalBase;
     let s = av.toString();
@@ -417,7 +423,6 @@ export class Amounts {
         n = (n * 10) % amountFractionalBase;
       }
     }
-
-    return `${a.currency}:${s}`;
+    return s
   }
 }
diff --git a/packages/taler-wallet-webextension/.storybook/preview.js 
b/packages/taler-wallet-webextension/.storybook/preview.js
index 920e6b1c..48866346 100644
--- a/packages/taler-wallet-webextension/.storybook/preview.js
+++ b/packages/taler-wallet-webextension/.storybook/preview.js
@@ -158,8 +158,6 @@ export const decorators = [
         </style>
         <LogoHeader />
         <NavBar path={path} devMode={path === '/dev'} />
-        <link key="1" rel="stylesheet" type="text/css" 
href="/static/style/pure.css" />
-        <link key="2" rel="stylesheet" type="text/css" 
href="/static/style/wallet.css" />
         <Story />
       </div>
     }
diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx 
b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index 66595d84..8f795ce8 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -85,6 +85,7 @@ export const WalletBox = styled.div<{ noPadding?: boolean }>`
     flex-direction: row;
     justify-content: space-between;
     display: flex;
+    background-color: #f7f7f7;
     & button {
       margin-right: 8px;
       margin-left: 8px;
@@ -199,6 +200,33 @@ export const Button = styled.button`
   }
 `;
 
+export const FontIcon = styled.div`
+  font-family: monospace;
+  font-size: x-large;
+  text-align: center;
+  font-weight: bold;
+  /* vertical-align: text-top; */
+`
+export const ButtonBox = styled(Button)`
+  padding: .5em;
+  width: 2em;
+  height: 2em;
+
+  & > ${FontIcon} {
+    width: 1em;
+    height: 1em;
+    display: inline;
+    line-height: 0px;
+  }
+  background-color: transparent;
+
+  border: 1px solid;
+  border-radius: 4px;
+  border-color: black;
+  color: black;
+`
+
+
 const ButtonVariant = styled(Button)`
   color: white;
   border-radius: 4px;
@@ -208,18 +236,35 @@ const ButtonVariant = styled(Button)`
 export const ButtonPrimary = styled(ButtonVariant)`
   background-color: rgb(66, 184, 221);
 `
+export const ButtonBoxPrimary = styled(ButtonBox)`
+  color: rgb(66, 184, 221);
+  border-color: rgb(66, 184, 221);
+`
 
 export const ButtonSuccess = styled(ButtonVariant)`
   background-color: rgb(28, 184, 65);
 `
+export const ButtonBoxSuccess = styled(ButtonBox)`
+  color: rgb(28, 184, 65);
+  border-color: rgb(28, 184, 65);
+`
 
 export const ButtonWarning = styled(ButtonVariant)`
   background-color: rgb(223, 117, 20);
 `
+export const ButtonBoxWarning = styled(ButtonBox)`
+  color: rgb(223, 117, 20);
+  border-color: rgb(223, 117, 20);
+`
 
 export const ButtonDestructive = styled(ButtonVariant)`
   background-color: rgb(202, 60, 60);
 `
+export const ButtonBoxDestructive = styled(ButtonBox)`
+  color: rgb(202, 60, 60);
+  border-color: rgb(202, 60, 60);
+`
+
 
 export const BoldLight = styled.div`
 color: gray;
@@ -336,6 +381,7 @@ export const CenteredTextBold = styled(CenteredText)`
   font-weight: bold;
   color: ${((props: any): any => String(props.color) as any) as any};
 `
+
 export const Input = styled.div<{ invalid?: boolean }>`
   & label {
     display: block;
@@ -359,7 +405,7 @@ export const ErrorBox = styled.div`
   /* margin: 0.5em; */
   padding-left: 1em;
   padding-right: 1em;
-  width: 100%;
+  /* width: 100%; */
   color: #721c24;
   background: #f8d7da;
 
diff --git 
a/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx 
b/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
index bfc32a8f..83d94ac0 100644
--- a/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
@@ -58,9 +58,7 @@ export function ProviderView({ info, onDelete, onSync, 
onBack, onExtend }: ViewP
   const isPaid = info.paymentStatus.type === ProviderPaymentType.Paid || 
info.paymentStatus.type === ProviderPaymentType.TermsChanged
   return (
     <PopupBox>
-      {info.backupProblem || info.lastError ? <header>
-        <Error info={info} />
-      </header> : undefined }
+      <Error info={info} />
       <header>
         <h3>{info.name} 
<SmallTextLight>{info.syncProviderBaseUrl}</SmallTextLight></h3>
         <PaymentStatus color={isPaid ? 'rgb(28, 184, 65)' : 'rgb(202, 60, 
60)'}>{isPaid ? 'Paid' : 'Unpaid'}</PaymentStatus>
diff --git 
a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx 
b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
index fc361f62..871e30b7 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
@@ -58,9 +58,7 @@ export function ProviderView({ info, onDelete, onSync, 
onBack, onExtend }: ViewP
   const isPaid = info.paymentStatus.type === ProviderPaymentType.Paid || 
info.paymentStatus.type === ProviderPaymentType.TermsChanged
   return (
     <WalletBox>
-      {info.backupProblem || info.lastError ? <header>
-        <Error info={info} />
-      </header> : undefined }
+      <Error info={info} />
       <header>
         <h3>{info.name} 
<SmallTextLight>{info.syncProviderBaseUrl}</SmallTextLight></h3>
         <PaymentStatus color={isPaid ? 'rgb(28, 184, 65)' : 'rgb(202, 60, 
60)'}>{isPaid ? 'Paid' : 'Unpaid'}</PaymentStatus>
diff --git 
a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx 
b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
index 0f7ea457..535509ce 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
@@ -40,8 +40,8 @@ export default {
 };
 
 const commonTransaction = {
-  amountRaw: 'USD:10',
-  amountEffective: 'USD:9',
+  amountRaw: 'KUDOS:11',
+  amountEffective: 'KUDOS:9.2',
   pending: false,
   timestamp: {
     t_ms: new Date().getTime()
@@ -62,7 +62,7 @@ const exampleData = {
   } as TransactionWithdrawal,
   payment: {
     ...commonTransaction,
-    amountEffective: 'USD:11',
+    amountEffective: 'KUDOS:11',
     type: TransactionType.Payment,
     info: {
       contractTermsHash: 'ASDZXCASD',
@@ -147,7 +147,7 @@ export const PaymentError = createExample(TestedComponent, {
 export const PaymentWithoutFee = createExample(TestedComponent, {
   transaction: {
     ...exampleData.payment,
-    amountRaw: 'USD:11',
+    amountRaw: 'KUDOS:11',
 
   }
 });
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx 
b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index d00abc16..ad00b3d1 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -14,7 +14,7 @@
  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { AmountJson, Amounts, i18n, Transaction, TransactionType } from 
"@gnu-taler/taler-util";
+import { AmountJson, AmountLike, Amounts, i18n, Transaction, TransactionType } 
from "@gnu-taler/taler-util";
 import { format } from "date-fns";
 import { Fragment, JSX, VNode, h } from "preact";
 import { route } from 'preact-router';
@@ -22,7 +22,7 @@ import { useEffect, useState } from "preact/hooks";
 import * as wxApi from "../wxApi";
 import { Pages } from "../NavigationBar";
 import emptyImg from "../../static/img/empty.png"
-import { Button, ButtonDestructive, ButtonPrimary, ListOfProducts, PopupBox, 
Row, RowBorderGray, SmallTextLight, WalletBox } from "../components/styled";
+import { Button, ButtonBox, ButtonBoxDestructive, ButtonDestructive, 
ButtonPrimary, ExtraLargeText, FontIcon, LargeText, ListOfProducts, PopupBox, 
Row, RowBorderGray, SmallTextLight, WalletBox } from "../components/styled";
 import { ErrorMessage } from "../components/ErrorMessage";
 
 export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
@@ -73,43 +73,54 @@ export function TransactionView({ transaction, onDelete, 
onRetry, onBack }: Wall
     return null
   }
 
-  function Fee({ value }: { value: AmountJson }) {
-    if (Amounts.isZero(value)) return null
-    return <span style="font-size: 16px;font-weight: normal;color: gray;">(fee 
{Amounts.stringify(value)})</span>
-  }
-
-  function TransactionTemplate({ upperRight, children }: { upperRight: VNode, 
children: VNode[] }) {
+  function TransactionTemplate({ children }: { children: VNode[] }) {
     return <WalletBox>
-      <header>
-        <SmallTextLight>
-          {transaction.timestamp.t_ms === "never" ? "never" : 
format(transaction.timestamp.t_ms, 'dd/MM/yyyy HH:mm:ss')}
-        </SmallTextLight>
-        <SmallTextLight>
-          {upperRight}
-        </SmallTextLight>
-      </header>
       <section>
         <ErrorMessage title={transaction?.error?.hint} />
-        {children}
+        <div style={{ textAlign: 'center' }}>
+          {children}
+        </div>
       </section>
       <footer>
-        <Button onClick={onBack}><i18n.Translate> &lt; 
back</i18n.Translate></Button>
+        <ButtonBox onClick={onBack}><i18n.Translate> 
<FontIcon>&#x2190;</FontIcon> </i18n.Translate></ButtonBox>
         <div>
           {transaction?.error ? <ButtonPrimary 
onClick={onRetry}><i18n.Translate>retry</i18n.Translate></ButtonPrimary> : null}
-          <ButtonDestructive 
onClick={onDelete}><i18n.Translate>delete</i18n.Translate></ButtonDestructive>
+          <ButtonBoxDestructive 
onClick={onDelete}><i18n.Translate>&#x1F5D1;</i18n.Translate></ButtonBoxDestructive>
         </div>
       </footer>
     </WalletBox>
   }
+  type Kind = 'positive' | 'negative' | 'neutral';
+  function Part({ text, title, kind, big }: { title: string, text: AmountLike, 
kind: Kind, big?: boolean }) {
+    const Text = big ? ExtraLargeText : LargeText;
+    return <div style={{ margin: '1em' }}>
+      <SmallTextLight style={{ margin: '.5em' }}>{title}</SmallTextLight>
+      <Text style={{ color: kind == 'positive' ? 'green' : (kind == 'negative' 
? 'red' : 'black') }}>
+        {text}
+      </Text>
+    </div>
+  }
+
+  function amountToString(text: AmountLike) {
+    const aj = Amounts.jsonifyAmount(text)
+    const amount = Amounts.stringifyValue(aj)
+    return `${amount} ${aj.currency}`
+  }
+
 
   if (transaction.type === TransactionType.Withdrawal) {
     const fee = Amounts.sub(
       Amounts.parseOrThrow(transaction.amountRaw),
       Amounts.parseOrThrow(transaction.amountEffective),
     ).amount
-    return <TransactionTemplate upperRight={<Fragment>From 
<b>{transaction.exchangeBaseUrl}</b></Fragment>}>
-      <h3>Withdraw <Status /></h3>
-      <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
+    return <TransactionTemplate>
+      <h2>Withdrawal <Status /></h2>
+      <div>{transaction.timestamp.t_ms === 'never' ? 'never': 
format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
+      <br />
+      <Part title="Total withdrawn" 
text={amountToString(transaction.amountEffective)} kind='positive' />
+      <Part title="Chosen amount" text={amountToString(transaction.amountRaw)} 
kind='neutral' />
+      <Part title="Exchange fee" text={amountToString(fee)} kind='negative' />
+      <Part title="Exchange" text={new 
URL(transaction.exchangeBaseUrl).hostname} kind='neutral' />
     </TransactionTemplate>
   }
 
@@ -123,13 +134,17 @@ export function TransactionView({ transaction, onDelete, 
onRetry, onBack }: Wall
       Amounts.parseOrThrow(transaction.amountRaw),
     ).amount
 
-    return <TransactionTemplate upperRight={<Fragment>To 
<b>{transaction.info.merchant.name}</b></Fragment>}>
-      <h3>Payment <Status /></h3>
-      <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
-      <span style="font-size:small; 
color:gray">#{transaction.info.orderId}</span>
-      <p>
-        {transaction.info.summary}
-      </p>
+    return <TransactionTemplate>
+      <h2>Payment <Status /></h2>
+      <div>{transaction.timestamp.t_ms === 'never' ? 'never': 
format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
+      <br />
+      <Part big title="Total paid" 
text={amountToString(transaction.amountEffective)} kind='negative' />
+      <Part big title="Purchase amount" 
text={amountToString(transaction.amountRaw)} kind='neutral' />
+      <Part big title="Fee" text={amountToString(fee)} kind='negative' />
+      <Part title="Merchant" text={transaction.info.merchant.name} 
kind='neutral' />
+      <Part title="Purchase" text={transaction.info.summary} kind='neutral' />
+      <Part title="Receipt" text={`#${transaction.info.orderId}`} 
kind='neutral' />
+
       <div>
         {transaction.info.products && transaction.info.products.length > 0 &&
           <ListOfProducts>
@@ -153,9 +168,13 @@ export function TransactionView({ transaction, onDelete, 
onRetry, onBack }: Wall
       Amounts.parseOrThrow(transaction.amountRaw),
       Amounts.parseOrThrow(transaction.amountEffective),
     ).amount
-    return <TransactionTemplate upperRight={<Fragment>To 
<b>{transaction.targetPaytoUri}</b></Fragment>}>
-      <h3>Deposit <Status /></h3>
-      <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
+    return <TransactionTemplate>
+      <h2>Deposit <Status /></h2>
+      <div>{transaction.timestamp.t_ms === 'never' ? 'never': 
format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
+      <br />
+      <Part big title="Total deposit" 
text={amountToString(transaction.amountEffective)} kind='negative' />
+      <Part big title="Purchase amount" 
text={amountToString(transaction.amountRaw)} kind='neutral' />
+      <Part big title="Fee" text={amountToString(fee)} kind='negative' />
     </TransactionTemplate>
   }
 
@@ -164,9 +183,13 @@ export function TransactionView({ transaction, onDelete, 
onRetry, onBack }: Wall
       Amounts.parseOrThrow(transaction.amountRaw),
       Amounts.parseOrThrow(transaction.amountEffective),
     ).amount
-    return <TransactionTemplate upperRight={<Fragment>From 
<b>{transaction.exchangeBaseUrl}</b></Fragment>}>
-      <h3>Refresh <Status /></h3>
-      <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
+    return <TransactionTemplate>
+      <h2>Refresh <Status /></h2>
+      <div>{transaction.timestamp.t_ms === 'never' ? 'never': 
format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
+      <br />
+      <Part big title="Total refresh" 
text={amountToString(transaction.amountEffective)} kind='negative' />
+      <Part big title="Refresh amount" 
text={amountToString(transaction.amountRaw)} kind='neutral' />
+      <Part big title="Fee" text={amountToString(fee)} kind='negative' />
     </TransactionTemplate>
   }
 
@@ -175,9 +198,13 @@ export function TransactionView({ transaction, onDelete, 
onRetry, onBack }: Wall
       Amounts.parseOrThrow(transaction.amountRaw),
       Amounts.parseOrThrow(transaction.amountEffective),
     ).amount
-    return <TransactionTemplate upperRight={<Fragment>From 
<b>{transaction.merchantBaseUrl}</b></Fragment>}>
-      <h3>Tip <Status /></h3>
-      <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
+    return <TransactionTemplate>
+      <h2>Tip <Status /></h2>
+      <div>{transaction.timestamp.t_ms === 'never' ? 'never': 
format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
+      <br />
+      <Part big title="Total tip" 
text={amountToString(transaction.amountEffective)} kind='positive' />
+      <Part big title="Received amount" 
text={amountToString(transaction.amountRaw)} kind='neutral' />
+      <Part big title="Fee" text={amountToString(fee)} kind='negative' />
     </TransactionTemplate>
   }
 
@@ -186,11 +213,17 @@ export function TransactionView({ transaction, onDelete, 
onRetry, onBack }: Wall
       Amounts.parseOrThrow(transaction.amountRaw),
       Amounts.parseOrThrow(transaction.amountEffective),
     ).amount
-    return <TransactionTemplate upperRight={<Fragment>From 
<b>{transaction.info.merchant.name}</b></Fragment>}>
-      <h3>Refund <Status /></h3>
-      <h1>{transaction.amountEffective} <Fee value={fee} /></h1>
+    return <TransactionTemplate>
+      <h2>Refund <Status /></h2>
+      <div>{transaction.timestamp.t_ms === 'never' ? 'never': 
format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
+      <br />
+      <Part big title="Total refund" 
text={amountToString(transaction.amountEffective)} kind='positive' />
+      <Part big title="Refund amount" 
text={amountToString(transaction.amountRaw)} kind='neutral' />
+      <Part big title="Fee" text={amountToString(fee)} kind='negative' />
+      <Part title="Merchant" text={transaction.info.merchant.name} 
kind='neutral' />
+      <Part title="Purchase" text={transaction.info.summary} kind='neutral' />
+      <Part title="Receipt" text={`#${transaction.info.orderId}`} 
kind='neutral' />
 
-      <span style="font-size:small; 
color:gray">#{transaction.info.orderId}</span>
       <p>
         {transaction.info.summary}
       </p>

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