/* This file is part of GNU Taler (C) 2022 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 */ import * as utils from "@gnu-taler/taler-util"; import { AbsoluteTime, ProviderInfo, ProviderPaymentStatus, ProviderPaymentType, } from "@gnu-taler/taler-util"; import { WalletApiOperation } from "@gnu-taler/taler-wallet-core"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { ErrorAlertView } from "../components/CurrentAlerts.js"; import { ErrorMessage } from "../components/ErrorMessage.js"; import { Loading } from "../components/Loading.js"; import { Time } from "../components/Time.js"; import { PaymentStatus, SmallLightText } from "../components/styled/index.js"; import { alertFromError } from "../context/alert.js"; import { useBackendContext } from "../context/backend.js"; import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; interface Props { pid: string; onBack: () => Promise; onPayProvider: (uri: string) => Promise; onWithdraw: (amount: string) => Promise; } export function ProviderDetailPage({ pid: providerURL, onBack, onPayProvider, onWithdraw, }: Props): VNode { const { i18n } = useTranslationContext(); const api = useBackendContext(); async function getProviderInfo(): Promise { //create a first list of backup info by currency const status = await api.wallet.call(WalletApiOperation.GetBackupInfo, {}); const providers = status.providers.filter( (p) => p.syncProviderBaseUrl === providerURL, ); return providers.length ? providers[0] : null; } const state = useAsyncAsHook(getProviderInfo); if (!state) { return ; } if (state.hasError) { return ( ); } const info = state.response; if (info === null) { return (

There is not known provider with url "{providerURL}".

); } return ( api.wallet .call(WalletApiOperation.RunBackupCycle, { providers: [providerURL], }) .then() } onPayProvider={async () => { if (info.paymentStatus.type !== ProviderPaymentType.Pending) return; if (!info.paymentStatus.talerUri) return; onPayProvider(info.paymentStatus.talerUri); }} onWithdraw={async () => { if (info.paymentStatus.type !== ProviderPaymentType.InsufficientBalance) return; onWithdraw(info.paymentStatus.amount); }} onDelete={() => api.wallet .call(WalletApiOperation.RemoveBackupProvider, { provider: providerURL, }) .then(onBack) } onBack={onBack} onExtend={async () => { null; }} /> ); } export interface ViewProps { info: ProviderInfo; onDelete: () => Promise; onSync: () => Promise; onBack: () => Promise; onExtend: () => Promise; onPayProvider: () => Promise; onWithdraw: () => Promise; } export function ProviderView({ info, onDelete, onPayProvider, onWithdraw, onSync, onBack, onExtend, }: ViewProps): VNode { const { i18n } = useTranslationContext(); const lb = info.lastSuccessfulBackupTimestamp ? AbsoluteTime.fromPreciseTimestamp(info.lastSuccessfulBackupTimestamp) : undefined; const isPaid = info.paymentStatus.type === ProviderPaymentType.Paid || info.paymentStatus.type === ProviderPaymentType.TermsChanged; return (

{info.name}{" "} {info.syncProviderBaseUrl}

{isPaid ? "Paid" : "Unpaid"}

Last backup: {" "}

{info.terms && (

Provider fee: {" "} {info.terms && info.terms.annualFee}{" "} per year

)}

{descriptionByStatus(info.paymentStatus, i18n)}

{info.paymentStatus.type === ProviderPaymentType.TermsChanged && (

terms has changed, extending the service will imply accepting the new terms of service

  old -> new
fee {info.paymentStatus.oldTerms.annualFee} -> {info.paymentStatus.newTerms.annualFee}
storage {info.paymentStatus.oldTerms.storageLimitInMegabytes} -> {info.paymentStatus.newTerms.storageLimitInMegabytes}
)}
{info.paymentStatus.type === ProviderPaymentType.Pending && info.paymentStatus.talerUri ? ( ) : undefined} {info.paymentStatus.type === ProviderPaymentType.InsufficientBalance ? ( ) : undefined}
); } function Error({ info }: { info: ProviderInfo }): VNode { const { i18n } = useTranslationContext(); if (info.lastError) { return ( ); } if (info.backupProblem) { switch (info.backupProblem.type) { case "backup-conflicting-device": return ( ); case "backup-unreadable": return ; default: return ( ); } } return ; } function descriptionByStatus( status: ProviderPaymentStatus, i18n: typeof utils.i18n, ): VNode { switch (status.type) { case ProviderPaymentType.Paid: case ProviderPaymentType.TermsChanged: if (status.paidUntil.t_ms === "never") { return ( service paid ); } return ( Backup valid until: {" "} ); case ProviderPaymentType.Unpaid: case ProviderPaymentType.InsufficientBalance: case ProviderPaymentType.Pending: return ; } }