gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] branch master updated (54723c9 -> 17b274d)


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated (54723c9 -> 17b274d)
Date: Thu, 02 Dec 2021 19:25:41 +0100

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

sebasjm pushed a change to branch master
in repository merchant-backoffice.

    from 54723c9  fixing issue taken from christian comments:
     new 92be26c  add prettier
     new a8f51ec  -format with prettier
     new b27854f  content
     new 17b274d  add formatting splitter

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 contrib/split-formatting-vs-content-in-commit.sh   |  10 +
 .../copyleft-header.js => copyleft-header.js       |   0
 package.json                                       |   3 +
 .../merchant-backoffice/src/InstanceRoutes.tsx     | 628 +++++++++++++--------
 .../src/components/menu/index.tsx                  | 224 +++++---
 packages/merchant-backoffice/src/utils/types.ts    |   8 +-
 pnpm-lock.yaml                                     |  11 +-
 7 files changed, 557 insertions(+), 327 deletions(-)
 create mode 100644 contrib/split-formatting-vs-content-in-commit.sh
 copy packages/merchant-backend/copyleft-header.js => copyleft-header.js (100%)

diff --git a/contrib/split-formatting-vs-content-in-commit.sh 
b/contrib/split-formatting-vs-content-in-commit.sh
new file mode 100644
index 0000000..74d973e
--- /dev/null
+++ b/contrib/split-formatting-vs-content-in-commit.sh
@@ -0,0 +1,10 @@
+FILES=$(git status --short --untracked-files=no --porcelain | colrm 1 3)
+git stash
+pnpx prettier $FILES -w
+git add $FILES
+git commit -S -m '-formatted with prettier'
+git stash pop
+git checkout --theirs -- $FILES
+git add $FILES
+git commit -S
+
diff --git a/packages/merchant-backend/copyleft-header.js b/copyleft-header.js
similarity index 100%
copy from packages/merchant-backend/copyleft-header.js
copy to copyleft-header.js
diff --git a/package.json b/package.json
index 1a18f02..2c3f3f4 100644
--- a/package.json
+++ b/package.json
@@ -9,5 +9,8 @@
     "typedoc": "pnpm run --filter '{packages}' typedoc",
     "pretty": "pnpm run --filter '{packages}' pretty",
     "check": "pnpm run --filter '{packages}' --if-present test"
+  },
+  "dependencies": {
+    "prettier": "2.4.1"
   }
 }
