gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] 03/07: improve app routing


From: gnunet
Subject: [taler-merchant-backoffice] 03/07: improve app routing
Date: Wed, 03 Mar 2021 18:44:10 +0100

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

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

commit 9128d984cefe1a337a63f5f02493d53ededc6ede
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Mar 3 14:34:54 2021 -0300

    improve app routing
---
 CHANGELOG.md                                     |  19 ++-
 packages/frontend/.storybook/preview.js          |   4 +-
 packages/frontend/src/AdminRoutes.tsx            |  68 +++++++++
 packages/frontend/src/ApplicationReadyRoutes.tsx | 167 ++++++++++++++---------
 packages/frontend/src/InstanceRoutes.tsx         |  34 +++--
 5 files changed, 214 insertions(+), 78 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 348addc..c674aa4 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,20 +13,31 @@ and this project adheres to [Semantic 
Versioning](https://semver.org/spec/v2.0.0
  - validate everything using onChange
  - feature: input as date format
  - bug: there is missing a mutate call when updating to remove the instance 
from cache
- - submit form on key press == enter
- - (WIP) remove checkbox from auth token, use button (manage auth)
- - (WIP) auth token config as popup with 3 actions (clear (sure?), cancel, set 
token)
 
  - add order section
  - add product section
  - add tips section
- - implement better error handling
+ - implement better error handling (improve creation of duplicated instances)
  - replace Yup and type definition with a taler-library for the purpose (first 
wait Florian to refactor wallet core)
  - add more doc style comments 
  - configure eslint
  - configure prettier
  - prune scss styles to reduce size
  - create a loading page to be use when the data is not ready
+ 
+## [Unreleased]
+ - submit form on key press == enter
+ - version of backoffice in sidebar
+ - fixed login dialog on mobile
+ - LangSelector ascomponent
+ - refactored Navigation and Sidebar
+ - do not display Logout when there is no token
+ - fix: Login Page should show on unauthorized
+ - fix: row clicking on card table was overriding checkbox onClick
+ - remove headers of the page
+ - clear all tokens now remove backend-url
+ - (WIP) remove checkbox from auth token, use button (manage auth)
+ - (WIP) auth token config as popup with 3 actions (clear (sure?), cancel, set 
token)
 
 ## [0.0.2] - 2021-02-25
  - REFACTOR: remove react-i18n and implement messageformat
diff --git a/packages/frontend/.storybook/preview.js 
b/packages/frontend/.storybook/preview.js
index 0299766..059edaa 100644
--- a/packages/frontend/.storybook/preview.js
+++ b/packages/frontend/.storybook/preview.js
@@ -1,6 +1,6 @@
 import "../src/scss/main.scss"
 import { MessageProvider } from "preact-messages";
-import { ConfigContext } from '../src/context/backend'
+import { ConfigContextProvider } from '../src/context/backend'
 import * as messages from '../src/messages'
 import { h } from 'preact';
 
@@ -35,5 +35,5 @@ export const decorators = [
       <Story />
     </MessageProvider>
   },
-  (Story) => <ConfigContext.Provider value={mockConfig}> <Story /> 
</ConfigContext.Provider>
+  (Story) => <ConfigContextProvider value={mockConfig}> <Story /> 
</ConfigContextProvider>
 ];
