diff options
Diffstat (limited to 'packages/auditor-backoffice-ui/src/ApplicationReadyRoutes.tsx')
-rw-r--r-- | packages/auditor-backoffice-ui/src/ApplicationReadyRoutes.tsx | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/packages/auditor-backoffice-ui/src/ApplicationReadyRoutes.tsx b/packages/auditor-backoffice-ui/src/ApplicationReadyRoutes.tsx new file mode 100644 index 000000000..414eee39d --- /dev/null +++ b/packages/auditor-backoffice-ui/src/ApplicationReadyRoutes.tsx @@ -0,0 +1,175 @@ +/* + This file is part of GNU Taler + (C) 2021-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 <http://www.gnu.org/licenses/> + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ +import { HttpStatusCode } from "@gnu-taler/taler-util"; +import { ErrorType, useTranslationContext } from "@gnu-taler/web-util/browser"; +import { createHashHistory } from "history"; +import { Fragment, VNode, h } from "preact"; +import { Route, Router, route } from "preact-router"; +import { useState } from "preact/hooks"; +import { InstanceRoutes } from "./InstanceRoutes.js"; +import { + NotConnectedAppMenu, + NotYetReadyAppMenu, + NotificationCard, +} from "./components/menu/index.js"; +import { useBackendContext } from "./context/backend.js"; +import { LoginToken } from "./declaration.js"; +import { useBackendInstancesTestForAdmin } from "./hooks/backend.js"; +import { LoginPage } from "./paths/login/index.js"; +import { Settings } from "./paths/settings/index.js"; +import { INSTANCE_ID_LOOKUP } from "./utils/constants.js"; + +/** + * Check if admin against /management/instances + * @returns + */ +export function ApplicationReadyRoutes(): VNode { + const { i18n } = useTranslationContext(); + const [unauthorized, setUnauthorized] = useState(false) + const { + url: backendURL, + updateToken, + alreadyTriedLogin, + } = useBackendContext(); + + function updateLoginStatus(token: LoginToken | undefined) { + updateToken(token) + setUnauthorized(false) + } + + const result = useBackendInstancesTestForAdmin(); + + const clearTokenAndGoToRoot = () => { + route("/"); + }; + const [showSettings, setShowSettings] = useState(false) + const unauthorizedAdmin = !result.loading + && !result.ok + && result.type === ErrorType.CLIENT + && result.status === HttpStatusCode.Unauthorized; + + if (!alreadyTriedLogin && !result.ok) { + return ( + <Fragment> + <NotConnectedAppMenu title="Welcome!" /> + <LoginPage onConfirm={updateToken} /> + </Fragment> + ); + } + + if (showSettings) { + return <Fragment> + <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="UI Settings" onLogout={clearTokenAndGoToRoot} isPasswordOk={false} /> + <Settings onClose={() => setShowSettings(false)} /> + </Fragment> + } + + if (result.loading) { + return <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Loading..." isPasswordOk={false} />; + } + + let admin = result.ok || unauthorizedAdmin; + let instanceNameByBackendURL: string | undefined; + + if (!admin) { + // * the testing against admin endpoint failed and it's not + // an authorization problem + // * merchant backend will return this SPA under the main + // endpoint or /instance/<id> endpoint + // => trying to infer the instance id + const path = new URL(backendURL).pathname; + const match = INSTANCE_ID_LOOKUP.exec(path); + if (!match || !match[1]) { + // this should be rare because + // query to /config is ok but the URL + // does not match our pattern + return ( + <Fragment> + <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Error" onLogout={clearTokenAndGoToRoot} isPasswordOk={false} /> + <NotificationCard + notification={{ + message: i18n.str`Couldn't access the server.`, + description: i18n.str`Could not infer instance id from url ${backendURL}`, + type: "ERROR", + }} + /> + {/* <ConnectionPage onConfirm={changeBackend} /> */} + </Fragment> + ); + } + + instanceNameByBackendURL = match[1]; + } + + if (unauthorized || unauthorizedAdmin) { + return <Fragment> + <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Login" onLogout={clearTokenAndGoToRoot} isPasswordOk={false} /> + <NotificationCard + notification={{ + message: i18n.str`Access denied`, + description: i18n.str`Check your token is valid`, + type: "ERROR", + }} + /> + <LoginPage onConfirm={updateLoginStatus} /> + </Fragment> + } + + const history = createHashHistory(); + return ( + <Router history={history}> + <Route + default + component={DefaultMainRoute} + admin={admin} + onUnauthorized={() => setUnauthorized(true)} + onLoginPass={() => { + setUnauthorized(false) + }} + instanceNameByBackendURL={instanceNameByBackendURL} + /> + </Router> + ); +} + +function DefaultMainRoute({ + instance, + admin, + onUnauthorized, + onLoginPass, + instanceNameByBackendURL, + url, //from preact-router +}: any): VNode { + const [instanceName, setInstanceName] = useState( + instanceNameByBackendURL || instance || "default", + ); + + return ( + <InstanceRoutes + admin={admin} + path={url} + onUnauthorized={onUnauthorized} + onLoginPass={onLoginPass} + id={instanceName} + setInstanceName={setInstanceName} + /> + ); +} |