diff --git a/packages/merchant-backoffice/src/InstanceRoutes.tsx 
b/packages/merchant-backoffice/src/InstanceRoutes.tsx
index 588cfb4..20a7601 100644
--- a/packages/merchant-backoffice/src/InstanceRoutes.tsx
+++ b/packages/merchant-backoffice/src/InstanceRoutes.tsx
@@ -15,327 +15,457 @@
  */
 
 /**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
 
-import { Fragment, FunctionComponent, h, VNode } from 'preact';
-import { Route, route, Router } from 'preact-router';
+import { Fragment, FunctionComponent, h, VNode } from "preact";
+import { Route, route, Router } from "preact-router";
 import { useCallback, useEffect, useMemo, useState } from "preact/hooks";
-import { Loading } from './components/exception/loading';
-import { NotificationCard } from './components/menu';
-import { useBackendContext } from './context/backend';
-import { InstanceContextProvider } from './context/instance';
-import { useBackendDefaultToken, useBackendInstanceToken } from './hooks';
+import { Loading } from "./components/exception/loading";
+import { NotificationCard } from "./components/menu";
+import { useBackendContext } from "./context/backend";
+import { InstanceContextProvider } from "./context/instance";
+import { useBackendDefaultToken, useBackendInstanceToken } from "./hooks";
 import { HttpError } from "./hooks/backend";
-import { useTranslator } from './i18n';
+import { useTranslator } from "./i18n";
 import InstanceCreatePage from "./paths/admin/create";
-import InstanceListPage from './paths/admin/list';
-import OrderCreatePage from './paths/instance/orders/create';
-import OrderDetailsPage from './paths/instance/orders/details';
-import OrderListPage from './paths/instance/orders/list';
-import ProductCreatePage from './paths/instance/products/create';
-import ProductListPage from './paths/instance/products/list';
-import ProductUpdatePage from './paths/instance/products/update';
-import TransferListPage from './paths/instance/transfers/list';
-import TransferCreatePage from './paths/instance/transfers/create';
-import ReservesCreatePage from './paths/instance/reserves/create';
-import ReservesDetailsPage from './paths/instance/reserves/details';
-import ReservesListPage from './paths/instance/reserves/list';
-import InstanceUpdatePage, { Props as InstanceUpdatePageProps, AdminUpdate as 
InstanceAdminUpdatePage } from "./paths/instance/update";
-import LoginPage from './paths/login';
-import NotFoundPage from './paths/notfound';
-import { Notification } from './utils/types';
+import InstanceListPage from "./paths/admin/list";
+import OrderCreatePage from "./paths/instance/orders/create";
+import OrderDetailsPage from "./paths/instance/orders/details";
+import OrderListPage from "./paths/instance/orders/list";
+import ProductCreatePage from "./paths/instance/products/create";
+import ProductListPage from "./paths/instance/products/list";
+import ProductUpdatePage from "./paths/instance/products/update";
+import TransferListPage from "./paths/instance/transfers/list";
+import TransferCreatePage from "./paths/instance/transfers/create";
+import ReservesCreatePage from "./paths/instance/reserves/create";
+import ReservesDetailsPage from "./paths/instance/reserves/details";
+import ReservesListPage from "./paths/instance/reserves/list";
+import InstanceUpdatePage, {
+  Props as InstanceUpdatePageProps,
+  AdminUpdate as InstanceAdminUpdatePage,
+} from "./paths/instance/update";
+import LoginPage from "./paths/login";
+import NotFoundPage from "./paths/notfound";
+import { Notification } from "./utils/types";
 
 export enum InstancePaths {
   // details = '/',
-  error = '/error',
-  update = '/update',
+  error = "/error",
+  update = "/update",
 
-  product_list = '/products',
-  product_update = '/product/:pid/update',
-  product_new = '/product/new',
+  product_list = "/products",
+  product_update = "/product/:pid/update",
+  product_new = "/product/new",
 
-  order_list = '/orders',
-  order_new = '/order/new',
-  order_details = '/order/:oid/details',
+  order_list = "/orders",
+  order_new = "/order/new",
+  order_details = "/order/:oid/details",
 
-  reserves_list = '/reserves',
-  reserves_details = '/reserves/:rid/details',
-  reserves_new = '/reserves/new',
+  reserves_list = "/reserves",
+  reserves_details = "/reserves/:rid/details",
+  reserves_new = "/reserves/new",
 
-  transfers_list = '/transfers',
-  transfers_new = '/transfer/new',
+  transfers_list = "/transfers",
+  transfers_new = "/transfer/new",
 }
 
 // eslint-disable-next-line @typescript-eslint/no-empty-function
-const noop = () => { }
+const noop = () => {};
 
 export enum AdminPaths {
-  list_instances = '/instances',
-  new_instance = '/instance/new',
-  update_instance = '/instance/:id/update',
+  list_instances = "/instances",
+  new_instance = "/instance/new",
+  update_instance = "/instance/:id/update",
 }
 
 export interface Props {
   id: string;
   admin?: boolean;
-  setInstanceName: (s:string) => void
+  setInstanceName: (s: string) => void;
 }
 
 export function InstanceRoutes({ id, admin, setInstanceName }: Props): VNode {
-  const [_, updateDefaultToken] = useBackendDefaultToken()
+  const [_, updateDefaultToken] = useBackendDefaultToken();
   const [token, updateToken] = useBackendInstanceToken(id);
-  const { updateLoginStatus: changeBackend, addTokenCleaner } = 
useBackendContext();
-  const cleaner = useCallback(() => { updateToken(undefined); }, [id]);
+  const { updateLoginStatus: changeBackend, addTokenCleaner } =
+    useBackendContext();
+  const cleaner = useCallback(() => {
+    updateToken(undefined);
+  }, [id]);
   const i18n = useTranslator();
-  const [globalNotification, setGlobalNotification] = useState<Notification & 
{ to: string } | undefined>(undefined)
+  const [globalNotification, setGlobalNotification] = useState<
+    (Notification & { to: string }) | undefined
+  >(undefined);
 
   useEffect(() => {
     addTokenCleaner(cleaner);
   }, [addTokenCleaner, cleaner]);
 
-  const changeToken = (token?:string) => {
+  const changeToken = (token?: string) => {
     if (admin) {
       updateToken(token);
     } else {
-      updateDefaultToken(token)
+      updateDefaultToken(token);
     }
-  }
+  };
   const updateLoginStatus = (url: string, token?: string) => {
     changeBackend(url);
-    if (!token) return
-    changeToken(token)
+    if (!token) return;
+    changeToken(token);
   };
 
-  const value = useMemo(() => ({ id, token, admin, changeToken }), [id, token, 
admin])
-
-  const ServerErrorRedirectTo = (to: InstancePaths | AdminPaths) => (error: 
HttpError) => {
-    setGlobalNotification({
-      message: i18n`The backend reported a problem: HTTP status 
#${error.status}`,
-      description: i18n`Diagnostic from ${error.info?.url} is 
"${error.message}"`,
-      type: 'ERROR',
-      to
-    })
-    return <Redirect to={to} />
+  const value = useMemo(
+    () => ({ id, token, admin, changeToken }),
+    [id, token, admin]
+  );
+
+  function ServerErrorRedirectTo(to: InstancePaths | AdminPaths) {
+    return function ServerErrorRedirectToImpl(error: HttpError) {
+      setGlobalNotification({
+        message: i18n`The backend reported a problem: HTTP status 
#${error.status}`,
+        description: i18n`Diagnostic from ${error.info?.url} is 
"${error.message}"`,
+        details:
+          error.clientError || error.serverError
+            ? error.error?.detail
+            : undefined,
+        type: "ERROR",
+        to,
+      });
+      return <Redirect to={to} />;
+    };
   }
 
-  const LoginPageAccessDenied = () => <Fragment>
-    <NotificationCard notification={{ message: i18n`Access denied`, 
description: i18n`The access token provided is invalid.`, type: 'ERROR', }} />
-    <LoginPage onConfirm={updateLoginStatus} />
-  </Fragment>
+  const LoginPageAccessDenied = () => (
+    <Fragment>
+      <NotificationCard
+        notification={{
+          message: i18n`Access denied`,
+          description: i18n`The access token provided is invalid.`,
+          type: "ERROR",
+        }}
+      />
+      <LoginPage onConfirm={updateLoginStatus} />
+    </Fragment>
+  );
 
   function IfAdminCreateDefaultOr<T>(Next: FunctionComponent<any>) {
     return function IfAdminCreateDefaultOrImpl(props?: T) {
-      if (admin && id === 'default') {
-        return <Fragment>
-          <NotificationCard notification={{
-            message: i18n`No 'default' instance configured yet.`,
-            description: i18n`Create a 'default' instance to begin using the 
merchant backoffice.`,
-            type: 'INFO'
-          }} />
-          <InstanceCreatePage forceId="default" onConfirm={() => {
-            route(AdminPaths.list_instances)
-          }} />
-        </Fragment>
+      if (admin && id === "default") {
+        return (
+          <Fragment>
+            <NotificationCard
+              notification={{
+                message: i18n`No 'default' instance configured yet.`,
+                description: i18n`Create a 'default' instance to begin using 
the merchant backoffice.`,
+                type: "INFO",
+              }}
+            />
+            <InstanceCreatePage
+              forceId="default"
+              onConfirm={() => {
+                route(AdminPaths.list_instances);
+              }}
+            />
+          </Fragment>
+        );
       }
       if (props) {
-        return <Next {...props} />
+        return <Next {...props} />;
       }
-      return <Next />
-
-    }
+      return <Next />;
+    };
   }
 
-  return <InstanceContextProvider value={value}>
-
-    <NotificationCard notification={globalNotification} />
-
-    <Router  onChange={(e) => {
-      const movingOutFromNotification = globalNotification && e.url !== 
globalNotification.to
-      if (movingOutFromNotification) {
-        setGlobalNotification(undefined)
-      }
-    }} >
-
-      <Route path="/" component={Redirect} to={InstancePaths.order_list} />
-
-      {/**
-       * Admin pages
-       */}
-      {admin &&
-        <Route path={AdminPaths.list_instances} component={InstanceListPage}
-          onCreate={() => { route(AdminPaths.new_instance) }}
-          onUpdate={(id: string): void => { route(`/instance/${id}/update`); }}
-          setInstanceName={setInstanceName}
+  return (
+    <InstanceContextProvider value={value}>
+      <NotificationCard notification={globalNotification} />
+
+      <Router
+        onChange={(e) => {
+          const movingOutFromNotification =
+            globalNotification && e.url !== globalNotification.to;
+          if (movingOutFromNotification) {
+            setGlobalNotification(undefined);
+          }
+        }}
+      >
+        <Route path="/" component={Redirect} to={InstancePaths.order_list} />
+
+        {/**
+         * Admin pages
+         */}
+        {admin && (
+          <Route
+            path={AdminPaths.list_instances}
+            component={InstanceListPage}
+            onCreate={() => {
+              route(AdminPaths.new_instance);
+            }}
+            onUpdate={(id: string): void => {
+              route(`/instance/${id}/update`);
+            }}
+            setInstanceName={setInstanceName}
+            onUnauthorized={LoginPageAccessDenied}
+            onLoadError={ServerErrorRedirectTo(InstancePaths.error)}
+          />
+        )}
+
+        {admin && (
+          <Route
+            path={AdminPaths.new_instance}
+            component={InstanceCreatePage}
+            onBack={() => route(AdminPaths.list_instances)}
+            onConfirm={() => {
+              route(AdminPaths.list_instances);
+            }}
+          />
+        )}
+
+        {admin && (
+          <Route
+            path={AdminPaths.update_instance}
+            component={AdminInstanceUpdatePage}
+            onBack={() => route(AdminPaths.list_instances)}
+            onConfirm={() => {
+              route(AdminPaths.list_instances);
+            }}
+            onUpdateError={ServerErrorRedirectTo(AdminPaths.list_instances)}
+            onLoadError={ServerErrorRedirectTo(AdminPaths.list_instances)}
+            onNotFound={NotFoundPage}
+          />
+        )}
+
+        {/**
+         * Update instance page
+         */}
+        <Route
+          path={InstancePaths.update}
+          component={InstanceUpdatePage}
+          onBack={() => {
+            route(`/`);
+          }}
+          onConfirm={() => {
+            route(`/`);
+          }}
+          onUpdateError={noop}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
           onUnauthorized={LoginPageAccessDenied}
           onLoadError={ServerErrorRedirectTo(InstancePaths.error)}
         />
-      }
 
-      {admin &&
-        <Route path={AdminPaths.new_instance} component={InstanceCreatePage}
-          onBack={() => route(AdminPaths.list_instances)}
-          onConfirm={() => { route(AdminPaths.list_instances); }}
+        {/**
+         * Product pages
+         */}
+        <Route
+          path={InstancePaths.product_list}
+          component={ProductListPage}
+          onUnauthorized={LoginPageAccessDenied}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
+          onCreate={() => {
+            route(InstancePaths.product_new);
+          }}
+          onSelect={(id: string) => {
+            route(InstancePaths.product_update.replace(":pid", id));
+          }}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
         />
-      }
-
-      {admin &&
-        <Route path={AdminPaths.update_instance} 
component={AdminInstanceUpdatePage}
-          onBack={() => route(AdminPaths.list_instances)}
-          onConfirm={() => { route(AdminPaths.list_instances); }}
-          onUpdateError={ServerErrorRedirectTo(AdminPaths.list_instances)}
-          onLoadError={ServerErrorRedirectTo(AdminPaths.list_instances)}
-          onNotFound={NotFoundPage}
+        <Route
+          path={InstancePaths.product_update}
+          component={ProductUpdatePage}
+          onUnauthorized={LoginPageAccessDenied}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.product_list)}
+          onConfirm={() => {
+            route(InstancePaths.product_list);
+          }}
+          onBack={() => {
+            route(InstancePaths.product_list);
+          }}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+        />
+        <Route
+          path={InstancePaths.product_new}
+          component={ProductCreatePage}
+          onConfirm={() => {
+            route(InstancePaths.product_list);
+          }}
+          onBack={() => {
+            route(InstancePaths.product_list);
+          }}
         />
