aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/merchant-backoffice-ui/src/AdminRoutes.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/Routing.tsx6
-rw-r--r--packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx27
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/index.ts150
-rw-r--r--packages/merchant-backoffice-ui/src/paths/login/index.tsx10
5 files changed, 23 insertions, 172 deletions
diff --git a/packages/merchant-backoffice-ui/src/AdminRoutes.tsx b/packages/merchant-backoffice-ui/src/AdminRoutes.tsx
index a35c4160e..b186f1408 100644
--- a/packages/merchant-backoffice-ui/src/AdminRoutes.tsx
+++ b/packages/merchant-backoffice-ui/src/AdminRoutes.tsx
@@ -46,8 +46,6 @@ export function AdminRoutes(): VNode {
route(InstancePaths.bank_list);
}}
- // onError={(error: any) => {
- // }}
/>
</Router>
);
diff --git a/packages/merchant-backoffice-ui/src/Routing.tsx b/packages/merchant-backoffice-ui/src/Routing.tsx
index 172214d0b..50a91c060 100644
--- a/packages/merchant-backoffice-ui/src/Routing.tsx
+++ b/packages/merchant-backoffice-ui/src/Routing.tsx
@@ -39,7 +39,7 @@ import { MerchantBackend } from "./declaration.js";
import { useInstanceBankAccounts } from "./hooks/bank.js";
import { useInstanceKYCDetails } from "./hooks/instance.js";
import { usePreference } from "./hooks/preference.js";
-import { useSessionState } from "./hooks/session.js";
+import { DEFAULT_ADMIN_USERNAME, useSessionState } from "./hooks/session.js";
import InstanceCreatePage from "./paths/admin/create/index.js";
import InstanceListPage from "./paths/admin/list/index.js";
import BankAccountCreatePage from "./paths/instance/accounts/create/index.js";
@@ -200,7 +200,7 @@ export function Routing(_p: Props): VNode {
function IfAdminCreateDefaultOr<T>(Next: FunctionComponent<unknown>) {
return function IfAdminCreateDefaultOrImpl(props?: T) {
- if (state.isAdmin && state.instance === "default") {
+ if (state.isAdmin && state.instance === DEFAULT_ADMIN_USERNAME) {
return (
<Fragment>
<NotificationCard
@@ -211,7 +211,7 @@ export function Routing(_p: Props): VNode {
}}
/>
<InstanceCreatePage
- forceId="default"
+ forceId={DEFAULT_ADMIN_USERNAME}
onConfirm={() => {
route(InstancePaths.bank_list);
}}
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index 0a15f122a..a9b9618bb 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -19,32 +19,32 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
-import { useTranslationContext } from "@gnu-taler/web-util/browser";
+import { useMerchantApiContext, useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
import { useConfigContext } from "../../context/config.js";
import { useInstanceKYCDetails } from "../../hooks/instance.js";
import { LangSelector } from "./LangSelector.js";
import { useSessionState } from "../../hooks/session.js";
-const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
+// const GIT_HASH = typeof __GIT_HASH__ !== "undefined" ? __GIT_HASH__ : undefined;
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
interface Props {
mobile?: boolean;
- mimic?: boolean;
}
export function Sidebar({
mobile,
- mimic,
}: Props): VNode {
const config = useConfigContext();
// const { url: backendURL } = useBackendContext()
const { i18n } = useTranslationContext();
const kycStatus = useInstanceKYCDetails();
const needKYC = kycStatus.ok && kycStatus.data.type === "redirect";
- const { state } = useSessionState();
-
+ const { state, logOut } = useSessionState();
+ const { url } = useMerchantApiContext();
+ const isLoggedIn = state.status === "loggedIn" || state.status === "impersonate"
+ const hasToken = isLoggedIn && state.token !== undefined
return (
<aside class="aside is-placed-left is-expanded" style={{ overflowY: "scroll" }}>
{mobile && (
@@ -71,7 +71,7 @@ export function Sidebar({
</div>
</div>
<div class="menu is-menu-main">
- {instance ? (
+ {isLoggedIn ? (
<Fragment>
<ul class="menu-list">
<li>
@@ -206,7 +206,7 @@ export function Sidebar({
<i class="mdi mdi-web" />
</span>
<span class="menu-item-label">
- {new URL(backendURL).hostname}
+ {url.hostname}
</span>
</div>
</li>
@@ -216,11 +216,11 @@ export function Sidebar({
ID
</span>
<span class="menu-item-label">
- {!instance ? "default" : instance}
+ {state.instance}
</span>
</div>
</li>
- {admin && !mimic && (
+ {state.isAdmin && state.status !== "impersonate" && (
<Fragment>
<p class="menu-label">
<i18n.Translate>Instances</i18n.Translate>
@@ -247,11 +247,14 @@ export function Sidebar({
</li>
</Fragment>
)}
- {isPasswordOk ?
+ {hasToken ?
<li>
<a
class="has-icon is-state-info is-hoverable"
- onClick={(): void => onLogout()}
+ onClick={(e): void => {
+ logOut()
+ e.preventDefault();
+ }}
>
<span class="icon">
<i class="mdi mdi-logout default" />
diff --git a/packages/merchant-backoffice-ui/src/hooks/index.ts b/packages/merchant-backoffice-ui/src/hooks/index.ts
deleted file mode 100644
index cb58cf066..000000000
--- a/packages/merchant-backoffice-ui/src/hooks/index.ts
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- 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 { buildCodecForObject, codecForMap, codecForString, codecForTimestamp } from "@gnu-taler/taler-util";
-import { buildStorageKey, useLocalStorage } from "@gnu-taler/web-util/browser";
-import { StateUpdater, useState } from "preact/hooks";
-import { LoginToken } from "../declaration.js";
-import { ValueOrFunction } from "../utils/types.js";
-
-const calculateRootPath = () => {
- const rootPath =
- typeof window !== undefined
- ? window.location.origin + window.location.pathname
- : "/";
-
- /**
- * By default, merchant backend serves the html content
- * from the /webui root. This should cover most of the
- * cases and the rootPath will be the merchant backend
- * URL where the instances are
- */
- return rootPath.replace("/webui/", "");
-};
-
-const loginTokenCodec = buildCodecForObject<LoginToken>()
- .property("token", codecForString())
- .property("expiration", codecForTimestamp)
- .build("loginToken")
-const TOKENS_KEY = buildStorageKey("merchant-token", codecForMap(loginTokenCodec));
-
-
-function useBackendURL(
- url?: string,
-): [string, StateUpdater<string>] {
- const [value, setter] = useSimpleLocalStorage(
- "merchant-base-url",
- url || calculateRootPath(),
- );
-
- const checkedSetter = (v: ValueOrFunction<string>) => {
- return setter((p) => (v instanceof Function ? v(p ?? "") : v).replace(/\/$/, ""));
- };
-
- return [value!, checkedSetter];
-}
-
-function useBackendDefaultToken(
-): [LoginToken | undefined, ((d: LoginToken | undefined) => void)] {
- const { update: setToken, value: tokenMap, reset } = useLocalStorage(TOKENS_KEY, {})
-
- // const tokenOfDefaultInstance = tokenMap["default"]
- // const clearCache = useMatchMutate()
- // useEffect(() => {
- // clearCache()
- // }, [tokenOfDefaultInstance])
-
- function updateToken(
- value: (LoginToken | undefined)
- ): void {
- if (value === undefined) {
- reset()
- } else {
- const res = { ...tokenMap, "default": value }
- setToken(res)
- }
- }
- return [tokenMap["default"], updateToken];
-}
-
-function useBackendInstanceToken(
- id: string,
-): [LoginToken | undefined, ((d: LoginToken | undefined) => void)] {
- const { update: setToken, value: tokenMap, reset } = useLocalStorage(TOKENS_KEY, {})
- const [defaultToken, defaultSetToken] = useBackendDefaultToken();
-
- // instance named 'default' use the default token
- if (id === "default") {
- return [defaultToken, defaultSetToken];
- }
- function updateToken(
- value: (LoginToken | undefined)
- ): void {
- if (value === undefined) {
- reset()
- } else {
- const res = { ...tokenMap, [id]: value }
- setToken(res)
- }
- }
-
- return [tokenMap[id], updateToken];
-}
-
-function useLang(initial?: string): [string, StateUpdater<string>] {
- const browserLang =
- typeof window !== "undefined"
- ? navigator.language || (navigator as any).userLanguage
- : undefined;
- const defaultLang = (browserLang || initial || "en").substring(0, 2);
- return useSimpleLocalStorage("lang-preference", defaultLang) as [string, StateUpdater<string>];
-}
-
-function useSimpleLocalStorage(
- 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 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];
-}
diff --git a/packages/merchant-backoffice-ui/src/paths/login/index.tsx b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
index d155dd255..d94b7e506 100644
--- a/packages/merchant-backoffice-ui/src/paths/login/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/login/index.tsx
@@ -19,6 +19,7 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
+import { HttpStatusCode } from "@gnu-taler/taler-util";
import {
useMerchantApiContext,
useTranslationContext,
@@ -27,9 +28,8 @@ import { ComponentChildren, Fragment, VNode, h } from "preact";
import { useState } from "preact/hooks";
import { NotificationCard } from "../../components/menu/index.js";
import { AccessToken } from "../../declaration.js";
-import { useSessionState } from "../../hooks/session.js";
+import { DEFAULT_ADMIN_USERNAME, useSessionState } from "../../hooks/session.js";
import { Notification } from "../../utils/types.js";
-import { HttpStatusCode } from "@gnu-taler/taler-util";
interface Props {
}
@@ -41,7 +41,7 @@ function normalizeToken(r: string): AccessToken {
export function LoginPage(_p: Props): VNode {
const [token, setToken] = useState("");
const [notif, setNotif] = useState<Notification | undefined>(undefined);
- const { logIn } = useSessionState();
+ const { state, logIn } = useSessionState();
const { lib } = useMerchantApiContext();
const { i18n } = useTranslationContext();
@@ -57,7 +57,7 @@ export function LoginPage(_p: Props): VNode {
});
if (result.type === "ok") {
const { access_token } = result.body;
- logIn({ token: access_token });
+ logIn({ instance: state.instance, token: access_token });
return;
} else {
switch(result.case) {
@@ -79,7 +79,7 @@ export function LoginPage(_p: Props): VNode {
}
}
- if (admin && id !== "default") {
+ if (state.isAdmin && state.instance !== DEFAULT_ADMIN_USERNAME) {
//admin trying to access another instance
return (
<div class="columns is-centered" style={{ margin: "auto" }}>