wallet transaction detail
This commit is contained in:
parent
9f09f5a1a5
commit
aa0edbdd68
@ -145,7 +145,7 @@ interface WithdrawalDetailsForTalerBankIntegrationApi {
|
||||
|
||||
// This should only be used for actual withdrawals
|
||||
// and not for tips that have their own transactions type.
|
||||
interface TransactionWithdrawal extends TransactionCommon {
|
||||
export interface TransactionWithdrawal extends TransactionCommon {
|
||||
type: TransactionType.Withdrawal;
|
||||
|
||||
/**
|
||||
@ -266,7 +266,7 @@ export interface OrderShortInfo {
|
||||
fulfillmentMessage_i18n?: InternationalizedString;
|
||||
}
|
||||
|
||||
interface TransactionRefund extends TransactionCommon {
|
||||
export interface TransactionRefund extends TransactionCommon {
|
||||
type: TransactionType.Refund;
|
||||
|
||||
// ID for the transaction that is refunded
|
||||
@ -282,7 +282,7 @@ interface TransactionRefund extends TransactionCommon {
|
||||
amountEffective: AmountString;
|
||||
}
|
||||
|
||||
interface TransactionTip extends TransactionCommon {
|
||||
export interface TransactionTip extends TransactionCommon {
|
||||
type: TransactionType.Tip;
|
||||
|
||||
// Raw amount of the tip, without extra fees that apply
|
||||
@ -297,7 +297,7 @@ interface TransactionTip extends TransactionCommon {
|
||||
// A transaction shown for refreshes that are not associated to other transactions
|
||||
// such as a refresh necessary before coin expiration.
|
||||
// It should only be returned by the API if the effective amount is different from zero.
|
||||
interface TransactionRefresh extends TransactionCommon {
|
||||
export interface TransactionRefresh extends TransactionCommon {
|
||||
type: TransactionType.Refresh;
|
||||
|
||||
// Exchange that the coins are refreshed with
|
||||
@ -314,7 +314,7 @@ interface TransactionRefresh extends TransactionCommon {
|
||||
* Deposit transaction, which effectively sends
|
||||
* money from this wallet somewhere else.
|
||||
*/
|
||||
interface TransactionDeposit extends TransactionCommon {
|
||||
export interface TransactionDeposit extends TransactionCommon {
|
||||
type: TransactionType.Deposit;
|
||||
|
||||
depositGroupId: string;
|
||||
|
@ -12,12 +12,13 @@
|
||||
"test": "jest ./tests",
|
||||
"compile": "tsc && rollup -c",
|
||||
"build-storybook": "build-storybook",
|
||||
"storybook": "start-storybook -p 6006",
|
||||
"storybook": "start-storybook -s static -p 6006",
|
||||
"watch": "tsc --watch & rollup -w -c"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gnu-taler/taler-util": "workspace:*",
|
||||
"@gnu-taler/taler-wallet-core": "workspace:*",
|
||||
"date-fns": "^2.22.1",
|
||||
"preact": "^10.5.13",
|
||||
"preact-router": "^3.2.1",
|
||||
"tslib": "^2.1.0"
|
||||
|
@ -19,7 +19,7 @@ export enum Pages {
|
||||
return_coins = '/return-coins',
|
||||
tips = '/tips',
|
||||
withdraw = '/withdraw',
|
||||
popup = '/popup/:rest',
|
||||
popup = '/popup/:rest*',
|
||||
}
|
||||
|
||||
export function Application() {
|
||||
|
191
packages/taler-wallet-webextension/src/pages/popup.stories.tsx
Normal file
191
packages/taler-wallet-webextension/src/pages/popup.stories.tsx
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
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, TransactionPayment, TransactionType, TransactionWithdrawal, TransactionDeposit, TransactionRefresh, TransactionTip, TransactionRefund, WithdrawalType, TransactionCommon } from '@gnu-taler/taler-util';
|
||||
import { Fragment, h } from 'preact';
|
||||
import { WalletTransactionView as Component } from './popup';
|
||||
|
||||
export default {
|
||||
title: 'popup/transaction details',
|
||||
component: Component,
|
||||
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 }}>
|
||||
<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,
|
||||
type: TransactionType.Payment,
|
||||
info: {
|
||||
contractTermsHash: 'ASDZXCASD',
|
||||
merchant: {
|
||||
name: 'the merchant',
|
||||
},
|
||||
orderId: '#12345',
|
||||
products: [],
|
||||
summary: 'the summary',
|
||||
fulfillmentMessage: '',
|
||||
},
|
||||
proposalId: '#proposalId',
|
||||
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: '#refundId',
|
||||
info: {
|
||||
contractTermsHash: 'ASDZXCASD',
|
||||
merchant: {
|
||||
name: 'the merchant',
|
||||
},
|
||||
orderId: '#12345',
|
||||
products: [],
|
||||
summary: 'the summary',
|
||||
fulfillmentMessage: '',
|
||||
},
|
||||
} as TransactionRefund,
|
||||
}
|
||||
|
||||
function dynamic<T>(props: any) {
|
||||
const r = (args: any) => <Component {...args} />
|
||||
r.args = props
|
||||
return r
|
||||
}
|
||||
|
||||
export const NotYetLoaded = dynamic({});
|
||||
|
||||
export const Withdraw = dynamic({
|
||||
transaction: exampleData.withdraw
|
||||
});
|
||||
|
||||
export const WithdrawPending = dynamic({
|
||||
transaction: { ...exampleData.withdraw, pending: true },
|
||||
});
|
||||
|
||||
|
||||
export const Payment = dynamic({
|
||||
transaction: exampleData.payment
|
||||
});
|
||||
|
||||
export const PaymentPending = dynamic({
|
||||
transaction: { ...exampleData.payment, pending: true },
|
||||
});
|
||||
|
||||
export const PaymentWithProducts = dynamic({
|
||||
transaction: {
|
||||
...exampleData.payment,
|
||||
info: {
|
||||
...exampleData.payment.info,
|
||||
products: [{
|
||||
description: 't-shirt',
|
||||
}, {
|
||||
description: 'beer',
|
||||
}]
|
||||
}
|
||||
} as TransactionPayment,
|
||||
});
|
||||
|
||||
|
||||
export const Deposit = dynamic({
|
||||
transaction: exampleData.deposit
|
||||
});
|
||||
|
||||
export const DepositPending = dynamic({
|
||||
transaction: { ...exampleData.deposit, pending: true }
|
||||
});
|
||||
|
||||
export const Refresh = dynamic({
|
||||
transaction: exampleData.refresh
|
||||
});
|
||||
|
||||
export const Tip = dynamic({
|
||||
transaction: exampleData.tip
|
||||
});
|
||||
|
||||
export const TipPending = dynamic({
|
||||
transaction: { ...exampleData.tip, pending: true }
|
||||
});
|
||||
|
||||
export const Refund = dynamic({
|
||||
transaction: exampleData.refund
|
||||
});
|
||||
|
||||
export const RefundPending = dynamic({
|
||||
transaction: { ...exampleData.refund , pending: true }
|
||||
});
|
||||
|
||||
export const RefundWithProducts = dynamic({
|
||||
transaction: {
|
||||
...exampleData.refund,
|
||||
info: {
|
||||
...exampleData.refund.info,
|
||||
products: [{
|
||||
description: 't-shirt',
|
||||
}, {
|
||||
description: 'beer',
|
||||
}]
|
||||
}
|
||||
} as TransactionRefund,
|
||||
});
|
@ -38,7 +38,8 @@ import {
|
||||
Timestamp,
|
||||
amountFractionalBase,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { Component, ComponentChildren, JSX } from "preact";
|
||||
import { format } from "date-fns";
|
||||
import { Component, ComponentChildren, Fragment, JSX } from "preact";
|
||||
import { route, Route, Router } from 'preact-router';
|
||||
import { Match } from 'preact-router/match';
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
@ -268,6 +269,7 @@ interface TransactionLayoutProps {
|
||||
amount: AmountString | "unknown";
|
||||
timestamp: Timestamp;
|
||||
title: string;
|
||||
id: string;
|
||||
subtitle: string;
|
||||
iconPath: string;
|
||||
pending: boolean;
|
||||
@ -297,7 +299,7 @@ function TransactionLayout(props: TransactionLayoutProps): JSX.Element {
|
||||
>
|
||||
<div style={{ fontSize: "small", color: "gray" }}>{dateStr}</div>
|
||||
<div style={{ fontVariant: "small-caps", fontSize: "x-large" }}>
|
||||
<span>{props.title}</span>
|
||||
<a href={Pages.transaction.replace(':tid', props.id)}><span>{props.title}</span></a>
|
||||
{props.pending ? (
|
||||
<span style={{ color: "darkblue" }}> (Pending)</span>
|
||||
) : null}
|
||||
@ -320,6 +322,7 @@ function TransactionItem(props: { tx: Transaction }): JSX.Element {
|
||||
case TransactionType.Withdrawal:
|
||||
return (
|
||||
<TransactionLayout
|
||||
id={tx.transactionId}
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"credit"}
|
||||
title="Withdrawal"
|
||||
@ -332,6 +335,7 @@ function TransactionItem(props: { tx: Transaction }): JSX.Element {
|
||||
case TransactionType.Payment:
|
||||
return (
|
||||
<TransactionLayout
|
||||
id={tx.transactionId}
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"debit"}
|
||||
title="Payment"
|
||||
@ -344,6 +348,7 @@ function TransactionItem(props: { tx: Transaction }): JSX.Element {
|
||||
case TransactionType.Refund:
|
||||
return (
|
||||
<TransactionLayout
|
||||
id={tx.transactionId}
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"credit"}
|
||||
title="Refund"
|
||||
@ -356,6 +361,7 @@ function TransactionItem(props: { tx: Transaction }): JSX.Element {
|
||||
case TransactionType.Tip:
|
||||
return (
|
||||
<TransactionLayout
|
||||
id={tx.transactionId}
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"credit"}
|
||||
title="Tip"
|
||||
@ -368,6 +374,7 @@ function TransactionItem(props: { tx: Transaction }): JSX.Element {
|
||||
case TransactionType.Refresh:
|
||||
return (
|
||||
<TransactionLayout
|
||||
id={tx.transactionId}
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"credit"}
|
||||
title="Refresh"
|
||||
@ -380,6 +387,7 @@ function TransactionItem(props: { tx: Transaction }): JSX.Element {
|
||||
case TransactionType.Deposit:
|
||||
return (
|
||||
<TransactionLayout
|
||||
id={tx.transactionId}
|
||||
amount={tx.amountEffective}
|
||||
debitCreditIndicator={"debit"}
|
||||
title="Refresh"
|
||||
@ -420,6 +428,223 @@ function WalletHistory(props: any): JSX.Element {
|
||||
);
|
||||
}
|
||||
|
||||
interface WalletTransactionProps {
|
||||
transaction?: Transaction,
|
||||
onDelete: () => void,
|
||||
onBack: () => void,
|
||||
}
|
||||
|
||||
export function WalletTransactionView({ transaction, onDelete, onBack }: WalletTransactionProps) {
|
||||
if (!transaction) {
|
||||
return <div>Loading ...</div>;
|
||||
}
|
||||
|
||||
function Footer() {
|
||||
return <footer style={{ marginTop: 'auto', display: 'flex' }}>
|
||||
<button onClick={onBack}>back</button>
|
||||
<div style={{ width: '100%', flexDirection: 'row', justifyContent: 'flex-end', display: 'flex' }}>
|
||||
<button onClick={onDelete}>remove</button>
|
||||
|
||||
</div>
|
||||
|
||||
</footer>
|
||||
}
|
||||
|
||||
function Pending() {
|
||||
if (!transaction?.pending) return null
|
||||
return <span style={{fontWeight:'normal', fontSize:16, color: 'gray'}}>(pending...)</span>
|
||||
}
|
||||
|
||||
function CommonFields() {
|
||||
if (!transaction) return null;
|
||||
return <Fragment>
|
||||
<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>
|
||||
</Fragment>
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Withdrawal) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: '20rem' }} >
|
||||
<section>
|
||||
<h1>Withdrawal <Pending /></h1>
|
||||
<p>
|
||||
From <b>{transaction.exchangeBaseUrl}</b>
|
||||
</p>
|
||||
<table class={transaction.pending ? "detailsTable pending" : "detailsTable"}>
|
||||
<CommonFields />
|
||||
</table>
|
||||
</section>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Payment) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: '20rem' }} >
|
||||
<section>
|
||||
<h1>Payment ({transaction.proposalId}) <Pending /></h1>
|
||||
<p>
|
||||
To <b>{transaction.info.merchant.name}</b>
|
||||
</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>
|
||||
}
|
||||
<CommonFields />
|
||||
</table>
|
||||
</section>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Deposit) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: '20rem' }} >
|
||||
<section>
|
||||
<h1>Deposit ({transaction.depositGroupId}) <Pending /></h1>
|
||||
<p>
|
||||
To <b>{transaction.targetPaytoUri}</b>
|
||||
</p>
|
||||
<table class={transaction.pending ? "detailsTable pending" : "detailsTable"}>
|
||||
<CommonFields />
|
||||
</table>
|
||||
</section>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Refresh) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: '20rem' }} >
|
||||
<section>
|
||||
<h1>Refresh <Pending /></h1>
|
||||
<p>
|
||||
From <b>{transaction.exchangeBaseUrl}</b>
|
||||
</p>
|
||||
<table class={transaction.pending ? "detailsTable pending" : "detailsTable"}>
|
||||
<CommonFields />
|
||||
</table>
|
||||
</section>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Tip) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: '20rem' }} >
|
||||
<section>
|
||||
<h1>Tip <Pending /></h1>
|
||||
<p>
|
||||
From <b>{transaction.merchantBaseUrl}</b>
|
||||
</p>
|
||||
<table class={transaction.pending ? "detailsTable pending" : "detailsTable"}>
|
||||
<CommonFields />
|
||||
</table>
|
||||
</section>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (transaction.type === TransactionType.Refund) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: '20rem' }} >
|
||||
<section>
|
||||
<h1>Refund ({transaction.refundedTransactionId}) <Pending /></h1>
|
||||
<p>
|
||||
From <b>{transaction.info.merchant.name}</b>
|
||||
</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>
|
||||
}
|
||||
<CommonFields />
|
||||
</table>
|
||||
</section>
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return <div></div>
|
||||
}
|
||||
|
||||
function WalletTransaction({ tid }: { tid: string }): JSX.Element {
|
||||
const [transaction, setTransaction] = useState<
|
||||
Transaction | undefined
|
||||
>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async (): Promise<void> => {
|
||||
const res = await wxApi.getTransactions();
|
||||
const ts = res.transactions.filter(t => t.transactionId === tid)
|
||||
if (ts.length === 1) {
|
||||
setTransaction(ts[0]);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
return <WalletTransactionView
|
||||
transaction={transaction}
|
||||
onDelete={() => wxApi.deleteTransaction(tid)}
|
||||
onBack={() => { history.go(-1) }}
|
||||
/>
|
||||
}
|
||||
|
||||
class WalletSettings extends Component<any, any> {
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
@ -597,6 +822,7 @@ export function WalletPopup(): JSX.Element {
|
||||
<Route path={Pages.settings} component={WalletSettings} />
|
||||
<Route path={Pages.debug} component={WalletDebug} />
|
||||
<Route path={Pages.history} component={WalletHistory} />
|
||||
<Route path={Pages.transaction} component={WalletTransaction} />
|
||||
</Router>
|
||||
</div>
|
||||
</div>
|
||||
@ -605,6 +831,7 @@ export function WalletPopup(): JSX.Element {
|
||||
|
||||
enum Pages {
|
||||
balance = '/popup/balance',
|
||||
transaction = '/popup/transaction/:tid',
|
||||
settings = '/popup/settings',
|
||||
debug = '/popup/debug',
|
||||
history = '/popup/history',
|
||||
|
@ -35,6 +35,7 @@ import {
|
||||
PrepareTipRequest,
|
||||
PrepareTipResult,
|
||||
AcceptTipRequest,
|
||||
DeleteTransactionRequest,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { OperationFailedError } from "@gnu-taler/taler-wallet-core";
|
||||
|
||||
@ -130,6 +131,15 @@ export function getTransactions(): Promise<TransactionsResponse> {
|
||||
return callBackend("getTransactions", {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get balances for all currencies/exchanges.
|
||||
*/
|
||||
export function deleteTransaction(transactionId: string): Promise<void> {
|
||||
return callBackend("deleteTransaction", {
|
||||
transactionId
|
||||
} as DeleteTransactionRequest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a refund and accept it.
|
||||
*/
|
||||
|
@ -238,3 +238,25 @@ button.accept:disabled {
|
||||
font-weight: bold;
|
||||
background: #00fa9a;
|
||||
}
|
||||
|
||||
table.detailsTable td {
|
||||
text-align: right;
|
||||
border: 0px;
|
||||
border-bottom: 1px;
|
||||
}
|
||||
|
||||
table.detailsTable td {
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
|
||||
table.detailsTable tr:last-child td {
|
||||
border-bottom: 0px;
|
||||
}
|
||||
|
||||
table.detailsTable {
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
table.detailsTable.pending {
|
||||
color: gray;
|
||||
}
|
@ -224,6 +224,7 @@ importers:
|
||||
'@types/node': ^14.14.22
|
||||
ava: 3.15.0
|
||||
babel-plugin-transform-react-jsx: ^6.24.1
|
||||
date-fns: ^2.22.1
|
||||
enzyme: ^3.11.0
|
||||
enzyme-adapter-preact-pure: ^3.1.0
|
||||
history: 4.10.1
|
||||
@ -243,6 +244,7 @@ importers:
|
||||
dependencies:
|
||||
'@gnu-taler/taler-util': link:../taler-util
|
||||
'@gnu-taler/taler-wallet-core': link:../taler-wallet-core
|
||||
date-fns: 2.22.1
|
||||
preact: 10.5.13
|
||||
preact-router: 3.2.1_preact@10.5.13
|
||||
tslib: 2.1.0
|
||||
@ -8087,6 +8089,11 @@ packages:
|
||||
whatwg-url: 8.5.0
|
||||
dev: true
|
||||
|
||||
/date-fns/2.22.1:
|
||||
resolution: {integrity: sha512-yUFPQjrxEmIsMqlHhAhmxkuH769baF21Kk+nZwZGyrMoyLA+LugaQtC0+Tqf9CBUUULWwUJt6Q5ySI3LJDDCGg==}
|
||||
engines: {node: '>=0.11'}
|
||||
dev: false
|
||||
|
||||
/date-time/3.1.0:
|
||||
resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==}
|
||||
engines: {node: '>=6'}
|
||||
|
Loading…
Reference in New Issue
Block a user