-      }
-
-      {/**
-       * Update instance page
-       */}
-      <Route path={InstancePaths.update} component={InstanceUpdatePage}
-        onBack={() => { route(`/`); }}
-        onConfirm={() => { route(`/`); }}
-        onUpdateError={noop}
-        onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-        onUnauthorized={LoginPageAccessDenied}
-        onLoadError={ServerErrorRedirectTo(InstancePaths.error)}
-      />
-
-      {/**
-       * Product pages
-       */}
-      <Route path={InstancePaths.product_list} component={ProductListPage}
-        onUnauthorized={LoginPageAccessDenied}
-        onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
-        onCreate={() => { route(InstancePaths.product_new) }}
-        onSelect={(id: string) => { 
route(InstancePaths.product_update.replace(':pid', id)) }}
-        onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-      />
-      <Route path={InstancePaths.product_update} component={ProductUpdatePage}
-        onUnauthorized={LoginPageAccessDenied}
-        onLoadError={ServerErrorRedirectTo(InstancePaths.product_list)}
-        onConfirm={() => { route(InstancePaths.product_list); }}
-        onBack={() => { route(InstancePaths.product_list); }}
-        onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-      />
-      <Route path={InstancePaths.product_new}
-        component={ProductCreatePage}
-        onConfirm={() => { route(InstancePaths.product_list); }}
-        onBack={() => { route(InstancePaths.product_list); }}
-      />
-
-      {/**
-       * Order pages
-       */}
-      <Route path={InstancePaths.order_list} component={OrderListPage}
-        onCreate={() => { route(InstancePaths.order_new) }}
-        onSelect={(id: string) => { 
route(InstancePaths.order_details.replace(':oid', id)) }}
-        onUnauthorized={LoginPageAccessDenied}
-        onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
-        onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-      />
-      <Route path={InstancePaths.order_details} component={OrderDetailsPage}
-        onUnauthorized={LoginPageAccessDenied}
-        onLoadError={ServerErrorRedirectTo(InstancePaths.order_list)}
-        onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-        onBack={() => { route(InstancePaths.order_list) }}
-      />
-      <Route path={InstancePaths.order_new} component={OrderCreatePage}
-        onConfirm={() => { route(InstancePaths.order_list) }}
-        onBack={() => { route(InstancePaths.order_list) }}
-      />
 