diff --git a/packages/frontend/src/AdminRoutes.tsx 
b/packages/frontend/src/AdminRoutes.tsx
new file mode 100644
index 0000000..cf70d3f
--- /dev/null
+++ b/packages/frontend/src/AdminRoutes.tsx
@@ -0,0 +1,68 @@
+import { h, VNode } from "preact";
+import Router, { route, Route } from "preact-router";
+import { RootPaths, Redirect } from "./index";
+import NotFoundPage from './routes/notfound';
+import InstanceListPage from './routes/instances/list';
+import InstanceCreatePage from "./routes/instances/create";
+import { MerchantBackend } from "./declaration";
+import { useMessageTemplate } from "preact-messages";
+import { Notification } from "./utils/types";
+import { InstanceRoutes } from "./InstanceRoutes";
+
+interface Props {
+  pushNotification: (n: Notification) => void;
+  instances: MerchantBackend.Instances.Instance[]
+  addTokenCleaner: any;
+}
+export function AdminRoutes({ instances, pushNotification, addTokenCleaner }: 
Props): VNode {
+  const i18n = useMessageTemplate();
+
+  return <Router>
+    <Route path={RootPaths.root} component={Redirect} 
to={RootPaths.list_instances} />
+
+    <Route path={RootPaths.list_instances} component={InstanceListPage}
+
+      onCreate={() => {
+        route(RootPaths.new_instance);
+      }}
+
+      instances={instances}
+
+      onUpdate={(id: string): void => {
+        route(`/instance/${id}/update`);
+      }}
+
+    // onUnauthorized={() => <LoginPage
+    //   withMessage={{ message: i18n`Access denied`, description: i18n`Check 
your token is valid`, type: 'ERROR', }}
+    //   onConfirm={updateLoginStatus} />}
+
+    // onQueryError={(error: SwrError) => <LoginPage
+    //   withMessage={{ message: i18n`Problem reaching the server`, 
description: i18n`Got message: ${error.message} from: ${error.backend} 
(hasToken: ${error.hasToken})`, type: 'ERROR', }}
+    //   onConfirm={updateLoginStatus} />}
+
+    />
+
+    <Route path={RootPaths.new_instance} component={InstanceCreatePage}
+
+      onBack={() => route(RootPaths.list_instances)}
+
+      onConfirm={() => {
+        pushNotification({ message: i18n`create_success`, type: 'SUCCESS' });
+        route(RootPaths.list_instances);
+      }}
+
+      onError={(error: any) => {
+        pushNotification({ message: i18n`create_error`, type: 'ERROR' });
+      }}
+    />
+
+    <Route path={RootPaths.instance_id_route} component={InstanceRoutes}
+      pushNotification={pushNotification}
+      addTokenCleaner={addTokenCleaner}
+      parent="/instance/:id"
+    />
+
+    <Route default component={NotFoundPage} />
+
+  </Router>
+}
\ No newline at end of file
diff --git a/packages/frontend/src/ApplicationReadyRoutes.tsx 
b/packages/frontend/src/ApplicationReadyRoutes.tsx
index 61c098c..0b0fc92 100644
--- a/packages/frontend/src/ApplicationReadyRoutes.tsx
+++ b/packages/frontend/src/ApplicationReadyRoutes.tsx
@@ -18,73 +18,118 @@
 *
 * @author Sebastian Javier Marchano (sebasjm)
 */
-import { h, VNode } from 'preact';
-import { useContext } from "preact/hooks";
-import { Route, Router, route } from 'preact-router';
-import { useMessageTemplate } from 'preact-messages';
+import { Fragment, h, VNode } from 'preact';
+import { route } from 'preact-router';
 import { Notification } from "./utils/types";
-import { BackendContext } from './context/backend';
-import { SwrError } from "./hooks/backend";
+import { useBackendContext } from './context/backend';
+import { useBackendInstances } from "./hooks/backend";
 import { InstanceRoutes } from "./InstanceRoutes";
-import { RootPaths, Redirect } from "./index";
-import NotFoundPage from './routes/notfound';
 import LoginPage from './routes/login';
-import InstanceListPage from './routes/instances/list';
-import InstanceCreatePage from "./routes/instances/create";
-import { Notifications } from './components/notifications';
-
-export function ApplicationReadyRoutes({ pushNotification, addTokenCleaner }: 
{ pushNotification: (n: Notification) => void; addTokenCleaner: any; }): VNode {
-  const { changeBackend, updateToken } = useContext(BackendContext);
+import { INSTANCE_ID_LOOKUP } from './utils/constants';
+import { Menu } from './components/menu';
+import { AdminRoutes } from './AdminRoutes';
+import { useMessageTemplate } from 'preact-messages';
+interface Props {
+  pushNotification: (n: Notification) => void;
+  addTokenCleaner: any;
+  clearAllTokens: () => void;
+}
+export function ApplicationReadyRoutes({ pushNotification, addTokenCleaner, 
clearAllTokens }: Props): VNode {
+  const i18n = useMessageTemplate();
+  const { url: currentBaseUrl, changeBackend, updateToken } = 
useBackendContext();
 
   const updateLoginStatus = (url: string, token?: string) => {
     changeBackend(url);
-    if (token)
-      updateToken(token);
+    if (token) updateToken(token);
   };
-  const i18n = useMessageTemplate();
-
-  return <Router>
-    <Route path={RootPaths.root} component={Redirect}
-      to={RootPaths.list_instances} />
-
-    <Route path={RootPaths.list_instances} component={InstanceListPage}
-
-      onCreate={() => {
-        route(RootPaths.new_instance);
-      }}
-
-      onUpdate={(id: string): void => {
-        route(`/instance/${id}/update`);
-      }}
-
-      onUnauthorized={() => <LoginPage
-        withMessage={{ message: i18n`Access denied`, description: i18n`Check 
your token is valid`, type: 'ERROR', }}
-        onConfirm={updateLoginStatus} />}
-
-      onQueryError={(error: SwrError) => <LoginPage
-        withMessage={{ message: i18n`Problem reaching the server`, 
description: i18n`Got message: ${error.message} from: ${error.backend} 
(hasToken: ${error.hasToken})`, type: 'ERROR', }}
-        onConfirm={updateLoginStatus} />}  
-
-    />
-
-    <Route path={RootPaths.new_instance} component={InstanceCreatePage}
-
-      onBack={() => route(RootPaths.list_instances)}
-
-      onConfirm={() => {
-        pushNotification({ message: i18n`create_success`, type: 'SUCCESS' });
-        route(RootPaths.list_instances);
-      }}
-
-      onError={(error: any) => {
-        pushNotification({ message: i18n`create_error`, type: 'ERROR' });
-      }} />
-
-    <Route path={RootPaths.instance_id_route} component={InstanceRoutes}
+  const list = useBackendInstances()
+
+  if (!list.data) {
+    if (list.unauthorized) {
+      return <Fragment>
+        <Menu onLogout={() => {
+          clearAllTokens();
+          route('/')
+        }} />
+        <LoginPage
+          withMessage={{ message: i18n`Access denied`, description: i18n`Check 
your token is valid`, type: 'ERROR', }}
+          onConfirm={updateLoginStatus}
+        />
+      </Fragment>
+    }
+    if (list.notfound) {
+      try {
+        const path = new URL(currentBaseUrl).pathname
+        const match = INSTANCE_ID_LOOKUP.exec(path)
+        if (!match || !match[1]) throw new Error(i18n`Could not infer instance 
id from url ${currentBaseUrl}`)
+        return <Fragment>
+          <Menu instance={match[1]} onLogout={() => {
+            clearAllTokens();
+            route('/')
+          }} />
+          <InstanceRoutes
+            id={match[1]}
+            addTokenCleaner={addTokenCleaner}
+            pushNotification={pushNotification}
+          />
+        </Fragment>
+      } catch (e) {
+        // this should be rare becuase
+        // query to /config is ok but the URL
+        // doest not match with our pattern
+        return <Fragment>
+          <Menu onLogout={() => {
+            clearAllTokens();
+            route('/')
+          }} />
+          <LoginPage
+            withMessage={{ message: i18n`Couldnt access the server`, 
description: e.message, type: 'ERROR', }}
+            onConfirm={updateLoginStatus}
+          />
+        </Fragment>
+      }
+    }
+    if (!list.error) {
+      return <div id="app">
+        <section class="section is-title-bar">
+
+          <div class="level">
+            <div class="level-left">
+              <div class="level-item">
+                <ul>
+                  <li>loading s</li>
+                </ul>
+              </div>
+            </div>
+          </div>
+        </section>
+      </div>
+    }
+    return <div id="app">
+      <section class="section is-title-bar">
+
+        <div class="level">
+          <div class="level-left">
+            <div class="level-item">
+              <ul>
+                <li>There was an unexpected error</li>
+                <li>{JSON.stringify(list.error)}</li>
+              </ul>
+            </div>
+          </div>
+        </div>
+      </section>
+    </div>
+  }
+
+  return <Fragment>
+    <Menu onLogout={() => {
+      clearAllTokens();
+      route('/')
+    }} />
+    <AdminRoutes instances={list.data.instances}
+      addTokenCleaner={addTokenCleaner}
       pushNotification={pushNotification}
-      addTokenCleaner={addTokenCleaner} />
-
-    <Route default component={NotFoundPage} />
-
-  </Router>;
+    />
+  </Fragment>
 }
diff --git a/packages/frontend/src/InstanceRoutes.tsx 
b/packages/frontend/src/InstanceRoutes.tsx
index 14c1da6..b3adc92 100644
--- a/packages/frontend/src/InstanceRoutes.tsx
+++ b/packages/frontend/src/InstanceRoutes.tsx
@@ -20,28 +20,29 @@
 */
 
 import { h, VNode } from 'preact';
-import { useCallback, useContext, useEffect, useMemo } from "preact/hooks";
+import { useCallback, useEffect, useMemo } from "preact/hooks";
 import { Route, Router, route } from 'preact-router';
 import { useMessageTemplate } from 'preact-messages';
 import { useBackendInstanceToken } from './hooks';
-import { BackendContext, InstanceContext } from './context/backend';
+import { InstanceContextProvider, useBackendContext } from './context/backend';
 import { SwrError } from "./hooks/backend";
 import { InstancePaths } from "./index";
 import { Notification } from './utils/types';
 import NotFoundPage from './routes/notfound';
 import LoginPage from './routes/login';
-import InstanceDetailsPage from "./routes/instances/details";
 import InstanceUpdatePage from "./routes/instances/update";
+import DetailPage from './routes/instances/details';
 
 export interface Props {
   id: string;
   pushNotification: (n: Notification) => void;
   addTokenCleaner: any;
+  parent?: string;
 }
 
-export function InstanceRoutes({ id, pushNotification, addTokenCleaner }: 
Props): VNode {
+export function InstanceRoutes({ id, pushNotification, addTokenCleaner, parent 
}: Props): VNode {
   const [token, updateToken] = useBackendInstanceToken(id);
-  const { changeBackend } = useContext(BackendContext);
+  const { changeBackend } = useBackendContext();
   const cleaner = useCallback(() => { updateToken(undefined); }, [id]);
   const i18n = useMessageTemplate('');
 
@@ -55,12 +56,23 @@ export function InstanceRoutes({ id, pushNotification, 
addTokenCleaner }: Props)
       updateToken(token);
   };
 
-  const value = useMemo(() => ({ id, token }), [id, token])
+  const value = useMemo(() => ({ id, token, admin: !!parent }), [id, token])
 
-  return <InstanceContext.Provider value={value}>
+  return <InstanceContextProvider value={value}>
     <Router>
+      <Route path={(!parent? "" : parent) + InstancePaths.details}
+        component={DetailPage}
 
-      <Route path={InstancePaths.update}
+        onUnauthorized={() => <LoginPage
+          withMessage={{ message: i18n`Access denied`, description: i18n`Check 
your token is valid`, type: 'ERROR', }}
+          onConfirm={updateLoginStatus} />}
+
+        onLoadError={(error: SwrError) => <LoginPage
+          withMessage={{ message: i18n`Problem reaching the server`, 
description: i18n`Got message: ${error.message} from: ${error.backend} 
(hasToken: ${error.hasToken})`, type: 'ERROR', }}
+          onConfirm={updateLoginStatus} />}
+      />     
+
+      <Route path={(!parent? "" : parent) + InstancePaths.update}
         component={InstanceUpdatePage}
 
         onUnauthorized={() => <LoginPage
@@ -72,12 +84,12 @@ export function InstanceRoutes({ id, pushNotification, 
addTokenCleaner }: Props)
           onConfirm={updateLoginStatus} />}
 
         onBack={() => {
-          route(`/instances`);
+          route(`/`);
         }}
 
         onConfirm={() => {
           pushNotification({ message: i18n`create_success`, type: 'SUCCESS' });
-          route(`/instances`);
+          route(`/`);
         }}
 
         onUpdateError={(e: Error) => {
@@ -87,6 +99,6 @@ export function InstanceRoutes({ id, pushNotification, 
addTokenCleaner }: Props)
 
       <Route default component={NotFoundPage} />
     </Router>
-  </InstanceContext.Provider>;
+  </InstanceContextProvider>;
 
 }

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