/* This file is part of GNU Taler (C) 2022-2024 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 { AbsoluteTime, AmountString, Amounts, CurrencySpecification, HttpStatusCode, TalerCorebankApi, TalerError, assertUnreachable, } from "@gnu-taler/taler-util"; import { Attention, RouteDefinition, useBankCoreApiContext, useTranslationContext, } from "@gnu-taler/web-util/browser"; import { format, sub } from "date-fns"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; import { ErrorLoadingWithDebug } from "../../components/ErrorLoadingWithDebug.js"; import { Transactions } from "../../components/Transactions/index.js"; import { useConversionInfo, useLastMonitorInfo } from "../../hooks/regional.js"; import { RenderAmount } from "../PaytoWireTransferForm.js"; import { WireTransfer } from "../WireTransfer.js"; import { AccountList } from "./AccountList.js"; /** * Query account information and show QR code if there is pending withdrawal */ interface Props { routeCreate: RouteDefinition; routeDownloadStats: RouteDefinition; routeCreateWireTransfer: RouteDefinition<{ account?: string; subject?: string; amount?: string; }>; routeShowAccount: RouteDefinition<{ account: string }>; routeRemoveAccount: RouteDefinition<{ account: string }>; routeUpdatePasswordAccount: RouteDefinition<{ account: string }>; routeShowCashoutsAccount: RouteDefinition<{ account: string }>; onAuthorizationRequired: () => void; } export function AdminHome({ routeCreate, routeRemoveAccount, routeShowAccount, routeUpdatePasswordAccount, routeDownloadStats, routeCreateWireTransfer, onAuthorizationRequired, }: Props): VNode { return ( ); } function getDateForTimeframe( date: AbsoluteTime, timeframe: TalerCorebankApi.MonitorTimeframeParam, locale: Locale, ): string { if (date.t_ms === "never") return "--"; switch (timeframe) { case TalerCorebankApi.MonitorTimeframeParam.hour: return `${format(date.t_ms, "HH", { locale })}hs`; case TalerCorebankApi.MonitorTimeframeParam.day: return format(date.t_ms, "EEEE", { locale }); case TalerCorebankApi.MonitorTimeframeParam.month: return format(date.t_ms, "MMMM", { locale }); case TalerCorebankApi.MonitorTimeframeParam.year: return format(date.t_ms, "yyyy", { locale }); case TalerCorebankApi.MonitorTimeframeParam.decade: return format(date.t_ms, "yyyy", { locale }); } assertUnreachable(timeframe); } export function getTimeframesForDate( time: Date, timeframe: TalerCorebankApi.MonitorTimeframeParam, ): { current: AbsoluteTime; previous: AbsoluteTime } { switch (timeframe) { case TalerCorebankApi.MonitorTimeframeParam.hour: return { current: AbsoluteTime.fromMilliseconds( sub(time, { hours: 1 }).getTime(), ), previous: AbsoluteTime.fromMilliseconds( sub(time, { hours: 2 }).getTime(), ), }; case TalerCorebankApi.MonitorTimeframeParam.day: return { current: AbsoluteTime.fromMilliseconds( sub(time, { days: 1 }).getTime(), ), previous: AbsoluteTime.fromMilliseconds( sub(time, { days: 4 }).getTime(), ), }; case TalerCorebankApi.MonitorTimeframeParam.month: return { current: AbsoluteTime.fromMilliseconds( sub(time, { months: 1 }).getTime(), ), previous: AbsoluteTime.fromMilliseconds( sub(time, { months: 2 }).getTime(), ), }; case TalerCorebankApi.MonitorTimeframeParam.year: return { current: AbsoluteTime.fromMilliseconds( sub(time, { years: 1 }).getTime(), ), previous: AbsoluteTime.fromMilliseconds( sub(time, { years: 2 }).getTime(), ), }; case TalerCorebankApi.MonitorTimeframeParam.decade: return { current: AbsoluteTime.fromMilliseconds( sub(time, { years: 10 }).getTime(), ), previous: AbsoluteTime.fromMilliseconds( sub(time, { years: 20 }).getTime(), ), }; default: assertUnreachable(timeframe); } } function Metrics({ routeDownloadStats, }: { routeDownloadStats: RouteDefinition; }): VNode { const { i18n, dateLocale } = useTranslationContext(); const [metricType, setMetricType] = useState( TalerCorebankApi.MonitorTimeframeParam.hour, ); const { config } = useBankCoreApiContext(); const respInfo = useConversionInfo(); const params = getTimeframesForDate(new Date(), metricType); const resp = useLastMonitorInfo(params.current, params.previous, metricType); if (!resp) return ; if (resp instanceof TalerError) { return ; } if (!respInfo) return ; if (respInfo instanceof TalerError) { return ; } if (respInfo.type === "fail") { switch (respInfo.case) { case HttpStatusCode.NotImplemented: { return ( Cashout should be enable by configuration and the conversion rate should be initialized with fee, ratio and rounding mode. ); } default: { assertUnreachable(respInfo.case); } } } if (resp.current.type !== "ok") { switch (resp.current.case) { case HttpStatusCode.BadRequest: return ( The request parameters are wrong ); case HttpStatusCode.Unauthorized: return ( The user is unauthorized ); default: { assertUnreachable(resp.current); } } } if (resp.previous.type !== "ok") { switch (resp.previous.case) { case HttpStatusCode.BadRequest: return ( The request parameters are wrong ); case HttpStatusCode.Unauthorized: return ( The user is unauthorized ); default: { assertUnreachable(resp.previous); } } } return (

Transaction volume report

{i18n.str`Trading volume on ${getDateForTimeframe( params.current, metricType, dateLocale, )} compared to ${getDateForTimeframe( params.previous, metricType, dateLocale, )}`}

{resp.current.body.type !== "with-conversions" || resp.previous.body.type !== "with-conversions" ? undefined : (
Cashin
Transferred from an external account to an account in this bank.
Cashout
Transferred from an account in this bank to an external account.
)}
Payin
Transferred from an account to a Taler exchange.
Payout
Transferred from a Taler exchange to another account.
); } function MetricValue({ current, previous, spec, }: { spec: CurrencySpecification; current: AmountString | undefined; previous: AmountString | undefined; }): VNode { const { i18n } = useTranslationContext(); const cmp = current && previous ? Amounts.cmp(current, previous) : 0; const cv = !current ? undefined : Amounts.stringifyValue(current); const currAmount = !cv ? undefined : Number.parseFloat(cv); const prevAmount = !previous ? undefined : Number.parseFloat(Amounts.stringifyValue(previous)); const rate = !currAmount || Number.isNaN(currAmount) || !prevAmount || Number.isNaN(prevAmount) ? 0 : cmp === -1 ? 1 - Math.round(currAmount) / Math.round(prevAmount) : cmp === 1 ? Math.round(currAmount) / Math.round(prevAmount) - 1 : 0; const negative = cmp === 0 ? undefined : cmp === -1; const rateStr = `${(Math.abs(rate) * 100).toFixed(2)}%`; return (
{!current ? ( "-" ) : ( )}
from{" "} {!previous ? ( "-" ) : ( )}
{!!rate && ( {negative ? ( ) : ( )} {negative ? ( Decreased by ) : ( Increased by )} {rateStr} )}
); }