-      {/**
-       * Transfer pages
-       */}
-      <Route path={InstancePaths.transfers_list} component={TransferListPage}
-        onUnauthorized={LoginPageAccessDenied}
-        onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-        onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
-        onCreate={() => { route(InstancePaths.transfers_new) }}
-      />
+        {/**
+         * Order pages
+         */}
+        <Route
+          path={InstancePaths.order_list}
+          component={OrderListPage}
+          onCreate={() => {
+            route(InstancePaths.order_new);
+          }}
+          onSelect={(id: string) => {
+            route(InstancePaths.order_details.replace(":oid", id));
+          }}
+          onUnauthorized={LoginPageAccessDenied}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+        />
+        <Route
+          path={InstancePaths.order_details}
+          component={OrderDetailsPage}
+          onUnauthorized={LoginPageAccessDenied}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.order_list)}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+          onBack={() => {
+            route(InstancePaths.order_list);
+          }}
+        />
+        <Route
+          path={InstancePaths.order_new}
+          component={OrderCreatePage}
+          onConfirm={() => {
+            route(InstancePaths.order_list);
+          }}
+          onBack={() => {
+            route(InstancePaths.order_list);
+          }}
+        />
 
-      <Route path={InstancePaths.transfers_new} component={TransferCreatePage}
-        onConfirm={() => { route(InstancePaths.transfers_list) }}
-        onBack={() => { route(InstancePaths.transfers_list) }}
-      />
+        {/**
+         * Transfer pages
+         */}
+        <Route
+          path={InstancePaths.transfers_list}
+          component={TransferListPage}
+          onUnauthorized={LoginPageAccessDenied}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
+          onCreate={() => {
+            route(InstancePaths.transfers_new);
+          }}
+        />
 
