[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.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-merchant-backoffice] branch master updated: refactor navigation, part 2,
gnunet <=