aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/wallet
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-11-15 11:18:58 -0300
committerSebastian <sebasjm@gmail.com>2021-11-15 11:18:58 -0300
commit1d4815c66c395f4fcc86c30e20f3d005e3cb9ff5 (patch)
tree99e8241a5eb5af4d752be93a460004bc0c6255aa /packages/taler-wallet-webextension/src/wallet
parent9692f589c687a2ba39a705ca4238cf123f444c61 (diff)
downloadwallet-core-1d4815c66c395f4fcc86c30e20f3d005e3cb9ff5.tar.xz
prettier
Diffstat (limited to 'packages/taler-wallet-webextension/src/wallet')
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx307
-rw-r--r--packages/taler-wallet-webextension/src/wallet/BackupPage.tsx177
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx84
-rw-r--r--packages/taler-wallet-webextension/src/wallet/BalancePage.tsx129
-rw-r--r--packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx39
-rw-r--r--packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx94
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.stories.tsx198
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.tsx103
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx92
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx41
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx40
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx323
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx269
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx25
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx54
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx32
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Settings.tsx109
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx213
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx442
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx20
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Welcome.tsx76
21 files changed, 1700 insertions, 1167 deletions
diff --git a/packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx
index 9a53fefe2..b2771bc2a 100644
--- a/packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx
@@ -15,179 +15,184 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { ProviderPaymentType } from '@gnu-taler/taler-wallet-core';
-import { addDays } from 'date-fns';
-import { BackupView as TestedComponent } from './BackupPage';
-import { createExample } from '../test-utils';
+import { ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import { addDays } from "date-fns";
+import { BackupView as TestedComponent } from "./BackupPage";
+import { createExample } from "../test-utils";
export default {
- title: 'wallet/backup/list',
+ title: "wallet/backup/list",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const LotOfProviders = createExample(TestedComponent, {
- providers: [{
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
+ providers: [
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": addDays(new Date(), 13).getTime()
- }
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: addDays(new Date(), 13).getTime(),
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Pending,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Pending,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.InsufficientBalance,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.InsufficientBalance,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.TermsChanged,
- newTerms: {
- annualFee: 'USD:2',
- storageLimitInMegabytes: 8,
- supportedProtocolVersion: '2',
- },
- oldTerms: {
- annualFee: 'USD:1',
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.TermsChanged,
+ newTerms: {
+ annualFee: "USD:2",
+ storageLimitInMegabytes: 8,
+ supportedProtocolVersion: "2",
+ },
+ oldTerms: {
+ annualFee: "USD:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "1",
+ },
+ paidUntil: {
+ t_ms: "never",
+ },
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
storageLimitInMegabytes: 16,
- supportedProtocolVersion: '1',
-
+ supportedProtocolVersion: "0.0",
},
- paidUntil: {
- t_ms: 'never'
- }
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }]
+ ],
});
-
export const OneProvider = createExample(TestedComponent, {
- providers: [{
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ providers: [
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }]
+ ],
});
-
export const Empty = createExample(TestedComponent, {
- providers: []
+ providers: [],
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
index 712329bf8..c3be0203e 100644
--- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
@@ -14,15 +14,29 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { i18n, Timestamp } from "@gnu-taler/taler-util";
-import { ProviderInfo, ProviderPaymentStatus } from "@gnu-taler/taler-wallet-core";
-import { differenceInMonths, formatDuration, intervalToDuration } from "date-fns";
+import {
+ ProviderInfo,
+ ProviderPaymentStatus,
+} from "@gnu-taler/taler-wallet-core";
+import {
+ differenceInMonths,
+ formatDuration,
+ intervalToDuration,
+} from "date-fns";
import { Fragment, JSX, VNode, h } from "preact";
import {
- BoldLight, ButtonPrimary, ButtonSuccess, Centered,
- CenteredText, CenteredBoldText, PopupBox, RowBorderGray,
- SmallText, SmallLightText, WalletBox
+ BoldLight,
+ ButtonPrimary,
+ ButtonSuccess,
+ Centered,
+ CenteredText,
+ CenteredBoldText,
+ PopupBox,
+ RowBorderGray,
+ SmallText,
+ SmallLightText,
+ WalletBox,
} from "../components/styled";
import { useBackupStatus } from "../hooks/useBackupStatus";
import { Pages } from "../NavigationBar";
@@ -32,49 +46,68 @@ interface Props {
}
export function BackupPage({ onAddProvider }: Props): VNode {
- const status = useBackupStatus()
+ const status = useBackupStatus();
if (!status) {
- return <div>Loading...</div>
+ return <div>Loading...</div>;
}
- return <BackupView providers={status.providers} onAddProvider={onAddProvider} onSyncAll={status.sync} />;
+ return (
+ <BackupView
+ providers={status.providers}
+ onAddProvider={onAddProvider}
+ onSyncAll={status.sync}
+ />
+ );
}
export interface ViewProps {
- providers: ProviderInfo[],
+ providers: ProviderInfo[];
onAddProvider: () => void;
onSyncAll: () => Promise<void>;
}
-export function BackupView({ providers, onAddProvider, onSyncAll }: ViewProps): VNode {
+export function BackupView({
+ providers,
+ onAddProvider,
+ onSyncAll,
+}: ViewProps): VNode {
return (
<WalletBox>
<section>
- {providers.map((provider) => <BackupLayout
- status={provider.paymentStatus}
- timestamp={provider.lastSuccessfulBackupTimestamp}
- id={provider.syncProviderBaseUrl}
- active={provider.active}
- title={provider.name}
- />
+ {providers.map((provider) => (
+ <BackupLayout
+ status={provider.paymentStatus}
+ timestamp={provider.lastSuccessfulBackupTimestamp}
+ id={provider.syncProviderBaseUrl}
+ active={provider.active}
+ title={provider.name}
+ />
+ ))}
+ {!providers.length && (
+ <Centered style={{ marginTop: 100 }}>
+ <BoldLight>No backup providers configured</BoldLight>
+ <ButtonSuccess onClick={onAddProvider}>
+ <i18n.Translate>Add provider</i18n.Translate>
+ </ButtonSuccess>
+ </Centered>
)}
- {!providers.length && <Centered style={{ marginTop: 100 }}>
- <BoldLight>No backup providers configured</BoldLight>
- <ButtonSuccess onClick={onAddProvider}><i18n.Translate>Add provider</i18n.Translate></ButtonSuccess>
- </Centered>}
</section>
- {!!providers.length && <footer>
- <div />
- <div>
- <ButtonPrimary onClick={onSyncAll}>{
- providers.length > 1 ?
- <i18n.Translate>Sync all backups</i18n.Translate> :
- <i18n.Translate>Sync now</i18n.Translate>
- }</ButtonPrimary>
- <ButtonSuccess onClick={onAddProvider}>Add provider</ButtonSuccess>
- </div>
- </footer>}
+ {!!providers.length && (
+ <footer>
+ <div />
+ <div>
+ <ButtonPrimary onClick={onSyncAll}>
+ {providers.length > 1 ? (
+ <i18n.Translate>Sync all backups</i18n.Translate>
+ ) : (
+ <i18n.Translate>Sync now</i18n.Translate>
+ )}
+ </ButtonPrimary>
+ <ButtonSuccess onClick={onAddProvider}>Add provider</ButtonSuccess>
+ </div>
+ </footer>
+ )}
</WalletBox>
- )
+ );
}
interface TransactionLayoutProps {
@@ -92,55 +125,73 @@ function BackupLayout(props: TransactionLayoutProps): JSX.Element {
timeStyle: "short",
} as any);
-
return (
<RowBorderGray>
<div style={{ color: !props.active ? "grey" : undefined }}>
- <a href={Pages.provider_detail.replace(':pid', encodeURIComponent(props.id))}><span>{props.title}</span></a>
-
- {dateStr && <SmallText style={{ marginTop: 5 }}>Last synced: {dateStr}</SmallText>}
- {!dateStr && <SmallLightText style={{ marginTop: 5 }}>Not synced</SmallLightText>}
+ <a
+ href={Pages.provider_detail.replace(
+ ":pid",
+ encodeURIComponent(props.id),
+ )}
+ >
+ <span>{props.title}</span>
+ </a>
+
+ {dateStr && (
+ <SmallText style={{ marginTop: 5 }}>Last synced: {dateStr}</SmallText>
+ )}
+ {!dateStr && (
+ <SmallLightText style={{ marginTop: 5 }}>Not synced</SmallLightText>
+ )}
</div>
<div>
- {props.status?.type === 'paid' ?
- <ExpirationText until={props.status.paidUntil} /> :
+ {props.status?.type === "paid" ? (
+ <ExpirationText until={props.status.paidUntil} />
+ ) : (
<div>{props.status.type}</div>
- }
+ )}
</div>
</RowBorderGray>
);
}
function ExpirationText({ until }: { until: Timestamp }) {
- return <Fragment>
- <CenteredText> Expires in </CenteredText>
- <CenteredBoldText {...({ color: colorByTimeToExpire(until) })}> {daysUntil(until)} </CenteredBoldText>
- </Fragment>
+ return (
+ <Fragment>
+ <CenteredText> Expires in </CenteredText>
+ <CenteredBoldText {...{ color: colorByTimeToExpire(until) }}>
+ {" "}
+ {daysUntil(until)}{" "}
+ </CenteredBoldText>
+ </Fragment>
+ );
}
function colorByTimeToExpire(d: Timestamp) {
- if (d.t_ms === 'never') return 'rgb(28, 184, 65)'
- const months = differenceInMonths(d.t_ms, new Date())
- return months > 1 ? 'rgb(28, 184, 65)' : 'rgb(223, 117, 20)';
+ if (d.t_ms === "never") return "rgb(28, 184, 65)";
+ const months = differenceInMonths(d.t_ms, new Date());
+ return months > 1 ? "rgb(28, 184, 65)" : "rgb(223, 117, 20)";
}
function daysUntil(d: Timestamp) {
- if (d.t_ms === 'never') return undefined
+ if (d.t_ms === "never") return undefined;
const duration = intervalToDuration({
start: d.t_ms,
end: new Date(),
- })
+ });
const str = formatDuration(duration, {
- delimiter: ', ',
+ delimiter: ", ",
format: [
- duration?.years ? 'years' : (
- duration?.months ? 'months' : (
- duration?.days ? 'days' : (
- duration.hours ? 'hours' : 'minutes'
- )
- )
- )
- ]
- })
- return `${str}`
-} \ No newline at end of file
+ duration?.years
+ ? "years"
+ : duration?.months
+ ? "months"
+ : duration?.days
+ ? "days"
+ : duration.hours
+ ? "hours"
+ : "minutes",
+ ],
+ });
+ return `${str}`;
+}
diff --git a/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
index cccda203e..2432c31eb 100644
--- a/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
@@ -15,28 +15,25 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample, NullLink } from '../test-utils';
-import { BalanceView as TestedComponent } from './BalancePage';
+import { createExample, NullLink } from "../test-utils";
+import { BalanceView as TestedComponent } from "./BalancePage";
export default {
- title: 'wallet/balance',
+ title: "wallet/balance",
component: TestedComponent,
- argTypes: {
- }
+ argTypes: {},
};
-
-export const NotYetLoaded = createExample(TestedComponent, {
-});
+export const NotYetLoaded = createExample(TestedComponent, {});
export const GotError = createExample(TestedComponent, {
balance: {
hasError: true,
- message: 'Network error'
+ message: "Network error",
},
Linker: NullLink,
});
@@ -45,7 +42,7 @@ export const EmptyBalance = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: []
+ balances: [],
},
},
Linker: NullLink,
@@ -55,13 +52,15 @@ export const SomeCoins = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:10.5',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:10.5",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -71,13 +70,15 @@ export const SomeCoinsAndIncomingMoney = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:2.23',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:5.11',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:2.23",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:5.11",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -87,19 +88,22 @@ export const SomeCoinsInTwoCurrencies = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:2',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:5',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- },{
- available: 'EUR:4',
- hasPendingTransactions: false,
- pendingIncoming: 'EUR:5',
- pendingOutgoing: 'EUR:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:2",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:5",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "EUR:4",
+ hasPendingTransactions: false,
+ pendingIncoming: "EUR:5",
+ pendingOutgoing: "EUR:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
diff --git a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
index eb5a0447c..f3c08a3e8 100644
--- a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
@@ -15,19 +15,30 @@
*/
import {
- amountFractionalBase, Amounts,
- Balance, BalancesResponse,
- i18n
+ amountFractionalBase,
+ Amounts,
+ Balance,
+ BalancesResponse,
+ i18n,
} from "@gnu-taler/taler-util";
-import { JSX } from "preact";
+import { JSX, h } from "preact";
import { ButtonPrimary, Centered, WalletBox } from "../components/styled/index";
import { BalancesHook, useBalances } from "../hooks/useBalances";
import { PageLink, renderAmount } from "../renderHtml";
-
-export function BalancePage({ goToWalletManualWithdraw }: { goToWalletManualWithdraw: () => void }) {
- const balance = useBalances()
- return <BalanceView balance={balance} Linker={PageLink} goToWalletManualWithdraw={goToWalletManualWithdraw} />
+export function BalancePage({
+ goToWalletManualWithdraw,
+}: {
+ goToWalletManualWithdraw: () => void;
+}) {
+ const balance = useBalances();
+ return (
+ <BalanceView
+ balance={balance}
+ Linker={PageLink}
+ goToWalletManualWithdraw={goToWalletManualWithdraw}
+ />
+ );
}
export interface BalanceViewProps {
@@ -36,9 +47,13 @@ export interface BalanceViewProps {
goToWalletManualWithdraw: () => void;
}
-export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: BalanceViewProps) {
+export function BalanceView({
+ balance,
+ Linker,
+ goToWalletManualWithdraw,
+}: BalanceViewProps) {
if (!balance) {
- return <span />
+ return <span />;
}
if (balance.hasError) {
@@ -50,19 +65,24 @@ export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: Balan
diagnostics.
</p>
</div>
- )
+ );
}
if (balance.response.balances.length === 0) {
return (
- <p><i18n.Translate>
- You have no balance to show. Need some{" "}
- <Linker pageName="/welcome">help</Linker> getting started?
- </i18n.Translate></p>
- )
+ <p>
+ <i18n.Translate>
+ You have no balance to show. Need some{" "}
+ <Linker pageName="/welcome">help</Linker> getting started?
+ </i18n.Translate>
+ </p>
+ );
}
- return <ShowBalances wallet={balance.response}
- onWithdraw={goToWalletManualWithdraw}
- />
+ return (
+ <ShowBalances
+ wallet={balance.response}
+ onWithdraw={goToWalletManualWithdraw}
+ />
+ );
}
function formatPending(entry: Balance): JSX.Element {
@@ -75,13 +95,15 @@ function formatPending(entry: Balance): JSX.Element {
if (!Amounts.isZero(pendingIncoming)) {
incoming = (
- <span><i18n.Translate>
- <span style={{ color: "darkgreen" }}>
- {"+"}
- {renderAmount(entry.pendingIncoming)}
- </span>{" "}
- incoming
- </i18n.Translate></span>
+ <span>
+ <i18n.Translate>
+ <span style={{ color: "darkgreen" }}>
+ {"+"}
+ {renderAmount(entry.pendingIncoming)}
+ </span>{" "}
+ incoming
+ </i18n.Translate>
+ </span>
);
}
@@ -100,27 +122,36 @@ function formatPending(entry: Balance): JSX.Element {
);
}
-
-function ShowBalances({ wallet, onWithdraw }: { wallet: BalancesResponse, onWithdraw: () => void }) {
- return <WalletBox>
- <section>
- <Centered>{wallet.balances.map((entry) => {
- const av = Amounts.parseOrThrow(entry.available);
- const v = av.value + av.fraction / amountFractionalBase;
- return (
- <p key={av.currency}>
- <span>
- <span style={{ fontSize: "5em", display: "block" }}>{v}</span>{" "}
- <span>{av.currency}</span>
- </span>
- {formatPending(entry)}
- </p>
- );
- })}</Centered>
- </section>
- <footer>
- <div />
- <ButtonPrimary onClick={onWithdraw} >Withdraw</ButtonPrimary>
- </footer>
- </WalletBox>
+function ShowBalances({
+ wallet,
+ onWithdraw,
+}: {
+ wallet: BalancesResponse;
+ onWithdraw: () => void;
+}) {
+ return (
+ <WalletBox>
+ <section>
+ <Centered>
+ {wallet.balances.map((entry) => {
+ const av = Amounts.parseOrThrow(entry.available);
+ const v = av.value + av.fraction / amountFractionalBase;
+ return (
+ <p key={av.currency}>
+ <span>
+ <span style={{ fontSize: "5em", display: "block" }}>{v}</span>{" "}
+ <span>{av.currency}</span>
+ </span>
+ {formatPending(entry)}
+ </p>
+ );
+ })}
+ </Centered>
+ </section>
+ <footer>
+ <div />
+ <ButtonPrimary onClick={onWithdraw}>Withdraw</ButtonPrimary>
+ </footer>
+ </WalletBox>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
index 35da52392..6eab8dc3a 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
@@ -15,42 +15,39 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { CreateManualWithdraw as TestedComponent } from './CreateManualWithdraw';
+import { createExample } from "../test-utils";
+import { CreateManualWithdraw as TestedComponent } from "./CreateManualWithdraw";
export default {
- title: 'wallet/manual withdraw/creation',
+ title: "wallet/manual withdraw/creation",
component: TestedComponent,
- argTypes: {
- }
+ argTypes: {},
};
-
-export const InitialState = createExample(TestedComponent, {
-});
+export const InitialState = createExample(TestedComponent, {});
export const WithExchangeFilled = createExample(TestedComponent, {
- currency: 'COL',
- initialExchange: 'http://exchange.taler:8081',
+ currency: "COL",
+ initialExchange: "http://exchange.taler:8081",
});
export const WithExchangeAndAmountFilled = createExample(TestedComponent, {
- currency: 'COL',
- initialExchange: 'http://exchange.taler:8081',
- initialAmount: '10'
+ currency: "COL",
+ initialExchange: "http://exchange.taler:8081",
+ initialAmount: "10",
});
export const WithExchangeError = createExample(TestedComponent, {
- initialExchange: 'http://exchange.tal',
- error: 'The exchange url seems invalid'
+ initialExchange: "http://exchange.tal",
+ error: "The exchange url seems invalid",
});
export const WithAmountError = createExample(TestedComponent, {
- currency: 'COL',
- initialExchange: 'http://exchange.taler:8081',
- initialAmount: 'e'
+ currency: "COL",
+ initialExchange: "http://exchange.taler:8081",
+ initialAmount: "e",
});
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
index be2cbe41d..b48dcbaf2 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
@@ -1,8 +1,35 @@
+/*
+ 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 { AmountJson, Amounts } from "@gnu-taler/taler-util";
-import { VNode } from "preact";
+import { VNode, h } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
import { ErrorMessage } from "../components/ErrorMessage";
-import { ButtonPrimary, Input, InputWithLabel, LightText, WalletBox } from "../components/styled";
+import {
+ ButtonPrimary,
+ Input,
+ InputWithLabel,
+ LightText,
+ WalletBox,
+} from "../components/styled";
export interface Props {
error: string | undefined;
@@ -13,44 +40,73 @@ export interface Props {
onCreate: (exchangeBaseUrl: string, amount: AmountJson) => Promise<void>;
}
-export function CreateManualWithdraw({ onExchangeChange, initialExchange, initialAmount, error, currency, onCreate }: Props): VNode {
+export function CreateManualWithdraw({
+ onExchangeChange,
+ initialExchange,
+ initialAmount,
+ error,
+ currency,
+ onCreate,
+}: Props): VNode {
const [exchange, setExchange] = useState(initialExchange || "");
const [amount, setAmount] = useState(initialAmount || "");
- const parsedAmount = Amounts.parse(`${currency}:${amount}`)
+ const parsedAmount = Amounts.parse(`${currency}:${amount}`);
let timeout = useRef<number | undefined>(undefined);
useEffect(() => {
- if (timeout) window.clearTimeout(timeout.current)
+ if (timeout) window.clearTimeout(timeout.current);
timeout.current = window.setTimeout(async () => {
- onExchangeChange(exchange)
+ onExchangeChange(exchange);
}, 1000);
- }, [exchange])
-
+ }, [exchange]);
return (
<WalletBox>
<section>
- <ErrorMessage title={error && "Can't create the reserve"} description={error} />
+ <ErrorMessage
+ title={error && "Can't create the reserve"}
+ description={error}
+ />
<h2>Manual Withdrawal</h2>
- <LightText>Choose a exchange to create a reserve and then fill the reserve to withdraw the coins</LightText>
+ <LightText>
+ Choose a exchange to create a reserve and then fill the reserve to
+ withdraw the coins
+ </LightText>
<p>
<Input invalid={!!exchange && !currency}>
<label>Exchange</label>
- <input type="text" placeholder="https://" value={exchange} onChange={(e) => setExchange(e.currentTarget.value)} />
+ <input
+ type="text"
+ placeholder="https://"
+ value={exchange}
+ onChange={(e) => setExchange(e.currentTarget.value)}
+ />
<small>http://exchange.taler:8081</small>
</Input>
- {currency && <InputWithLabel invalid={!!amount && !parsedAmount}>
- <label>Amount</label>
- <div>
- <div>{currency}</div>
- <input type="number" style={{ paddingLeft: `${currency.length}em` }} value={amount} onChange={e => setAmount(e.currentTarget.value)} />
- </div>
- </InputWithLabel>}
+ {currency && (
+ <InputWithLabel invalid={!!amount && !parsedAmount}>
+ <label>Amount</label>
+ <div>
+ <div>{currency}</div>
+ <input
+ type="number"
+ style={{ paddingLeft: `${currency.length}em` }}
+ value={amount}
+ onChange={(e) => setAmount(e.currentTarget.value)}
+ />
+ </div>
+ </InputWithLabel>
+ )}
</p>
</section>
<footer>
<div />
- <ButtonPrimary disabled={!parsedAmount || !exchange} onClick={() => onCreate(exchange, parsedAmount!)}>Create</ButtonPrimary>
+ <ButtonPrimary
+ disabled={!parsedAmount || !exchange}
+ onClick={() => onCreate(exchange, parsedAmount!)}
+ >
+ Create
+ </ButtonPrimary>
</footer>
</WalletBox>
);
diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
index 0ac4be9a6..9ae3ac3bd 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
@@ -15,133 +15,146 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import {
PaymentStatus,
- TransactionCommon, TransactionDeposit, TransactionPayment,
- TransactionRefresh, TransactionRefund, TransactionTip, TransactionType,
+ TransactionCommon,
+ TransactionDeposit,
+ TransactionPayment,
+ TransactionRefresh,
+ TransactionRefund,
+ TransactionTip,
+ TransactionType,
TransactionWithdrawal,
- WithdrawalType
-} from '@gnu-taler/taler-util';
-import { HistoryView as TestedComponent } from './History';
-import { createExample } from '../test-utils';
-
+ WithdrawalType,
+} from "@gnu-taler/taler-util";
+import { HistoryView as TestedComponent } from "./History";
+import { createExample } from "../test-utils";
export default {
- title: 'wallet/history/list',
+ title: "wallet/history/list",
component: TestedComponent,
};
-let count = 0
-const commonTransaction = () => ({
- amountRaw: 'USD:10',
- amountEffective: 'USD:9',
- pending: false,
- timestamp: {
- t_ms: new Date().getTime() - (count++ * 1000 * 60 * 60 * 7)
- },
- transactionId: '12',
-} as TransactionCommon)
+let count = 0;
+const commonTransaction = () =>
+ ({
+ amountRaw: "USD:10",
+ amountEffective: "USD:9",
+ pending: false,
+ timestamp: {
+ t_ms: new Date().getTime() - count++ * 1000 * 60 * 60 * 7,
+ },
+ transactionId: "12",
+ } as TransactionCommon);
const exampleData = {
withdraw: {
...commonTransaction(),
type: TransactionType.Withdrawal,
- exchangeBaseUrl: 'http://exchange.demo.taler.net',
+ exchangeBaseUrl: "http://exchange.demo.taler.net",
withdrawalDetails: {
confirmed: false,
- exchangePaytoUris: ['payto://x-taler-bank/bank/account'],
+ exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
type: WithdrawalType.ManualTransfer,
- }
+ },
} as TransactionWithdrawal,
payment: {
...commonTransaction(),
- amountEffective: 'USD:11',
+ amountEffective: "USD:11",
type: TransactionType.Payment,
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'Blog',
+ name: "Blog",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
- summary: 'the summary',
- fulfillmentMessage: '',
+ summary: "the summary",
+ fulfillmentMessage: "",
},
- proposalId: '1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ proposalId: "1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
status: PaymentStatus.Accepted,
} as TransactionPayment,
deposit: {
...commonTransaction(),
type: TransactionType.Deposit,
- depositGroupId: '#groupId',
- targetPaytoUri: 'payto://x-taler-bank/bank/account',
+ depositGroupId: "#groupId",
+ targetPaytoUri: "payto://x-taler-bank/bank/account",
} as TransactionDeposit,
refresh: {
...commonTransaction(),
type: TransactionType.Refresh,
- exchangeBaseUrl: 'http://exchange.taler',
+ exchangeBaseUrl: "http://exchange.taler",
} as TransactionRefresh,
tip: {
...commonTransaction(),
type: TransactionType.Tip,
- merchantBaseUrl: 'http://ads.merchant.taler.net/',
+ merchantBaseUrl: "http://ads.merchant.taler.net/",
} as TransactionTip,
refund: {
...commonTransaction(),
type: TransactionType.Refund,
- refundedTransactionId: 'payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ refundedTransactionId:
+ "payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'the merchant',
+ name: "the merchant",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
- summary: 'the summary',
- fulfillmentMessage: '',
+ summary: "the summary",
+ fulfillmentMessage: "",
},
} as TransactionRefund,
-}
+};
export const Empty = createExample(TestedComponent, {
list: [],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
-
export const One = createExample(TestedComponent, {
list: [exampleData.withdraw],
- balances: [{
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const OnePending = createExample(TestedComponent, {
- list: [{
- ...exampleData.withdraw,
- pending: true
- }],
- balances: [{
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ list: [
+ {
+ ...exampleData.withdraw,
+ pending: true,
+ },
+ ],
+ balances: [
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const Several = createExample(TestedComponent, {
@@ -154,20 +167,23 @@ export const Several = createExample(TestedComponent, {
...exampleData.payment,
info: {
...exampleData.payment.info,
- summary: 'this is a long summary that may be cropped because its too long',
+ summary:
+ "this is a long summary that may be cropped because its too long",
},
},
exampleData.refund,
exampleData.tip,
exampleData.deposit,
],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const SeveralWithTwoCurrencies = createExample(TestedComponent, {
@@ -181,18 +197,20 @@ export const SeveralWithTwoCurrencies = createExample(TestedComponent, {
exampleData.tip,
exampleData.deposit,
],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }, {
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 8160f8574..aabe50a29 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -14,7 +14,12 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountString, Balance, Transaction, TransactionsResponse } from "@gnu-taler/taler-util";
+import {
+ AmountString,
+ Balance,
+ Transaction,
+ TransactionsResponse,
+} from "@gnu-taler/taler-util";
import { format } from "date-fns";
import { Fragment, h, JSX } from "preact";
import { useEffect, useState } from "preact/hooks";
@@ -23,13 +28,14 @@ import { TransactionItem } from "../components/TransactionItem";
import { useBalances } from "../hooks/useBalances";
import * as wxApi from "../wxApi";
-
export function HistoryPage(props: any): JSX.Element {
const [transactions, setTransactions] = useState<
TransactionsResponse | undefined
>(undefined);
- const balance = useBalances()
- const balanceWithoutError = balance?.hasError ? [] : (balance?.response.balances || [])
+ const balance = useBalances();
+ const balanceWithoutError = balance?.hasError
+ ? []
+ : balance?.response.balances || [];
useEffect(() => {
const fetchData = async (): Promise<void> => {
@@ -43,45 +49,74 @@ export function HistoryPage(props: any): JSX.Element {
return <div>Loading ...</div>;
}
- return <HistoryView balances={balanceWithoutError} list={[...transactions.transactions].reverse()} />;
+ return (
+ <HistoryView
+ balances={balanceWithoutError}
+ list={[...transactions.transactions].reverse()}
+ />
+ );
}
function amountToString(c: AmountString) {
- const idx = c.indexOf(':')
- return `${c.substring(idx + 1)} ${c.substring(0, idx)}`
+ const idx = c.indexOf(":");
+ return `${c.substring(idx + 1)} ${c.substring(0, idx)}`;
}
-
-
-export function HistoryView({ list, balances }: { list: Transaction[], balances: Balance[] }) {
+export function HistoryView({
+ list,
+ balances,
+}: {
+ list: Transaction[];
+ balances: Balance[];
+}) {
const byDate = list.reduce(function (rv, x) {
- const theDate = x.timestamp.t_ms === "never" ? "never" : format(x.timestamp.t_ms, 'dd MMMM yyyy');
+ const theDate =
+ x.timestamp.t_ms === "never"
+ ? "never"
+ : format(x.timestamp.t_ms, "dd MMMM yyyy");
(rv[theDate] = rv[theDate] || []).push(x);
return rv;
}, {} as { [x: string]: Transaction[] });
- const multiCurrency = balances.length > 1
+ const multiCurrency = balances.length > 1;
- return <WalletBox noPadding>
- {balances.length > 0 && <header>
- {balances.length === 1 && <div class="title">
- Balance: <span>{amountToString(balances[0].available)}</span>
- </div>}
- {balances.length > 1 && <div class="title">
- Balance: <ul style={{ margin: 0 }}>
- {balances.map(b => <li>{b.available}</li>)}
- </ul>
- </div>}
- </header>}
- <section>
- {Object.keys(byDate).map((d,i) => {
- return <Fragment key={i}>
- <DateSeparator>{d}</DateSeparator>
- {byDate[d].map((tx, i) => (
- <TransactionItem key={i} tx={tx} multiCurrency={multiCurrency}/>
- ))}
- </Fragment>
- })}
- </section>
- </WalletBox>
+ return (
+ <WalletBox noPadding>
+ {balances.length > 0 && (
+ <header>
+ {balances.length === 1 && (
+ <div class="title">
+ Balance: <span>{amountToString(balances[0].available)}</span>
+ </div>
+ )}
+ {balances.length > 1 && (
+ <div class="title">
+ Balance:{" "}
+ <ul style={{ margin: 0 }}>
+ {balances.map((b) => (
+ <li>{b.available}</li>
+ ))}
+ </ul>
+ </div>
+ )}
+ </header>
+ )}
+ <section>
+ {Object.keys(byDate).map((d, i) => {
+ return (
+ <Fragment key={i}>
+ <DateSeparator>{d}</DateSeparator>
+ {byDate[d].map((tx, i) => (
+ <TransactionItem
+ key={i}
+ tx={tx}
+ multiCurrency={multiCurrency}
+ />
+ ))}
+ </Fragment>
+ );
+ })}
+ </section>
+ </WalletBox>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
index dcc0002e6..102978f9e 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
@@ -14,68 +14,84 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
-import { VNode } from "preact";
-import { useEffect, useRef, useState } from "preact/hooks";
+import { VNode, h } from "preact";
+import { useState } from "preact/hooks";
import { CreateManualWithdraw } from "./CreateManualWithdraw";
-import * as wxApi from '../wxApi'
-import { AcceptManualWithdrawalResult, AmountJson, Amounts } from "@gnu-taler/taler-util";
+import * as wxApi from "../wxApi";
+import {
+ AcceptManualWithdrawalResult,
+ AmountJson,
+ Amounts,
+} from "@gnu-taler/taler-util";
import { ReserveCreated } from "./ReserveCreated.js";
-import { route } from 'preact-router';
+import { route } from "preact-router";
import { Pages } from "../NavigationBar.js";
-interface Props {
-
-}
+interface Props {}
-export function ManualWithdrawPage({ }: Props): VNode {
- const [success, setSuccess] = useState<AcceptManualWithdrawalResult | undefined>(undefined)
- const [currency, setCurrency] = useState<string | undefined>(undefined)
- const [error, setError] = useState<string | undefined>(undefined)
+export function ManualWithdrawPage({}: Props): VNode {
+ const [success, setSuccess] = useState<
+ AcceptManualWithdrawalResult | undefined
+ >(undefined);
+ const [currency, setCurrency] = useState<string | undefined>(undefined);
+ const [error, setError] = useState<string | undefined>(undefined);
- async function onExchangeChange(exchange: string | undefined) {
- if (!exchange) return
+ async function onExchangeChange(exchange: string | undefined): Promise<void> {
+ if (!exchange) return;
try {
- const r = await fetch(`${exchange}/keys`)
- const j = await r.json()
+ const r = await fetch(`${exchange}/keys`);
+ const j = await r.json();
if (j.currency) {
await wxApi.addExchange({
exchangeBaseUrl: `${exchange}/`,
- forceUpdate: true
- })
- setCurrency(j.currency)
+ forceUpdate: true,
+ });
+ setCurrency(j.currency);
}
} catch (e) {
- setError('The exchange url seems invalid')
- setCurrency(undefined)
+ setError("The exchange url seems invalid");
+ setCurrency(undefined);
}
}
- async function doCreate(exchangeBaseUrl: string, amount: AmountJson) {
+ async function doCreate(
+ exchangeBaseUrl: string,
+ amount: AmountJson,
+ ): Promise<void> {
try {
- const resp = await wxApi.acceptManualWithdrawal(exchangeBaseUrl, Amounts.stringify(amount))
- setSuccess(resp)
+ const resp = await wxApi.acceptManualWithdrawal(
+ exchangeBaseUrl,
+ Amounts.stringify(amount),
+ );
+ setSuccess(resp);
} catch (e) {
if (e instanceof Error) {
- setError(e.message)
+ setError(e.message);
} else {
- setError('unexpected error')
+ setError("unexpected error");
}
- setSuccess(undefined)
+ setSuccess(undefined);
}
}
if (success) {
- return <ReserveCreated reservePub={success.reservePub} paytos={success.exchangePaytoUris} onBack={() => {
- route(Pages.balance)
- }}/>
+ return (
+ <ReserveCreated
+ reservePub={success.reservePub}
+ paytos={success.exchangePaytoUris}
+ onBack={() => {
+ route(Pages.balance);
+ }}
+ />
+ );
}
- return <CreateManualWithdraw
- error={error} currency={currency}
- onCreate={doCreate} onExchangeChange={onExchangeChange}
- />;
+ return (
+ <CreateManualWithdraw
+ error={error}
+ currency={currency}
+ onCreate={doCreate}
+ onExchangeChange={onExchangeChange}
+ />
+ );
}
-
-
-
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx
index d1e76c053..5c4e56b15 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx
@@ -15,38 +15,37 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { ConfirmProviderView as TestedComponent } from './ProviderAddPage';
+import { createExample } from "../test-utils";
+import { ConfirmProviderView as TestedComponent } from "./ProviderAddPage";
export default {
- title: 'wallet/backup/confirm',
+ title: "wallet/backup/confirm",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const DemoService = createExample(TestedComponent, {
- url: 'https://sync.demo.taler.net/',
+ url: "https://sync.demo.taler.net/",
provider: {
- annual_fee: 'KUDOS:0.1',
- storage_limit_in_megabytes: 20,
- supported_protocol_version: '1'
- }
+ annual_fee: "KUDOS:0.1",
+ storage_limit_in_megabytes: 20,
+ supported_protocol_version: "1",
+ },
});
export const FreeService = createExample(TestedComponent, {
- url: 'https://sync.taler:9667/',
+ url: "https://sync.taler:9667/",
provider: {
- annual_fee: 'ARS:0',
- storage_limit_in_megabytes: 20,
- supported_protocol_version: '1'
- }
+ annual_fee: "ARS:0",
+ storage_limit_in_megabytes: 20,
+ supported_protocol_version: "1",
+ },
});
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx
index 4890e5e9c..75292b7e4 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx
@@ -15,39 +15,37 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { SetUrlView as TestedComponent } from './ProviderAddPage';
+import { createExample } from "../test-utils";
+import { SetUrlView as TestedComponent } from "./ProviderAddPage";
export default {
- title: 'wallet/backup/add',
+ title: "wallet/backup/add",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
-export const Initial = createExample(TestedComponent, {
-});
+export const Initial = createExample(TestedComponent, {});
export const WithValue = createExample(TestedComponent, {
- initialValue: 'sync.demo.taler.net'
-});
+ initialValue: "sync.demo.taler.net",
+});
export const WithConnectionError = createExample(TestedComponent, {
- withError: 'Network error'
-});
+ withError: "Network error",
+});
export const WithClientError = createExample(TestedComponent, {
- withError: 'URL may not be right: (404) Not Found'
-});
+ withError: "URL may not be right: (404) Not Found",
+});
export const WithServerError = createExample(TestedComponent, {
- withError: 'Try another server: (500) Internal Server Error'
-});
+ withError: "Try another server: (500) Internal Server Error",
+});
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx
index 67ff83442..a170620a3 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx
@@ -15,224 +15,221 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { ProviderPaymentType } from '@gnu-taler/taler-wallet-core';
-import { createExample } from '../test-utils';
-import { ProviderView as TestedComponent } from './ProviderDetailPage';
+import { ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import { createExample } from "../test-utils";
+import { ProviderView as TestedComponent } from "./ProviderDetailPage";
export default {
- title: 'wallet/backup/details',
+ title: "wallet/backup/details",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const Active = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveErrorSync = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
},
lastAttemptedBackupTimestamp: {
- "t_ms": 1625063925078
+ t_ms: 1625063925078,
},
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
lastError: {
code: 2002,
- details: 'details',
- hint: 'error hint from the server',
- message: 'message'
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ details: "details",
+ hint: "error hint from the server",
+ message: "message",
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveBackupProblemUnreadable = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
backupProblem: {
- type: 'backup-unreadable'
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ type: "backup-unreadable",
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveBackupProblemDevice = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
backupProblem: {
- type: 'backup-conflicting-device',
- myDeviceId: 'my-device-id',
- otherDeviceId: 'other-device-id',
+ type: "backup-conflicting-device",
+ myDeviceId: "my-device-id",
+ otherDeviceId: "other-device-id",
backupTimestamp: {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactiveUnpaid = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactiveInsufficientBalance = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.InsufficientBalance,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.InsufficientBalance,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactivePending = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Pending,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Pending,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
-
export const ActiveTermsChanged = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.TermsChanged,
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.TermsChanged,
paidUntil: {
- t_ms: 1656599921000
+ t_ms: 1656599921000,
},
newTerms: {
- "annualFee": "EUR:10",
- "storageLimitInMegabytes": 8,
- "supportedProtocolVersion": "0.0"
+ annualFee: "EUR:10",
+ storageLimitInMegabytes: 8,
+ supportedProtocolVersion: "0.0",
},
oldTerms: {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
index c45458eb7..bd64b0760 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
@@ -14,13 +14,23 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { i18n, Timestamp } from "@gnu-taler/taler-util";
-import { ProviderInfo, ProviderPaymentStatus, ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import {
+ ProviderInfo,
+ ProviderPaymentStatus,
+ ProviderPaymentType,
+} from "@gnu-taler/taler-wallet-core";
import { format, formatDuration, intervalToDuration } from "date-fns";
import { Fragment, VNode, h } from "preact";
import { ErrorMessage } from "../components/ErrorMessage";
-import { Button, ButtonDestructive, ButtonPrimary, PaymentStatus, WalletBox, SmallLightText } from "../components/styled";
+import {
+ Button,
+ ButtonDestructive,
+ ButtonPrimary,
+ PaymentStatus,
+ WalletBox,
+ SmallLightText,
+} from "../components/styled";
import { useProviderStatus } from "../hooks/useProviderStatus";
interface Props {
@@ -29,20 +39,29 @@ interface Props {
}
export function ProviderDetailPage({ pid, onBack }: Props): VNode {
- const status = useProviderStatus(pid)
+ const status = useProviderStatus(pid);
if (!status) {
- return <div><i18n.Translate>Loading...</i18n.Translate></div>
+ return (
+ <div>
+ <i18n.Translate>Loading...</i18n.Translate>
+ </div>
+ );
}
if (!status.info) {
- onBack()
- return <div />
+ onBack();
+ return <div />;
}
- return <ProviderView info={status.info}
- onSync={status.sync}
- onDelete={() => status.remove().then(onBack)}
- onBack={onBack}
- onExtend={() => { null }}
- />;
+ return (
+ <ProviderView
+ info={status.info}
+ onSync={status.sync}
+ onDelete={() => status.remove().then(onBack)}
+ onBack={onBack}
+ onExtend={() => {
+ null;
+ }}
+ />
+ );
}
export interface ViewProps {
@@ -53,124 +72,185 @@ export interface ViewProps {
onExtend: () => void;
}
-export function ProviderView({ info, onDelete, onSync, onBack, onExtend }: ViewProps): VNode {
- const lb = info?.lastSuccessfulBackupTimestamp
- const isPaid = info.paymentStatus.type === ProviderPaymentType.Paid || info.paymentStatus.type === ProviderPaymentType.TermsChanged
+export function ProviderView({
+ info,
+ onDelete,
+ onSync,
+ onBack,
+ onExtend,
+}: ViewProps): VNode {
+ const lb = info?.lastSuccessfulBackupTimestamp;
+ const isPaid =
+ info.paymentStatus.type === ProviderPaymentType.Paid ||
+ info.paymentStatus.type === ProviderPaymentType.TermsChanged;
return (
<WalletBox>
<Error info={info} />
<header>
- <h3>{info.name} <SmallLightText>{info.syncProviderBaseUrl}</SmallLightText></h3>
- <PaymentStatus color={isPaid ? 'rgb(28, 184, 65)' : 'rgb(202, 60, 60)'}>{isPaid ? 'Paid' : 'Unpaid'}</PaymentStatus>
+ <h3>
+ {info.name}{" "}
+ <SmallLightText>{info.syncProviderBaseUrl}</SmallLightText>
+ </h3>
+ <PaymentStatus color={isPaid ? "rgb(28, 184, 65)" : "rgb(202, 60, 60)"}>
+ {isPaid ? "Paid" : "Unpaid"}
+ </PaymentStatus>
</header>
<section>
- <p><b>Last backup:</b> {lb == null || lb.t_ms == "never" ? "never" : format(lb.t_ms, 'dd MMM yyyy')} </p>
- <ButtonPrimary onClick={onSync}><i18n.Translate>Back up</i18n.Translate></ButtonPrimary>
- {info.terms && <Fragment>
- <p><b>Provider fee:</b> {info.terms && info.terms.annualFee} per year</p>
- </Fragment>
- }
+ <p>
+ <b>Last backup:</b>{" "}
+ {lb == null || lb.t_ms == "never"
+ ? "never"
+ : format(lb.t_ms, "dd MMM yyyy")}{" "}
+ </p>
+ <ButtonPrimary onClick={onSync}>
+ <i18n.Translate>Back up</i18n.Translate>
+ </ButtonPrimary>
+ {info.terms && (
+ <Fragment>
+ <p>
+ <b>Provider fee:</b> {info.terms && info.terms.annualFee} per year
+ </p>
+ </Fragment>
+ )}
<p>{descriptionByStatus(info.paymentStatus)}</p>
- <ButtonPrimary disabled onClick={onExtend}><i18n.Translate>Extend</i18n.Translate></ButtonPrimary>
-
- {info.paymentStatus.type === ProviderPaymentType.TermsChanged && <div>
- <p><i18n.Translate>terms has changed, extending the service will imply accepting the new terms of service</i18n.Translate></p>
- <table>
- <thead>
- <tr>
- <td></td>
- <td><i18n.Translate>old</i18n.Translate></td>
- <td> -&gt;</td>
- <td><i18n.Translate>new</i18n.Translate></td>
- </tr>
- </thead>
- <tbody>
-
- <tr>
- <td><i18n.Translate>fee</i18n.Translate></td>
- <td>{info.paymentStatus.oldTerms.annualFee}</td>
- <td>-&gt;</td>
- <td>{info.paymentStatus.newTerms.annualFee}</td>
- </tr>
- <tr>
- <td><i18n.Translate>storage</i18n.Translate></td>
- <td>{info.paymentStatus.oldTerms.storageLimitInMegabytes}</td>
- <td>-&gt;</td>
- <td>{info.paymentStatus.newTerms.storageLimitInMegabytes}</td>
- </tr>
- </tbody>
- </table>
- </div>}
+ <ButtonPrimary disabled onClick={onExtend}>
+ <i18n.Translate>Extend</i18n.Translate>
+ </ButtonPrimary>
+ {info.paymentStatus.type === ProviderPaymentType.TermsChanged && (
+ <div>
+ <p>
+ <i18n.Translate>
+ terms has changed, extending the service will imply accepting
+ the new terms of service
+ </i18n.Translate>
+ </p>
+ <table>
+ <thead>
+ <tr>
+ <td></td>
+ <td>
+ <i18n.Translate>old</i18n.Translate>
+ </td>
+ <td> -&gt;</td>
+ <td>
+ <i18n.Translate>new</i18n.Translate>
+ </td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <i18n.Translate>fee</i18n.Translate>
+ </td>
+ <td>{info.paymentStatus.oldTerms.annualFee}</td>
+ <td>-&gt;</td>
+ <td>{info.paymentStatus.newTerms.annualFee}</td>
+ </tr>
+ <tr>
+ <td>
+ <i18n.Translate>storage</i18n.Translate>
+ </td>
+ <td>{info.paymentStatus.oldTerms.storageLimitInMegabytes}</td>
+ <td>-&gt;</td>
+ <td>{info.paymentStatus.newTerms.storageLimitInMegabytes}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ )}
</section>
<footer>
- <Button onClick={onBack}><i18n.Translate> &lt; back</i18n.Translate></Button>
+ <Button onClick={onBack}>
+ <i18n.Translate> &lt; back</i18n.Translate>
+ </Button>
<div>
- <ButtonDestructive onClick={onDelete}><i18n.Translate>remove provider</i18n.Translate></ButtonDestructive>
+ <ButtonDestructive onClick={onDelete}>
+ <i18n.Translate>remove provider</i18n.Translate>
+ </ButtonDestructive>
</div>
</footer>
</WalletBox>
- )
+ );
}
function daysSince(d?: Timestamp) {
- if (!d || d.t_ms === 'never') return 'never synced'
+ if (!d || d.t_ms === "never") return "never synced";
const duration = intervalToDuration({
start: d.t_ms,
end: new Date(),
- })
+ });
const str = formatDuration(duration, {
- delimiter: ', ',
+ delimiter: ", ",
format: [
- duration?.years ? i18n.str`years` : (
- duration?.months ? i18n.str`months` : (
- duration?.days ? i18n.str`days` : (
- duration?.hours ? i18n.str`hours` : (
- duration?.minutes ? i18n.str`minutes` : i18n.str`seconds`
- )
- )
- )
- )
- ]
- })
- return `synced ${str} ago`
+ duration?.years
+ ? i18n.str`years`
+ : duration?.months
+ ? i18n.str`months`
+ : duration?.days
+ ? i18n.str`days`
+ : duration?.hours
+ ? i18n.str`hours`
+ : duration?.minutes
+ ? i18n.str`minutes`
+ : i18n.str`seconds`,
+ ],
+ });
+ return `synced ${str} ago`;
}
function Error({ info }: { info: ProviderInfo }) {
if (info.lastError) {
- return <ErrorMessage title={info.lastError.hint} />
+ return <ErrorMessage title={info.lastError.hint} />;
}
if (info.backupProblem) {
switch (info.backupProblem.type) {
case "backup-conflicting-device":
- return <ErrorMessage title={<Fragment>
- <i18n.Translate>There is conflict with another backup from <b>{info.backupProblem.otherDeviceId}</b></i18n.Translate>
- </Fragment>} />
+ return (
+ <ErrorMessage
+ title={
+ <Fragment>
+ <i18n.Translate>
+ There is conflict with another backup from{" "}
+ <b>{info.backupProblem.otherDeviceId}</b>
+ </i18n.Translate>
+ </Fragment>
+ }
+ />
+ );
case "backup-unreadable":
- return <ErrorMessage title="Backup is not readable" />
+ return <ErrorMessage title="Backup is not readable" />;
default:
- return <ErrorMessage title={<Fragment>
- <i18n.Translate>Unknown backup problem: {JSON.stringify(info.backupProblem)}</i18n.Translate>
- </Fragment>} />
+ return (
+ <ErrorMessage
+ title={
+ <Fragment>
+ <i18n.Translate>
+ Unknown backup problem: {JSON.stringify(info.backupProblem)}
+ </i18n.Translate>
+ </Fragment>
+ }
+ />
+ );
}
}
- return null
+ return null;
}
function colorByStatus(status: ProviderPaymentType) {
switch (status) {
case ProviderPaymentType.InsufficientBalance:
- return 'rgb(223, 117, 20)'
+ return "rgb(223, 117, 20)";
case ProviderPaymentType.Unpaid:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
case ProviderPaymentType.Paid:
- return 'rgb(28, 184, 65)'
+ return "rgb(28, 184, 65)";
case ProviderPaymentType.Pending:
- return 'gray'
+ return "gray";
case ProviderPaymentType.InsufficientBalance:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
case ProviderPaymentType.TermsChanged:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
}
}
@@ -180,16 +260,19 @@ function descriptionByStatus(status: ProviderPaymentStatus) {
// return i18n.str`not paid yet`
case ProviderPaymentType.Paid:
case ProviderPaymentType.TermsChanged:
- if (status.paidUntil.t_ms === 'never') {
- return i18n.str`service paid`
+ if (status.paidUntil.t_ms === "never") {
+ return i18n.str`service paid`;
} else {
- return <Fragment>
- <b>Backup valid until:</b> {format(status.paidUntil.t_ms, 'dd MMM yyyy')}
- </Fragment>
+ return (
+ <Fragment>
+ <b>Backup valid until:</b>{" "}
+ {format(status.paidUntil.t_ms, "dd MMM yyyy")}
+ </Fragment>
+ );
}
case ProviderPaymentType.Unpaid:
case ProviderPaymentType.InsufficientBalance:
case ProviderPaymentType.Pending:
- return ''
+ return "";
}
}
diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
index ca524f4e2..c552b19ba 100644
--- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
@@ -15,26 +15,23 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { ReserveCreated as TestedComponent } from './ReserveCreated';
+import { createExample } from "../test-utils";
+import { ReserveCreated as TestedComponent } from "./ReserveCreated";
export default {
- title: 'wallet/manual withdraw/reserve created',
+ title: "wallet/manual withdraw/reserve created",
component: TestedComponent,
- argTypes: {
- }
+ argTypes: {},
};
-
export const InitialState = createExample(TestedComponent, {
- reservePub: 'ASLKDJQWLKEJASLKDJSADLKASJDLKSADJ',
+ reservePub: "ASLKDJQWLKEJASLKDJSADLKASJDLKSADJ",
paytos: [
- 'payto://x-taler-bank/bank.taler:5882/exchangeminator?amount=COL%3A1&message=Taler+Withdrawal+A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG',
- 'payto://x-taler-bank/international-bank.com/myaccount?amount=COL%3A1&message=Taler+Withdrawal+TYQTE7VA4M9GZQ4TR06YBNGA05AJGMFNSK4Q62NXR2FKNDB1J4EX',
- ]
+ "payto://x-taler-bank/bank.taler:5882/exchangeminator?amount=COL%3A1&message=Taler+Withdrawal+A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG",
+ "payto://x-taler-bank/international-bank.com/myaccount?amount=COL%3A1&message=Taler+Withdrawal+TYQTE7VA4M9GZQ4TR06YBNGA05AJGMFNSK4Q62NXR2FKNDB1J4EX",
+ ],
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
index e01336e02..9008e9751 100644
--- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
@@ -1,8 +1,7 @@
-import { Fragment, VNode } from "preact";
+import { h, Fragment, VNode } from "preact";
import { useState } from "preact/hooks";
import { QR } from "../components/QR";
import { ButtonBox, FontIcon, WalletBox } from "../components/styled";
-
export interface Props {
reservePub: string;
paytos: string[];
@@ -10,30 +9,57 @@ export interface Props {
}
export function ReserveCreated({ reservePub, paytos, onBack }: Props): VNode {
- const [opened, setOpened] = useState(-1)
+ const [opened, setOpened] = useState(-1);
return (
<WalletBox>
<section>
<h2>Reserve created!</h2>
- <p>Now you need to send money to the exchange to one of the following accounts</p>
- <p>To complete the setup of the reserve, you must now initiate a wire transfer using the given wire transfer subject and crediting the specified amount to the indicated account of the exchange.</p>
+ <p>
+ Now you need to send money to the exchange to one of the following
+ accounts
+ </p>
+ <p>
+ To complete the setup of the reserve, you must now initiate a wire
+ transfer using the given wire transfer subject and crediting the
+ specified amount to the indicated account of the exchange.
+ </p>
</section>
<section>
<ul>
{paytos.map((href, idx) => {
- const url = new URL(href)
- return <li key={idx}><p>
- <a href="" onClick={(e) => { setOpened(o => o === idx ? -1 : idx); e.preventDefault() }}>{url.pathname}</a>
- {opened === idx && <Fragment>
- <p>If your system supports RFC 8905, you can do this by opening <a href={href}>this URI</a> or scan the QR with your wallet</p>
- <QR text={href} />
- </Fragment>}
- </p></li>
+ const url = new URL(href);
+ return (
+ <li key={idx}>
+ <p>
+ <a
+ href=""
+ onClick={(e) => {
+ setOpened((o) => (o === idx ? -1 : idx));
+ e.preventDefault();
+ }}
+ >
+ {url.pathname}
+ </a>
+ {opened === idx && (
+ <Fragment>
+ <p>
+ If your system supports RFC 8905, you can do this by
+ opening <a href={href}>this URI</a> or scan the QR with
+ your wallet
+ </p>
+ <QR text={href} />
+ </Fragment>
+ )}
+ </p>
+ </li>
+ );
})}
</ul>
</section>
<footer>
- <ButtonBox onClick={onBack}><FontIcon>&#x2190;</FontIcon></ButtonBox>
+ <ButtonBox onClick={onBack}>
+ <FontIcon>&#x2190;</FontIcon>
+ </ButtonBox>
<div />
</footer>
</WalletBox>
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
index a04a0b4fd..6cc1368d5 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
@@ -15,39 +15,41 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { SettingsView as TestedComponent } from './Settings';
+import { createExample } from "../test-utils";
+import { SettingsView as TestedComponent } from "./Settings";
export default {
- title: 'wallet/settings',
+ title: "wallet/settings",
component: TestedComponent,
argTypes: {
setDeviceName: () => Promise.resolve(),
- }
+ },
};
export const AllOff = createExample(TestedComponent, {
- deviceName: 'this-is-the-device-name',
+ deviceName: "this-is-the-device-name",
setDeviceName: () => Promise.resolve(),
});
export const OneChecked = createExample(TestedComponent, {
- deviceName: 'this-is-the-device-name',
+ deviceName: "this-is-the-device-name",
permissionsEnabled: true,
setDeviceName: () => Promise.resolve(),
});
export const WithOneExchange = createExample(TestedComponent, {
- deviceName: 'this-is-the-device-name',
+ deviceName: "this-is-the-device-name",
permissionsEnabled: true,
setDeviceName: () => Promise.resolve(),
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'http://exchange.taler',
- paytoUris: ['payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator']
- }]
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "http://exchange.taler",
+ paytoUris: ["payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator"],
+ },
+ ],
});
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index 8d18586b1..8d8f3cdbc 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -14,7 +14,6 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { ExchangeListItem, i18n } from "@gnu-taler/taler-util";
import { VNode, h, Fragment } from "preact";
import { Checkbox } from "../components/Checkbox";
@@ -30,18 +29,28 @@ import * as wxApi from "../wxApi";
export function SettingsPage(): VNode {
const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
- const { devMode, toggleDevMode } = useDevContext()
- const { name, update } = useBackupDeviceName()
- const [lang, changeLang] = useLang()
+ const { devMode, toggleDevMode } = useDevContext();
+ const { name, update } = useBackupDeviceName();
+ const [lang, changeLang] = useLang();
const exchangesHook = useAsyncAsHook(() => wxApi.listExchanges());
- return <SettingsView
- lang={lang} changeLang={changeLang}
- knownExchanges={!exchangesHook || exchangesHook.hasError ? [] : exchangesHook.response.exchanges}
- deviceName={name} setDeviceName={update}
- permissionsEnabled={permissionsEnabled} togglePermissions={togglePermissions}
- developerMode={devMode} toggleDeveloperMode={toggleDevMode}
- />;
+ return (
+ <SettingsView
+ lang={lang}
+ changeLang={changeLang}
+ knownExchanges={
+ !exchangesHook || exchangesHook.hasError
+ ? []
+ : exchangesHook.response.exchanges
+ }
+ deviceName={name}
+ setDeviceName={update}
+ permissionsEnabled={permissionsEnabled}
+ togglePermissions={togglePermissions}
+ developerMode={devMode}
+ toggleDeveloperMode={toggleDevMode}
+ />
+ );
}
export interface ViewProps {
@@ -56,52 +65,72 @@ export interface ViewProps {
knownExchanges: Array<ExchangeListItem>;
}
-import { strings as messages } from '../i18n/strings'
+import { strings as messages } from "../i18n/strings";
type LangsNames = {
- [P in keyof typeof messages]: string
-}
+ [P in keyof typeof messages]: string;
+};
const names: LangsNames = {
- es: 'Español [es]',
- en: 'English [en]',
- fr: 'Français [fr]',
- de: 'Deutsch [de]',
- sv: 'Svenska [sv]',
- it: 'Italiano [it]',
-}
+ es: "Español [es]",
+ en: "English [en]",
+ fr: "Français [fr]",
+ de: "Deutsch [de]",
+ sv: "Svenska [sv]",
+ it: "Italiano [it]",
+};
-
-export function SettingsView({ knownExchanges, lang, changeLang, deviceName, setDeviceName, permissionsEnabled, togglePermissions, developerMode, toggleDeveloperMode }: ViewProps): VNode {
+export function SettingsView({
+ knownExchanges,
+ lang,
+ changeLang,
+ deviceName,
+ setDeviceName,
+ permissionsEnabled,
+ togglePermissions,
+ developerMode,
+ toggleDeveloperMode,
+}: ViewProps): VNode {
return (
<WalletBox>
<section>
-
- <h2><i18n.Translate>Known exchanges</i18n.Translate></h2>
- {!knownExchanges || !knownExchanges.length ? <div>
- No exchange yet!
- </div> :
+ <h2>
+ <i18n.Translate>Known exchanges</i18n.Translate>
+ </h2>
+ {!knownExchanges || !knownExchanges.length ? (
+ <div>No exchange yet!</div>
+ ) : (
<table>
- {knownExchanges.map(e => <tr>
- <td>{e.currency}</td>
- <td><a href={e.exchangeBaseUrl}>{e.exchangeBaseUrl}</a></td>
- </tr>)}
+ {knownExchanges.map((e) => (
+ <tr>
+ <td>{e.currency}</td>
+ <td>
+ <a href={e.exchangeBaseUrl}>{e.exchangeBaseUrl}</a>
+ </td>
+ </tr>
+ ))}
</table>
- }
-
- <h2><i18n.Translate>Permissions</i18n.Translate></h2>
- <Checkbox label="Automatically open wallet based on page content"
+ )}
+
+ <h2>
+ <i18n.Translate>Permissions</i18n.Translate>
+ </h2>
+ <Checkbox
+ label="Automatically open wallet based on page content"
name="perm"
description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
- enabled={permissionsEnabled} onToggle={togglePermissions}
+ enabled={permissionsEnabled}
+ onToggle={togglePermissions}
/>
<h2>Config</h2>
- <Checkbox label="Developer mode"
+ <Checkbox
+ label="Developer mode"
name="devMode"
description="(More options and information useful for debugging)"
- enabled={developerMode} onToggle={toggleDeveloperMode}
+ enabled={developerMode}
+ onToggle={toggleDeveloperMode}
/>
</section>
</WalletBox>
- )
+ );
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
index 535509cef..c9a3f47cb 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
@@ -15,110 +15,116 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import {
PaymentStatus,
- TransactionCommon, TransactionDeposit, TransactionPayment,
- TransactionRefresh, TransactionRefund, TransactionTip, TransactionType,
+ TransactionCommon,
+ TransactionDeposit,
+ TransactionPayment,
+ TransactionRefresh,
+ TransactionRefund,
+ TransactionTip,
+ TransactionType,
TransactionWithdrawal,
- WithdrawalType
-} from '@gnu-taler/taler-util';
-import { createExample } from '../test-utils';
-import { TransactionView as TestedComponent } from './Transaction';
+ WithdrawalType,
+} from "@gnu-taler/taler-util";
+import { createExample } from "../test-utils";
+import { TransactionView as TestedComponent } from "./Transaction";
export default {
- title: 'wallet/history/details',
+ title: "wallet/history/details",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
const commonTransaction = {
- amountRaw: 'KUDOS:11',
- amountEffective: 'KUDOS:9.2',
+ amountRaw: "KUDOS:11",
+ amountEffective: "KUDOS:9.2",
pending: false,
timestamp: {
- t_ms: new Date().getTime()
+ t_ms: new Date().getTime(),
},
- transactionId: '12',
-} as TransactionCommon
+ transactionId: "12",
+} as TransactionCommon;
const exampleData = {
withdraw: {
...commonTransaction,
type: TransactionType.Withdrawal,
- exchangeBaseUrl: 'http://exchange.taler',
+ exchangeBaseUrl: "http://exchange.taler",
withdrawalDetails: {
confirmed: false,
- exchangePaytoUris: ['payto://x-taler-bank/bank/account'],
+ exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
type: WithdrawalType.ManualTransfer,
- }
+ },
} as TransactionWithdrawal,
payment: {
...commonTransaction,
- amountEffective: 'KUDOS:11',
+ amountEffective: "KUDOS:11",
type: TransactionType.Payment,
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'the merchant',
+ name: "the merchant",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
summary: "Essay: Why the Devil's Advocate Doesn't Help Reach the Truth",
- fulfillmentMessage: '',
+ fulfillmentMessage: "",
},
- proposalId: '1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ proposalId: "1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
status: PaymentStatus.Accepted,
} as TransactionPayment,
deposit: {
...commonTransaction,
type: TransactionType.Deposit,
- depositGroupId: '#groupId',
- targetPaytoUri: 'payto://x-taler-bank/bank/account',
+ depositGroupId: "#groupId",
+ targetPaytoUri: "payto://x-taler-bank/bank/account",
} as TransactionDeposit,
refresh: {
...commonTransaction,
type: TransactionType.Refresh,
- exchangeBaseUrl: 'http://exchange.taler',
+ exchangeBaseUrl: "http://exchange.taler",
} as TransactionRefresh,
tip: {
...commonTransaction,
type: TransactionType.Tip,
- merchantBaseUrl: 'http://merchant.taler',
+ merchantBaseUrl: "http://merchant.taler",
} as TransactionTip,
refund: {
...commonTransaction,
type: TransactionType.Refund,
- refundedTransactionId: 'payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ refundedTransactionId:
+ "payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'the merchant',
+ name: "the merchant",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
- summary: 'the summary',
- fulfillmentMessage: '',
+ summary: "the summary",
+ fulfillmentMessage: "",
},
} as TransactionRefund,
-}
+};
const transactionError = {
code: 2000,
details: "details",
hint: "this is a hint for the error",
- message: 'message'
-}
+ message: "message",
+};
export const Withdraw = createExample(TestedComponent, {
- transaction: exampleData.withdraw
+ transaction: exampleData.withdraw,
});
export const WithdrawError = createExample(TestedComponent, {
@@ -132,24 +138,22 @@ export const WithdrawPending = createExample(TestedComponent, {
transaction: { ...exampleData.withdraw, pending: true },
});
-
export const Payment = createExample(TestedComponent, {
- transaction: exampleData.payment
+ transaction: exampleData.payment,
});
export const PaymentError = createExample(TestedComponent, {
transaction: {
...exampleData.payment,
- error: transactionError
+ error: transactionError,
},
});
export const PaymentWithoutFee = createExample(TestedComponent, {
transaction: {
...exampleData.payment,
- amountRaw: 'KUDOS:11',
-
- }
+ amountRaw: "KUDOS:11",
+ },
});
export const PaymentPending = createExample(TestedComponent, {
@@ -161,27 +165,33 @@ export const PaymentWithProducts = createExample(TestedComponent, {
...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,
- }]
- }
+ 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,
});
@@ -190,75 +200,79 @@ export const PaymentWithLongSummary = createExample(TestedComponent, {
...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,
- }]
- }
+ 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
+ transaction: exampleData.deposit,
});
export const DepositError = createExample(TestedComponent, {
transaction: {
...exampleData.deposit,
- error: transactionError
+ error: transactionError,
},
});
export const DepositPending = createExample(TestedComponent, {
- transaction: { ...exampleData.deposit, pending: true }
+ transaction: { ...exampleData.deposit, pending: true },
});
export const Refresh = createExample(TestedComponent, {
- transaction: exampleData.refresh
+ transaction: exampleData.refresh,
});
export const RefreshError = createExample(TestedComponent, {
transaction: {
...exampleData.refresh,
- error: transactionError
+ error: transactionError,
},
});
export const Tip = createExample(TestedComponent, {
- transaction: exampleData.tip
+ transaction: exampleData.tip,
});
export const TipError = createExample(TestedComponent, {
transaction: {
...exampleData.tip,
- error: transactionError
+ error: transactionError,
},
});
export const TipPending = createExample(TestedComponent, {
- transaction: { ...exampleData.tip, pending: true }
+ transaction: { ...exampleData.tip, pending: true },
});
export const Refund = createExample(TestedComponent, {
- transaction: exampleData.refund
+ transaction: exampleData.refund,
});
export const RefundError = createExample(TestedComponent, {
transaction: {
...exampleData.refund,
- error: transactionError
+ error: transactionError,
},
});
export const RefundPending = createExample(TestedComponent, {
- transaction: { ...exampleData.refund, pending: true }
+ transaction: { ...exampleData.refund, pending: true },
});
export const RefundWithProducts = createExample(TestedComponent, {
@@ -266,11 +280,14 @@ export const RefundWithProducts = createExample(TestedComponent, {
...exampleData.refund,
info: {
...exampleData.refund.info,
- products: [{
- description: 't-shirt',
- }, {
- description: 'beer',
- }]
- }
+ products: [
+ {
+ description: "t-shirt",
+ },
+ {
+ description: "beer",
+ },
+ ],
+ },
} as TransactionRefund,
});
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index cf41efb59..7de6982e7 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -14,27 +14,43 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountLike, Amounts, i18n, Transaction, TransactionType } from "@gnu-taler/taler-util";
+import {
+ AmountLike,
+ Amounts,
+ i18n,
+ Transaction,
+ TransactionType,
+} from "@gnu-taler/taler-util";
import { format } from "date-fns";
-import { JSX, VNode } from "preact";
-import { route } from 'preact-router';
+import { JSX, VNode, h } from "preact";
+import { route } from "preact-router";
import { useEffect, useState } from "preact/hooks";
import emptyImg from "../../static/img/empty.png";
import { ErrorMessage } from "../components/ErrorMessage";
import { Part } from "../components/Part";
-import { ButtonBox, ButtonBoxDestructive, ButtonPrimary, FontIcon, ListOfProducts, RowBorderGray, SmallLightText, WalletBox, WarningBox } from "../components/styled";
+import {
+ ButtonBox,
+ ButtonBoxDestructive,
+ ButtonPrimary,
+ FontIcon,
+ ListOfProducts,
+ RowBorderGray,
+ SmallLightText,
+ WalletBox,
+ WarningBox,
+} from "../components/styled";
import { Pages } from "../NavigationBar";
import * as wxApi from "../wxApi";
-export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
- const [transaction, setTransaction] = useState<
- Transaction | undefined
- >(undefined);
+export function TransactionPage({ 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);
+ const ts = res.transactions.filter((t) => t.transactionId === tid);
if (ts.length === 1) {
setTransaction(ts[0]);
} else {
@@ -45,13 +61,22 @@ export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
}, [tid]);
if (!transaction) {
- return <div><i18n.Translate>Loading ...</i18n.Translate></div>;
+ return (
+ <div>
+ <i18n.Translate>Loading ...</i18n.Translate>
+ </div>
+ );
}
- return <TransactionView
- transaction={transaction}
- onDelete={() => wxApi.deleteTransaction(tid).then(_ => history.go(-1))}
- onRetry={() => wxApi.retryTransaction(tid).then(_ => history.go(-1))}
- onBack={() => { route(Pages.history) }} />;
+ return (
+ <TransactionView
+ transaction={transaction}
+ onDelete={() => wxApi.deleteTransaction(tid).then((_) => history.go(-1))}
+ onRetry={() => wxApi.retryTransaction(tid).then((_) => history.go(-1))}
+ onBack={() => {
+ route(Pages.history);
+ }}
+ />
+ );
}
export interface WalletTransactionProps {
@@ -61,173 +86,310 @@ export interface WalletTransactionProps {
onBack: () => void;
}
-export function TransactionView({ transaction, onDelete, onRetry, onBack }: WalletTransactionProps) {
-
+export function TransactionView({
+ transaction,
+ onDelete,
+ onRetry,
+ onBack,
+}: WalletTransactionProps) {
function TransactionTemplate({ children }: { children: VNode[] }) {
- return <WalletBox>
- <section style={{ padding: 8, textAlign: 'center'}}>
- <ErrorMessage title={transaction?.error?.hint} />
- {transaction.pending && <WarningBox>This transaction is not completed</WarningBox>}
- </section>
- <section>
- <div style={{ textAlign: 'center' }}>
- {children}
- </div>
- </section>
- <footer>
- <ButtonBox onClick={onBack}><i18n.Translate> <FontIcon>&#x2190;</FontIcon> </i18n.Translate></ButtonBox>
- <div>
- {transaction?.error ? <ButtonPrimary onClick={onRetry}><i18n.Translate>retry</i18n.Translate></ButtonPrimary> : null}
- <ButtonBoxDestructive onClick={onDelete}><i18n.Translate>&#x1F5D1;</i18n.Translate></ButtonBoxDestructive>
- </div>
- </footer>
- </WalletBox>
+ return (
+ <WalletBox>
+ <section style={{ padding: 8, textAlign: "center" }}>
+ <ErrorMessage title={transaction?.error?.hint} />
+ {transaction.pending && (
+ <WarningBox>This transaction is not completed</WarningBox>
+ )}
+ </section>
+ <section>
+ <div style={{ textAlign: "center" }}>{children}</div>
+ </section>
+ <footer>
+ <ButtonBox onClick={onBack}>
+ <i18n.Translate>
+ {" "}
+ <FontIcon>&#x2190;</FontIcon>{" "}
+ </i18n.Translate>
+ </ButtonBox>
+ <div>
+ {transaction?.error ? (
+ <ButtonPrimary onClick={onRetry}>
+ <i18n.Translate>retry</i18n.Translate>
+ </ButtonPrimary>
+ ) : null}
+ <ButtonBoxDestructive onClick={onDelete}>
+ <i18n.Translate>&#x1F5D1;</i18n.Translate>
+ </ButtonBoxDestructive>
+ </div>
+ </footer>
+ </WalletBox>
+ );
}
function amountToString(text: AmountLike) {
- const aj = Amounts.jsonifyAmount(text)
- const amount = Amounts.stringifyValue(aj)
- return `${amount} ${aj.currency}`
+ 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>
- <h2>Withdrawal</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>
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Withdrawal</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>
+ );
}
- const showLargePic = () => {
-
- }
+ const showLargePic = () => {};
if (transaction.type === TransactionType.Payment) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountEffective),
Amounts.parseOrThrow(transaction.amountRaw),
- ).amount
-
- return <TransactionTemplate>
- <h2>Payment </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' />
+ ).amount;
- <div>
- {transaction.info.products && transaction.info.products.length > 0 &&
- <ListOfProducts>
- {transaction.info.products.map((p, k) => <RowBorderGray key={k}>
- <a href="#" onClick={showLargePic}>
- <img src={p.image ? p.image : emptyImg} />
- </a>
- <div>
- {p.quantity && p.quantity > 0 && <SmallLightText>x {p.quantity} {p.unit}</SmallLightText>}
- <div>{p.description}</div>
- </div>
- </RowBorderGray>)}
- </ListOfProducts>
- }
- </div>
- </TransactionTemplate>
+ return (
+ <TransactionTemplate>
+ <h2>Payment </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>
+ {transaction.info.products.map((p, k) => (
+ <RowBorderGray key={k}>
+ <a href="#" onClick={showLargePic}>
+ <img src={p.image ? p.image : emptyImg} />
+ </a>
+ <div>
+ {p.quantity && p.quantity > 0 && (
+ <SmallLightText>
+ x {p.quantity} {p.unit}
+ </SmallLightText>
+ )}
+ <div>{p.description}</div>
+ </div>
+ </RowBorderGray>
+ ))}
+ </ListOfProducts>
+ )}
+ </div>
+ </TransactionTemplate>
+ );
}
if (transaction.type === TransactionType.Deposit) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Deposit </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>
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Deposit </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>
+ );
}
if (transaction.type === TransactionType.Refresh) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Refresh</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>
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Refresh</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>
+ );
}
if (transaction.type === TransactionType.Tip) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Tip</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>
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Tip</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>
+ );
}
if (transaction.type === TransactionType.Refund) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Refund</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' />
-
- <p>
- {transaction.info.summary}
- </p>
- <div>
- {transaction.info.products && transaction.info.products.length > 0 &&
- <ListOfProducts>
- {transaction.info.products.map((p, k) => <RowBorderGray key={k}>
- <a href="#" onClick={showLargePic}>
- <img src={p.image ? p.image : emptyImg} />
- </a>
- <div>
- {p.quantity && p.quantity > 0 && <SmallLightText>x {p.quantity} {p.unit}</SmallLightText>}
- <div>{p.description}</div>
- </div>
- </RowBorderGray>)}
- </ListOfProducts>
- }
- </div>
- </TransactionTemplate>
- }
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Refund</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"
+ />
+ <p>{transaction.info.summary}</p>
+ <div>
+ {transaction.info.products && transaction.info.products.length > 0 && (
+ <ListOfProducts>
+ {transaction.info.products.map((p, k) => (
+ <RowBorderGray key={k}>
+ <a href="#" onClick={showLargePic}>
+ <img src={p.image ? p.image : emptyImg} />
+ </a>
+ <div>
+ {p.quantity && p.quantity > 0 && (
+ <SmallLightText>
+ x {p.quantity} {p.unit}
+ </SmallLightText>
+ )}
+ <div>{p.description}</div>
+ </div>
+ </RowBorderGray>
+ ))}
+ </ListOfProducts>
+ )}
+ </div>
+ </TransactionTemplate>
+ );
+ }
- return <div></div>
+ return <div></div>;
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx
index 6579450b3..7e6588fac 100644
--- a/packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx
@@ -15,16 +15,15 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample } from '../test-utils';
-import { View as TestedComponent } from './Welcome';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample } from "../test-utils";
+import { View as TestedComponent } from "./Welcome";
export default {
- title: 'wallet/welcome',
+ title: "wallet/welcome",
component: TestedComponent,
};
@@ -32,11 +31,11 @@ export const Normal = createExample(TestedComponent, {
permissionsEnabled: true,
diagnostics: {
errors: [],
- walletManifestVersion: '1.0',
- walletManifestDisplayVersion: '1.0',
+ walletManifestVersion: "1.0",
+ walletManifestDisplayVersion: "1.0",
firefoxIdbProblem: false,
dbOutdated: false,
- }
+ },
});
export const TimedoutDiagnostics = createExample(TestedComponent, {
@@ -47,4 +46,3 @@ export const TimedoutDiagnostics = createExample(TestedComponent, {
export const RunningDiagnostics = createExample(TestedComponent, {
permissionsEnabled: false,
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/Welcome.tsx b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
index d11070d9a..0b8e5c609 100644
--- a/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
@@ -27,43 +27,55 @@ import { Diagnostics } from "../components/Diagnostics";
import { WalletBox } from "../components/styled";
import { useDiagnostics } from "../hooks/useDiagnostics";
import { WalletDiagnostics } from "@gnu-taler/taler-util";
-import { h } from 'preact';
+import { h } from "preact";
export function WelcomePage() {
- const [permissionsEnabled, togglePermissions] = useExtendedPermissions()
- const [diagnostics, timedOut] = useDiagnostics()
- return <View
- permissionsEnabled={permissionsEnabled} togglePermissions={togglePermissions}
- diagnostics={diagnostics} timedOut={timedOut}
- />
+ const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
+ const [diagnostics, timedOut] = useDiagnostics();
+ return (
+ <View
+ permissionsEnabled={permissionsEnabled}
+ togglePermissions={togglePermissions}
+ diagnostics={diagnostics}
+ timedOut={timedOut}
+ />
+ );
}
export interface ViewProps {
- permissionsEnabled: boolean,
- togglePermissions: () => void,
- diagnostics: WalletDiagnostics | undefined,
- timedOut: boolean,
+ permissionsEnabled: boolean;
+ togglePermissions: () => void;
+ diagnostics: WalletDiagnostics | undefined;
+ timedOut: boolean;
}
-export function View({ permissionsEnabled, togglePermissions, diagnostics, timedOut }: ViewProps): JSX.Element {
- return (<WalletBox>
- <h1>Browser Extension Installed!</h1>
- <div>
- <p>Thank you for installing the wallet.</p>
- <Diagnostics diagnostics={diagnostics} timedOut={timedOut} />
- <h2>Permissions</h2>
- <Checkbox label="Automatically open wallet based on page content"
- name="perm"
- description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
- enabled={permissionsEnabled} onToggle={togglePermissions}
- />
- <h2>Next Steps</h2>
- <a href="https://demo.taler.net/" style={{ display: "block" }}>
- Try the demo »
- </a>
- <a href="https://demo.taler.net/" style={{ display: "block" }}>
- Learn how to top up your wallet balance »
- </a>
- </div>
- </WalletBox>
+export function View({
+ permissionsEnabled,
+ togglePermissions,
+ diagnostics,
+ timedOut,
+}: ViewProps): JSX.Element {
+ return (
+ <WalletBox>
+ <h1>Browser Extension Installed!</h1>
+ <div>
+ <p>Thank you for installing the wallet.</p>
+ <Diagnostics diagnostics={diagnostics} timedOut={timedOut} />
+ <h2>Permissions</h2>
+ <Checkbox
+ label="Automatically open wallet based on page content"
+ name="perm"
+ description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
+ enabled={permissionsEnabled}
+ onToggle={togglePermissions}
+ />
+ <h2>Next Steps</h2>
+ <a href="https://demo.taler.net/" style={{ display: "block" }}>
+ Try the demo »
+ </a>
+ <a href="https://demo.taler.net/" style={{ display: "block" }}>
+ Learn how to top up your wallet balance »
+ </a>
+ </div>
+ </WalletBox>
);
}