gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] branch master updated: refactor navigation,


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated: refactor navigation, part 2
Date: Mon, 15 Mar 2021 14:04:59 +0100

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

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

The following commit(s) were added to refs/heads/master by this push:
     new 9ee8200  refactor navigation, part 2
9ee8200 is described below

commit 9ee8200672c49b91a6ee3ad3caf8c109d8c98d18
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Wed Mar 10 14:27:02 2021 -0300

    refactor navigation, part 2
---
 CHANGELOG.md                                       |  34 ++++-
 .../frontend/src/components/exception/loading.tsx  |   5 +
 .../{auth/index.tsx => exception/login.tsx}        |   0
 .../frontend/src/components/form/InputBoolean.tsx  |  80 +++++++++++
 packages/frontend/src/components/menu/SideBar.tsx  |  18 ++-
 packages/frontend/src/components/menu/index.tsx    | 148 ++++++++++++---------
 packages/frontend/src/hooks/backend.ts             |  94 ++++++-------
 packages/frontend/src/messages/en.po               |  35 ++++-
 .../src/routes/instance/orders/list/Table.tsx      |  13 +-
 .../src/routes/instance/orders/list/index.tsx      |  33 ++++-
 .../src/routes/instance/products/list/Table.tsx    |   2 +-
 .../src/routes/instance/tips/list/Table.tsx        |   2 +-
 .../src/routes/instance/tips/list/index.tsx        |   4 +-
 .../src/routes/instance/transfers/list/Table.tsx   |   2 +-
 packages/frontend/src/routes/login/index.tsx       |   2 +-
 packages/frontend/src/scss/main.scss               |   9 ++
 16 files changed, 343 insertions(+), 138 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 28448f2..a67e119 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,10 +5,13 @@ The format is based on [Keep a 
Changelog](https://keepachangelog.com/en/1.0.0/),
 and this project adheres to [Semantic 
Versioning](https://semver.org/spec/v2.0.0.html).
 
 ## [Future work]
+ - notifications should tale place between title and content, and not disapear 
(#6788)
+ - complete product list information (#6792)
+ - complete order list information (#6793)
+ - gettext templates should be generated from the source code (#6791)
+
  - date format (error handling)
- - connection errors
  - allow point separator for amounts
- - prevent letters to be input in numbers
  - red color when input is invalid (onchange)
  - validate everything using onChange
  - feature: input as date format
@@ -30,8 +33,35 @@ and this project adheres to [Semantic 
Versioning](https://semver.org/spec/v2.0.0
 
  - create default instance if it is not already
  
+ - confirmation page when creating instances
  
+
+main action => refund
+exchange errors
+existing refund
+
+new refund, amount, < allow
+
+product
+increase total
+increase lost
+changes taxes
+changes prices
+update descripcion
+
+deletiing product
+
+
 ## [Unreleased]
+ - change the admin title to "instances" if we are listing the instances and 
"settings: $ID" on updating instances (#6790)
+ - update title with: Taler Backoffice: $PAGE_TITLE (#6790)
+ - paths should be /orders instead of /o (same others)
+ - if there is enough space for tables in mobile, make the scrollables (#6789)
+
+## [0.0.4] - 2021-03-11
+ - prevent letters to be input in numbers
+ - instance id in instance list should be clickable
+ - edit button to go to instance settings
  - add order section
  - add product section
  - add tips section
diff --git a/packages/frontend/src/components/exception/loading.tsx 
b/packages/frontend/src/components/exception/loading.tsx
new file mode 100644
index 0000000..0cd56cb
--- /dev/null
+++ b/packages/frontend/src/components/exception/loading.tsx
@@ -0,0 +1,5 @@
+import { h, VNode } from "preact";
+
+export function Loading():VNode {
+  return <div>loading...</div>
+}
\ No newline at end of file
diff --git a/packages/frontend/src/components/auth/index.tsx 
b/packages/frontend/src/components/exception/login.tsx
similarity index 100%
rename from packages/frontend/src/components/auth/index.tsx
rename to packages/frontend/src/components/exception/login.tsx
diff --git a/packages/frontend/src/components/form/InputBoolean.tsx 
b/packages/frontend/src/components/form/InputBoolean.tsx
new file mode 100644
index 0000000..3a4e36b
--- /dev/null
+++ b/packages/frontend/src/components/form/InputBoolean.tsx
@@ -0,0 +1,80 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+import { h, VNode } from "preact";
+import { Message, useMessage } from "preact-messages";
+import { useField } from "./Field";
+
+interface Props<T> {
+  name: T;
+  readonly?: boolean;
+  expand?: boolean;
+  threeState?: boolean;
+  toBoolean?: (v?: any) => boolean | undefined;
+  fromBoolean?: (s: boolean | undefined) => any;
+}
+
+const defaultToBoolean = (f?: any): boolean | undefined => f || ''
+const defaultFromBoolean = (v: boolean | undefined): any => v as any
+
+
+
+export function InputBoolean<T>({ name, readonly, threeState, expand, 
fromBoolean = defaultFromBoolean, toBoolean = defaultToBoolean }: Props<keyof 
T>): VNode {
+  const { error, value, onChange } = useField<T>(name);
+
+  const placeholder = useMessage(`fields.instance.${name}.placeholder`);
+  const tooltip = useMessage(`fields.instance.${name}.tooltip`);
+
+  const onCheckboxClick = (): void => {
+    const c = toBoolean(value)
+    if (c === false && threeState) return onChange(undefined as any)
+    return onChange(fromBoolean(!c))
+  }
+
+  return <div class="field is-horizontal">
+    <div class="field-label is-normal">
+      <label class="label">
+        <Message id={`fields.instance.${name}.label`} />
+        {tooltip && <span class="icon has-tooltip-right" 
data-tooltip={tooltip}>
+          <i class="mdi mdi-information" />
+        </span>}
+      </label>
+    </div>
+    <div class="field-body is-flex-grow-3">
+      <div class="field">
+        <p class={expand ? "control is-expanded" : "control"}>
+          <label class="b-checkbox checkbox">
+            <input type="checkbox" class={toBoolean(value) === undefined ? 
"is-indeterminate" : ""}
+              checked={toBoolean(value)}
+              placeholder={placeholder} readonly={readonly}
+              name={String(name)} disabled={readonly}
+              onChange={onCheckboxClick} />
+
+            <span class="check" />
+          </label>
+          <Message id={`fields.instance.${name}.help`}> </Message>
+        </p>
+        {error ? <p class="help is-danger">
+          <Message id={`validation.${error.type}`} 
fields={error.params}>{error.message} </Message>
+        </p> : null}
+      </div>
+    </div>
+  </div>;
+}
diff --git a/packages/frontend/src/components/menu/SideBar.tsx 
b/packages/frontend/src/components/menu/SideBar.tsx
index e534c77..919d547 100644
--- a/packages/frontend/src/components/menu/SideBar.tsx
+++ b/packages/frontend/src/components/menu/SideBar.tsx
@@ -70,25 +70,25 @@ export function Sidebar({ mobile, instance, onLogout }: 
Props): VNode {
           </Fragment>}
           <li>
             <a href="/o" class="has-icon">
-              <span class="icon"><i class="mdi mdi-square-edit-outline" 
/></span>
+              <span class="icon"><i class="mdi mdi-cash-register" /></span>
               <span class="menu-item-label">Orders</span>
             </a>
           </li>
           <li>
             <a href="/p" class="has-icon">
-              <span class="icon"><i class="mdi mdi-account-circle" /></span>
+              <span class="icon"><i class="mdi mdi-shopping" /></span>
               <span class="menu-item-label">Products</span>
             </a>
           </li>
           <li>
             <a href="/t" class="has-icon">
-              <span class="icon"><i class="mdi mdi-account-circle" /></span>
+              <span class="icon"><i class="mdi mdi-bank" /></span>
               <span class="menu-item-label">Transfers</span>
             </a>
           </li>
           <li>
             <a href="/r" class="has-icon">
-              <span class="icon"><i class="mdi mdi-account-circle" /></span>
+              <span class="icon"><i class="mdi mdi-cash" /></span>
               <span class="menu-item-label">Tips</span>
             </a>
           </li>
@@ -105,7 +105,15 @@ export function Sidebar({ mobile, instance, onLogout }: 
Props): VNode {
             <div >
               <span style={{ width: '3rem' }} class="icon"><i class="mdi 
mdi-web" /></span>
               <span class="menu-item-label">
-                {new URL(backend.url).hostname} / {!instance ? "default" : 
instance}
+                {new URL(backend.url).hostname}
+              </span>
+            </div>
+          </li>
+          <li>
+            <div >
+              <span style={{ width: '3rem' }} class="icon">ID</span>
+              <span class="menu-item-label">
+                {!instance ? "default" : instance}
               </span>
             </div>
           </li>
diff --git a/packages/frontend/src/components/menu/index.tsx 
b/packages/frontend/src/components/menu/index.tsx
index b7d0874..f3fe639 100644
--- a/packages/frontend/src/components/menu/index.tsx
+++ b/packages/frontend/src/components/menu/index.tsx
@@ -14,66 +14,88 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { h, VNode } from "preact";
-import { useEffect, useState } from "preact/hooks";
-import { AdminPaths } from "../../AdminRoutes";
-import { InstancePaths } from "../../InstanceRoutes";
-import { NavigationBar } from "./NavigationBar";
-import { Sidebar } from "./SideBar";
-import Match from 'preact-router/match';
-
-interface Props {
-  title?: string;
-  instance?: string;
-  onLogout?: () => void;
-}
-
-function getInstanceTitle(path: string, id: string): string {
-
-  switch (path) {
-    case InstancePaths.details: return `${id}`
-    case InstancePaths.update: return `${id}: Settings`
-    case InstancePaths.order_list: return `${id}: Orders`
-    case InstancePaths.order_new: return `${id}: New order`
-    case InstancePaths.order_update: return `${id}: Update 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.tips_list: return `${id}: Tips`
-    case InstancePaths.tips_new: return `${id}: New tip`
-    case InstancePaths.tips_update: return `${id}: Update tip`
-    case InstancePaths.transfers_list: return `${id}: Transfers`
-    case InstancePaths.transfers_new: return `${id}: New Transfer`
-    default: return '';
-  }
-}
-
-const INSTANCE_ID_LOOKUP = /^\/instance\/([^/]*)\//
-function getAdminTitle(path: string) {
-  if (path === AdminPaths.new_instance) return `New instance`
-  if (path === AdminPaths.list_instances) return `Instances`
-  const match = INSTANCE_ID_LOOKUP.exec(path)
-  if (match && match[1]) return 
getInstanceTitle(path.replace(INSTANCE_ID_LOOKUP, '/'), match[1]);
-  return getInstanceTitle(path, 'default')
-}
-
-export function Menu({ onLogout, title, instance }: Props): VNode {
-  const [mobileOpen, setMobileOpen] = useState(false)
-
-  return <Match>{({ path }: any) => {
-    const titleWithSubtitle = title ? title : (instance ? 
getInstanceTitle(path, instance) : getAdminTitle(path))
-
-    useEffect(() => {
-      document.title = 'Taler Backoffice: ' + titleWithSubtitle
-    }, [titleWithSubtitle])
-
-    return (
-      <div class={mobileOpen ? "has-aside-mobile-expanded" : ""} onClick={() 
=> setMobileOpen(false)}>
-        <NavigationBar onMobileMenu={() => setMobileOpen(!mobileOpen)} 
title={titleWithSubtitle} />
-        {onLogout && <Sidebar onLogout={onLogout} instance={instance} 
mobile={mobileOpen} />}
-      </div>
-    )
-  }}</Match>
-
-
-}
\ No newline at end of file
+ import { h, VNode } from "preact";
+ import { useEffect, useState } from "preact/hooks";
+ import { AdminPaths } from "../../AdminRoutes";
+ import { InstancePaths } from "../../InstanceRoutes";
+ import { NavigationBar } from "./NavigationBar";
+ import { Sidebar } from "./SideBar";
+ import Match from 'preact-router/match';
+ 
+ 
+ function getInstanceTitle(path: string, id: string): string {
+ 
+   switch (path) {
+     case InstancePaths.details: return `${id}`
+     case InstancePaths.update: return `${id}: Settings`
+     case InstancePaths.order_list: return `${id}: Orders`
+     case InstancePaths.order_new: return `${id}: New order`
+     case InstancePaths.order_update: return `${id}: Update 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.tips_list: return `${id}: Tips`
+     case InstancePaths.tips_new: return `${id}: New tip`
+     case InstancePaths.tips_update: return `${id}: Update tip`
+     case InstancePaths.transfers_list: return `${id}: Transfers`
+     case InstancePaths.transfers_new: return `${id}: New Transfer`
+     default: return '';
+   }
+ }
+ 
+ const INSTANCE_ID_LOOKUP = /^\/instance\/([^/]*)\//
+ function getAdminTitle(path: string) {
+   if (path === AdminPaths.new_instance) return `New instance`
+   if (path === AdminPaths.list_instances) return `Instances`
+   const match = INSTANCE_ID_LOOKUP.exec(path)
+   if (match && match[1]) return 
getInstanceTitle(path.replace(INSTANCE_ID_LOOKUP, '/'), match[1]);
+   return getInstanceTitle(path, 'default')
+ }
+ 
+ interface MenuProps {
+   title?: string;
+   instance: string;
+   admin?: boolean;
+   onLogout?: () => void;
+ }
+ 
+ 
+ export function Menu({ onLogout, title, instance, admin }: MenuProps): VNode {
+   const [mobileOpen, setMobileOpen] = useState(false)
+ 
+   return <Match>{({ path }: any) => {
+     const titleWithSubtitle = title ? title : (!admin ? 
getInstanceTitle(path, instance) : getAdminTitle(path))
+ 
+     useEffect(() => {
+       document.title = 'Taler Backoffice: ' + titleWithSubtitle
+     }, [titleWithSubtitle])
+ 
+     return (
+       <div class={mobileOpen ? "has-aside-mobile-expanded" : ""} onClick={() 
=> setMobileOpen(false)}>
+         <NavigationBar onMobileMenu={() => setMobileOpen(!mobileOpen)} 
title={titleWithSubtitle} />
+         {onLogout && <Sidebar onLogout={onLogout} admin={admin} 
instance={instance} mobile={mobileOpen} />}
+       </div>
+     )
+   }}</Match>
+ 
+ }
+ 
+ interface NotYetReadyAppMenuProps {
+   title: string;
+   onLogout?: () => void;
+ }
+ 
+ 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>
+ 
+ }
+ 
\ No newline at end of file
diff --git a/packages/frontend/src/hooks/backend.ts 
b/packages/frontend/src/hooks/backend.ts
index f5ed418..20e056a 100644
--- a/packages/frontend/src/hooks/backend.ts
+++ b/packages/frontend/src/hooks/backend.ts
@@ -19,12 +19,15 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import useSWR, { mutate } from 'swr';
+import useSWR, { mutate, cache } from 'swr';
 import axios from 'axios'
 import { MerchantBackend } from '../declaration';
-import { useContext } from 'preact/hooks';
 import { useBackendContext, useInstanceContext } from '../context/backend';
 
+function mutateAll(re: RegExp) {
+  cache.keys().filter(key => re.test(key)).forEach(key => mutate(key, null))
+}
+
 type HttpResponse<T> = HttpResponseOk<T> | HttpResponseError;
 
 interface HttpResponseOk<T> {
@@ -90,6 +93,12 @@ function fetcher(url: string, token: string, backend: 
string) {
   return request(`${backend}${url}`, { token })
 }
 
+type YesOrNo = 'yes' | 'no';
+
+function orderFetcher(url: string, token: string, backend: string, paid?: 
YesOrNo, refunded?: YesOrNo, wired?: YesOrNo) {
+  return request(`${backend}${url}`, { token, params: { paid, refunded, wired 
} })
+}
+
 function transferFetcher(url: string, token: string, backend: string) {
   return request(`${backend}${url}`, { token, params: { payto_uri: '' } })
 }
@@ -108,7 +117,7 @@ export function useAdminMutateAPI(): AdminMutateAPI {
       data: instance
     })
 
-    mutate(['/private/instances', token, url], null)
+    mutateAll(/@"\/private\/instances"@/)
   }
 
   const deleteInstance = async (id: string): Promise<void> => {
@@ -117,7 +126,7 @@ export function useAdminMutateAPI(): AdminMutateAPI {
       token,
     })
 
-    mutate(['/private/instances', token, url], null)
+    mutateAll(/@"\/private\/instances"@/)
   }
 
   return { createInstance, deleteInstance }
@@ -138,8 +147,8 @@ export function useProductMutateAPI(): ProductMutateAPI {
   const { url, token } = !admin ? {
     url: baseUrl, token: adminToken
   } : {
-      url: `${baseUrl}/instances/${id}`, token: instanceToken
-    }
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
 
   const createProduct = async (data: 
MerchantBackend.Products.ProductAddDetail): Promise<void> => {
@@ -149,8 +158,7 @@ export function useProductMutateAPI(): ProductMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/products', adminToken, baseUrl], null)
-    mutate([`/private/products`, token, url], null)
+    mutateAll(/@"\/private\/products"@/)
   }
 
   const updateProduct = async (productId: string, data: 
MerchantBackend.Products.ProductPatchDetail): Promise<void> => {
@@ -160,8 +168,7 @@ export function useProductMutateAPI(): ProductMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/products', adminToken, baseUrl], null)
-    mutate([`/private/products`, token, url], null)
+    mutateAll(/@"\/private\/products"@/)
   }
 
   const deleteProduct = async (productId: string): Promise<void> => {
@@ -170,8 +177,7 @@ export function useProductMutateAPI(): ProductMutateAPI {
       token,
     })
 
-    if (adminToken) mutate(['/private/products', adminToken, baseUrl], null)
-    mutate([`/private/products`, token, url], null)
+    mutateAll(/@"\/private\/products"@/)
   }
 
   const lockProduct = async (productId: string, data: 
MerchantBackend.Products.LockRequest): Promise<void> => {
@@ -181,8 +187,7 @@ export function useProductMutateAPI(): ProductMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/products', adminToken, baseUrl], null)
-    mutate([`/private/products`, token, url], null)
+    mutateAll(/@"\/private\/products"@/)
   }
 
   return { createProduct, updateProduct, deleteProduct, lockProduct }
@@ -202,8 +207,8 @@ export function useOrderMutateAPI(): OrderMutateAPI {
   const { url, token } = !admin ? {
     url: baseUrl, token: adminToken
   } : {
-      url: `${baseUrl}/instances/${id}`, token: instanceToken
-    }
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
   const createOrder = async (data: MerchantBackend.Orders.PostOrderRequest): 
Promise<MerchantBackend.Orders.PostOrderResponse> => {
     const res = await request(`${url}/private/orders`, {
@@ -212,8 +217,7 @@ export function useOrderMutateAPI(): OrderMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/orders', adminToken, baseUrl], null)
-    mutate([`/private/orders`, token, url], null)
+    mutateAll(/@"\/private\/orders"@/)
     return res
   }
   const forgetOrder = async (orderId: string, data: 
MerchantBackend.Orders.ForgetRequest): Promise<void> => {
@@ -223,8 +227,7 @@ export function useOrderMutateAPI(): OrderMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/orders', adminToken, baseUrl], null)
-    mutate([`/private/orders`, token, url], null)
+    mutateAll(/@"\/private\/orders"@/)
   }
   const deleteOrder = async (orderId: string): Promise<void> => {
     await request(`${url}/private/orders/${orderId}`, {
@@ -232,8 +235,7 @@ export function useOrderMutateAPI(): OrderMutateAPI {
       token
     })
 
-    if (adminToken) mutate(['/private/orders', adminToken, baseUrl], null)
-    mutate([`/private/orders`, token, url], null)
+    mutateAll(/@"\/private\/orders"@/)
   }
   return { createOrder, forgetOrder, deleteOrder }
 }
@@ -249,8 +251,8 @@ export function useTransferMutateAPI(): TransferMutateAPI {
   const { url, token } = !admin ? {
     url: baseUrl, token: adminToken
   } : {
-      url: `${baseUrl}/instances/${id}`, token: instanceToken
-    }
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
   const informTransfer = async (data: 
MerchantBackend.Transfers.TransferInformation): 
Promise<MerchantBackend.Transfers.MerchantTrackTransferResponse> => {
     const res = await request(`${url}/private/transfers`, {
@@ -259,8 +261,7 @@ export function useTransferMutateAPI(): TransferMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/transfers', adminToken, baseUrl], null)
-    mutate([`/private/transfers`, token, url], null)
+    mutateAll(/@"\/private\/transfers"@/)
     return res
   }
 
@@ -281,8 +282,8 @@ export function useTipsMutateAPI(): TipsMutateAPI {
   const { url, token } = !admin ? {
     url: baseUrl, token: adminToken
   } : {
-      url: `${baseUrl}/instances/${id}`, token: instanceToken
-    }
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
   //reserves
   const createReserve = async (data: 
MerchantBackend.Tips.ReserveCreateRequest): 
Promise<MerchantBackend.Tips.ReserveCreateConfirmation> => {
@@ -292,8 +293,7 @@ export function useTipsMutateAPI(): TipsMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/reserves', adminToken, baseUrl], null)
-    mutate([`/private/reserves`, token, url], null)
+    mutateAll(/@"\/private\/reserves"@/)
     return res
   }
 
@@ -304,8 +304,7 @@ export function useTipsMutateAPI(): TipsMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/reserves', adminToken, baseUrl], null)
-    mutate([`/private/reserves`, token, url], null)
+    mutateAll(/@"\/private\/reserves"@/)
     return res
   }
 
@@ -316,8 +315,7 @@ export function useTipsMutateAPI(): TipsMutateAPI {
       data
     })
 
-    if (adminToken) mutate(['/private/reserves', adminToken, baseUrl], null)
-    mutate([`/private/reserves`, token, url], null)
+    mutateAll(/@"\/private\/reserves"@/)
     return res
   }
 
@@ -327,8 +325,7 @@ export function useTipsMutateAPI(): TipsMutateAPI {
       token,
     })
 
-    if (adminToken) mutate(['/private/reserves', adminToken, baseUrl], null)
-    mutate([`/private/reserves`, token, url], null)
+    mutateAll(/@"\/private\/reserves"@/)
   }
 
 
@@ -423,25 +420,30 @@ export function useInstanceProducts(): 
HttpResponse<MerchantBackend.Products.Inv
   const { url, token } = !admin ? {
     url: baseUrl, token: baseToken
   } : {
-      url: `${baseUrl}/instances/${id}`, token: instanceToken
-    }
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
   const { data, error } = 
useSWR<MerchantBackend.Products.InventorySummaryResponse, 
SwrError>([`/private/products`, token, url], fetcher)
 
   return { data, unauthorized: error?.status === 401, notfound: error?.status 
=== 404, error }
 }
 
-export function useInstanceOrders(): 
HttpResponse<MerchantBackend.Orders.OrderHistory> {
+export interface InstanceOrderFilter {
+  paid?: YesOrNo;
+  refunded?: YesOrNo;
+  wired?: YesOrNo;
+}
+export function useInstanceOrders(args?: InstanceOrderFilter): 
HttpResponse<MerchantBackend.Orders.OrderHistory> {
   const { url: baseUrl, token: baseToken } = useBackendContext();
   const { token: instanceToken, id, admin } = useInstanceContext();
 
   const { url, token } = !admin ? {
     url: baseUrl, token: baseToken
   } : {
-      url: `${baseUrl}/instances/${id}`, token: instanceToken
-    }
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
-  const { data, error } = useSWR<MerchantBackend.Orders.OrderHistory, 
SwrError>([`/private/orders`, token, url], fetcher)
+  const { data, error } = useSWR<MerchantBackend.Orders.OrderHistory, 
SwrError>([`/private/orders`, token, url, args?.paid, args?.refunded, 
args?.wired], orderFetcher)
 
   return { data, unauthorized: error?.status === 401, notfound: error?.status 
=== 404, error }
 }
@@ -453,8 +455,8 @@ export function useInstanceTips(): 
HttpResponse<MerchantBackend.Tips.TippingRese
   const { url, token } = !admin ? {
     url: baseUrl, token: baseToken
   } : {
-      url: `${baseUrl}/instances/${id}`, token: instanceToken
-    }
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
   const { data, error } = useSWR<MerchantBackend.Tips.TippingReserveStatus, 
SwrError>([`/private/reserves`, token, url], fetcher)
 
@@ -468,8 +470,8 @@ export function useInstanceTransfers(): 
HttpResponse<MerchantBackend.Transfers.T
   const { url, token } = !admin ? {
     url: baseUrl, token: baseToken
   } : {
-      url: `${baseUrl}/instances/${id}`, token: instanceToken
-    }
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
   const { data, error } = useSWR<MerchantBackend.Transfers.TransferList, 
SwrError>([`/private/transfers`, token, url], transferFetcher)
 
diff --git a/packages/frontend/src/messages/en.po 
b/packages/frontend/src/messages/en.po
index d12bbaf..c22199a 100644
--- a/packages/frontend/src/messages/en.po
+++ b/packages/frontend/src/messages/en.po
@@ -58,8 +58,8 @@ msgstr "Use this token to secure an instance with a password"
 msgid "fields.instance.payto_uris.label"
 msgstr "Account address"
 
-msgid "fields.instance.payto_uris.help"
-msgstr "x-taler-bank/bank.taler:5882/blogger"
+#  msgid "fields.instance.payto_uris.help"
+#  msgstr "x-taler-bank/bank.taler:5882/blogger"
 
 msgid "fields.instance.default_max_deposit_fee.label"
 msgstr "Max deposit fee label"
@@ -104,7 +104,7 @@ msgid "fields.instance.address.building_number.label"
 msgstr "Building Number"
 
 msgid "fields.instance.address.address_lines.label"
-msgstr "Adress Line"
+msgstr "Address"
 
 msgid "fields.instance.jurisdiction.label"
 msgstr "Jurisdiction"
@@ -137,7 +137,7 @@ msgid "fields.instance.jurisdiction.building_number.label"
 msgstr "Building Number"
 
 msgid "fields.instance.jurisdiction.address_lines.label"
-msgstr "Adress Line"
+msgstr "Address"
 
 msgid "fields.instance.default_pay_delay.label"
 msgstr "Pay delay"
@@ -250,3 +250,30 @@ msgstr "Exchange Initial Amount"
 
 msgid "fields.tips.merchant_initial_amount.label"
 msgstr "Merchant Initial Amount"
+
+msgid "fields.instance.paid.placeholder"
+msgstr ""
+
+msgid "fields.instance.paid.tooltip"
+msgstr "three state boolean"
+
+msgid "fields.instance.paid.label"
+msgstr "Paid"
+
+msgid "fields.instance.refunded.placeholder"
+msgstr ""
+
+#  msgid "fields.instance.refunded.tooltip"
+#  msgstr ""
+
+msgid "fields.instance.refunded.label"
+msgstr "Refunded"
+
+msgid "fields.instance.wired.placeholder"
+msgstr ""
+
+#  msgid "fields.instance.wired.tooltip"
+#  msgstr ""
+
+msgid "fields.instance.wired.label"
+msgstr "Wired"
\ No newline at end of file
diff --git a/packages/frontend/src/routes/instance/orders/list/Table.tsx 
b/packages/frontend/src/routes/instance/orders/list/Table.tsx
index cb7991f..f96f683 100644
--- a/packages/frontend/src/routes/instance/orders/list/Table.tsx
+++ b/packages/frontend/src/routes/instance/orders/list/Table.tsx
@@ -19,15 +19,14 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { h, VNode } from "preact"
+import { Fragment, h, VNode } from "preact"
 import { Message } from "preact-messages"
-import { StateUpdater, useEffect, useState } from "preact/hooks"
+import { StateUpdater, useCallback, useEffect, useRef, useState } from 
"preact/hooks"
 import { MerchantBackend, WidthId } from "../../../../declaration"
 import { Actions, buildActions } from "../../../../utils/table";
 
 type Entity = MerchantBackend.Orders.OrderHistoryEntry & { id: string }
-
-interface Props {
+  interface Props {
   instances: Entity[];
   onUpdate: (id: string) => void;
   onDelete: (id: Entity) => void;
@@ -56,7 +55,7 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected }:
 
   return <div class="card has-table">
     <header class="card-header">
-      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-account-multiple" /></span><Message id="Orders" /></p>
+      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-cash-register" /></span><Message id="Orders" /></p>
 
       <div class="card-header-icon" aria-label="more options">
 
@@ -85,6 +84,8 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected }:
       </div>
     </div>
   </div>
+
+
 }
 interface TableProps {
   rowSelection: string[];
@@ -127,7 +128,7 @@ function Table({ rowSelection, rowSelectionHandler, 
instances, onUpdate, onDelet
             <td onClick={(): void => onUpdate(i.id)} style={{ cursor: 
'pointer' }} >{i.amount}</td>
             <td onClick={(): void => onUpdate(i.id)} style={{ cursor: 
'pointer' }} >{i.summary}</td>
             <td onClick={(): void => onUpdate(i.id)} style={{ cursor: 
'pointer' }} >{i.paid}</td>
-            <td class="is-actions-cell">
+            <td class="is-actions-cell right-sticky">
               <div class="buttons is-right">
                 <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onDelete(i)}>
                   <span class="icon"><i class="mdi mdi-trash-can" /></span>
diff --git a/packages/frontend/src/routes/instance/orders/list/index.tsx 
b/packages/frontend/src/routes/instance/orders/list/index.tsx
index d1cff4c..13ea48e 100644
--- a/packages/frontend/src/routes/instance/orders/list/index.tsx
+++ b/packages/frontend/src/routes/instance/orders/list/index.tsx
@@ -1,27 +1,48 @@
 import { h, VNode } from 'preact';
+import { useState } from 'preact/hooks';
 import { useConfigContext } from '../../../../context/backend';
 import { MerchantBackend } from '../../../../declaration';
-import { SwrError, useInstanceOrders, useOrderMutateAPI, useProductMutateAPI } 
from '../../../../hooks/backend';
+import { InstanceOrderFilter, SwrError, useInstanceOrders, useOrderMutateAPI, 
useProductMutateAPI } from '../../../../hooks/backend';
 import { CardTable } from './Table';
+import { FormProvider, FormErrors } from "../../../../components/form/Field"
+import { InputBoolean } from "../../../../components/form/InputBoolean";
 
 interface Props {
   onUnauthorized: () => VNode;
   onLoadError: (e: SwrError) => VNode;
   onCreate: () => void;
 }
+
+const fromBooleanToYesAndNo = {
+  fromBoolean: (b?: boolean) => b === true ? 'yes' : (b === false ? 'no' : 
undefined),
+  toBoolean: (b: string) => b === 'yes' ? true : (b === 'no' ? false : 
undefined)
+}
+
 export default function ({ onUnauthorized, onLoadError, onCreate }: Props): 
VNode {
-  const result = useInstanceOrders()
+  const [filter, setFilter] = useState<InstanceOrderFilter>({})
+  const result = useInstanceOrders(filter)
   const { createOrder, deleteOrder } = useOrderMutateAPI()
   const { currency } = useConfigContext()
+
+  let instances: (MerchantBackend.Orders.OrderHistoryEntry & {id: string})[];
+  
   if (!result.data) {
     if (result.unauthorized) return onUnauthorized()
     if (result.error) return onLoadError(result.error)
-    return <div>
-      loading ....
-    </div>
+    //if loading asume empty list
+    instances = []
+  } else {
+    instances = result.data.orders.map(o => ({ ...o, id: o.order_id }))
   }
+
   return <section class="section is-main-section">
-    <CardTable instances={result.data.orders.map(o => ({ ...o, id: o.order_id 
}))}
+    <FormProvider<InstanceOrderFilter> errors={{}} object={filter} 
valueHandler={(e) => setFilter(e as any)} >
+      <InputBoolean<InstanceOrderFilter> name="paid" threeState  
{...fromBooleanToYesAndNo} />
+      <InputBoolean<InstanceOrderFilter> name="refunded" 
{...fromBooleanToYesAndNo} />
+      <InputBoolean<InstanceOrderFilter> name="wired" 
{...fromBooleanToYesAndNo} />
+    </FormProvider>
+
+    <CardTable instances={instances}
       onCreate={() => createOrder({
         order: {
           amount: `${currency}:${Math.floor(Math.random() * 20 + 1)}`,
diff --git a/packages/frontend/src/routes/instance/products/list/Table.tsx 
b/packages/frontend/src/routes/instance/products/list/Table.tsx
index ab3795b..a3ea4aa 100644
--- a/packages/frontend/src/routes/instance/products/list/Table.tsx
+++ b/packages/frontend/src/routes/instance/products/list/Table.tsx
@@ -56,7 +56,7 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected }:
 
   return <div class="card has-table">
     <header class="card-header">
-      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-account-multiple" /></span><Message id="Products" /></p>
+      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-shopping" /></span><Message id="Products" /></p>
 
       <div class="card-header-icon" aria-label="more options">
 
diff --git a/packages/frontend/src/routes/instance/tips/list/Table.tsx 
b/packages/frontend/src/routes/instance/tips/list/Table.tsx
index bd818fd..5e1aed7 100644
--- a/packages/frontend/src/routes/instance/tips/list/Table.tsx
+++ b/packages/frontend/src/routes/instance/tips/list/Table.tsx
@@ -56,7 +56,7 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected }:
 
   return <div class="card has-table">
     <header class="card-header">
-      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-account-multiple" /></span><Message id="Tips" /></p>
+      <p class="card-header-title"><span class="icon"><i class="mdi mdi-cash" 
/></span><Message id="Tips" /></p>
 
       <div class="card-header-icon" aria-label="more options">
 
diff --git a/packages/frontend/src/routes/instance/tips/list/index.tsx 
b/packages/frontend/src/routes/instance/tips/list/index.tsx
index 9c7ea6d..c68f7f9 100644
--- a/packages/frontend/src/routes/instance/tips/list/index.tsx
+++ b/packages/frontend/src/routes/instance/tips/list/index.tsx
@@ -23,12 +23,12 @@ export default function ({ onUnauthorized, onLoadError }: 
Props): VNode {
     <CardTable instances={result.data.reserves.filter(r => r.active).map(o => 
({ ...o, id: o.reserve_pub }))}
       onCreate={() => createReserve({
         // explode with basic
-        wire_method: 'x-taler-bank',
+        wire_method: 'x-taler-ban',
         initial_balance: `${currency}:${Math.floor(Math.random() * 20 + 1)}`,
         //explode with 1
         // hangs with /asd/asd/
         // http://localhost:8081/
-        exchange_url: 'http://exchange.taler:8081',
+        exchange_url: 'https://exchange-demo.rigel.ar/',
       })}
       onDelete={(reserve: MerchantBackend.Tips.ReserveStatusEntry) => 
deleteReserve(reserve.reserve_pub)}
       onUpdate={() => null}
diff --git a/packages/frontend/src/routes/instance/transfers/list/Table.tsx 
b/packages/frontend/src/routes/instance/transfers/list/Table.tsx
index b6586ba..9b77e94 100644
--- a/packages/frontend/src/routes/instance/transfers/list/Table.tsx
+++ b/packages/frontend/src/routes/instance/transfers/list/Table.tsx
@@ -56,7 +56,7 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected }:
 
   return <div class="card has-table">
     <header class="card-header">
-      <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-account-multiple" /></span><Message id="Transfers" /></p>
+      <p class="card-header-title"><span class="icon"><i class="mdi mdi-bank" 
/></span><Message id="Transfers" /></p>
 
       <div class="card-header-icon" aria-label="more options">
 
diff --git a/packages/frontend/src/routes/login/index.tsx 
b/packages/frontend/src/routes/login/index.tsx
index 909bd10..91dc94c 100644
--- a/packages/frontend/src/routes/login/index.tsx
+++ b/packages/frontend/src/routes/login/index.tsx
@@ -19,7 +19,7 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 import { h, VNode } from "preact";
-import { LoginModal } from '../../components/auth';
+import { LoginModal } from '../../components/exception/login';
 import { Notification } from "../../utils/types";
 
 interface Props {
diff --git a/packages/frontend/src/scss/main.scss 
b/packages/frontend/src/scss/main.scss
index 9e9e5c0..5b150b9 100644
--- a/packages/frontend/src/scss/main.scss
+++ b/packages/frontend/src/scss/main.scss
@@ -81,4 +81,13 @@ div {
           border-width: 0.25em;
       }
   }
+}
+
+input[type=checkbox]:indeterminate + .check {
+  background: red !important;
+}
+
+.right-sticky {
+  position: sticky;
+  right: 0px;
 }
\ No newline at end of file

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