-      {/**
-       * reserves pages
-       */}
-      <Route path={InstancePaths.reserves_list} component={ReservesListPage}
-        onUnauthorized={LoginPageAccessDenied}
-        onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-        onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
-        onSelect={(id: string) => { 
route(InstancePaths.reserves_details.replace(':rid', id)) }}
-        onCreate={() => { route(InstancePaths.reserves_new) }}
-      />
+        <Route
+          path={InstancePaths.transfers_new}
+          component={TransferCreatePage}
+          onConfirm={() => {
+            route(InstancePaths.transfers_list);
+          }}
+          onBack={() => {
+            route(InstancePaths.transfers_list);
+          }}
+        />
 
-      <Route path={InstancePaths.reserves_details} 
component={ReservesDetailsPage}
-        onUnauthorized={LoginPageAccessDenied}
-        onLoadError={ServerErrorRedirectTo(InstancePaths.reserves_list)}
-        onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
-        onBack={() => { route(InstancePaths.reserves_list) }}
-      />
+        {/**
+         * reserves pages
+         */}
+        <Route
+          path={InstancePaths.reserves_list}
+          component={ReservesListPage}
+          onUnauthorized={LoginPageAccessDenied}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.update)}
+          onSelect={(id: string) => {
+            route(InstancePaths.reserves_details.replace(":rid", id));
+          }}
+          onCreate={() => {
+            route(InstancePaths.reserves_new);
+          }}
+        />
 
-      <Route path={InstancePaths.reserves_new} component={ReservesCreatePage}
-        onConfirm={() => { route(InstancePaths.reserves_list) }}
-        onBack={() => { route(InstancePaths.reserves_list) }}
-      />
-      {/**
-       * Example pages
-       */}
-      <Route path="/loading" component={Loading} />
-      <Route default component={NotFoundPage} />
-    </Router>
-  </InstanceContextProvider>;
+        <Route
+          path={InstancePaths.reserves_details}
+          component={ReservesDetailsPage}
+          onUnauthorized={LoginPageAccessDenied}
+          onLoadError={ServerErrorRedirectTo(InstancePaths.reserves_list)}
+          onNotFound={IfAdminCreateDefaultOr(NotFoundPage)}
+          onBack={() => {
+            route(InstancePaths.reserves_list);
+          }}
+        />
 
+        <Route
+          path={InstancePaths.reserves_new}
+          component={ReservesCreatePage}
+          onConfirm={() => {
+            route(InstancePaths.reserves_list);
+          }}
+          onBack={() => {
+            route(InstancePaths.reserves_list);
+          }}
+        />
+        {/**
+         * Example pages
+         */}
+        <Route path="/loading" component={Loading} />
+        <Route default component={NotFoundPage} />
+      </Router>
+    </InstanceContextProvider>
+  );
 }
 
 export function Redirect({ to }: { to: string }): null {
   useEffect(() => {
-    route(to, true)
-  })
-  return null
+    route(to, true);
+  });
+  return null;
 }
 
