first backup list prototype
This commit is contained in:
parent
05e89a3cf7
commit
23dab91ee9
@ -0,0 +1,88 @@
|
||||
import { Amounts } from "@gnu-taler/taler-util";
|
||||
// import { ProviderInfo } from "@gnu-taler/taler-wallet-core/src/operations/backup/index.js";
|
||||
|
||||
|
||||
export interface ProvidersByCurrency {
|
||||
[s:string] : any | undefined
|
||||
}
|
||||
|
||||
const list = {
|
||||
"trustedAuditors": [],
|
||||
"trustedExchanges": [
|
||||
{
|
||||
"currency": "ARS",
|
||||
"exchangeBaseUrl": "http://exchange.taler:8081/",
|
||||
"exchangeMasterPub": "WHA6G542TW8B10N3E857M3P252HV7B896TSP1HP6NREG96ADA4MG"
|
||||
},
|
||||
{
|
||||
"currency": "KUDOS",
|
||||
"exchangeBaseUrl": "https://exchange.demo.taler.net/",
|
||||
"exchangeMasterPub": "FH1Y8ZMHCTPQ0YFSZECDH8C9407JR3YN0MF1706PTG24Q4NEWGV0"
|
||||
},
|
||||
{
|
||||
"currency": "USD",
|
||||
"exchangeBaseUrl": "https://exchange.demo.taler.net/",
|
||||
"exchangeMasterPub": "FH1Y8ZMHCTPQ0YFSZECDH8C9407JR3YN0MF1706PTG24Q4NEWGV0"
|
||||
},
|
||||
{
|
||||
"currency": "EUR",
|
||||
"exchangeBaseUrl": "https://exchange.demo.taler.net/",
|
||||
"exchangeMasterPub": "FH1Y8ZMHCTPQ0YFSZECDH8C9407JR3YN0MF1706PTG24Q4NEWGV0"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const status = {
|
||||
"deviceId": "thenameofthisdevice",
|
||||
"walletRootPub": "83DYRKK262TG72H1SD09CTWXQFC151P2DXF9WYH30J8EQ7EAZMCG",
|
||||
"providers": [
|
||||
{
|
||||
"active": false,
|
||||
"syncProviderBaseUrl": "http://sync.demo.taler.net/",
|
||||
"paymentProposalIds": [],
|
||||
"paymentStatus": {
|
||||
"type": "unpaid"
|
||||
},
|
||||
"terms": {
|
||||
"annualFee": "KUDOS:0.1",
|
||||
"storageLimitInMegabytes": 16,
|
||||
"supportedProtocolVersion": "0.0"
|
||||
}
|
||||
}, {
|
||||
"active": true,
|
||||
"syncProviderBaseUrl": "http://sync.taler:9967/",
|
||||
"lastSuccessfulBackupTimestamp": {
|
||||
"t_ms": 1625063925078
|
||||
},
|
||||
"paymentProposalIds": [
|
||||
"43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
|
||||
],
|
||||
"paymentStatus": {
|
||||
"type": "paid",
|
||||
"paidUntil": {
|
||||
"t_ms": 1656599921000
|
||||
}
|
||||
},
|
||||
"terms": {
|
||||
"annualFee": "ARS:1",
|
||||
"storageLimitInMegabytes": 16,
|
||||
"supportedProtocolVersion": "0.0"
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
export function useProvidersByCurrency(): ProvidersByCurrency {
|
||||
const currencies = list.trustedExchanges.map(e => e.currency)
|
||||
const providerByCurrency = status.providers.reduce((p, c) => {
|
||||
if (c.terms) {
|
||||
p[Amounts.parseOrThrow(c.terms.annualFee).currency] = c
|
||||
}
|
||||
return p
|
||||
}, {} as Record<string, any | undefined>)
|
||||
|
||||
|
||||
return providerByCurrency
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
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 { FunctionalComponent } from 'preact';
|
||||
import { BackupView as TestedComponent } from './BackupPage';
|
||||
|
||||
export default {
|
||||
title: 'popup/backup/list',
|
||||
component: TestedComponent,
|
||||
argTypes: {
|
||||
onRetry: { action: 'onRetry' },
|
||||
onDelete: { action: 'onDelete' },
|
||||
onBack: { action: 'onBack' },
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) {
|
||||
const r = (args: any) => <Component {...args} />
|
||||
r.args = props
|
||||
return r
|
||||
}
|
||||
|
||||
export const Example = createExample(TestedComponent, {
|
||||
deviceName: "somedevicename",
|
||||
providers: {
|
||||
ARS: {
|
||||
"active": true,
|
||||
"syncProviderBaseUrl": "http://sync.taler:9967/",
|
||||
"lastSuccessfulBackupTimestamp": {
|
||||
"t_ms": 1625063925078
|
||||
},
|
||||
"paymentProposalIds": [
|
||||
"43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
|
||||
],
|
||||
"paymentStatus": {
|
||||
"type": 'paid',
|
||||
"paidUntil": {
|
||||
"t_ms": 1656599921000
|
||||
}
|
||||
},
|
||||
"terms": {
|
||||
"annualFee": "ARS:1",
|
||||
"storageLimitInMegabytes": 16,
|
||||
"supportedProtocolVersion": "0.0"
|
||||
}
|
||||
},
|
||||
KUDOS: {
|
||||
"active": false,
|
||||
"syncProviderBaseUrl": "http://sync.demo.taler.net/",
|
||||
"paymentProposalIds": [],
|
||||
"paymentStatus": {
|
||||
"type": 'unpaid',
|
||||
},
|
||||
"terms": {
|
||||
"annualFee": "KUDOS:0.1",
|
||||
"storageLimitInMegabytes": 16,
|
||||
"supportedProtocolVersion": "0.0"
|
||||
}
|
||||
},
|
||||
USD: undefined,
|
||||
EUR: undefined
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -15,21 +15,126 @@
|
||||
*/
|
||||
|
||||
|
||||
import { VNode } from "preact";
|
||||
import { useDevContext } from "../context/useDevContext";
|
||||
import { useExtendedPermissions } from "../hooks/useExtendedPermissions";
|
||||
import { Timestamp } from "@gnu-taler/taler-util";
|
||||
// import { ProviderPaymentStatus } from "@gnu-taler/taler-wallet-core/src/operations/backup";
|
||||
import { formatDuration, intervalToDuration } from "date-fns";
|
||||
import { JSX, VNode } from "preact";
|
||||
import { ProvidersByCurrency, useProvidersByCurrency } from "../hooks/useProvidersByCurrency";
|
||||
|
||||
export function BackupPage(): VNode {
|
||||
return <BackupView />;
|
||||
const providers = useProvidersByCurrency()
|
||||
return <BackupView deviceName={"thisdevicename"} providers={providers}/>;
|
||||
}
|
||||
|
||||
export interface ViewProps {
|
||||
deviceName: string;
|
||||
providers: ProvidersByCurrency
|
||||
}
|
||||
|
||||
export function BackupView({}: ViewProps): VNode {
|
||||
export function BackupView({ deviceName, providers }: ViewProps): VNode {
|
||||
return (
|
||||
<div>
|
||||
Backup page
|
||||
<div style={{ height: 'calc(320px - 34px - 16px)', overflow: 'auto' }}>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', width: '100%', justifyContent: 'space-between' }}>
|
||||
<h2 style={{ width: 240, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', marginTop: 10, marginBottom:10 }}>
|
||||
{deviceName}
|
||||
</h2>
|
||||
<div style={{ flexDirection: 'row', marginTop: 'auto', marginBottom: 'auto' }}>
|
||||
<button class="pure-button button-secondary">rename</button>
|
||||
</div>
|
||||
</div>
|
||||
{Object.keys(providers).map((currency) => {
|
||||
const provider = providers[currency]
|
||||
if (!provider) {
|
||||
return <BackupLayout
|
||||
id={currency}
|
||||
title={currency}
|
||||
/>
|
||||
}
|
||||
return <BackupLayout
|
||||
status={provider.paymentStatus}
|
||||
timestamp={provider.lastSuccessfulBackupTimestamp}
|
||||
id={currency}
|
||||
active={provider.active}
|
||||
subtitle={provider.syncProviderBaseUrl}
|
||||
title={currency}
|
||||
/>
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
interface TransactionLayoutProps {
|
||||
status?: any;
|
||||
timestamp?: Timestamp;
|
||||
title: string;
|
||||
id: string;
|
||||
subtitle?: string;
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
function BackupLayout(props: TransactionLayoutProps): JSX.Element {
|
||||
const date = !props.timestamp ? undefined : new Date(props.timestamp.t_ms);
|
||||
const dateStr = date?.toLocaleString([], {
|
||||
dateStyle: "medium",
|
||||
timeStyle: "short",
|
||||
} as any);
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
border: "1px solid gray",
|
||||
borderRadius: "0.5em",
|
||||
margin: "0.5em 0",
|
||||
justifyContent: "space-between",
|
||||
padding: "0.5em",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", color: !props.active ? "gray" : undefined }}
|
||||
>
|
||||
{dateStr && <div style={{ fontSize: "small", color: "gray" }}>{dateStr}</div>}
|
||||
{!dateStr && <div style={{ fontSize: "small", color: "red" }}>never synced</div>}
|
||||
<div style={{ fontVariant: "small-caps", fontSize: "x-large" }}>
|
||||
<a href=""><span>{props.title}</span></a>
|
||||
</div>
|
||||
|
||||
<div>{props.subtitle}</div>
|
||||
</div>
|
||||
<div style={{
|
||||
marginLeft: "auto",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
alignSelf: "center"
|
||||
}}>
|
||||
<div style={{}}>
|
||||
{!props.status ? "missing" : (
|
||||
props.status?.type === 'paid' ? daysUntil(props.status.paidUntil) : 'unpaid'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function daysUntil(d: Timestamp) {
|
||||
if (d.t_ms === 'never') return undefined
|
||||
const duration = intervalToDuration({
|
||||
start: d.t_ms,
|
||||
end: new Date(),
|
||||
})
|
||||
const str = formatDuration(duration, {
|
||||
delimiter: ', ',
|
||||
format: [
|
||||
duration?.years ? 'years' : (
|
||||
duration?.months ? 'months' : (
|
||||
duration?.days ? 'days' : (
|
||||
duration.hours ? 'hours' : 'minutes'
|
||||
)
|
||||
)
|
||||
)
|
||||
]
|
||||
})
|
||||
return `${str} left`
|
||||
}
|
@ -24,9 +24,7 @@
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import {
|
||||
classifyTalerUri, i18n, TalerUriType
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { i18n } from "@gnu-taler/taler-util";
|
||||
import { ComponentChildren, JSX } from "preact";
|
||||
import Match from "preact-router/match";
|
||||
import { useDevContext } from "../context/useDevContext";
|
||||
|
@ -126,12 +126,18 @@ export function getBalance(): Promise<BalancesResponse> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get balances for all currencies/exchanges.
|
||||
* Retrieve the full event history for this wallet.
|
||||
*/
|
||||
export function getTransactions(): Promise<TransactionsResponse> {
|
||||
return callBackend("getTransactions", {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get currency from known auditors and exchanges
|
||||
*/
|
||||
export function listCurrencies(): Promise<TransactionsResponse> {
|
||||
return callBackend("listCurrencies", {});
|
||||
}
|
||||
/**
|
||||
* Retry a transaction
|
||||
* @param transactionId
|
||||
|
Loading…
Reference in New Issue
Block a user