summaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2024-03-22 09:03:27 -0300
committerSebastian <sebasjm@gmail.com>2024-03-26 16:57:57 -0300
commita427958be6d32ce8d907c885d577c8a05ef450a0 (patch)
tree90da92c072ccf01a6d9618cd4f78ae25f50929e6 /packages
parent8aa9ce6d20b41b7eb9b438a56ccd34cb0da35f80 (diff)
downloadwallet-core-a427958be6d32ce8d907c885d577c8a05ef450a0.tar.gz
wallet-core-a427958be6d32ce8d907c885d577c8a05ef450a0.tar.bz2
wallet-core-a427958be6d32ce8d907c885d577c8a05ef450a0.zip
wip
Diffstat (limited to 'packages')
-rw-r--r--packages/merchant-backoffice-ui/src/AdminRoutes.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/Application.tsx2
-rw-r--r--packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx174
-rw-r--r--packages/merchant-backoffice-ui/src/Routing.tsx (renamed from packages/merchant-backoffice-ui/src/Rounting.tsx)74
-rw-r--r--packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx19
-rw-r--r--packages/merchant-backoffice-ui/src/components/menu/index.tsx93
-rw-r--r--packages/merchant-backoffice-ui/src/hooks/session.ts6
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx10
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx3
-rw-r--r--packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx3
-rw-r--r--packages/taler-util/src/taler-types.ts1
11 files changed, 71 insertions, 316 deletions
diff --git a/packages/merchant-backoffice-ui/src/AdminRoutes.tsx b/packages/merchant-backoffice-ui/src/AdminRoutes.tsx
index 36c9f39ea..a35c4160e 100644
--- a/packages/merchant-backoffice-ui/src/AdminRoutes.tsx
+++ b/packages/merchant-backoffice-ui/src/AdminRoutes.tsx
@@ -17,7 +17,7 @@ import { h, VNode } from "preact";
import { Router, route, Route } from "preact-router";
import InstanceCreatePage from "./paths/admin/create/index.js";
import InstanceListPage from "./paths/admin/list/index.js";
-import { InstancePaths } from "./Rounting.js";
+import { InstancePaths } from "./Routing.js";
export enum AdminPaths {
list_instances = "/instances",
diff --git a/packages/merchant-backoffice-ui/src/Application.tsx b/packages/merchant-backoffice-ui/src/Application.tsx
index 9e6a6179f..d752d612d 100644
--- a/packages/merchant-backoffice-ui/src/Application.tsx
+++ b/packages/merchant-backoffice-ui/src/Application.tsx
@@ -26,7 +26,7 @@ import {
TalerWalletIntegrationBrowserProvider,
TranslationProvider
} from "@gnu-taler/web-util/browser";
-import { Fragment, VNode, h } from "preact";
+import { VNode, h } from "preact";
import { useEffect, useState } from "preact/hooks";
import { SWRConfig } from "swr";
import { Routing } from "./Routing.js";
diff --git a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx
deleted file mode 100644
index 7cbb47f68..000000000
--- a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx
+++ /dev/null
@@ -1,174 +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 { 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 "./Rounting.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}
- />
- );
-}
diff --git a/packages/merchant-backoffice-ui/src/Rounting.tsx b/packages/merchant-backoffice-ui/src/Routing.tsx
index a10310aa8..172214d0b 100644
--- a/packages/merchant-backoffice-ui/src/Rounting.tsx
+++ b/packages/merchant-backoffice-ui/src/Routing.tsx
@@ -26,21 +26,20 @@ import {
urlPattern,
useTranslationContext,
} from "@gnu-taler/web-util/browser";
-import { format } from "date-fns";
import { Fragment, FunctionComponent, VNode, h } from "preact";
import { Route, Router, route } from "preact-router";
-import { useEffect, useErrorBoundary, useMemo, useState } from "preact/hooks";
+import { useEffect, useErrorBoundary, useState } from "preact/hooks";
import { Loading } from "./components/exception/loading.js";
import {
Menu,
NotConnectedAppMenu,
NotificationCard,
} from "./components/menu/index.js";
-import { InstanceContextProvider } from "./context/instance.js";
-import { LoginToken, MerchantBackend } from "./declaration.js";
+import { MerchantBackend } from "./declaration.js";
import { useInstanceBankAccounts } from "./hooks/bank.js";
import { useInstanceKYCDetails } from "./hooks/instance.js";
-import { dateFormatForSettings, usePreference } from "./hooks/preference.js";
+import { usePreference } from "./hooks/preference.js";
+import { 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";
@@ -75,7 +74,6 @@ import { LoginPage } from "./paths/login/index.js";
import NotFoundPage from "./paths/notfound/index.js";
import { Settings } from "./paths/settings/index.js";
import { Notification } from "./utils/types.js";
-import { useSessionState } from "./hooks/session.js";
export enum InstancePaths {
error = "/error",
@@ -143,8 +141,6 @@ export const publicPages = {
export function Routing(_p: Props): VNode {
const { i18n } = useTranslationContext();
const { state } = useSessionState();
- const admin = state.isAdmin;
- const id = state.instance;
type GlobalNotifState =
| (Notification & { to: string | undefined })
@@ -152,24 +148,12 @@ export function Routing(_p: Props): VNode {
const [globalNotification, setGlobalNotification] =
useState<GlobalNotifState>(undefined);
- // const changeToken = (token?: LoginToken) => {
- // if (admin) {
- // updateToken(token);
- // } else {
- // updateDefaultToken(token);
- // }
- // onLoginPass();
- // };
-
const [error] = useErrorBoundary();
- // const value = useMemo(
- // () => ({ id, token, admin, changeToken }),
- // [id, token, admin],
- // );
-
const instance = useInstanceBankAccounts();
const accounts = !instance.ok ? undefined : instance.data.accounts;
+ const shouldWarnAboutMissingBankAccounts = !state.isAdmin && accounts !== undefined && accounts.length < 1
+ const shouldLogin = state.status === "loggedOut" || state.status === "expired";
function ServerErrorRedirectTo(to: InstancePaths | AdminPaths) {
return function ServerErrorRedirectToImpl(
@@ -216,7 +200,7 @@ export function Routing(_p: Props): VNode {
function IfAdminCreateDefaultOr<T>(Next: FunctionComponent<unknown>) {
return function IfAdminCreateDefaultOrImpl(props?: T) {
- if (admin && id === "default") {
+ if (state.isAdmin && state.instance === "default") {
return (
<Fragment>
<NotificationCard
@@ -242,14 +226,7 @@ export function Routing(_p: Props): VNode {
};
}
- const clearTokenAndGoToRoot = () => {
- route("/");
- // clear all tokens
- updateToken(undefined);
- updateDefaultToken(undefined);
- };
-
- if (state.status === "loggedOut" || state.status === "expired") {
+ if (shouldLogin) {
return (
<Fragment>
<NotConnectedAppMenu title="Welcome!" />
@@ -258,20 +235,10 @@ export function Routing(_p: Props): VNode {
);
}
- if (accounts !== undefined && !admin && accounts.length < 1) {
+ if (shouldWarnAboutMissingBankAccounts) {
return (
<Fragment>
- <Menu
- instance={id}
- admin={admin}
- onShowSettings={() => {
- route(InstancePaths.interface);
- }}
- path={path}
- onLogout={clearTokenAndGoToRoot}
- setInstanceName={setInstanceName}
- isPasswordOk={defaultToken !== undefined}
- />
+ <Menu />
<NotificationCard
notification={{
type: "INFO",
@@ -286,17 +253,7 @@ export function Routing(_p: Props): VNode {
return (
<Fragment>
- <Menu
- instance={id}
- admin={admin}
- onShowSettings={() => {
- route(InstancePaths.interface);
- }}
- path={path}
- onLogout={clearTokenAndGoToRoot}
- setInstanceName={setInstanceName}
- isPasswordOk={defaultToken !== undefined}
- />
+ <Menu />
<KycBanner />
<NotificationCard notification={globalNotification} />
{error && (
@@ -330,7 +287,7 @@ export function Routing(_p: Props): VNode {
{/**
* Admin pages
*/}
- {admin && (
+ {state.isAdmin && (
<Route
path={AdminPaths.list_instances}
component={InstanceListPage}
@@ -340,12 +297,11 @@ export function Routing(_p: Props): VNode {
onUpdate={(id: string): void => {
route(`/instance/${id}/update`);
}}
- setInstanceName={setInstanceName}
onUnauthorized={LoginPageAccessDenied}
onLoadError={ServerErrorRedirectTo(InstancePaths.error)}
/>
)}
- {admin && (
+ {state.isAdmin && (
<Route
path={AdminPaths.new_instance}
component={InstanceCreatePage}
@@ -355,7 +311,7 @@ export function Routing(_p: Props): VNode {
}}
/>
)}
- {admin && (
+ {state.isAdmin && (
<Route
path={AdminPaths.update_instance}
component={AdminInstanceUpdatePage}
@@ -774,7 +730,7 @@ function KycBanner(): VNode {
const oneDay = { d_ms: 1000 * 60 * 60 * 24 };
const tomorrow = AbsoluteTime.addDuration(now, oneDay);
-
+
return (
<NotificationCard
notification={{
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index 92551cc4c..0a15f122a 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -21,38 +21,29 @@
import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { Fragment, h, VNode } from "preact";
-import { useBackendContext } from "../../context/backend.js";
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 VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
interface Props {
- onLogout: () => void;
- onShowSettings: () => void;
mobile?: boolean;
- instance: string;
- admin?: boolean;
mimic?: boolean;
- isPasswordOk: boolean;
}
export function Sidebar({
mobile,
- instance,
- onShowSettings,
- onLogout,
- admin,
mimic,
- isPasswordOk
}: Props): VNode {
const config = useConfigContext();
- const { url: backendURL } = useBackendContext()
+ // const { url: backendURL } = useBackendContext()
const { i18n } = useTranslationContext();
const kycStatus = useInstanceKYCDetails();
const needKYC = kycStatus.ok && kycStatus.data.type === "redirect";
+ const { state } = useSessionState();
return (
<aside class="aside is-placed-left is-expanded" style={{ overflowY: "scroll" }}>
@@ -197,7 +188,9 @@ export function Sidebar({
<ul class="menu-list">
<li>
<a class="has-icon is-state-info is-hoverable"
- onClick={(): void => onShowSettings()}
+ onClick={(e): void => {
+ e.preventDefault()
+ }}
>
<span class="icon">
<i class="mdi mdi-newspaper" />
diff --git a/packages/merchant-backoffice-ui/src/components/menu/index.tsx b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
index 57d401ffa..fa2de563e 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/index.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
@@ -17,10 +17,12 @@
import { ComponentChildren, Fragment, h, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { AdminPaths } from "../../AdminRoutes.js";
-import { InstancePaths } from "../../Rounting.js";
+import { InstancePaths } from "../../Routing.js";
import { Notification } from "../../utils/types.js";
import { NavigationBar } from "./NavigationBar.js";
import { Sidebar } from "./SideBar.js";
+import { useSessionState } from "../../hooks/session.js";
+import { useNavigationContext } from "@gnu-taler/web-util/browser";
function getInstanceTitle(path: string, id: string): string {
switch (path) {
@@ -77,13 +79,7 @@ function getAdminTitle(path: string, instance: string) {
return getInstanceTitle(path, instance);
}
-interface MenuProps {
- title?: string;
- instance: string;
- admin?: boolean;
- onLogout?: () => void;
- onShowSettings: () => void;
-}
+interface MenuProps {}
function WithTitle({
title,
@@ -98,25 +94,19 @@ function WithTitle({
return <Fragment>{children}</Fragment>;
}
-export function Menu({
- onLogout,
- onShowSettings,
- title,
- instance,
- path,
- admin,
- setInstanceName,
- isPasswordOk
-}: MenuProps): VNode {
+export function Menu(_p: MenuProps): VNode {
const [mobileOpen, setMobileOpen] = useState(false);
- const titleWithSubtitle = title
- ? title
- : !admin
- ? getInstanceTitle(path, instance)
- : getAdminTitle(path, instance);
- const adminInstance = instance === "default";
- const mimic = admin && !adminInstance;
+ const { state, logIn } = useSessionState();
+ const { path } = useNavigationContext();
+
+ const titleWithSubtitle = !state.isAdmin
+ ? getInstanceTitle(path, state.instance)
+ : getAdminTitle(path, state.instance);
+
+ const isLoggedIn =
+ state.status === "loggedIn" || state.status === "impersonate";
+
return (
<WithTitle title={titleWithSubtitle}>
<div
@@ -128,32 +118,32 @@ export function Menu({
title={titleWithSubtitle}
/>
- {onLogout && (
- <Sidebar
- onShowSettings={onShowSettings}
- onLogout={onLogout}
- admin={admin}
- mimic={mimic}
- instance={instance}
- mobile={mobileOpen}
- isPasswordOk={isPasswordOk}
- />
+ {isLoggedIn && (
+ <Sidebar mobile={mobileOpen} mimic={state.status === "impersonate"} />
)}
- {mimic && (
- <nav class="level" style={{
- zIndex: 100,
- position: "fixed",
- width: "50%",
- marginLeft: "20%"
- }}>
+ {state.status === "impersonate" && (
+ <nav
+ class="level"
+ style={{
+ zIndex: 100,
+ position: "fixed",
+ width: "50%",
+ marginLeft: "20%",
+ }}
+ >
<div class="level-item has-text-centered has-background-warning">
<p class="is-size-5">
- You are viewing the instance <b>&quot;{instance}&quot;</b>.{" "}
+ You are viewing the instance <b>&quot;{state.instance}&quot;</b>
+ .{" "}
<a
href="#/instances"
onClick={(e) => {
- setInstanceName("default");
+ logIn({
+ instance: state.originalInstance,
+ token: state.originalToken,
+ });
+ e.preventDefault();
}}
>
go back
@@ -235,17 +225,16 @@ export function NotConnectedAppMenu({
);
}
-export function NotYetReadyAppMenu({
- onLogout,
- onShowSettings,
- title,
- isPasswordOk
-}: NotYetReadyAppMenuProps): VNode {
+export function NotYetReadyAppMenu({ title }: NotYetReadyAppMenuProps): VNode {
const [mobileOpen, setMobileOpen] = useState(false);
+ const { state } = useSessionState();
useEffect(() => {
document.title = `Taler Backoffice: ${title}`;
}, [title]);
+
+ const isLoggedIn =
+ state.status === "loggedIn" || state.status === "impersonate";
return (
<div
@@ -256,9 +245,7 @@ export function NotYetReadyAppMenu({
onMobileMenu={() => setMobileOpen(!mobileOpen)}
title={title}
/>
- {onLogout && (
- <Sidebar onShowSettings={onShowSettings} onLogout={onLogout} instance="" mobile={mobileOpen} isPasswordOk={isPasswordOk} />
- )}
+ {isLoggedIn && <Sidebar mobile={mobileOpen} />}
</div>
);
}
diff --git a/packages/merchant-backoffice-ui/src/hooks/session.ts b/packages/merchant-backoffice-ui/src/hooks/session.ts
index 7b06ea290..8bf075e94 100644
--- a/packages/merchant-backoffice-ui/src/hooks/session.ts
+++ b/packages/merchant-backoffice-ui/src/hooks/session.ts
@@ -111,8 +111,8 @@ export interface SessionStateHandler {
state: SessionState;
logOut(): void;
expired(): void;
- logIn(info: { token: AccessToken }): void;
- impersonate(info: { instance: string; token: AccessToken }): void;
+ logIn(info: { instance: string; token?: AccessToken }): void;
+ impersonate(info: { instance: string; token?: AccessToken }): void;
}
const SESSION_STATE_KEY = buildStorageKey("merchant-session", codecForSessionState());
@@ -170,7 +170,7 @@ export function useSessionState(): SessionStateHandler {
// admin is defined by the username
const nextState: SessionState = {
status: "loggedIn",
- instance: state.instance,
+ instance: info.instance,
token: info.token,
isAdmin: state.instance === DEFAULT_ADMIN_USERNAME,
};
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
index 0011ae1a9..711a5a4f0 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/TableActive.tsx
@@ -23,6 +23,7 @@ import { useTranslationContext } from "@gnu-taler/web-util/browser";
import { h, VNode } from "preact";
import { StateUpdater, useEffect, useState } from "preact/hooks";
import { MerchantBackend } from "../../../declaration.js";
+import { useSessionState } from "../../../hooks/session.js";
interface Props {
instances: MerchantBackend.Instances.Instance[];
@@ -31,7 +32,6 @@ interface Props {
onPurge: (id: MerchantBackend.Instances.Instance) => void;
onCreate: () => void;
selected?: boolean;
- setInstanceName: (s: string) => void;
}
export function CardTable({
@@ -39,7 +39,6 @@ export function CardTable({
onCreate,
onUpdate,
onPurge,
- setInstanceName,
onDelete,
selected,
}: Props): VNode {
@@ -114,7 +113,6 @@ export function CardTable({
instances={instances}
onPurge={onPurge}
onUpdate={onUpdate}
- setInstanceName={setInstanceName}
onDelete={onDelete}
rowSelection={rowSelection}
rowSelectionHandler={rowSelectionHandler}
@@ -135,7 +133,6 @@ interface TableProps {
onDelete: (id: MerchantBackend.Instances.Instance) => void;
onPurge: (id: MerchantBackend.Instances.Instance) => void;
rowSelectionHandler: StateUpdater<string[]>;
- setInstanceName: (s: string) => void;
}
function toggleSelected<T>(id: T): (prev: T[]) => T[] {
@@ -146,13 +143,13 @@ function toggleSelected<T>(id: T): (prev: T[]) => T[] {
function Table({
rowSelection,
rowSelectionHandler,
- setInstanceName,
instances,
onUpdate,
onDelete,
onPurge,
}: TableProps): VNode {
const { i18n } = useTranslationContext();
+ const { impersonate } = useSessionState()
return (
<div class="table-container">
<table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
@@ -203,7 +200,8 @@ function Table({
<a
href={`#/orders?instance=${i.id}`}
onClick={(e) => {
- setInstanceName(i.id);
+ impersonate({instance: i.id});
+ e.preventDefault();
}}
>
{i.id}
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx
index 35b59633b..09ad338d2 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/View.tsx
@@ -32,7 +32,6 @@ interface Props {
onDelete: (id: MerchantBackend.Instances.Instance) => void;
onPurge: (id: MerchantBackend.Instances.Instance) => void;
selected?: boolean;
- setInstanceName: (s: string) => void;
}
export function View({
@@ -41,7 +40,6 @@ export function View({
onDelete,
onPurge,
onUpdate,
- setInstanceName,
selected,
}: Props): VNode {
const [show, setShow] = useState<"active" | "deleted" | null>("active");
@@ -100,7 +98,6 @@ export function View({
instances={showingInstances}
onDelete={onDelete}
onPurge={onPurge}
- setInstanceName={setInstanceName}
onUpdate={onUpdate}
selected={selected}
onCreate={onCreate}
diff --git a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
index d01460ac9..561e275ad 100644
--- a/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/admin/list/index.tsx
@@ -42,7 +42,6 @@ interface Props {
onUnauthorized: () => VNode;
onNotFound: () => VNode;
onLoadError: (error: HttpError<MerchantBackend.ErrorDetail>) => VNode;
- setInstanceName: (s: string) => void;
}
export default function Instances({
@@ -51,7 +50,6 @@ export default function Instances({
onNotFound,
onCreate,
onUpdate,
- setInstanceName,
}: Props): VNode {
const result = useBackendInstances();
const [deleting, setDeleting] =
@@ -86,7 +84,6 @@ export default function Instances({
onCreate={onCreate}
onPurge={setPurging}
onUpdate={onUpdate}
- setInstanceName={setInstanceName}
selected={!!deleting}
/>
{deleting && (
diff --git a/packages/taler-util/src/taler-types.ts b/packages/taler-util/src/taler-types.ts
index 6d317a98a..7cc703fd6 100644
--- a/packages/taler-util/src/taler-types.ts
+++ b/packages/taler-util/src/taler-types.ts
@@ -1431,6 +1431,7 @@ export const codecForMerchantContractTerms = (): Codec<MerchantContractTerms> =>
.property("exchanges", codecForList(codecForExchangeHandle()))
.property("products", codecOptional(codecForList(codecForProduct())))
.property("extra", codecForAny())
+ .property("minimum_age", codecOptional(codecForNumber()))
.build("MerchantContractTerms");
export const codecForPeerContractTerms = (): Codec<PeerContractTerms> =>