-function AdminInstanceUpdatePage({ id, ...rest }: { id: string } & 
InstanceUpdatePageProps) {
+function AdminInstanceUpdatePage({
+  id,
+  ...rest
+}: { id: string } & InstanceUpdatePageProps) {
   const [token, changeToken] = useBackendInstanceToken(id);
   const { updateLoginStatus: changeBackend } = useBackendContext();
   const updateLoginStatus = (url: string, token?: string) => {
     changeBackend(url);
-    if (token)
-    changeToken(token);
+    if (token) changeToken(token);
   };
-  const value = useMemo(() => ({ id, token, admin: true, changeToken }), [id, 
token])
+  const value = useMemo(
+    () => ({ id, token, admin: true, changeToken }),
+    [id, token]
+  );
   const i18n = useTranslator();
 
-  return <InstanceContextProvider value={value}>
-    <InstanceAdminUpdatePage {...rest}
-      instanceId={id}
-      onLoadError={(error: HttpError) => {
-        return <Fragment>
-          <NotificationCard notification={{
-            message: i18n`The backend reported a problem: HTTP status 
#${error.status}`,
-            description: i18n`Diagnostic from ${error.info?.url} is 
"${error.message}"`,
-            type: 'ERROR'
-          }} />
-          <LoginPage onConfirm={updateLoginStatus} />
-        </Fragment>
-      }}
-
-      onUnauthorized={() => {
-        return <Fragment>
-          <NotificationCard notification={{
-            message: i18n`Access denied`,
-            description: i18n`The access token provided is invalid`,
-            type: 'ERROR',
-          }} />
-          <LoginPage onConfirm={updateLoginStatus} />
-        </Fragment>
-      }}
-
-    />
-  </InstanceContextProvider>
+  return (
+    <InstanceContextProvider value={value}>
+      <InstanceAdminUpdatePage
+        {...rest}
+        instanceId={id}
+        onLoadError={(error: HttpError) => {
+          return (
+            <Fragment>
+              <NotificationCard
+                notification={{
+                  message: i18n`The backend reported a problem: HTTP status 
#${error.status}`,
+                  description: i18n`Diagnostic from ${error.info?.url} is 
"${error.message}"`,
+                  details:
+                    error.clientError || error.serverError
+                      ? error.error?.detail
+                      : undefined,
+                  type: "ERROR",
+                }}
+              />
+              <LoginPage onConfirm={updateLoginStatus} />
+            </Fragment>
+          );
+        }}
+        onUnauthorized={() => {
+          return (
+            <Fragment>
+              <NotificationCard
+                notification={{
+                  message: i18n`Access denied`,
+                  description: i18n`The access token provided is invalid`,
+                  type: "ERROR",
+                }}
+              />
+              <LoginPage onConfirm={updateLoginStatus} />
+            </Fragment>
+          );
+        }}
+      />
+    </InstanceContextProvider>
+  );
 }
diff --git a/packages/merchant-backoffice/src/components/menu/index.tsx 
b/packages/merchant-backoffice/src/components/menu/index.tsx
index fcba281..0a621af 100644
--- a/packages/merchant-backoffice/src/components/menu/index.tsx
+++ b/packages/merchant-backoffice/src/components/menu/index.tsx
@@ -15,7 +15,7 @@
  */
 
 import { ComponentChildren, Fragment, h, VNode } from "preact";
-import Match from 'preact-router/match';
+import Match from "preact-router/match";
 import { useEffect, useState } from "preact/hooks";
 import { AdminPaths } from "../../AdminRoutes";
 import { InstancePaths } from "../../InstanceRoutes";
@@ -23,28 +23,37 @@ import { Notification } from "../../utils/types";
 import { NavigationBar } from "./NavigationBar";
 import { Sidebar } from "./SideBar";
 
-
 function getInstanceTitle(path: string, id: string): string {
-
   switch (path) {
-    case InstancePaths.update: return `${id}: Settings`
-    case InstancePaths.order_list: return `${id}: Orders`
-    case InstancePaths.order_new: return `${id}: New order`
-    case InstancePaths.product_list: return `${id}: Products`
-    case InstancePaths.product_new: return `${id}: New product`
-    case InstancePaths.product_update: return `${id}: Update product`
-    case InstancePaths.reserves_new: return `${id}: New reserve`
-    case InstancePaths.reserves_list: return `${id}: Reserves`
-    case InstancePaths.transfers_list: return `${id}: Transfers`
-    case InstancePaths.transfers_new: return `${id}: New transfer`
-    default: return '';
+    case InstancePaths.update:
+      return `${id}: Settings`;
+    case InstancePaths.order_list:
+      return `${id}: Orders`;
+    case InstancePaths.order_new:
+      return `${id}: New order`;
+    case InstancePaths.product_list:
+      return `${id}: Products`;
+    case InstancePaths.product_new:
+      return `${id}: New product`;
+    case InstancePaths.product_update:
+      return `${id}: Update product`;
+    case InstancePaths.reserves_new:
+      return `${id}: New reserve`;
+    case InstancePaths.reserves_list:
+      return `${id}: Reserves`;
+    case InstancePaths.transfers_list:
+      return `${id}: Transfers`;
+    case InstancePaths.transfers_new:
+      return `${id}: New transfer`;
+    default:
+      return "";
   }
 }
 
 function getAdminTitle(path: string, instance: string) {
-  if (path === AdminPaths.new_instance) return `New instance`
-  if (path === AdminPaths.list_instances) return `Instances`
-  return getInstanceTitle(path, instance)
+  if (path === AdminPaths.new_instance) return `New instance`;
+  if (path === AdminPaths.list_instances) return `Instances`;
+  return getInstanceTitle(path, instance);
 }
 
 interface MenuProps {
@@ -52,41 +61,85 @@ interface MenuProps {
   instance: string;
   admin?: boolean;
   onLogout?: () => void;
-  setInstanceName: (s:string) => void;
+  setInstanceName: (s: string) => void;
 }
 
-function WithTitle({ title, children }: { title: string, children: 
ComponentChildren }): VNode {
+function WithTitle({
+  title,
+  children,
+}: {
+  title: string;
+  children: ComponentChildren;
+}): VNode {
   useEffect(() => {
-    document.title = `Taler Backoffice: ${title}`
-  }, [title])
-  return <Fragment>{children}</Fragment>
+    document.title = `Taler Backoffice: ${title}`;
+  }, [title]);
+  return <Fragment>{children}</Fragment>;
 }
 
-export function Menu({ onLogout, title, instance, admin, setInstanceName }: 
MenuProps): VNode {
-  const [mobileOpen, setMobileOpen] = useState(false)
-
-  return <Match>{({ path }: any) => {
-    const titleWithSubtitle = title ? title : (!admin ? getInstanceTitle(path, 
instance) : getAdminTitle(path, instance))
-    const adminInstance = instance === "default"
-    const mimic = admin && !adminInstance
-    return (<WithTitle title={titleWithSubtitle}>
-      <div class={mobileOpen ? "has-aside-mobile-expanded" : ""} onClick={() 
=> setMobileOpen(false)}>
-        <NavigationBar onMobileMenu={() => setMobileOpen(!mobileOpen)} 
title={titleWithSubtitle} />
-
-        {onLogout && <Sidebar onLogout={onLogout} admin={admin} mimic={mimic} 
instance={instance} mobile={mobileOpen} />}
-
-        {mimic && <nav class="level">
-          <div class="level-item has-text-centered has-background-warning">
-            <p class="is-size-5">You are viewing the instance 
<b>"{instance}"</b>. <a href="#/instances" onClick={(e) => {
-              setInstanceName('default')
-            }}>go back</a></p>
-          </div>
-        </nav>}
-      </div>
-    </WithTitle>
-    )
-  }}</Match>
-
+export function Menu({
+  onLogout,
+  title,
+  instance,
+  admin,
+  setInstanceName,
+}: MenuProps): VNode {
+  const [mobileOpen, setMobileOpen] = useState(false);
+
+  return (
+    <Match>
+      {({ path }: any) => {
+        const titleWithSubtitle = title
+          ? title
+          : !admin
+          ? getInstanceTitle(path, instance)
+          : getAdminTitle(path, instance);
+        const adminInstance = instance === "default";
+        const mimic = admin && !adminInstance;
+        return (
+          <WithTitle title={titleWithSubtitle}>
+            <div
+              class={mobileOpen ? "has-aside-mobile-expanded" : ""}
+              onClick={() => setMobileOpen(false)}
+            >
+              <NavigationBar
+                onMobileMenu={() => setMobileOpen(!mobileOpen)}
+                title={titleWithSubtitle}
+              />
+
+              {onLogout && (
+                <Sidebar
+                  onLogout={onLogout}
+                  admin={admin}
+                  mimic={mimic}
+                  instance={instance}
+                  mobile={mobileOpen}
+                />
+              )}
+
+              {mimic && (
+                <nav class="level">
+                  <div class="level-item has-text-centered 
has-background-warning">
+                    <p class="is-size-5">
+                      You are viewing the instance <b>"{instance}"</b>.{" "}
+                      <a
+                        href="#/instances"
+                        onClick={(e) => {
+                          setInstanceName("default");
+                        }}
+                      >
+                        go back
+                      </a>
+                    </p>
+                  </div>
+                </nav>
+              )}
+            </div>
+          </WithTitle>
+        );
+      }}
+    </Match>
+  );
 }
 
 interface NotYetReadyAppMenuProps {
@@ -97,36 +150,61 @@ interface NotYetReadyAppMenuProps {
 interface NotifProps {
   notification?: Notification;
 }
-export function NotificationCard({ notification: n }: NotifProps): VNode | 
null {
-  if (!n) return null
-  return <div class="notification">
-    <div class="columns is-vcentered">
-      <div class="column is-12">
-        <article class={n.type === 'ERROR' ? "message is-danger" : (n.type === 
'WARN' ? "message is-warning" : "message is-info")}>
-          <div class="message-header">
-            <p>{n.message}</p>
-          </div>
-          {n.description &&
-            <div class="message-body">
-              {n.description}
-            </div>}
-        </article>
+export function NotificationCard({
+  notification: n,
+}: NotifProps): VNode | null {
+  if (!n) return null;
+  return (
+    <div class="notification">
+      <div class="columns is-vcentered">
+        <div class="column is-12">
+          <article
+            class={
+              n.type === "ERROR"
+                ? "message is-danger"
+                : n.type === "WARN"
+                ? "message is-warning"
+                : "message is-info"
+            }
+          >
+            <div class="message-header">
+              <p>{n.message}</p>
+            </div>
+            {n.description && (
+              <div class="message-body">
+                <div>{n.description}</div>
+                {n.details && <pre>{n.details}</pre>}
+              </div>
+            )}
+          </article>
+        </div>
       </div>
     </div>
-  </div>
+  );
 }
 
-export function NotYetReadyAppMenu({ onLogout, title }: 
NotYetReadyAppMenuProps): VNode {
-  const [mobileOpen, setMobileOpen] = useState(false)
+export function NotYetReadyAppMenu({
+  onLogout,
+  title,
+}: NotYetReadyAppMenuProps): VNode {
+  const [mobileOpen, setMobileOpen] = useState(false);
 
   useEffect(() => {
-    document.title = `Taler Backoffice: ${title}`
-  }, [title])
-
-  return <div class={mobileOpen ? "has-aside-mobile-expanded" : ""} 
onClick={() => setMobileOpen(false)}>
-    <NavigationBar onMobileMenu={() => setMobileOpen(!mobileOpen)} 
title={title} />
-    {onLogout && <Sidebar onLogout={onLogout} instance="" mobile={mobileOpen} 
/>}
-  </div>
-
+    document.title = `Taler Backoffice: ${title}`;
+  }, [title]);
+
+  return (
+    <div
+      class={mobileOpen ? "has-aside-mobile-expanded" : ""}
+      onClick={() => setMobileOpen(false)}
+    >
+      <NavigationBar
+        onMobileMenu={() => setMobileOpen(!mobileOpen)}
+        title={title}
+      />
+      {onLogout && (
+        <Sidebar onLogout={onLogout} instance="" mobile={mobileOpen} />
+      )}
+    </div>
+  );
 }
-
diff --git a/packages/merchant-backoffice/src/utils/types.ts 
b/packages/merchant-backoffice/src/utils/types.ts
index 9e49d39..a3f23ac 100644
--- a/packages/merchant-backoffice/src/utils/types.ts
+++ b/packages/merchant-backoffice/src/utils/types.ts
@@ -14,7 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { VNode } from "preact"
+import { VNode } from "preact";
 
 export interface KeyValue {
   [key: string]: string;
@@ -23,9 +23,9 @@ export interface KeyValue {
 export interface Notification {
   message: string;
   description?: string | VNode;
+  details?: string | VNode;
   type: MessageType;
 }
 
-export type ValueOrFunction<T> = T | ((p: T) => T)
-export type MessageType = 'INFO' | 'WARN' | 'ERROR' | 'SUCCESS'
-
+export type ValueOrFunction<T> = T | ((p: T) => T);
+export type MessageType = "INFO" | "WARN" | "ERROR" | "SUCCESS";
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index f73b71d..7a58e7e 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3,7 +3,10 @@ lockfileVersion: 5.3
 importers:
 
   .:
-    specifiers: {}
+    specifiers:
+      prettier: 2.4.1
+    dependencies:
+      prettier: 2.4.1
 
   packages/bank:
     specifiers:
@@ -17604,6 +17607,12 @@ packages:
     hasBin: true
     dev: true
 
+  /prettier/2.4.1:
+    resolution: {integrity: 
sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+    dev: false
+
   /pretty-bytes/4.0.2:
     resolution: {integrity: sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=}
     engines: {node: '>=4'}

-- 
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]