gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] 02/08: wip


From: gnunet
Subject: [taler-wallet-core] 02/08: wip
Date: Tue, 26 Mar 2024 20:58:49 +0100

This is an automated email from the git hooks/post-receive script.

sebasjm pushed a commit to branch master
in repository wallet-core.

commit a427958be6d32ce8d907c885d577c8a05ef450a0
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Fri Mar 22 09:03:27 2024 -0300

    wip
---
 .../merchant-backoffice-ui/src/AdminRoutes.tsx     |   2 +-
 .../merchant-backoffice-ui/src/Application.tsx     |   2 +-
 .../src/ApplicationReadyRoutes.tsx                 | 174 ---------------------
 .../src/{Rounting.tsx => Routing.tsx}              |  74 ++-------
 .../src/components/menu/SideBar.tsx                |  19 +--
 .../src/components/menu/index.tsx                  |  93 +++++------
 .../merchant-backoffice-ui/src/hooks/session.ts    |   6 +-
 .../src/paths/admin/list/TableActive.tsx           |  10 +-
 .../src/paths/admin/list/View.tsx                  |   3 -
 .../src/paths/admin/list/index.tsx                 |   3 -
 packages/taler-util/src/taler-types.ts             |   1 +
 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
similarity index 93%
rename from packages/merchant-backoffice-ui/src/Rounting.tsx
rename to 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> =>

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]