summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx')
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx269
1 files changed, 176 insertions, 93 deletions
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 "";
}
}