taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit b2a86eed8fad115643a2e82bf4ad042aa98ce793
parent 07b566a1afb131d9137e543291de3a7368292360
Author: Florian Dold <florian@dold.me>
Date:   Mon, 26 Aug 2024 23:50:16 +0200

-formatting

Diffstat:
Mpackages/auditor-backoffice-ui/src/Application.tsx | 241+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mpackages/auditor-backoffice-ui/src/InstanceRoutes.tsx | 870+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mpackages/auditor-backoffice-ui/src/hooks/backend.ts | 409++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mpackages/auditor-backoffice-ui/src/hooks/index.ts | 97+++++++++++++++++++++++++++++++++++++++----------------------------------------
Mpackages/auditor-backoffice-ui/src/index.tsx | 3+--
5 files changed, 873 insertions(+), 747 deletions(-)

diff --git a/packages/auditor-backoffice-ui/src/Application.tsx b/packages/auditor-backoffice-ui/src/Application.tsx @@ -20,35 +20,33 @@ * @author Nic Eigel */ -import {HttpStatusCode, LibtoolVersion} from "@gnu-taler/taler-util"; +import { HttpStatusCode, LibtoolVersion } from "@gnu-taler/taler-util"; import { - ErrorType, - TranslationProvider, - useTranslationContext + ErrorType, + TranslationProvider, + useTranslationContext, } from "@gnu-taler/web-util/browser"; -import {Fragment, VNode, h, render} from "preact"; -import {useMemo} from "preact/hooks"; -import {ApplicationReadyRoutes} from "./ApplicationReadyRoutes.js"; -import {Loading} from "./components/exception/loading.js"; +import { Fragment, VNode, h } from "preact"; +import { useMemo } from "preact/hooks"; +import { ApplicationReadyRoutes } from "./ApplicationReadyRoutes.js"; +import { Loading } from "./components/exception/loading.js"; import { - NotConnectedAppMenu, - NotificationCard + NotConnectedAppMenu, + NotificationCard, } from "./components/menu/index.js"; -import { - BackendContextProvider -} from "./context/backend.js"; -import {ConfigContextProvider} from "./context/config.js"; -import {useBackendConfig} from "./hooks/backend.js"; +import { BackendContextProvider } from "./context/backend.js"; +import { ConfigContextProvider } from "./context/config.js"; +import { useBackendConfig } from "./hooks/backend.js"; import { strings } from "./i18n/strings.js"; export function Application(): VNode { - return ( - <BackendContextProvider> - <TranslationProvider source={strings}> - <ApplicationStatusRoutes/> - </TranslationProvider> - </BackendContextProvider> - ); + return ( + <BackendContextProvider> + <TranslationProvider source={strings}> + <ApplicationStatusRoutes /> + </TranslationProvider> + </BackendContextProvider> + ); } /** @@ -57,110 +55,110 @@ export function Application(): VNode { * @returns */ function ApplicationStatusRoutes(): VNode { - const result = useBackendConfig(); - const {i18n} = useTranslationContext(); + const result = useBackendConfig(); + const { i18n } = useTranslationContext(); - const configData = result.ok && result.data - ? result.data - : undefined; - const ctx = useMemo(() => (configData), [configData]); + const configData = result.ok && result.data ? result.data : undefined; + const ctx = useMemo(() => configData, [configData]); - if (!result.ok) { - if (result.loading) return <Loading/>; - if ( - result.type === ErrorType.CLIENT && - result.status === HttpStatusCode.Unauthorized - ) { - return ( - <Fragment> - <NotConnectedAppMenu title="Login"/> - <NotificationCard - notification={{ - message: i18n.str`Checking the /config endpoint got authorization error`, - type: "ERROR", - description: `The /config endpoint of the backend server should be accessible`, - }} - /> - </Fragment> - ); - } - if ( - result.type === ErrorType.CLIENT && - result.status === HttpStatusCode.NotFound - ) { - return ( - <Fragment> - <NotConnectedAppMenu title="Error"/> - <NotificationCard - notification={{ - message: i18n.str`Could not find /config endpoint on this URL`, - type: "ERROR", - description: `Check the URL or contact the system administrator.`, - }} - /> - </Fragment> - ); - } - if (result.type === ErrorType.SERVER) { - <Fragment> - <NotConnectedAppMenu title="Error"/> - <NotificationCard - notification={{ - message: i18n.str`Server response with an error code`, - type: "ERROR", - description: i18n.str`Got message "${result.message}" from ${result.info?.url}`, - }} - /> - </Fragment>; - } - if (result.type === ErrorType.UNREADABLE) { - <Fragment> - <NotConnectedAppMenu title="Error"/> - <NotificationCard - notification={{ - message: i18n.str`Response from server is unreadable, http status: ${result.status}`, - type: "ERROR", - description: i18n.str`Got message "${result.message}" from ${result.info?.url}`, - }} - /> - </Fragment>; - } - return ( - <Fragment> - <NotConnectedAppMenu title="Error"/> - <NotificationCard - notification={{ - message: i18n.str`Unexpected Error`, - type: "ERROR", - description: i18n.str`Got message "${result.message}" from ${result.info?.url}`, - }} - /> - </Fragment> - ); + if (!result.ok) { + if (result.loading) return <Loading />; + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.Unauthorized + ) { + return ( + <Fragment> + <NotConnectedAppMenu title="Login" /> + <NotificationCard + notification={{ + message: i18n.str`Checking the /config endpoint got authorization error`, + type: "ERROR", + description: `The /config endpoint of the backend server should be accessible`, + }} + /> + </Fragment> + ); } - - const SUPPORTED_VERSION = "1:0:1" - if (result.data && !LibtoolVersion.compare( - SUPPORTED_VERSION, - result.data.version, - )?.compatible) { - return <Fragment> - <NotConnectedAppMenu title="Error"/> - <NotificationCard - notification={{ - message: i18n.str`Incompatible version`, - type: "ERROR", - description: i18n.str`Auditor backend server version ${result.data.version} is not compatible with the supported version ${SUPPORTED_VERSION}`, - }} - /> + if ( + result.type === ErrorType.CLIENT && + result.status === HttpStatusCode.NotFound + ) { + return ( + <Fragment> + <NotConnectedAppMenu title="Error" /> + <NotificationCard + notification={{ + message: i18n.str`Could not find /config endpoint on this URL`, + type: "ERROR", + description: `Check the URL or contact the system administrator.`, + }} + /> </Fragment> + ); + } + if (result.type === ErrorType.SERVER) { + <Fragment> + <NotConnectedAppMenu title="Error" /> + <NotificationCard + notification={{ + message: i18n.str`Server response with an error code`, + type: "ERROR", + description: i18n.str`Got message "${result.message}" from ${result.info?.url}`, + }} + /> + </Fragment>; } + if (result.type === ErrorType.UNREADABLE) { + <Fragment> + <NotConnectedAppMenu title="Error" /> + <NotificationCard + notification={{ + message: i18n.str`Response from server is unreadable, http status: ${result.status}`, + type: "ERROR", + description: i18n.str`Got message "${result.message}" from ${result.info?.url}`, + }} + /> + </Fragment>; + } + return ( + <Fragment> + <NotConnectedAppMenu title="Error" /> + <NotificationCard + notification={{ + message: i18n.str`Unexpected Error`, + type: "ERROR", + description: i18n.str`Got message "${result.message}" from ${result.info?.url}`, + }} + /> + </Fragment> + ); + } + const SUPPORTED_VERSION = "1:0:1"; + if ( + result.data && + !LibtoolVersion.compare(SUPPORTED_VERSION, result.data.version)?.compatible + ) { return ( - <div class="has-navbar-fixed-top"> - <ConfigContextProvider value={ctx!}> - <ApplicationReadyRoutes/> - </ConfigContextProvider> - </div> + <Fragment> + <NotConnectedAppMenu title="Error" /> + <NotificationCard + notification={{ + message: i18n.str`Incompatible version`, + type: "ERROR", + description: i18n.str`Auditor backend server version ${result.data.version} is not compatible with the supported version ${SUPPORTED_VERSION}`, + }} + /> + </Fragment> ); -} -\ No newline at end of file + } + + return ( + <div class="has-navbar-fixed-top"> + <ConfigContextProvider value={ctx!}> + <ApplicationReadyRoutes /> + </ConfigContextProvider> + </div> + ); +} diff --git a/packages/auditor-backoffice-ui/src/InstanceRoutes.tsx b/packages/auditor-backoffice-ui/src/InstanceRoutes.tsx @@ -20,202 +20,284 @@ * @author Nicola Eigel */ -import {TranslatedString} from "@gnu-taler/taler-util"; -import { - useTranslationContext, -} from "@gnu-taler/web-util/browser"; -import {VNode, h} from "preact"; -import {Route, Router, route} from "preact-router"; -import {useEffect, useErrorBoundary, useMemo, useState} from "preact/hooks"; -import {Menu, NotificationCard} from "./components/menu/index.js"; -import {EntityContextProvider} from "./context/entity.js"; -import {Notification} from "./utils/types.js"; -import NotFoundPage from "./paths/notfound/index.js"; -import {Settings} from "./paths/settings/index.js"; +import { TranslatedString } from "@gnu-taler/taler-util"; +import { useTranslationContext } from "@gnu-taler/web-util/browser"; +import { VNode, h } from "preact"; +import { Route, Router, route } from "preact-router"; +import { useEffect, useErrorBoundary, useMemo, useState } from "preact/hooks"; +import { Menu, NotificationCard } from "./components/menu/index.js"; +import { EntityContextProvider } from "./context/entity.js"; +import { AuditorBackend } from "./declaration.js"; import DefaultList from "./paths/default/index.js"; -import { - AuditorBackend, -} from "./declaration.js"; -import FinanceDashboard from "./paths/finance/index.js"; import DetailsDashboard from "./paths/details/index.js"; +import FinanceDashboard from "./paths/finance/index.js"; +import NotFoundPage from "./paths/notfound/index.js"; import OperationsDashboard from "./paths/operations/index.js"; import SecurityDashboard from "./paths/security/index.js"; +import { Settings } from "./paths/settings/index.js"; +import { Notification } from "./utils/types.js"; export enum Paths { - error = "/error", - settings = "/settings", + error = "/error", + settings = "/settings", - key_figures = "/key-figures", - critical_errors = "/critical-errors", - operating_status = "/operating-status", - detail_view = "/detail-view", + key_figures = "/key-figures", + critical_errors = "/critical-errors", + operating_status = "/operating-status", + detail_view = "/detail-view", - amount_arithmethic_inconsistency_list = "/amount-arithmetic-inconsistencies", + amount_arithmethic_inconsistency_list = "/amount-arithmetic-inconsistencies", - bad_sig_losses_list = "/bad-sig-losses", + bad_sig_losses_list = "/bad-sig-losses", - balance_list = "/balance", + balance_list = "/balance", - closure_lag_list = "/closure-lags", + closure_lag_list = "/closure-lags", - coin_inconsistency_list = "/coin-inconsistencies", + coin_inconsistency_list = "/coin-inconsistencies", - denomination_key_validity_withdraw_inconsistency_list = "/denomination-key-validity-withdraw-inconsistencies", + denomination_key_validity_withdraw_inconsistency_list = "/denomination-key-validity-withdraw-inconsistencies", - denomination_pending_list = "/denominations-pending", + denomination_pending_list = "/denominations-pending", - denomination_without_sig_list = "/denominations-without-sig", + denomination_without_sig_list = "/denominations-without-sig", - deposit_confirmation_list = "/deposit-confirmations", - deposit_confirmation_update = "/deposit-confirmation/:rowid/update", + deposit_confirmation_list = "/deposit-confirmations", + deposit_confirmation_update = "/deposit-confirmation/:rowid/update", - emergency_list = "/emergencies", + emergency_list = "/emergencies", - emergency_by_count_list = "/emergencies-by-count", + emergency_by_count_list = "/emergencies-by-count", - exchange_signkey_list = "/exchange-sign-keys", + exchange_signkey_list = "/exchange-sign-keys", - fee_time_inconsistency_list = "/fee-time-inconsistencies", + fee_time_inconsistency_list = "/fee-time-inconsistencies", - historic_denomination_revenue_list = "/historic-denomination-revenues", + historic_denomination_revenue_list = "/historic-denomination-revenues", - misattribution_in_inconsistency_list = "/misattribution-in-inconsistencies", + misattribution_in_inconsistency_list = "/misattribution-in-inconsistencies", - progress_list = "/progress", + progress_list = "/progress", - purse_not_closed_inconsistency_list = "/purse-not-closed-inconsistencies", + purse_not_closed_inconsistency_list = "/purse-not-closed-inconsistencies", - purse_list = "/purses", + purse_list = "/purses", - refresh_hanging_list = "/refreshes-hanging", + refresh_hanging_list = "/refreshes-hanging", - reserve_balance_insufficient_inconsistency_list = "/reserve-balance-insufficient-inconsistencies", + reserve_balance_insufficient_inconsistency_list = "/reserve-balance-insufficient-inconsistencies", - reserve_balance_summary_wrong_inconsistency_list = "/reserve-balance-summary-wrong-inconsistencies", + reserve_balance_summary_wrong_inconsistency_list = "/reserve-balance-summary-wrong-inconsistencies", - reserve_in_inconsistency_list = "/reserve-in-inconsistencies", + reserve_in_inconsistency_list = "/reserve-in-inconsistencies", - reserve_not_closed_inconsistency_list = "/reserve-not-closed-inconsistencies", + reserve_not_closed_inconsistency_list = "/reserve-not-closed-inconsistencies", - reserves_list = "/reserves", + reserves_list = "/reserves", - row_inconsistency_list = "/row-inconsistencies", + row_inconsistency_list = "/row-inconsistencies", - row_minor_inconsistency_list = "/row-minor-inconsistencies", + row_minor_inconsistency_list = "/row-minor-inconsistencies", - wire_format_inconsistency_list = "/wire-format-inconsistencies", + wire_format_inconsistency_list = "/wire-format-inconsistencies", - wire_out_inconsistency_list = "/wire-out-inconsistencies" + wire_out_inconsistency_list = "/wire-out-inconsistencies", } interface TestProps { - title: string; - endpoint: string; - entity: any; + title: string; + endpoint: string; + entity: any; } function getInstanceTitle(path: string): TestProps { - switch (path) { - case Paths.key_figures: - return {title: `Key figures`, endpoint: "helper", entity: null}; - case Paths.critical_errors: - return {title: `Critical errors`, endpoint: "helper", entity: null}; - case Paths.operating_status: - return {title: `Operating status`, endpoint: "helper", entity: null}; - case Paths.detail_view: - return {title: `Inconsistencies`, endpoint: "helper", entity: null}; - case Paths.amount_arithmethic_inconsistency_list: - let amountArithmeticInconsistency: AuditorBackend.AmountArithmeticInconsistency.ClassAmountArithmeticInconsistency = {} as AuditorBackend.AmountArithmeticInconsistency.ClassAmountArithmeticInconsistency; - return { - title: `Amount arithmetic inconsistencies`, - endpoint: "amount-arithmetic-inconsistency", - entity: amountArithmeticInconsistency - }; - case Paths.bad_sig_losses_list: - return {title: `Bad Sig Losses`, endpoint: "bad-sig-losses", entity: null}; - case Paths.balance_list: - return {title: "Balances", endpoint: "balances", entity: null}; - case Paths.closure_lag_list: - return {title: `Closure Lags`, endpoint: "closure-lags", entity: null}; - case Paths.coin_inconsistency_list: - return {title: `Coin inconsistencies`, endpoint: "coin-inconsistency", entity: null}; - case Paths.denomination_key_validity_withdraw_inconsistency_list: - return {title: `Denomination key validity withdraw inconsistency`, endpoint: "denomination-key-validity-withdraw-inconsistency", entity: null}; - case Paths.denomination_pending_list: - return {title: `Denominations pending`, endpoint: "denomination-pending", entity: null}; - case Paths.denomination_without_sig_list: - return {title: `Denominations without sigs`, endpoint: "denominations-without-sigs", entity: null}; - case Paths.deposit_confirmation_list: - return {title: "Deposit Confirmations", endpoint: "deposit-confirmation", entity: null}; - case Paths.emergency_list: - return {title: "Emergencies", endpoint: "emergency", entity: null}; - case Paths.emergency_by_count_list: - return {title: "Emergencies by count", endpoint: "emergency-by-count", entity: null}; - case Paths.fee_time_inconsistency_list: - return {title: "Fee time inconsistencies", endpoint: "fee-time-inconsistency", entity: null}; - case Paths.historic_denomination_revenue_list: - return {title: "Historic denomination revenue", endpoint: "historic-denomination-revenue", entity: null}; - case Paths.misattribution_in_inconsistency_list: - return {title: "Misattribution in inconsistencies", endpoint: "misattribution-in-inconsistency", entity: null}; - case Paths.progress_list: - return {title: "Progress", endpoint: "progress", entity: null}; - case Paths.purse_not_closed_inconsistency_list: - return {title: "Purse not closed inconsistencies", endpoint: "purse-not-closed-inconsistencies", entity: null}; - case Paths.purse_list: - return {title: "Purses", endpoint: "purses", entity: null}; - case Paths.refresh_hanging_list: - return {title: "Refreshes hanging", endpoint: "refreshes-hanging", entity: null}; - case Paths.reserves_list: - return {title: "Reserves", endpoint: "reserves ", entity: null}; - case Paths.reserve_balance_insufficient_inconsistency_list: - return {title: "Reserve balance insufficient inconsistencies", endpoint: "reserve-balance-insufficient-inconsistency", entity: null}; - case Paths.reserve_balance_summary_wrong_inconsistency_list: - return {title: "Reserve balance summary wrong inconsistencies", endpoint: "reserve-balance-summary-wrong-inconsistency", entity: null}; - case Paths.reserve_in_inconsistency_list: - return {title: "Reserves in inconsistencies", endpoint: "reserve-in-inconsistency", entity: null}; - case Paths.reserve_not_closed_inconsistency_list: - return {title: "Reserves not closed inconsistencies", endpoint: "reserve-not-closed-inconsistency", entity: null}; - case Paths.row_inconsistency_list: - return {title: "Row inconsistencies", endpoint: "row-inconsistency", entity: null}; - case Paths.row_minor_inconsistency_list: - return {title: "Row minor inconsistencies", endpoint: "row-minor-inconsistencies", entity: null}; - case Paths.wire_format_inconsistency_list: - let wireFormatInconsistency: AuditorBackend.WireFormatInconsistency.ClassWireFormatInconsistency = {} as AuditorBackend.WireFormatInconsistency.ClassWireFormatInconsistency; - return {title: "Wire format inconsistencies", endpoint: "wire-format-inconsistency", entity: wireFormatInconsistency}; - case Paths.wire_out_inconsistency_list: - return {title: "Wire out inconsistencies", endpoint: "wire-out-inconsistency", entity: null}; - case Paths.settings: - return {title: `Settings`, endpoint: "settings", entity: null}; - default: - return {title: "", endpoint: "", entity: null}; - } + switch (path) { + case Paths.key_figures: + return { title: `Key figures`, endpoint: "helper", entity: null }; + case Paths.critical_errors: + return { title: `Critical errors`, endpoint: "helper", entity: null }; + case Paths.operating_status: + return { title: `Operating status`, endpoint: "helper", entity: null }; + case Paths.detail_view: + return { title: `Inconsistencies`, endpoint: "helper", entity: null }; + case Paths.amount_arithmethic_inconsistency_list: + let amountArithmeticInconsistency: AuditorBackend.AmountArithmeticInconsistency.ClassAmountArithmeticInconsistency = + {} as AuditorBackend.AmountArithmeticInconsistency.ClassAmountArithmeticInconsistency; + return { + title: `Amount arithmetic inconsistencies`, + endpoint: "amount-arithmetic-inconsistency", + entity: amountArithmeticInconsistency, + }; + case Paths.bad_sig_losses_list: + return { + title: `Bad Sig Losses`, + endpoint: "bad-sig-losses", + entity: null, + }; + case Paths.balance_list: + return { title: "Balances", endpoint: "balances", entity: null }; + case Paths.closure_lag_list: + return { title: `Closure Lags`, endpoint: "closure-lags", entity: null }; + case Paths.coin_inconsistency_list: + return { + title: `Coin inconsistencies`, + endpoint: "coin-inconsistency", + entity: null, + }; + case Paths.denomination_key_validity_withdraw_inconsistency_list: + return { + title: `Denomination key validity withdraw inconsistency`, + endpoint: "denomination-key-validity-withdraw-inconsistency", + entity: null, + }; + case Paths.denomination_pending_list: + return { + title: `Denominations pending`, + endpoint: "denomination-pending", + entity: null, + }; + case Paths.denomination_without_sig_list: + return { + title: `Denominations without sigs`, + endpoint: "denominations-without-sigs", + entity: null, + }; + case Paths.deposit_confirmation_list: + return { + title: "Deposit Confirmations", + endpoint: "deposit-confirmation", + entity: null, + }; + case Paths.emergency_list: + return { title: "Emergencies", endpoint: "emergency", entity: null }; + case Paths.emergency_by_count_list: + return { + title: "Emergencies by count", + endpoint: "emergency-by-count", + entity: null, + }; + case Paths.fee_time_inconsistency_list: + return { + title: "Fee time inconsistencies", + endpoint: "fee-time-inconsistency", + entity: null, + }; + case Paths.historic_denomination_revenue_list: + return { + title: "Historic denomination revenue", + endpoint: "historic-denomination-revenue", + entity: null, + }; + case Paths.misattribution_in_inconsistency_list: + return { + title: "Misattribution in inconsistencies", + endpoint: "misattribution-in-inconsistency", + entity: null, + }; + case Paths.progress_list: + return { title: "Progress", endpoint: "progress", entity: null }; + case Paths.purse_not_closed_inconsistency_list: + return { + title: "Purse not closed inconsistencies", + endpoint: "purse-not-closed-inconsistencies", + entity: null, + }; + case Paths.purse_list: + return { title: "Purses", endpoint: "purses", entity: null }; + case Paths.refresh_hanging_list: + return { + title: "Refreshes hanging", + endpoint: "refreshes-hanging", + entity: null, + }; + case Paths.reserves_list: + return { title: "Reserves", endpoint: "reserves ", entity: null }; + case Paths.reserve_balance_insufficient_inconsistency_list: + return { + title: "Reserve balance insufficient inconsistencies", + endpoint: "reserve-balance-insufficient-inconsistency", + entity: null, + }; + case Paths.reserve_balance_summary_wrong_inconsistency_list: + return { + title: "Reserve balance summary wrong inconsistencies", + endpoint: "reserve-balance-summary-wrong-inconsistency", + entity: null, + }; + case Paths.reserve_in_inconsistency_list: + return { + title: "Reserves in inconsistencies", + endpoint: "reserve-in-inconsistency", + entity: null, + }; + case Paths.reserve_not_closed_inconsistency_list: + return { + title: "Reserves not closed inconsistencies", + endpoint: "reserve-not-closed-inconsistency", + entity: null, + }; + case Paths.row_inconsistency_list: + return { + title: "Row inconsistencies", + endpoint: "row-inconsistency", + entity: null, + }; + case Paths.row_minor_inconsistency_list: + return { + title: "Row minor inconsistencies", + endpoint: "row-minor-inconsistencies", + entity: null, + }; + case Paths.wire_format_inconsistency_list: + let wireFormatInconsistency: AuditorBackend.WireFormatInconsistency.ClassWireFormatInconsistency = + {} as AuditorBackend.WireFormatInconsistency.ClassWireFormatInconsistency; + return { + title: "Wire format inconsistencies", + endpoint: "wire-format-inconsistency", + entity: wireFormatInconsistency, + }; + case Paths.wire_out_inconsistency_list: + return { + title: "Wire out inconsistencies", + endpoint: "wire-out-inconsistency", + entity: null, + }; + case Paths.settings: + return { title: `Settings`, endpoint: "settings", entity: null }; + default: + return { title: "", endpoint: "", entity: null }; + } } export interface Props { - path: string; + path: string; } export function InstanceRoutes({ - // id, - path, - // setInstanceName - }: Props): VNode { - const {i18n} = useTranslationContext(); - - type GlobalNotifState = (Notification & { to: string | undefined }) | undefined; - const [globalNotification, setGlobalNotification] = - useState<GlobalNotifState>(undefined); - - const [error] = useErrorBoundary(); - const {title, endpoint, entity} = getInstanceTitle(path.replace("app/#", "")); - - const value = useMemo( - () => ({title, path, endpoint, entity}), - [title, path, endpoint, entity], - ); - - //TODO add if needed - /*function ServerErrorRedirectTo(to: Paths) { + // id, + path, + // setInstanceName +}: Props): VNode { + const { i18n } = useTranslationContext(); + + type GlobalNotifState = + | (Notification & { to: string | undefined }) + | undefined; + const [globalNotification, setGlobalNotification] = + useState<GlobalNotifState>(undefined); + + const [error] = useErrorBoundary(); + const { title, endpoint, entity } = getInstanceTitle( + path.replace("app/#", ""), + ); + + const value = useMemo( + () => ({ title, path, endpoint, entity }), + [title, path, endpoint, entity], + ); + + //TODO add if needed + /*function ServerErrorRedirectTo(to: Paths) { return function ServerErrorRedirectToImpl( error: HttpError<AuditorBackend.ErrorDetail>, ) { @@ -242,231 +324,272 @@ export function InstanceRoutes({ }; }*/ + return ( + <EntityContextProvider value={value}> + <Menu + // instance={id} + path={path} + title={"Settings"} + onShowSettings={() => { + route(Paths.settings); + }} + /> + <NotificationCard notification={globalNotification} /> + {error && ( + <NotificationCard + notification={{ + message: "Internal error, please report", + type: "ERROR", + description: ( + <pre> + { + (error instanceof Error + ? error.stack + : String(error)) as TranslatedString + } + </pre> + ), + }} + /> + )} + <Router + onChange={(e) => { + const movingOutFromNotification = + globalNotification && e.url !== globalNotification.to; + if (movingOutFromNotification) { + setGlobalNotification(undefined); + } + }} + > + <Route path="/" component={Redirect} to={Paths.key_figures} /> + + <Route + path={Paths.key_figures} + component={FinanceDashboard} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.critical_errors} + component={SecurityDashboard} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.operating_status} + component={OperationsDashboard} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.detail_view} + component={DetailsDashboard} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.amount_arithmethic_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.bad_sig_losses_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.balance_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.closure_lag_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.coin_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.denomination_key_validity_withdraw_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.denomination_pending_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.denomination_without_sig_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.deposit_confirmation_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.emergency_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + <Route + path={Paths.emergency_by_count_list} + component={DefaultList} + onNotFound={NotFoundPage} + //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} + /> + { + <Route + path={Paths.exchange_signkey_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.fee_time_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.historic_denomination_revenue_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.misattribution_in_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.progress_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.purse_not_closed_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.purse_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.refresh_hanging_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.reserve_balance_insufficient_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.reserve_balance_summary_wrong_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.reserve_in_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.reserve_not_closed_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.reserves_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.row_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.row_minor_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.wire_out_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + { + <Route + path={Paths.wire_format_inconsistency_list} + component={DefaultList} + onNotFound={NotFoundPage} + /> + } + <Route path={Paths.settings} component={Settings} /> - return ( - <EntityContextProvider value={value}> - <Menu - // instance={id} - path={path} - title={"Settings"} - onShowSettings={() => { - route(Paths.settings); - }}/> - <NotificationCard notification={globalNotification}/> - {error && - <NotificationCard notification={{ - message: "Internal error, please report", - type: "ERROR", - description: <pre> - {(error instanceof Error ? error.stack : String(error)) as TranslatedString} - </pre>, - }}/> - } - <Router - onChange={(e) => { - const movingOutFromNotification = - globalNotification && e.url !== globalNotification.to; - if (movingOutFromNotification) { - setGlobalNotification(undefined); - } - }} - > - <Route path="/" component={Redirect} to={Paths.key_figures}/> - - <Route - path={Paths.key_figures} - component={FinanceDashboard} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.critical_errors} - component={SecurityDashboard} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.operating_status} - component={OperationsDashboard} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.detail_view} - component={DetailsDashboard} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.amount_arithmethic_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.bad_sig_losses_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.balance_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.closure_lag_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.coin_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.denomination_key_validity_withdraw_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.denomination_pending_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.denomination_without_sig_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.deposit_confirmation_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.emergency_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - <Route - path={Paths.emergency_by_count_list} - component={DefaultList} - onNotFound={NotFoundPage} - //onLoadError={ServerErrorRedirectTo(Paths.balance_list)} - /> - {<Route - path={Paths.exchange_signkey_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.fee_time_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.historic_denomination_revenue_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.misattribution_in_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.progress_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.purse_not_closed_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.purse_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.refresh_hanging_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.reserve_balance_insufficient_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.reserve_balance_summary_wrong_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.reserve_in_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.reserve_not_closed_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.reserves_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.row_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.row_minor_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.wire_out_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - {<Route - path={Paths.wire_format_inconsistency_list} - component={DefaultList} - onNotFound={NotFoundPage} - />} - <Route - path={Paths.settings} - component={Settings} - /> - - {//TODO add if needed - /** - * Example pages - */} - {/* <Route path="/loading" component={Loading}/> + { + //TODO add if needed + /** + * Example pages + */ + } + {/* <Route path="/loading" component={Loading}/> <Route default component={NotFoundPage}/>*/} - </Router> - </EntityContextProvider> - ); + </Router> + </EntityContextProvider> + ); } -export function Redirect({to}: { to: string }): null { - useEffect(() => { - route(to, true); - }); - return null; -} -\ No newline at end of file +export function Redirect({ to }: { to: string }): null { + useEffect(() => { + route(to, true); + }); + return null; +} diff --git a/packages/auditor-backoffice-ui/src/hooks/backend.ts b/packages/auditor-backoffice-ui/src/hooks/backend.ts @@ -21,149 +21,159 @@ */ import { - HttpResponse, - HttpResponseOk, - RequestError, - RequestOptions, - useApiContext, + HttpResponse, + HttpResponseOk, + RequestError, + RequestOptions, + useApiContext, } from "@gnu-taler/web-util/browser"; -import {useCallback, useEffect, useState} from "preact/hooks"; -import {useSWRConfig} from "swr"; +import { useCallback, useEffect, useState } from "preact/hooks"; +import { useSWRConfig } from "swr"; import { useBackendContext } from "../context/backend.js"; import { AuditorBackend } from "../declaration.js"; export function useMatchMutate(): ( - re?: RegExp, - value?: unknown, + re?: RegExp, + value?: unknown, ) => Promise<any> { - const {cache, mutate} = useSWRConfig(); + const { cache, mutate } = useSWRConfig(); - if (!(cache instanceof Map)) { - throw new Error( - "matchMutate requires the cache provider to be a Map instance", - ); - } - - return function matchRegexMutate(re?: RegExp) { - return mutate((key) => { - // evict if no key or regex === all - if (!key || !re) return true - // match string - if (typeof key === 'string' && re.test(key)) return true - // record or object have the path at [0] - if (typeof key === 'object' && re.test(key[0])) return true - //key didn't match regex - return false - }, undefined, { - revalidate: true, - }); - }; + if (!(cache instanceof Map)) { + throw new Error( + "matchMutate requires the cache provider to be a Map instance", + ); + } + + return function matchRegexMutate(re?: RegExp) { + return mutate( + (key) => { + // evict if no key or regex === all + if (!key || !re) return true; + // match string + if (typeof key === "string" && re.test(key)) return true; + // record or object have the path at [0] + if (typeof key === "object" && re.test(key[0])) return true; + //key didn't match regex + return false; + }, + undefined, + { + revalidate: true, + }, + ); + }; } const CHECK_CONFIG_INTERVAL_OK = 5 * 60 * 1000; const CHECK_CONFIG_INTERVAL_FAIL = 2 * 1000; export function useBackendConfig(): HttpResponse< - AuditorBackend.VersionResponse | undefined, - RequestError<AuditorBackend.ErrorDetail> + AuditorBackend.VersionResponse | undefined, + RequestError<AuditorBackend.ErrorDetail> > { - const {request} = useBackendBaseRequest(); - - type Type = AuditorBackend.VersionResponse; - type State = { data: HttpResponse<Type, RequestError<AuditorBackend.ErrorDetail>>, timer: number } - const [result, setResult] = useState<State>({data: {loading: true}, timer: 0}); - - useEffect(() => { - if (result.timer) { - clearTimeout(result.timer); - } - - function tryConfig(): void { - request<Type>(`/config`) - .then((data) => { - const timer: any = setTimeout(() => { - tryConfig(); - }, CHECK_CONFIG_INTERVAL_OK); - setResult({data, timer}); - }) - .catch((error) => { - const timer: any = setTimeout(() => { - tryConfig(); - }, CHECK_CONFIG_INTERVAL_FAIL); - const data = error.cause; - setResult({data, timer}); - }); - } - - tryConfig(); - }, [request]); - - return result.data; + const { request } = useBackendBaseRequest(); + + type Type = AuditorBackend.VersionResponse; + type State = { + data: HttpResponse<Type, RequestError<AuditorBackend.ErrorDetail>>; + timer: number; + }; + const [result, setResult] = useState<State>({ + data: { loading: true }, + timer: 0, + }); + + useEffect(() => { + if (result.timer) { + clearTimeout(result.timer); + } + + function tryConfig(): void { + request<Type>("config") + .then((data) => { + const timer: any = setTimeout(() => { + tryConfig(); + }, CHECK_CONFIG_INTERVAL_OK); + setResult({ data, timer }); + }) + .catch((error) => { + const timer: any = setTimeout(() => { + tryConfig(); + }, CHECK_CONFIG_INTERVAL_FAIL); + const data = error.cause; + setResult({ data, timer }); + }); + } + + tryConfig(); + }, [request]); + + return result.data; } export function useBackendToken(): HttpResponse< AuditorBackend.VersionResponse, RequestError<AuditorBackend.ErrorDetail> > { - const {request} = useBackendBaseRequest(); - - type Type = AuditorBackend.VersionResponse; - type State = { data: HttpResponse<Type, RequestError<AuditorBackend.ErrorDetail>>, timer: number } - const [result, setResult] = useState<State>({data: {loading: true}, timer: 0}); - - useEffect(() => { - if (result.timer) { - clearTimeout(result.timer); - } - - function tryToken(): void { - request<Type>(`/monitoring/balances`) - .then((data) => { - const timer: any = setTimeout(() => { - tryToken(); - }, CHECK_CONFIG_INTERVAL_OK); - setResult({data, timer}); - }) - .catch((error) => { - const timer: any = setTimeout(() => { - tryToken(); - }, CHECK_CONFIG_INTERVAL_FAIL); - const data = error.cause; - setResult({data, timer}); - }); - } - - tryToken(); - }, [request]); - - return result.data; + const { request } = useBackendBaseRequest(); + + type Type = AuditorBackend.VersionResponse; + type State = { + data: HttpResponse<Type, RequestError<AuditorBackend.ErrorDetail>>; + timer: number; + }; + const [result, setResult] = useState<State>({ + data: { loading: true }, + timer: 0, + }); + + useEffect(() => { + if (result.timer) { + clearTimeout(result.timer); + } + + function tryToken(): void { + request<Type>(`/monitoring/balances`) + .then((data) => { + const timer: any = setTimeout(() => { + tryToken(); + }, CHECK_CONFIG_INTERVAL_OK); + setResult({ data, timer }); + }) + .catch((error) => { + const timer: any = setTimeout(() => { + tryToken(); + }, CHECK_CONFIG_INTERVAL_FAIL); + const data = error.cause; + setResult({ data, timer }); + }); + } + + tryToken(); + }, [request]); + + return result.data; } interface useBackendInstanceRequestType { - - request: <T>( - endpoint: string, - options?: RequestOptions, - ) => Promise<HttpResponseOk<T>>; - fetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>; - multiFetcher: <T>(params: string[]) => Promise<HttpResponseOk<T>[]>; - depositConfirmationFetcher: <T>( - params: [ - endpoint: string, - ], - ) => Promise<HttpResponseOk<T>>; + request: <T>( + endpoint: string, + options?: RequestOptions, + ) => Promise<HttpResponseOk<T>>; + fetcher: <T>(endpoint: string) => Promise<HttpResponseOk<T>>; + multiFetcher: <T>(params: string[]) => Promise<HttpResponseOk<T>[]>; + depositConfirmationFetcher: <T>( + params: [endpoint: string], + ) => Promise<HttpResponseOk<T>>; } interface useBackendBaseRequestType { - - request: <T>( - endpoint: string, - options?: RequestOptions - ) => Promise<HttpResponseOk<T>>; + request: <T>( + endpoint: string, + options?: RequestOptions, + ) => Promise<HttpResponseOk<T>>; } -type YesOrNo = "yes" | "no"; - /** * * @param root the request is intended to the base URL and no the instance URL @@ -171,91 +181,91 @@ type YesOrNo = "yes" | "no"; */ //TODO: Add token export function useBackendBaseRequest(): useBackendBaseRequestType { - const {url: backend} = useBackendContext(); - const {request: requestHandler} = useApiContext(); - //const { token } = useBackendTokenContext(); - const token = "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"; - - - const request = useCallback( - function requestImpl<T>( - endpoint: string, - //todo: remove - options: RequestOptions = {}, - ): Promise<HttpResponseOk<T>> { - return requestHandler<T>(backend, endpoint, {...options, token}).then(res => { - return res; - }).catch(err => { - throw err; - }); - }, - [backend], - ); + const { url: backend } = useBackendContext(); + const { request: requestHandler } = useApiContext(); + //const { token } = useBackendTokenContext(); + const token = + "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"; + + const request = useCallback( + function requestImpl<T>( + endpoint: string, + //todo: remove + options: RequestOptions = {}, + ): Promise<HttpResponseOk<T>> { + return requestHandler<T>(backend, endpoint, { ...options, token }) + .then((res) => { + return res; + }) + .catch((err) => { + throw err; + }); + }, + [backend], + ); - return {request}; + return { request }; } - export function useBackendRequest(): useBackendInstanceRequestType { - const {url: rootBackendUrl} = useBackendContext(); - // const {id} = useInstanceContext(); - const {request: requestHandler} = useApiContext(); - - //TODO: check - const baseUrl = "http://localhost:8083/"; - const token = "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"; - - - - - const request = useCallback( - function requestImpl<T>( - endpoint: string, - options: RequestOptions = {}, - ): Promise<HttpResponseOk<T>> { - return requestHandler<T>(baseUrl, endpoint, {...options, token}); - }, - [baseUrl], - ); - - const multiFetcher = useCallback( - function multiFetcherImpl<T>( - params: string[], - options: RequestOptions = {}, - ): Promise<HttpResponseOk<T>[]> { - return Promise.all( - params.map((endpoint) => - requestHandler<T>(baseUrl, endpoint, {...options, token}), - ), - ); - }, - [baseUrl], - ); - - const fetcher = useCallback( - function fetcherImpl<T>(endpoint: string): Promise<HttpResponseOk<T>> { - return requestHandler<T>(baseUrl, endpoint, {token}); - }, - [baseUrl], - ); - - const depositConfirmationFetcher = useCallback( - function orderFetcherImpl<T>( - args: [endpoint: string, - ], - ): Promise<HttpResponseOk<T>> { - const [endpoint] = args; - const params: any = {"token": "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"}; - return requestHandler<T>(baseUrl, endpoint, {params, token}); - }, - [baseUrl], - ); - - - return { - request, - fetcher, - depositConfirmationFetcher, - multiFetcher - }; -} -\ No newline at end of file + const { url: rootBackendUrl } = useBackendContext(); + // const {id} = useInstanceContext(); + const { request: requestHandler } = useApiContext(); + + //TODO: check + const baseUrl = "http://localhost:8083/"; + const token = + "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0"; + + const request = useCallback( + function requestImpl<T>( + endpoint: string, + options: RequestOptions = {}, + ): Promise<HttpResponseOk<T>> { + return requestHandler<T>(baseUrl, endpoint, { ...options, token }); + }, + [baseUrl], + ); + + const multiFetcher = useCallback( + function multiFetcherImpl<T>( + params: string[], + options: RequestOptions = {}, + ): Promise<HttpResponseOk<T>[]> { + return Promise.all( + params.map((endpoint) => + requestHandler<T>(baseUrl, endpoint, { ...options, token }), + ), + ); + }, + [baseUrl], + ); + + const fetcher = useCallback( + function fetcherImpl<T>(endpoint: string): Promise<HttpResponseOk<T>> { + return requestHandler<T>(baseUrl, endpoint, { token }); + }, + [baseUrl], + ); + + const depositConfirmationFetcher = useCallback( + function orderFetcherImpl<T>( + args: [endpoint: string], + ): Promise<HttpResponseOk<T>> { + const [endpoint] = args; + const params: any = { + token: + "D4CST1Z6AHN3RT03M0T9NSTF2QGHTB5ZD2D3RYZB4HAWG8SX0JEFWBXCKXZHMB7Y3Z7KVFW0B3XPXD5BHCFP8EB0R6CNH2KAWDWVET0", + }; + return requestHandler<T>(baseUrl, endpoint, { params, token }); + }, + [baseUrl], + ); + + return { + request, + fetcher, + depositConfirmationFetcher, + multiFetcher, + }; +} diff --git a/packages/auditor-backoffice-ui/src/hooks/index.ts b/packages/auditor-backoffice-ui/src/hooks/index.ts @@ -17,63 +17,63 @@ import { StateUpdater, useState } from "preact/hooks"; import { ValueOrFunction } from "../utils/types.js"; -export function useBackendURL( - url?: string, -): [string, StateUpdater<string>] { - const [value, setter] = useSimpleLocalStorage( - "auditor-base-url", - url || calculateRootPath(), - ); +export function useBackendURL(url?: string): [string, StateUpdater<string>] { + const [value, setter] = useSimpleLocalStorage( + "auditor-base-url", + url || calculateRootPath(), + ); - const checkedSetter = (v: ValueOrFunction<string>) => { - return setter((p) => (v instanceof Function ? v(p ?? "") : v).replace(/\/$/, "")); - }; + const checkedSetter = (v: ValueOrFunction<string>) => { + return setter((p) => + (v instanceof Function ? v(p ?? "") : v).replace(/\/$/, ""), + ); + }; - return [value!, checkedSetter]; + return [value!, checkedSetter]; } const calculateRootPath = () => { - const rootPath = - typeof window !== undefined - ? window.location.origin + window.location.pathname - : "/"; + const rootPath = + typeof window !== undefined + ? window.location.origin + window.location.pathname + : "/"; - /** - * By default, auditor backend serves the html content - * from the /webui root. This should cover most of the - * cases and the rootPath will be the auditor backend - * URL where the instances are - */ - return rootPath.replace("/spa/", ""); + /** + * By default, auditor backend serves the html content + * from the /webui root. This should cover most of the + * cases and the rootPath will be the auditor backend + * URL where the instances are + */ + return rootPath.replace("/spa/", ""); }; export function useSimpleLocalStorage( - key: string, - initialValue?: string, + key: string, + initialValue?: string, ): [string | undefined, StateUpdater<string | undefined>] { - const [storedValue, setStoredValue] = useState<string | undefined>( - (): string | undefined => { - return typeof window !== "undefined" - ? window.localStorage.getItem(key) || initialValue - : initialValue; - }, - ); + const [storedValue, setStoredValue] = useState<string | undefined>( + (): string | undefined => { + return typeof window !== "undefined" + ? window.localStorage.getItem(key) || initialValue + : initialValue; + }, + ); - const setValue = ( - value?: string | ((val?: string) => string | undefined), - ) => { - setStoredValue((p) => { - const toStore = value instanceof Function ? value(p) : value; - if (typeof window !== "undefined") { - if (!toStore) { - window.localStorage.removeItem(key); - } else { - window.localStorage.setItem(key, toStore); - } - } - return toStore; - }); - }; + const setValue = ( + value?: string | ((val?: string) => string | undefined), + ) => { + setStoredValue((p) => { + const toStore = value instanceof Function ? value(p) : value; + if (typeof window !== "undefined") { + if (!toStore) { + window.localStorage.removeItem(key); + } else { + window.localStorage.setItem(key, toStore); + } + } + return toStore; + }); + }; - return [storedValue, setValue]; -} -\ No newline at end of file + return [storedValue, setValue]; +} diff --git a/packages/auditor-backoffice-ui/src/index.tsx b/packages/auditor-backoffice-ui/src/index.tsx @@ -21,4 +21,4 @@ import "./scss/main.scss"; const app = document.getElementById("app"); -render(<Application />, app as any); -\ No newline at end of file +render(<Application />, app as any);