import { AmountString, Amounts, CurrencySpecification, TalerCorebankApi, TalerError, assertUnreachable } from "@gnu-taler/taler-util"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { format, getDate, getHours, getMonth, getYear, setDate, setHours, setMonth, setYear, 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 { useBankCoreApiContext } from "../../context/config.js"; import { useConversionInfo, useLastMonitorInfo } from "../../hooks/circuit.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 { onRegister: () => void; onCreateAccount: () => void; onShowAccountDetails: (aid: string) => void; onRemoveAccount: (aid: string) => void; onUpdateAccountPassword: (aid: string) => void; onShowCashoutForAccount: (aid: string) => void; } export function AdminHome({ onCreateAccount, onRegister, onRemoveAccount, onShowAccountDetails, onShowCashoutForAccount, onUpdateAccountPassword }: Props): VNode { return } function getDateForTimeframe(which: number, timeframe: TalerCorebankApi.MonitorTimeframeParam): string { const time = Date.now() switch (timeframe) { case TalerCorebankApi.MonitorTimeframeParam.hour: return `${format(setHours(time, which), "HH")}hs`; case TalerCorebankApi.MonitorTimeframeParam.day: return format(setDate(time, which), "EEEE"); case TalerCorebankApi.MonitorTimeframeParam.month: return format(setMonth(time, which), "MMMM"); case TalerCorebankApi.MonitorTimeframeParam.year: return format(setYear(time, which), "yyyy"); case TalerCorebankApi.MonitorTimeframeParam.decade: return format(setYear(time, which), "yyyy"); } assertUnreachable(timeframe) } export function getTimeframesForDate(time: Date, timeframe: TalerCorebankApi.MonitorTimeframeParam): { current: number, previous: number } { switch (timeframe) { case TalerCorebankApi.MonitorTimeframeParam.hour: return { current: getHours(sub(time, { hours: 1 })), previous: getHours(sub(time, { hours: 2 })) } case TalerCorebankApi.MonitorTimeframeParam.day: return { current: getDate(sub(time, { days: 1 })), previous: getDate(sub(time, { days: 2 })) } case TalerCorebankApi.MonitorTimeframeParam.month: return { current: getMonth(sub(time, { months: 1 })), previous: getMonth(sub(time, { months: 2 })) } case TalerCorebankApi.MonitorTimeframeParam.year: return { current: getYear(sub(time, { years: 1 })), previous: getYear(sub(time, { years: 2 })) } case TalerCorebankApi.MonitorTimeframeParam.decade: return { current: getYear(sub(time, { years: 10 })), previous: getYear(sub(time, { years: 20 })) } default: assertUnreachable(timeframe) } } function Metrics(): VNode { const { i18n } = 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 (resp.current.type !== "ok" || resp.previous.type !== "ok") { return } const fiatSpec = respInfo && (!(respInfo instanceof TalerError)) ? respInfo.body.fiat_currency_specification : undefined return Select a section { // const op = e.currentTarget.value as typeof metricType setMetricType(e.currentTarget.value as any) }}> Last hour Last day Last month Last year { e.preventDefault(); setMetricType(TalerCorebankApi.MonitorTimeframeParam.hour) }} data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.hour} class="rounded-l-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10" > Last hour { e.preventDefault(); setMetricType(TalerCorebankApi.MonitorTimeframeParam.day) }} data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.day} aria-current="page" class=" text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"> Last day { e.preventDefault(); setMetricType(TalerCorebankApi.MonitorTimeframeParam.month) }} data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.month} class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"> Last month { e.preventDefault(); setMetricType(TalerCorebankApi.MonitorTimeframeParam.year) }} data-selected={metricType == TalerCorebankApi.MonitorTimeframeParam.year} class="rounded-r-lg text-gray-500 hover:text-gray-700 data-[selected=true]:text-gray-900 group relative min-w-0 flex-1 overflow-hidden bg-white py-4 px-4 text-center text-sm font-medium hover:bg-gray-50 focus:z-10"> Last Year Trading volume on {getDateForTimeframe(params.current, metricType)} compared to {getDateForTimeframe(params.previous, metricType)} {!fiatSpec || resp.current.body.type !== "with-conversions" || resp.previous.body.type !== "with-conversions" ? undefined : Cashin Cashout } Payin Payout download stats as csv } 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 ? Descreased by : Increased by } {rateStr} } }