[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.
- [taler-merchant-backoffice] branch master updated (6c363c9 -> f3aea32), gnunet, 2021/03/03
- [taler-merchant-backoffice] 06/07: add left label to inputsecured, gnunet, 2021/03/03
- [taler-merchant-backoffice] 04/07: login modal should be sent on update, gnunet, 2021/03/03
- [taler-merchant-backoffice] 02/07: lang selector behavior, gnunet, 2021/03/03
- [taler-merchant-backoffice] 05/07: improve sidebar to show instance id and navbar to show a title, gnunet, 2021/03/03
- [taler-merchant-backoffice] 01/07: fixed some comments, gnunet, 2021/03/03
- [taler-merchant-backoffice] 03/07: improve app routing,
gnunet <=
- [taler-merchant-backoffice] 07/07: refactor backend mutate api to use token from instance id, implemented new passwod endpoint, gnunet, 2021/03/03