From 37d0f9438e6e6507c46d56324e38a5f0c391ab45 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Fri, 4 Aug 2023 13:32:08 -0300
Subject: accesstoken in memory and better login when switching between
 accounts

---
 packages/merchant-backoffice-ui/src/components/menu/index.tsx | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

(limited to 'packages/merchant-backoffice-ui/src/components/menu/index.tsx')

diff --git a/packages/merchant-backoffice-ui/src/components/menu/index.tsx b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
index 56573b8ca..2beaf6956 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/index.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
@@ -130,7 +130,12 @@ export function Menu({
         )}
 
         {mimic && (
-          <nav class="level">
+          <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>.{" "}
-- 
cgit v1.2.3


From 7d1621767cec57e9e7217f620844655279ab1af5 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Mon, 7 Aug 2023 06:51:10 -0300
Subject: ui settings view

---
 .../merchant-backoffice-ui/src/Application.tsx     | 24 +++++---
 .../src/ApplicationReadyRoutes.tsx                 | 14 ++++-
 .../merchant-backoffice-ui/src/InstanceRoutes.tsx  |  7 +++
 .../src/components/exception/login.tsx             |  2 +-
 .../src/components/menu/NavigationBar.tsx          |  2 -
 .../src/components/menu/SideBar.tsx                | 64 ++++++++++++++--------
 .../src/components/menu/index.tsx                  |  7 ++-
 .../src/paths/instance/orders/list/ListPage.tsx    |  4 +-
 .../paths/instance/templates/create/CreatePage.tsx | 38 ++++++-------
 .../src/paths/settings/index.tsx                   | 15 +++++
 10 files changed, 118 insertions(+), 59 deletions(-)
 create mode 100644 packages/merchant-backoffice-ui/src/paths/settings/index.tsx

(limited to 'packages/merchant-backoffice-ui/src/components/menu/index.tsx')

diff --git a/packages/merchant-backoffice-ui/src/Application.tsx b/packages/merchant-backoffice-ui/src/Application.tsx
index 23510c456..f6a81ff8d 100644
--- a/packages/merchant-backoffice-ui/src/Application.tsx
+++ b/packages/merchant-backoffice-ui/src/Application.tsx
@@ -26,7 +26,7 @@ import {
 } from "@gnu-taler/web-util/browser";
 import { Fragment, h, VNode } from "preact";
 import { route } from "preact-router";
-import { useMemo } from "preact/hooks";
+import { useMemo, useState } from "preact/hooks";
 import { ApplicationReadyRoutes } from "./ApplicationReadyRoutes.js";
 import { Loading } from "./components/exception/loading.js";
 import {
@@ -42,6 +42,7 @@ import { useBackendConfig } from "./hooks/backend.js";
 import { strings } from "./i18n/strings.js";
 import LoginPage from "./paths/login/index.js";
 import { HttpStatusCode } from "@gnu-taler/taler-util";
+import { Settings } from "./paths/settings/index.js";
 
 export function Application(): VNode {
   return (
@@ -70,10 +71,19 @@ function ApplicationStatusRoutes(): VNode {
     : { currency: "unknown", version: "unknown" };
   const ctx = useMemo(() => ({ currency, version }), [currency, version]);
 
+  const [showSettings, setShowSettings] = useState(false)
+
+  if (showSettings) {
+    return <Fragment>
+      <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="UI Settings" />
+      <Settings />
+    </Fragment>
+  }
+
   if (!triedToLog) {
     return (
       <Fragment>
-        <NotYetReadyAppMenu title="Welcome!" />
+        <NotYetReadyAppMenu title="Welcome!" onShowSettings={() => setShowSettings(true)} />
         <LoginPage onConfirm={updateLoginInfoAndGoToRoot} />
       </Fragment>
     );
@@ -87,7 +97,7 @@ function ApplicationStatusRoutes(): VNode {
     ) {
       return (
         <Fragment>
-          <NotYetReadyAppMenu title="Login" />
+          <NotYetReadyAppMenu title="Login" onShowSettings={() => setShowSettings(true)} />
           <LoginPage onConfirm={updateLoginInfoAndGoToRoot} />
         </Fragment>
       );
@@ -98,7 +108,7 @@ function ApplicationStatusRoutes(): VNode {
     ) {
       return (
         <Fragment>
-          <NotYetReadyAppMenu title="Error" />
+          <NotYetReadyAppMenu title="Error" onShowSettings={() => setShowSettings(true)} />
           <NotificationCard
             notification={{
               message: i18n.str`Server not found`,
@@ -112,7 +122,7 @@ function ApplicationStatusRoutes(): VNode {
     }
     if (result.type === ErrorType.SERVER) {
       <Fragment>
-        <NotYetReadyAppMenu title="Error" />
+        <NotYetReadyAppMenu title="Error" onShowSettings={() => setShowSettings(true)} />
         <NotificationCard
           notification={{
             message: i18n.str`Server response with an error code`,
@@ -125,7 +135,7 @@ function ApplicationStatusRoutes(): VNode {
     }
     if (result.type === ErrorType.UNREADABLE) {
       <Fragment>
-        <NotYetReadyAppMenu title="Error" />
+        <NotYetReadyAppMenu title="Error" onShowSettings={() => setShowSettings(true)} />
         <NotificationCard
           notification={{
             message: i18n.str`Response from server is unreadable, http status: ${result.status}`,
@@ -138,7 +148,7 @@ function ApplicationStatusRoutes(): VNode {
     }
     return (
       <Fragment>
-        <NotYetReadyAppMenu title="Error" />
+        <NotYetReadyAppMenu title="Error" onShowSettings={() => setShowSettings(true)} />
         <NotificationCard
           notification={{
             message: i18n.str`Unexpected Error`,
diff --git a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx
index 7731dac88..277c2b176 100644
--- a/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx
+++ b/packages/merchant-backoffice-ui/src/ApplicationReadyRoutes.tsx
@@ -33,6 +33,7 @@ import { InstanceRoutes } from "./InstanceRoutes.js";
 import LoginPage from "./paths/login/index.js";
 import { INSTANCE_ID_LOOKUP } from "./utils/constants.js";
 import { HttpStatusCode } from "@gnu-taler/taler-util";
+import { Settings } from "./paths/settings/index.js";
 
 export function ApplicationReadyRoutes(): VNode {
   const { i18n } = useTranslationContext();
@@ -48,8 +49,15 @@ export function ApplicationReadyRoutes(): VNode {
     clearAllTokens();
     route("/");
   };
+  const [showSettings, setShowSettings] = useState(false)
 
-  if (result.loading) return <NotYetReadyAppMenu title="Loading..." />;
+  if (showSettings) {
+    return <Fragment>
+      <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="UI Settings" onLogout={clearTokenAndGoToRoot} />
+      <Settings/>
+    </Fragment>
+  }
+  if (result.loading) return <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Loading..." />;
 
   let admin = true;
   let instanceNameByBackendURL;
@@ -61,7 +69,7 @@ export function ApplicationReadyRoutes(): VNode {
     ) {
       return (
         <Fragment>
-          <NotYetReadyAppMenu title="Login" onLogout={clearTokenAndGoToRoot} />
+          <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Login" onLogout={clearTokenAndGoToRoot} />
           <NotificationCard
             notification={{
               message: i18n.str`Access denied`,
@@ -81,7 +89,7 @@ export function ApplicationReadyRoutes(): VNode {
       // does not match our pattern
       return (
         <Fragment>
-          <NotYetReadyAppMenu title="Error" onLogout={clearTokenAndGoToRoot} />
+          <NotYetReadyAppMenu onShowSettings={() => setShowSettings(true)} title="Error" onLogout={clearTokenAndGoToRoot} />
           <NotificationCard
             notification={{
               message: i18n.str`Couldn't access the server.`,
diff --git a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
index cb4abdd40..1547442ea 100644
--- a/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
+++ b/packages/merchant-backoffice-ui/src/InstanceRoutes.tsx
@@ -68,6 +68,7 @@ import LoginPage from "./paths/login/index.js";
 import NotFoundPage from "./paths/notfound/index.js";
 import { Notification } from "./utils/types.js";
 import { MerchantBackend } from "./declaration.js";
+import { Settings } from "./paths/settings/index.js";
 
 export enum InstancePaths {
   // details = '/',
@@ -100,6 +101,8 @@ export enum InstancePaths {
   webhooks_list = "/webhooks",
   webhooks_update = "/webhooks/:tid/update",
   webhooks_new = "/webhooks/new",
+
+  settings = "/settings",
 }
 
 // eslint-disable-next-line @typescript-eslint/no-empty-function
@@ -240,6 +243,9 @@ export function InstanceRoutes({
       <Menu
         instance={id}
         admin={admin}
+        onShowSettings={() => {
+          route("/settings")
+        }}
         path={path}
         onLogout={clearTokenAndGoToRoot}
         setInstanceName={setInstanceName}
@@ -558,6 +564,7 @@ export function InstanceRoutes({
           }}
         />
         <Route path={InstancePaths.kyc} component={ListKYCPage} />
+        <Route path={InstancePaths.settings} component={Settings} />
         {/**
          * Example pages
          */}
diff --git a/packages/merchant-backoffice-ui/src/components/exception/login.tsx b/packages/merchant-backoffice-ui/src/components/exception/login.tsx
index 984b6fe06..f2f94a7c5 100644
--- a/packages/merchant-backoffice-ui/src/components/exception/login.tsx
+++ b/packages/merchant-backoffice-ui/src/components/exception/login.tsx
@@ -229,7 +229,7 @@ export function LoginModal({ onConfirm, withMessage }: Props): VNode {
   );
 }
 
-function AsyncButton({onClick, children}:{onClick: () => Promise<void>, children: ComponentChildren}):VNode {
+function AsyncButton({ onClick, children }: { onClick: () => Promise<void>, children: ComponentChildren }): VNode {
   const [running, setRunning] = useState(false)
   return <button class="button is-info" disabled={running} onClick={() => {
     setRunning(true)
diff --git a/packages/merchant-backoffice-ui/src/components/menu/NavigationBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/NavigationBar.tsx
index 9624a2c38..9f1b33893 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/NavigationBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/NavigationBar.tsx
@@ -20,7 +20,6 @@
  */
 
 import { h, VNode } from "preact";
-import { LangSelector } from "./LangSelector.js";
 import logo from "../../assets/logo-2021.svg";
 
 interface Props {
@@ -65,7 +64,6 @@ export function NavigationBar({ onMobileMenu, title }: Props): VNode {
         </a>
         <div class="navbar-end">
           <div class="navbar-item" style={{ paddingTop: 4, paddingBottom: 4 }}>
-            <LangSelector />
           </div>
         </div>
       </div>
diff --git a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
index 6fee600eb..f3cf80b92 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/SideBar.tsx
@@ -31,6 +31,7 @@ const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : undefined;
 
 interface Props {
   onLogout: () => void;
+  onShowSettings: () => void;
   mobile?: boolean;
   instance: string;
   admin?: boolean;
@@ -40,6 +41,7 @@ interface Props {
 export function Sidebar({
   mobile,
   instance,
+  onShowSettings,
   onLogout,
   admin,
   mimic,
@@ -78,21 +80,8 @@ export function Sidebar({
       <div class="menu is-menu-main">
         {instance ? (
           <Fragment>
-            <p class="menu-label">
-              <i18n.Translate>Instance</i18n.Translate>
-            </p>
             <ul class="menu-list">
-              <li>
-                <a href={"/update"} class="has-icon">
-                  <span class="icon">
-                    <i class="mdi mdi-square-edit-outline" />
-                  </span>
-                  <span class="menu-item-label">
-                    <i18n.Translate>Settings</i18n.Translate>
-                  </span>
-                </a>
-              </li>
-              <li>
+            <li>
                 <a href={"/orders"} class="has-icon">
                   <span class="icon">
                     <i class="mdi mdi-cash-register" />
@@ -132,6 +121,31 @@ export function Sidebar({
                   </span>
                 </a>
               </li>
+              {needKYC && (
+                <li>
+                  <a href={"/kyc"} class="has-icon">
+                    <span class="icon">
+                      <i class="mdi mdi-account-check" />
+                    </span>
+                    <span class="menu-item-label">KYC Status</span>
+                  </a>
+                </li>
+              )}
+            </ul>
+            <p class="menu-label">
+              <i18n.Translate>Configuration</i18n.Translate>
+            </p>
+            <ul class="menu-list">
+              <li>
+                <a href={"/update"} class="has-icon">
+                  <span class="icon">
+                    <i class="mdi mdi-square-edit-outline" />
+                  </span>
+                  <span class="menu-item-label">
+                    <i18n.Translate>Account</i18n.Translate>
+                  </span>
+                </a>
+              </li>
               <li>
                 <a href={"/reserves"} class="has-icon">
                   <span class="icon">
@@ -150,16 +164,6 @@ export function Sidebar({
                   </span>
                 </a>
               </li>
-              {needKYC && (
-                <li>
-                  <a href={"/kyc"} class="has-icon">
-                    <span class="icon">
-                      <i class="mdi mdi-account-check" />
-                    </span>
-                    <span class="menu-item-label">KYC Status</span>
-                  </a>
-                </li>
-              )}
             </ul>
           </Fragment>
         ) : undefined}
@@ -167,6 +171,18 @@ export function Sidebar({
           <i18n.Translate>Connection</i18n.Translate>
         </p>
         <ul class="menu-list">
+          <li>
+            <a class="has-icon is-state-info is-hoverable"
+              onClick={(): void => onShowSettings()}
+              >
+              <span class="icon">
+                <i class="mdi mdi-newspaper" />
+              </span>
+              <span class="menu-item-label">
+                <i18n.Translate>Settings</i18n.Translate>
+              </span>
+            </a>
+          </li>
           <li>
             <div>
               <span style={{ width: "3rem" }} class="icon">
diff --git a/packages/merchant-backoffice-ui/src/components/menu/index.tsx b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
index 2beaf6956..cdbae4ae0 100644
--- a/packages/merchant-backoffice-ui/src/components/menu/index.tsx
+++ b/packages/merchant-backoffice-ui/src/components/menu/index.tsx
@@ -75,6 +75,7 @@ interface MenuProps {
   instance: string;
   admin?: boolean;
   onLogout?: () => void;
+  onShowSettings: () => void;
   setInstanceName: (s: string) => void;
 }
 
@@ -93,6 +94,7 @@ function WithTitle({
 
 export function Menu({
   onLogout,
+  onShowSettings,
   title,
   instance,
   path,
@@ -121,6 +123,7 @@ export function Menu({
 
         {onLogout && (
           <Sidebar
+            onShowSettings={onShowSettings}
             onLogout={onLogout}
             admin={admin}
             mimic={mimic}
@@ -159,6 +162,7 @@ export function Menu({
 interface NotYetReadyAppMenuProps {
   title: string;
   onLogout?: () => void;
+  onShowSettings: () => void;
 }
 
 interface NotifProps {
@@ -199,6 +203,7 @@ export function NotificationCard({
 
 export function NotYetReadyAppMenu({
   onLogout,
+  onShowSettings,
   title,
 }: NotYetReadyAppMenuProps): VNode {
   const [mobileOpen, setMobileOpen] = useState(false);
@@ -217,7 +222,7 @@ export function NotYetReadyAppMenu({
         title={title}
       />
       {onLogout && (
-        <Sidebar onLogout={onLogout} instance="" mobile={mobileOpen} />
+        <Sidebar onShowSettings={onShowSettings} onLogout={onLogout} instance="" mobile={mobileOpen} />
       )}
     </div>
   );
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
index 56d9dda74..37770d273 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/orders/list/ListPage.tsx
@@ -164,7 +164,7 @@ export function ListPage({
             <div class="field has-addons">
               {jumpToDate && (
                 <div class="control">
-                  <a class="button" onClick={() => onSelectDate(undefined)}>
+                  <a class="button is-fullwidth" onClick={() => onSelectDate(undefined)}>
                     <span
                       class="icon"
                       data-tooltip={i18n.str`clear date filter`}
@@ -191,7 +191,7 @@ export function ListPage({
               <div class="control">
                 <span class="has-tooltip-left" data-tooltip={dateTooltip}>
                   <a
-                    class="button"
+                    class="button  is-fullwidth"
                     onClick={() => {
                       setPickDate(true);
                     }}
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
index 4dde202c4..e20b9bc27 100644
--- a/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
+++ b/packages/merchant-backoffice-ui/src/paths/instance/templates/create/CreatePage.tsx
@@ -85,34 +85,34 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
     template_contract: !state.template_contract
       ? undefined
       : undefinedIfEmpty({
-          amount: !state.template_contract?.amount
-            ? undefined
-            : !parsedPrice
+        amount: !state.template_contract?.amount
+          ? undefined
+          : !parsedPrice
             ? i18n.str`not valid`
             : Amounts.isZero(parsedPrice)
-            ? i18n.str`must be greater than 0`
-            : undefined,
-          minimum_age:
-            state.template_contract.minimum_age < 0
-              ? i18n.str`should be greater that 0`
+              ? i18n.str`must be greater than 0`
               : undefined,
-          pay_duration: !state.template_contract.pay_duration
-            ? i18n.str`can't be empty`
-            : state.template_contract.pay_duration.d_us === "forever"
+        minimum_age:
+          state.template_contract.minimum_age < 0
+            ? i18n.str`should be greater that 0`
+            : undefined,
+        pay_duration: !state.template_contract.pay_duration
+          ? i18n.str`can't be empty`
+          : state.template_contract.pay_duration.d_us === "forever"
             ? undefined
             : state.template_contract.pay_duration.d_us < 1000 * 1000 //less than one second
-            ? i18n.str`to short`
-            : undefined,
-        } as Partial<MerchantTemplateContractDetails>),
+              ? i18n.str`to short`
+              : undefined,
+      } as Partial<MerchantTemplateContractDetails>),
     pos_key: !state.pos_key
       ? !state.pos_algorithm
         ? undefined
         : i18n.str`required`
       : !isBase32RFC3548Charset(state.pos_key)
-      ? i18n.str`just letters and numbers from 2 to 7`
-      : state.pos_key.length !== 32
-      ? i18n.str`size of the key should be 32`
-      : undefined,
+        ? i18n.str`just letters and numbers from 2 to 7`
+        : state.pos_key.length !== 32
+          ? i18n.str`size of the key should be 32`
+          : undefined,
   };
 
   const hasErrors = Object.keys(errors).some(
@@ -139,7 +139,7 @@ export function CreatePage({ onCreate, onBack }: Props): VNode {
             >
               <InputWithAddon<Entity>
                 name="template_id"
-                addonBefore={`${backend.url}/instances/templates/`}
+                help={`${backend.url}/instances/templates/${state.template_id ?? ""}`}
                 label={i18n.str`Identifier`}
                 tooltip={i18n.str`Name of the template in URLs.`}
               />
diff --git a/packages/merchant-backoffice-ui/src/paths/settings/index.tsx b/packages/merchant-backoffice-ui/src/paths/settings/index.tsx
new file mode 100644
index 000000000..1d0b4128a
--- /dev/null
+++ b/packages/merchant-backoffice-ui/src/paths/settings/index.tsx
@@ -0,0 +1,15 @@
+import { VNode, h } from "preact";
+
+export function Settings(): VNode {
+  return <div>
+    <section class="section is-main-section">
+      <div class="columns">
+        <div class="column" />
+        <div class="column is-four-fifths">
+          settings view
+        </div>
+        <div class="column" />
+      </div>
+    </section>
+  </div>
+}
\ No newline at end of file
-- 
cgit v1.2.3

