gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] branch master updated (86d7aea -> 311086e)


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated (86d7aea -> 311086e)
Date: Fri, 26 Mar 2021 22:09:47 +0100

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

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

    from 86d7aea  input token as text
     new 26d5d2c  taking instance name from the request parameter
     new f4f672a  added copy payment url and order creation page
     new 311086e  fix linter

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CHANGELOG.md                                       | 19 ++++-
 packages/frontend/preact.config.js                 | 18 -----
 packages/frontend/src/AdminRoutes.tsx              |  1 -
 packages/frontend/src/ApplicationReadyRoutes.tsx   | 14 +++-
 packages/frontend/src/InstanceRoutes.tsx           | 28 ++++++-
 .../frontend/src/components/exception/login.tsx    | 10 ++-
 packages/frontend/src/components/menu/index.tsx    | 24 +++---
 .../notifications/CreatedSuccessfully.tsx          | 50 ++++++++++++
 packages/frontend/src/hooks/backend.ts             | 37 +++++++--
 packages/frontend/src/hooks/index.ts               | 49 ++++--------
 packages/frontend/src/messages/en.po               | 17 ++++
 .../admin/create/InstanceCreatedSuccessfully.tsx   | 65 ++++++++++++++++
 packages/frontend/src/paths/admin/create/index.tsx | 86 +++------------------
 packages/frontend/src/paths/admin/list/Table.tsx   |  3 +-
 .../paths/instance/orders/create/CreatePage.tsx    | 90 ++++++++++++++++++++++
 .../orders/create/OrderCreatedSuccessfully.tsx     | 88 +++++++++++++++++++++
 .../src/paths/instance/orders/create/index.tsx     | 45 ++++++++++-
 .../src/paths/instance/orders/list/Table.tsx       | 16 +++-
 .../src/paths/instance/orders/list/index.tsx       | 38 +++++----
 packages/frontend/src/schemas/index.ts             | 10 ++-
 20 files changed, 519 insertions(+), 189 deletions(-)
 create mode 100644 
packages/frontend/src/components/notifications/CreatedSuccessfully.tsx
 create mode 100644 
packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx
 create mode 100644 
packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
 create mode 100644 
packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 089f6d4..646d44e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,14 +24,29 @@ and this project adheres to [Semantic 
Versioning](https://semver.org/spec/v2.0.0
  - edit button to go to instance settings
  - check if there is a way to remove auto async for /routes 
/components/{async,routes} so it can be turned on when building 
non-single-bundle
  
- - product detail: we could have some button that brings us to thedetailed 
screen for the product
+ - product detail: we could have some button that brings us to the detailed 
screen for the product
+ - order id field to go
 
- - https://bugs.gnunet.org/view.php?id=6815
+created
+wired (if wired === true)
+refund
+
+error details
 
+fatal error: exchange error
+warning: exchange repotred problem
+ - navigation to another instance should not do full refresh
+ - cleanup instance and token management, because code is a mess and can be 
refactored 
 ## [Unreleased]
+ - fixed bug when updating token and not admin
+ - showing a yellow bar on non-default instance navigation (admin)
+ - 
+## [0.0.6] - 2021-03-25
  - complete order list information (#6793)
  - complete product list information (#6792)
  - missing fields in the instance update
+ - https://bugs.gnunet.org/view.php?id=6815
+ 
 
 ## [0.0.5] - 2021-03-18
  - change the admin title to "instances" if we are listing the instances and 
"settings: $ID" on updating instances (#6790)
diff --git a/packages/frontend/preact.config.js 
b/packages/frontend/preact.config.js
index f9f7cf1..a1898bd 100644
--- a/packages/frontend/preact.config.js
+++ b/packages/frontend/preact.config.js
@@ -61,21 +61,3 @@ export default {
     // config.plugins.push(new I18n())
   }
 }
-
-class I18n {
-  constructor(options) {
-    this.options = options
-  }
-
-  apply(compiler) {
-    compiler.hooks.normalModuleFactory.tap('I18n', (factory) => {
-      // console.log('factory', factory)
-      factory.hooks.parser.for('javascript/auto').tap('I18n', (parser, 
options) => {
-        // console.log('parser', parser)
-        parser.hooks.callAnyMember.for('console').tap('I18n', expression => {
-          console.log("expression", expression)
-        });
-      });
-    })
-  }
-}
\ No newline at end of file
diff --git a/packages/frontend/src/AdminRoutes.tsx 
b/packages/frontend/src/AdminRoutes.tsx
index d7d0dc3..160e04f 100644
--- a/packages/frontend/src/AdminRoutes.tsx
+++ b/packages/frontend/src/AdminRoutes.tsx
@@ -24,7 +24,6 @@ import InstanceCreatePage from "./paths/admin/create";
 export enum AdminPaths {
   list_instances = '/instances',
   new_instance = '/instance/new',
-  instance_id_route = '/instance/:id/:rest*',
 }
 
 export function AdminRoutes(): VNode {
diff --git a/packages/frontend/src/ApplicationReadyRoutes.tsx 
b/packages/frontend/src/ApplicationReadyRoutes.tsx
index d8a92ce..a4f3f4f 100644
--- a/packages/frontend/src/ApplicationReadyRoutes.tsx
+++ b/packages/frontend/src/ApplicationReadyRoutes.tsx
@@ -99,10 +99,16 @@ export function ApplicationReadyRoutes(): VNode {
     return <NotYetReadyAppMenu title="Loading..." />
   }
 
+  let instance
+  try {
+    const url = new URL(window.location.href)
+    instance = url.searchParams.get('instance')
+  } finally {
+    if (!instance) instance = 'default'
+  }
   return <Fragment>
-    <Menu instance="default" admin
-      onLogout={clearTokenAndGoToRoot}
-    />
-    <InstanceRoutes admin id="default" />
+    <Menu instance={instance} admin onLogout={clearTokenAndGoToRoot} />
+    <InstanceRoutes admin id={instance} />
   </Fragment>
+
 }
diff --git a/packages/frontend/src/InstanceRoutes.tsx 
b/packages/frontend/src/InstanceRoutes.tsx
index 7f16416..ba0c8b2 100644
--- a/packages/frontend/src/InstanceRoutes.tsx
+++ b/packages/frontend/src/InstanceRoutes.tsx
@@ -24,7 +24,7 @@ import { useCallback, useEffect, useMemo } from 
"preact/hooks";
 import { Route, Router, route } from 'preact-router';
 import { useMessageTemplate } from 'preact-messages';
 import { createHashHistory } from 'history';
-import { useBackendInstanceToken } from './hooks';
+import { useBackendDefaultToken, useBackendInstanceToken } from './hooks';
 import { InstanceContextProvider, useBackendContext } from './context/backend';
 import { SwrError, useInstanceDetails } from "./hooks/backend";
 // import { Notification } from './utils/types';
@@ -63,6 +63,7 @@ export enum InstancePaths {
   product_new = '/product/new',
 
   order_list = '/orders',
+  order_new = '/order/new',
   order_details = '/order/:oid/details',
   // order_new = '/order/new',
 
@@ -116,6 +117,7 @@ function AdminInstanceUpdatePage({ id, ...rest }: { id: 
string } & InstanceUpdat
 }
 
 export function InstanceRoutes({ id, admin }: Props): VNode {
+  const [_, updateDefaultToken] = useBackendDefaultToken()
   const [token, updateToken] = useBackendInstanceToken(id);
   const { changeBackend, addTokenCleaner } = useBackendContext();
   const cleaner = useCallback(() => { updateToken(undefined); }, [id]);
@@ -127,8 +129,12 @@ export function InstanceRoutes({ id, admin }: Props): 
VNode {
 
   const updateLoginStatus = (url: string, token?: string) => {
     changeBackend(url);
-    if (token)
+    if (!token) return
+    if (admin) {
       updateToken(token);
+    } else {
+      updateDefaultToken(token)
+    }
   };
 
   const value = useMemo(() => ({ id, token, admin }), [id, token])
@@ -365,7 +371,12 @@ export function InstanceRoutes({ id, admin }: Props): 
VNode {
             <LoginPage onConfirm={updateLoginStatus} />
           </Fragment>
         }}
+
+        onCreate={() => {
+          route(InstancePaths.order_new)
+        }}
       />
+
       <Route path={InstancePaths.order_details}
         component={OrderDetailsPage}
         
@@ -391,7 +402,18 @@ export function InstanceRoutes({ id, admin }: Props): 
VNode {
           route(InstancePaths.order_list)
         }}
       />
-      {/* 
+      <Route path={InstancePaths.order_new}
+        component={OrderCreatePage}
+        
+        onConfirm={() => {
+          route(InstancePaths.order_list)
+        }}
+
+        onBack={() => {
+          route(InstancePaths.order_list)
+        }}
+      />     
+       {/* 
       <Route path={InstancePaths.tips_list}
         component={TipListPage}
 
diff --git a/packages/frontend/src/components/exception/login.tsx 
b/packages/frontend/src/components/exception/login.tsx
index fde6698..92f6bbe 100644
--- a/packages/frontend/src/components/exception/login.tsx
+++ b/packages/frontend/src/components/exception/login.tsx
@@ -22,7 +22,7 @@
 import { h, VNode } from "preact";
 import { useMessageTemplate } from "preact-messages";
 import { useState } from "preact/hooks";
-import { useBackendContext } from "../../context/backend";
+import { useBackendContext, useInstanceContext } from "../../context/backend";
 import { Notification } from "../../utils/types";
 
 interface Props {
@@ -31,9 +31,11 @@ interface Props {
 }
 
 export function LoginModal({ onConfirm, withMessage }: Props): VNode {
-  const backend = useBackendContext()
-  const [token, setToken] = useState(backend.token || '')
-  const [url, setURL] = useState(backend.url)
+  const { url: backendUrl, token: baseToken } = useBackendContext()
+  const { admin, token: instanceToken } = useInstanceContext()
+  const [token, setToken] = useState(!admin ? baseToken : instanceToken || '')
+  
+  const [url, setURL] = useState(backendUrl)
   const i18n = useMessageTemplate()
 
   return <div class="columns is-centered">
diff --git a/packages/frontend/src/components/menu/index.tsx 
b/packages/frontend/src/components/menu/index.tsx
index af0b074..36b5639 100644
--- a/packages/frontend/src/components/menu/index.tsx
+++ b/packages/frontend/src/components/menu/index.tsx
@@ -22,6 +22,7 @@ import { NavigationBar } from "./NavigationBar";
 import { Sidebar } from "./SideBar";
 import Match from 'preact-router/match';
 import { Notification } from "../../utils/types";
+import { calculateRootPath } from "../../hooks";
 
 
 function getInstanceTitle(path: string, id: string): string {
@@ -45,12 +46,10 @@ function getInstanceTitle(path: string, id: string): string 
{
 }
 
 const INSTANCE_ID_LOOKUP = /^\/instance\/([^/]*)\//
-function getAdminTitle(path: string) {
+function getAdminTitle(path: string, instance: 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')
+  return getInstanceTitle(path, instance)
 }
 
 interface MenuProps {
@@ -71,12 +70,19 @@ 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))
-
+    const titleWithSubtitle = title ? title : (!admin ? getInstanceTitle(path, 
instance) : getAdminTitle(path, instance))
+    const adminInstance = instance === "default"
     return (<WithTitle title={titleWithSubtitle}>
       <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} />}
+        
+        {onLogout && <Sidebar onLogout={onLogout} admin={admin && 
adminInstance} instance={instance} mobile={mobileOpen} />}
+
+        { admin && !adminInstance && <nav class="level">
+          <div class="level-item has-text-centered has-background-warning">
+            <p class="is-size-5">You are viewing the instance 
<b>"{instance}"</b>. <a href={calculateRootPath()} >go back</a></p>
+          </div>
+        </nav> }
       </div>
     </WithTitle>
     )
@@ -92,7 +98,7 @@ interface NotYetReadyAppMenuProps {
 interface NotifProps {
   notification?: Notification;
 }
-export function NotificationCard({ notification:n }: NotifProps) {
+export function NotificationCard({ notification: n }: NotifProps) {
   if (!n) return null
   return <div class="notification">
     <div class="columns is-vcentered">
@@ -102,7 +108,7 @@ export function NotificationCard({ notification:n }: 
NotifProps) {
             <p>{n.message}</p>
           </div>
           <div class="message-body">
-          {n.description}
+            {n.description}
           </div>
         </article>
       </div>
diff --git 
a/packages/frontend/src/components/notifications/CreatedSuccessfully.tsx 
b/packages/frontend/src/components/notifications/CreatedSuccessfully.tsx
new file mode 100644
index 0000000..99498ed
--- /dev/null
+++ b/packages/frontend/src/components/notifications/CreatedSuccessfully.tsx
@@ -0,0 +1,50 @@
+/*
+ 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 { ComponentChildren, h } from "preact";
+
+interface Props {
+  onCreateAnother?: () => void;
+  onConfirm: () => void;
+  children: ComponentChildren;
+}
+
+export function CreatedSuccessfully({ children, onConfirm, onCreateAnother }: 
Props) {
+  return <div class="columns is-fullwidth is-vcentered content-full-size">
+    <div class="column" />
+    <div class="column is-three-quarters">
+      <div class="card">
+        <header class="card-header has-background-success">
+          <p class="card-header-title has-text-white-ter">
+            Created successfully
+        </p>
+        </header>
+        <div class="card-content">
+          {children}
+        </div>
+      </div>
+        <div class="buttons is-right">
+          {onCreateAnother && <button class="button is-info" 
onClick={onCreateAnother}>Create another</button>}
+          <button class="button is-info" onClick={onConfirm}>Continue</button>
+        </div>
+    </div>
+    <div class="column" />
+  </div>
+}
+
diff --git a/packages/frontend/src/hooks/backend.ts 
b/packages/frontend/src/hooks/backend.ts
index 59bcdd0..e8b9af5 100644
--- a/packages/frontend/src/hooks/backend.ts
+++ b/packages/frontend/src/hooks/backend.ts
@@ -220,6 +220,7 @@ interface OrderMutateAPI {
   forgetOrder: (id: string, data: MerchantBackend.Orders.ForgetRequest) => 
Promise<void>;
   refundOrder: (id: string, data: MerchantBackend.Orders.RefundRequest) => 
Promise<MerchantBackend.Orders.MerchantRefundResponse>;
   deleteOrder: (id: string) => Promise<void>;
+  getPaymentURL: (id: string) => Promise<string>;
 }
 
 export function useOrderMutateAPI(): OrderMutateAPI {
@@ -270,7 +271,16 @@ export function useOrderMutateAPI(): OrderMutateAPI {
 
     mutateAll(/@"\/private\/orders"@/)
   }
-  return { createOrder, forgetOrder, deleteOrder, refundOrder }
+
+  const getPaymentURL = async (orderId: string): Promise<string> => {
+    const data = await request(`${url}/private/orders/${orderId}`, {
+      method: 'get',
+      token
+    })
+    return data.taler_pay_uri || data.contract_terms?.fulfillment_url
+  }
+
+  return { createOrder, forgetOrder, deleteOrder, refundOrder, getPaymentURL }
 }
 
 export function useOrderDetails(oderId:string): 
HttpResponse<MerchantBackend.Orders.MerchantOrderStatusResponse> {
@@ -284,7 +294,6 @@ export function useOrderDetails(oderId:string): 
HttpResponse<MerchantBackend.Ord
   return { data, unauthorized: error?.status === 401, notfound: error?.status 
=== 404, error }
 }
 
-
 interface TransferMutateAPI {
   informTransfer: (data: MerchantBackend.Transfers.TransferInformation) => 
Promise<MerchantBackend.Transfers.MerchantTrackTransferResponse>;
 }
@@ -441,17 +450,26 @@ export function useInstanceMutateAPI(): InstaceMutateAPI {
 }
 
 export function useBackendInstances(): 
HttpResponse<MerchantBackend.Instances.InstancesResponse> {
-  const { url, token } = useBackendContext()
+  const { url } = useBackendContext()
+  const { token } = useInstanceContext();
+
   const { data, error } = useSWR<MerchantBackend.Instances.InstancesResponse, 
SwrError>(['/private/instances', token, url], fetcher)
 
   return { data, unauthorized: error?.status === 401, notfound: error?.status 
=== 404, error }
 }
 
 export function useInstanceDetails(): 
HttpResponse<MerchantBackend.Instances.QueryInstancesResponse> {
-  const { url: baseUrl } = useBackendContext();
-  const { token, id, admin } = useInstanceContext();
+  // const { url: baseUrl } = useBackendContext();
+  // const { token, id, admin } = useInstanceContext();
+  // const url = !admin ? baseUrl : `${baseUrl}/instances/${id}`
+  const { url: baseUrl, token: baseToken } = useBackendContext();
+  const { token: instanceToken, id, admin } = useInstanceContext();
 
-  const url = !admin ? baseUrl : `${baseUrl}/instances/${id}`
+  const { url, token } = !admin ? {
+    url: baseUrl, token: baseToken
+  } : {
+    url: `${baseUrl}/instances/${id}`, token: instanceToken
+  }
 
   const { data, error } = 
useSWR<MerchantBackend.Instances.QueryInstancesResponse, 
SwrError>([`/private/`, token, url], fetcher)
 
@@ -496,6 +514,12 @@ export function useInstanceOrders(args: 
InstanceOrderFilter, updateFilter: (d:Da
   const totalAfter = pageAfter * PAGE_SIZE;
   const totalBefore = args?.date ? pageBefore * PAGE_SIZE : 0;
 
+  /**
+   * FIXME: this can be cleaned up a little
+   * 
+   * the logic of double query should be inside the orderFetch so from the 
hook perspective and cache
+   * is just one query and one error status
+   */
   const { data:beforeData, error:beforeError } = 
useSWR<MerchantBackend.Orders.OrderHistory, SwrError>(
     [`/private/orders`, token, url, args?.paid, args?.refunded, args?.wired, 
args?.date, totalBefore],
     orderFetcher,
@@ -527,7 +551,6 @@ export function useInstanceOrders(args: 
InstanceOrderFilter, updateFilter: (d:Da
       setPageAfter(pageAfter + 1)
     } else { 
       const from = 
afterData?.orders?.[afterData?.orders?.length-1]?.timestamp?.t_ms
-      // console.log(afterData?.orders?.map(d => d.row_id), PAGE_SIZE, from && 
format(new Date(from), 'yyyy/MM/dd HH:mm:ss'))     
       if (from) updateFilter(new Date(from))
     }
   }
diff --git a/packages/frontend/src/hooks/index.ts 
b/packages/frontend/src/hooks/index.ts
index e1af7de..ab268e9 100644
--- a/packages/frontend/src/hooks/index.ts
+++ b/packages/frontend/src/hooks/index.ts
@@ -32,16 +32,26 @@ export function useBackendContextState() {
   const [cleaners, setCleaners] = useState([tokenCleaner])
   const addTokenCleaner = (c: () => void) => setCleaners(cs => [...cs, c])
   const addTokenCleanerMemo = useCallback((c: () => void) => { 
addTokenCleaner(c) }, [tokenCleaner])
+
   const clearAllTokens = () => {
     cleaners.forEach(c => c())
+    for (let i = 0; i < localStorage.length; i++) {
+      const k = localStorage.key(i)
+      if (k && /^backend-token/.test(k)) localStorage.removeItem(k)
+    }
     resetBackend()
   }
 
   return { url, token, triedToLog, changeBackend, updateToken, lang, setLang, 
resetBackend, clearAllTokens, addTokenCleaner: addTokenCleanerMemo }
 }
 
+export const calculateRootPath = () => {
+  const rootPath = typeof window !== undefined ? window.location.origin + 
window.location.pathname : '/'
+  return rootPath
+}
+
 export function useBackendURL(): [string, boolean, StateUpdater<string>, () => 
void] {
-  const [value, setter] = useNotNullLocalStorage('backend-url', typeof window 
!== 'undefined' ? window.location.origin : '')
+  const [value, setter] = useNotNullLocalStorage('backend-url', 
calculateRootPath())
   const [triedToLog, setTriedToLog] = useLocalStorage('tried-login')
 
   const checkedSetter = (v: ValueOrFunction<string>) => {
@@ -59,49 +69,18 @@ export function useBackendDefaultToken(): [string | 
undefined, StateUpdater<stri
   return useLocalStorage('backend-token')
 }
 
-export function useBackendInstanceToken(id: string): [string | undefined, 
StateUpdater<string | undefined>, VoidFunction] {
+export function useBackendInstanceToken(id: string): [string | undefined, 
StateUpdater<string | undefined>] {
   const [token, setToken] = useLocalStorage(`backend-token-${id}`)
-  const [ids, setIds] = useLocalStorage(`backend-token-ids`)
-
-  function clearAllTokens() {
-    // TODO: refactor this
-    ids?.split(',').map(i => localStorage.removeItem(`backend-token-${i}`))
-  }
-
-  useEffect(() => {
-    setIds((ids: string | undefined): string | undefined => {
-      if (!ids) return ids
-      const all = ids.split(',')
-      if (all.includes(id)) return ids
-      return all.concat(id).filter(Boolean).join(',')
-    })
-  }, [id, setIds])
-
   const [defaultToken, defaultSetToken] = useBackendDefaultToken()
 
   // instance named 'default' use the default token
   if (id === 'default') {
-    return [defaultToken, defaultSetToken, clearAllTokens]
+    return [defaultToken, defaultSetToken]
   }
 
-  return [token, setToken, clearAllTokens]
+  return [token, setToken]
 }
 
-// export function useBackend(): [State, StateUpdater<State>] {
-//   const [url, setUrl] = useLocalStorage('backend-url', 
window.location.origin)
-//   const [token, setToken] = useLocalStorage('backend-token')
-
-//   const updater: StateUpdater<State> = (value: State | ((value: State) => 
State)) => {
-//     const valueToStore = value instanceof Function ? value({ token, url: 
url || window.location.origin }) : value;
-//     setUrl(valueToStore.url)
-//     setToken(valueToStore.token)
-
-//     mutate('/private/instances', null)
-//   }
-
-//   return [{ token, url: url || window.location.origin }, updater]
-// }
-
 export function useLang(): [string, StateUpdater<string>] {
   const browserLang = typeof window !== "undefined" ? navigator.language || 
(navigator as any).userLanguage : undefined;
   const defaultLang = (browserLang || 'en').substring(0,2)
diff --git a/packages/frontend/src/messages/en.po 
b/packages/frontend/src/messages/en.po
index 8a52eec..4abba9a 100644
--- a/packages/frontend/src/messages/en.po
+++ b/packages/frontend/src/messages/en.po
@@ -341,3 +341,20 @@ msgstr "Order status URL"
 msgid "fields.instance.taler_pay_uri.label"
 msgstr "Taler Pay URI"
 
+#  msgid "fields.instance.amount.placeholder"
+#  msgstr ""
+
+#  msgid "fields.instance.amount.tooltip"
+#  msgstr ""
+
+msgid "fields.instance.amount.label"
+msgstr "Amount"
+
+#  msgid "fields.instance.summary.placeholder"
+#  msgstr ""
+
+#  msgid "fields.instance.summary.tooltip"
+#  msgstr ""
+
+msgid "fields.instance.summary.label"
+msgstr "Summary"
diff --git 
a/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx 
b/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx
new file mode 100644
index 0000000..982ff27
--- /dev/null
+++ b/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx
@@ -0,0 +1,65 @@
+/*
+ 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 } from "preact";
+import { CreatedSuccessfully } from 
"../../../components/notifications/CreatedSuccessfully";
+import { Entity } from "./index";
+
+export function InstanceCreatedSuccessfully({ entity, onConfirm }: { entity: 
Entity; onConfirm: () => void; }) {
+  return <CreatedSuccessfully onConfirm={onConfirm}>
+    <div class="field is-horizontal">
+      <div class="field-label is-normal">
+        <label class="label">ID</label>
+      </div>
+      <div class="field-body is-flex-grow-3">
+        <div class="field">
+          <p class="control">
+            <input class="input" readonly value={entity.id} />
+          </p>
+        </div>
+      </div>
+    </div>
+    <div class="field is-horizontal">
+      <div class="field-label is-normal">
+        <label class="label">Business Name</label>
+      </div>
+      <div class="field-body is-flex-grow-3">
+        <div class="field">
+          <p class="control">
+            <input class="input" readonly value={entity.name} />
+          </p>
+        </div>
+      </div>
+    </div>
+    <div class="field is-horizontal">
+      <div class="field-label is-normal">
+        <label class="label">Token</label>
+      </div>
+      <div class="field-body is-flex-grow-3">
+        <div class="field">
+          <p class="control">
+            {entity.auth.method === 'external' && 'external'}
+            {entity.auth.method === 'token' &&
+              <input class="input" readonly value={entity.auth.token} />}
+          </p>
+        </div>
+      </div>
+    </div>
+  </CreatedSuccessfully>;
+}
diff --git a/packages/frontend/src/paths/admin/create/index.tsx 
b/packages/frontend/src/paths/admin/create/index.tsx
index 7205e12..e832f3a 100644
--- a/packages/frontend/src/paths/admin/create/index.tsx
+++ b/packages/frontend/src/paths/admin/create/index.tsx
@@ -13,16 +13,18 @@
  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/>
  */
-import { ComponentChildren, Fragment, h, VNode } from "preact";
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
-import { Loading } from "../../../components/exception/loading";
-import { FormProvider } from "../../../components/form/Field";
-import { Input } from "../../../components/form/Input";
 import { NotificationCard } from "../../../components/menu";
 import { MerchantBackend } from "../../../declaration";
 import { useAdminMutateAPI } from "../../../hooks/backend";
 import { Notification } from "../../../utils/types";
 import { CreatePage } from "./CreatePage";
+import { InstanceCreatedSuccessfully } from "./InstanceCreatedSuccessfully";
 
 interface Props {
   onBack?: () => void;
@@ -30,7 +32,7 @@ interface Props {
   onError: (error: any) => void;
   forceId?: string;
 }
-type Entity = MerchantBackend.Instances.InstanceConfigurationMessage;
+export type Entity = MerchantBackend.Instances.InstanceConfigurationMessage;
 
 export default function Create({ onBack, onConfirm, onError, forceId }: 
Props): VNode {
   const { createInstance } = useAdminMutateAPI();
@@ -38,44 +40,7 @@ export default function Create({ onBack, onConfirm, onError, 
forceId }: Props):
   const [createdOk, setCreatedOk] = useState<Entity | undefined>(undefined);
 
   if (createdOk) {
-    return <CreatedSuccessfully onConfirm={onConfirm}>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">ID</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input class="input" readonly value={createdOk.id} readOnly />
-            </p>
-          </div>
-        </div>
-      </div>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Business Name</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input class="input" readonly value={createdOk.name} disabled />
-            </p>
-          </div>
-        </div>
-      </div>
-      <div class="field is-horizontal">
-        <div class="field-label is-normal">
-          <label class="label">Token</label>
-        </div>
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            <p class="control">
-              <input class="input" readonly value={createdOk.auth.token} 
disabled />
-            </p>
-          </div>
-        </div>
-      </div>
-    </CreatedSuccessfully>
+    return <InstanceCreatedSuccessfully entity={createdOk} 
onConfirm={onConfirm} />
   }
 
   return <Fragment>
@@ -97,39 +62,6 @@ export default function Create({ onBack, onConfirm, onError, 
forceId }: Props):
         })
       }} />
   </Fragment>
+  
 }
 
-interface CreatedSuccessfullyProps {
-  onConfirm: () => void;
-  children: ComponentChildren;
-}
-
-function CreatedSuccessfully({ children, onConfirm }: 
CreatedSuccessfullyProps) {
-  return <div class="columns is-fullwidth is-vcentered content-full-size">
-    <div class="column" />
-    <div class="column is-half">
-      <div class="card">
-        <header class="card-header has-background-success">
-          <p class="card-header-title has-text-white-ter">
-            Instance created successfully
-        </p>
-        </header>
-        <div class="card-content">
-          {children}
-        </div>
-        <footer class="card-footer">
-          <p class="card-footer-item" style={{ border: 'none' }}>
-            <span />
-          </p>
-          <p class="card-footer-item" style={{ border: 'none' }}>
-            <span />
-          </p>
-          <p class="card-footer-item">
-            <button class="button is-info" 
onClick={onConfirm}>Continue</button>
-          </p>
-        </footer>
-      </div>
-    </div>
-    <div class="column" />
-  </div>
-}
\ No newline at end of file
diff --git a/packages/frontend/src/paths/admin/list/Table.tsx 
b/packages/frontend/src/paths/admin/list/Table.tsx
index 20186a6..f0c3242 100644
--- a/packages/frontend/src/paths/admin/list/Table.tsx
+++ b/packages/frontend/src/paths/admin/list/Table.tsx
@@ -24,6 +24,7 @@ import { Message } from "preact-messages"
 import { StateUpdater, useEffect, useState } from "preact/hooks"
 import { useBackendContext } from "../../../context/backend";
 import { MerchantBackend } from "../../../declaration"
+import { calculateRootPath } from "../../../hooks";
 
 interface Props {
   instances: MerchantBackend.Instances.Instance[];
@@ -121,7 +122,7 @@ function Table({ rowSelection, rowSelectionHandler, 
instances, onUpdate, onDelet
                 <span class="check" />
               </label>
             </td>
-            <td><a href={`/instances/${i.id}`} {...{ native: true }} 
onClick={() => changeBackend(`${url}/instances/${i.id}`)} >{i.id}</a></td>
+            <td><a href={`${calculateRootPath()}?instance=${i.id}`} {...{ 
native: true }} >{i.id}</a></td>
             <td >{i.name}</td>
             <td class="is-actions-cell right-sticky">
               <div class="buttons is-right">
diff --git a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx 
b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
new file mode 100644
index 0000000..408bca7
--- /dev/null
+++ b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
@@ -0,0 +1,90 @@
+/*
+ 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 { useState } from "preact/hooks";
+import { MerchantBackend } from "../../../../declaration";
+import * as yup from 'yup';
+import { FormErrors, FormProvider } from "../../../../components/form/Field"
+import { OrderCreateSchema as schema } from "../../../../schemas"
+import { Message } from "preact-messages";
+import { Input } from "../../../../components/form/Input";
+import { useConfigContext } from "../../../../context/backend";
+import { InputCurrency } from "../../../../components/form/InputCurrency";
+
+type Entity = MerchantBackend.Orders.MinimalOrderDetail
+
+interface Props {
+  onCreate: (d: MerchantBackend.Orders.PostOrderRequest) => void;
+  onBack?: () => void;
+}
+
+interface KeyValue {
+  [key: string]: string;
+}
+
+function with_defaults(id?: string): Partial<Entity> {
+  return {};
+}
+
+export function CreatePage({ onCreate, onBack }: Props): VNode {
+  const [value, valueHandler] = useState(with_defaults())
+  const [errors, setErrors] = useState<FormErrors<Entity>>({})
+
+  const submit = (): void => {
+    try {
+      schema.validateSync(value, { abortEarly: false })
+      const order = schema.cast(value) as Entity
+      onCreate({ order });
+    } catch (err) {
+      const errors = err.inner as yup.ValidationError[]
+      const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ 
...prev, [cur.path]: { type: cur.type, params: cur.params, message: cur.message 
} }), {})
+      setErrors(pathMessages)
+    }
+  }
+  const config = useConfigContext()
+
+  return <div>
+
+    <section class="section is-main-section">
+      <div class="columns">
+        <div class="column" />
+        <div class="column is-two-thirds">
+          <FormProvider<Entity> errors={errors} object={value} 
valueHandler={valueHandler} >
+
+            <InputCurrency<Entity> name="amount" currency={config.currency} />
+
+            <Input<Entity> name="summary" />
+
+          </FormProvider>
+
+          <div class="buttons is-right mt-5">
+            {onBack && <button class="button" onClick={onBack} ><Message 
id="Cancel" /></button>}
+            <button class="button is-success" onClick={submit} ><Message 
id="Confirm" /></button>
+          </div>
+
+        </div>
+        <div class="column" />
+      </div>
+    </section>
+
+  </div>
+}
\ No newline at end of file
diff --git 
a/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx
 
b/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx
new file mode 100644
index 0000000..a477e82
--- /dev/null
+++ 
b/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx
@@ -0,0 +1,88 @@
+/*
+ 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/>
+ */
+ import { h } from "preact";
+import { useEffect, useState } from "preact/hooks";
+import { CreatedSuccessfully } from 
"../../../../components/notifications/CreatedSuccessfully";
+import { useOrderMutateAPI } from "../../../../hooks/backend";
+import { Entity } from "./index";
+
+interface Props {
+  entity: Entity;
+  onConfirm: () => void;
+  onCreateAnother?: () => void;
+}
+
+export function OrderCreatedSuccessfully({ entity, onConfirm, onCreateAnother 
}: Props) {
+  const { getPaymentURL } = useOrderMutateAPI()
+  const [url, setURL] = useState<string | undefined>(undefined)
+  
+  useEffect(() => {
+    getPaymentURL(entity.response.order_id).then(url => {
+      setURL(url)
+    })
+  },[entity.response.order_id])
+
+  return <CreatedSuccessfully onConfirm={onConfirm} 
onCreateAnother={onCreateAnother}>
+    <div class="field is-horizontal">
+      <div class="field-label is-normal">
+        <label class="label">Amount</label>
+      </div>
+      <div class="field-body is-flex-grow-3">
+        <div class="field">
+          <p class="control">
+            <input class="input" readonly value={entity.request.order.amount} 
/>
+          </p>
+        </div>
+      </div>
+    </div>
+    <div class="field is-horizontal">
+      <div class="field-label is-normal">
+        <label class="label">Summary</label>
+      </div>
+      <div class="field-body is-flex-grow-3">
+        <div class="field">
+          <p class="control">
+            <input class="input" readonly value={entity.request.order.summary} 
/>
+          </p>
+        </div>
+      </div>
+    </div>
+    <div class="field is-horizontal">
+      <div class="field-label is-normal">
+        <label class="label">Order ID</label>
+      </div>
+      <div class="field-body is-flex-grow-3">
+        <div class="field">
+          <p class="control">
+            <input class="input" readonly value={entity.response.order_id} />
+          </p>
+        </div>
+      </div>
+    </div>
+    <div class="field is-horizontal">
+      <div class="field-label is-normal">
+        <label class="label">Payment URL</label>
+      </div>
+      <div class="field-body is-flex-grow-3">
+        <div class="field">
+          <p class="control">
+            <input class="input" readonly value={url} />
+          </p>
+        </div>
+      </div>
+    </div>
+  </CreatedSuccessfully>;
+}
diff --git a/packages/frontend/src/paths/instance/orders/create/index.tsx 
b/packages/frontend/src/paths/instance/orders/create/index.tsx
index f0d2ae0..3d1dce0 100644
--- a/packages/frontend/src/paths/instance/orders/create/index.tsx
+++ b/packages/frontend/src/paths/instance/orders/create/index.tsx
@@ -19,8 +19,47 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { h, VNode } from 'preact';
+import { Fragment, h, VNode } from 'preact';
+import { useState } from 'preact/hooks';
+import { NotificationCard } from '../../../../components/menu';
+import { MerchantBackend } from '../../../../declaration';
+import { useOrderMutateAPI } from '../../../../hooks/backend';
+import { Notification } from '../../../../utils/types';
+import { CreatePage } from './CreatePage';
+import { OrderCreatedSuccessfully } from './OrderCreatedSuccessfully';
 
-export default function ():VNode {
-  return <div>order create page</div>
+export type Entity = {
+  request: MerchantBackend.Orders.PostOrderRequest,
+  response: MerchantBackend.Orders.PostOrderResponse
+}
+interface Props {
+  onBack?: () => void;
+  onConfirm: () => void;
+}
+export default function ({ onConfirm, onBack }: Props): VNode {
+  const { createOrder } = useOrderMutateAPI()
+  const [notif, setNotif] = useState<Notification | undefined>(undefined)
+  const [createdOk, setCreatedOk] = useState<Entity | undefined>(undefined);
+
+  if (createdOk) {
+    return <OrderCreatedSuccessfully entity={createdOk} onConfirm={onConfirm} 
onCreateAnother={() => setCreatedOk(undefined)} />
+  }
+
+  return <Fragment>
+    <NotificationCard notification={notif} />
+
+    <CreatePage
+      onBack={onBack}
+      onCreate={(request: MerchantBackend.Orders.PostOrderRequest) => {
+        createOrder(request).then((response) => {
+          setCreatedOk({ request, response })
+        }).catch((error) => {
+          setNotif({
+            message: 'could not create order',
+            type: "ERROR",
+            description: error.message
+          })
+        })
+      }} />
+  </Fragment>
 }
\ No newline at end of file
diff --git a/packages/frontend/src/paths/instance/orders/list/Table.tsx 
b/packages/frontend/src/paths/instance/orders/list/Table.tsx
index aa1f1cf..82b3c83 100644
--- a/packages/frontend/src/paths/instance/orders/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/orders/list/Table.tsx
@@ -38,6 +38,7 @@ type Entity = MerchantBackend.Orders.OrderHistoryEntry & { 
id: string }
 interface Props {
   instances: Entity[];
   onRefund: (id: string, value: MerchantBackend.Orders.RefundRequest) => void;
+  onCopyURL: (id: string) => void;
   onCreate: () => void;
   onSelect: (order: Entity) => void;
   onLoadMoreBefore?: () => void;
@@ -49,7 +50,7 @@ interface Props {
 // onLoadMoreAfter={result.loadMore} hasMoreAfter={!result.isReachingEnd}
 
 
-export function CardTable({ instances, onCreate, onRefund, onSelect, 
onLoadMoreAfter, onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: Props): VNode 
{
+export function CardTable({ instances, onCreate, onRefund, onCopyURL, 
onSelect, onLoadMoreAfter, onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: 
Props): VNode {
   const [actionQueue, actionQueueHandler] = useState<Actions<Entity>[]>([]);
   const [rowSelection, rowSelectionHandler] = useState<string[]>([])
 
@@ -74,6 +75,7 @@ export function CardTable({ instances, onCreate, onRefund, 
onSelect, onLoadMoreA
         <div class="table-wrapper has-mobile-cards">
           {instances.length > 0 ?
             <Table instances={instances} onSelect={onSelect} onRefund={(order) 
=> setShowRefund(order.id)}
+              onCopyURL={o => onCopyURL(o.id)}
               rowSelection={rowSelection} 
rowSelectionHandler={rowSelectionHandler}
               onLoadMoreAfter={onLoadMoreAfter} 
onLoadMoreBefore={onLoadMoreBefore}
               hasMoreAfter={hasMoreAfter} hasMoreBefore={hasMoreBefore}
@@ -96,6 +98,7 @@ interface TableProps {
   rowSelection: string[];
   instances: Entity[];
   onRefund: (id: Entity) => void;
+  onCopyURL: (id: Entity) => void;
   onSelect: (id: Entity) => void;
   rowSelectionHandler: StateUpdater<string[]>;
   onLoadMoreBefore?: () => void;
@@ -104,9 +107,9 @@ interface TableProps {
   onLoadMoreAfter?: () => void;
 }
 
-function Table({ instances, onSelect, onRefund, onLoadMoreAfter, 
onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: TableProps): VNode {
+function Table({ instances, onSelect, onRefund, onCopyURL, onLoadMoreAfter, 
onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: TableProps): VNode {
   return <div class="table-container">
-    {onLoadMoreBefore && <button class="button is-fullwidth" 
disabled={!hasMoreBefore} onClick={onLoadMoreBefore}> load more after </button>}
+    {onLoadMoreBefore && <button class="button is-fullwidth" 
disabled={!hasMoreBefore} onClick={onLoadMoreBefore}> load newer orders 
</button>}
     <table class="table is-striped is-hoverable is-fullwidth">
       <thead>
         <tr>
@@ -129,13 +132,18 @@ function Table({ instances, onSelect, onRefund, 
onLoadMoreAfter, onLoadMoreBefor
                     Refund
                   </button>
                 }
+                {(!i.paid || pos === 0) &&
+                  <button class="button is-small is-info jb-modal" 
type="button" onClick={(): void => onCopyURL(i)}>
+                    copy url
+                  </button>
+                }
               </div>
             </td>
           </tr>
         })}
       </tbody>
     </table>
-    {onLoadMoreAfter && <button class="button is-fullwidth" 
disabled={!hasMoreAfter} onClick={onLoadMoreAfter}> load more before </button>}
+    {onLoadMoreAfter && <button class="button is-fullwidth" 
disabled={!hasMoreAfter} onClick={onLoadMoreAfter}> load older orders </button>}
   </div>
 }
 
diff --git a/packages/frontend/src/paths/instance/orders/list/index.tsx 
b/packages/frontend/src/paths/instance/orders/list/index.tsx
index e3a4538..47f3673 100644
--- a/packages/frontend/src/paths/instance/orders/list/index.tsx
+++ b/packages/frontend/src/paths/instance/orders/list/index.tsx
@@ -40,13 +40,13 @@ interface Props {
 
 
 export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, 
onNotFound }: Props): VNode {
-  const [filter, setFilter] = useState<InstanceOrderFilter>({paid:'yes'})
+  const [filter, setFilter] = useState<InstanceOrderFilter>({ paid: 'yes' })
   const [pickDate, setPickDate] = useState(false)
 
-  const setNewDate = (date:Date) => setFilter(prev => ({...prev,date}))
+  const setNewDate = (date: Date) => setFilter(prev => ({ ...prev, date }))
 
   const result = useInstanceOrders(filter, setNewDate)
-  const { createOrder, refundOrder } = useOrderMutateAPI()
+  const { createOrder, refundOrder, getPaymentURL } = useOrderMutateAPI()
   const { currency } = useConfigContext()
 
   let instances: (MerchantBackend.Orders.OrderHistoryEntry & { id: string })[];
@@ -73,17 +73,11 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
   return <section class="section is-main-section">
     <NotificationCard notification={{
       message: 'DEMO WARNING',
-      type:'WARN',
+      type: 'WARN',
       description: 'refund button is being forced in the first row, other 
depends on the refundable property'
     }} />
     <NotificationCard notification={notif} />
 
-    <DatePicker
-      opened={pickDate}
-      closeFunction={() => setPickDate(false)}
-      dateReceiver={setNewDate}
-    />
-
     <div class="columns">
       <div class="column">
         <div class="tabs">
@@ -98,11 +92,11 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
       <div class="column ">
         <div class="buttons is-right">
           <div class="field has-addons">
-            { filter.date && <div class="control">
-              <a class="button" onClick={() => { setFilter(prev => ({ ...prev, 
date:undefined }) ) }}>
+            {filter.date && <div class="control">
+              <a class="button" onClick={() => { setFilter(prev => ({ ...prev, 
date: undefined })) }}>
                 <span class="icon"><i class="mdi mdi-close" /></span>
               </a>
-            </div> }
+            </div>}
             <div class="control">
               <input class="input" type="text" readonly value={!filter.date ? 
'' : format(filter.date, 'yyyy/MM/dd')} placeholder="pick a date" />
             </div>
@@ -116,19 +110,23 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
       </div>
     </div>
 
+    <DatePicker
+      opened={pickDate}
+      closeFunction={() => setPickDate(false)}
+      dateReceiver={setNewDate}
+    />
+
     <CardTable instances={instances}
-      onCreate={() => createOrder({
-        order: {
-          amount: `${currency}:${Math.floor(Math.random() * 20 + 1)}`,
-          summary: `some summary with a random number 
${Math.floor(Math.random() * 20 + 1)}`,
-        }
-      })}
+      onCreate={onCreate}
       onSelect={(order) => onSelect(order.id)}
+      onCopyURL={(id) => getPaymentURL(id).then(url => {
+        navigator.clipboard.writeText(url)
+      })}
       onRefund={(id, value) => refundOrder(id, value)
         .then(() => setNotif({
           message: 'refund created successfully',
           type: "SUCCESS"
-      })).catch((error) => setNotif({
+        })).catch((error) => setNotif({
           message: 'could not create the refund',
           type: "ERROR",
           description: error.message
diff --git a/packages/frontend/src/schemas/index.ts 
b/packages/frontend/src/schemas/index.ts
index 02d3f15..008be42 100644
--- a/packages/frontend/src/schemas/index.ts
+++ b/packages/frontend/src/schemas/index.ts
@@ -111,4 +111,12 @@ export const RefoundSchema = yup.object().shape({
   refund: yup.string()
     .required()
     .test('amount', 'the amount is not valid', currencyWithAmountIsValid),
-})
\ No newline at end of file
+})
+
+
+export const OrderCreateSchema = yup.object().shape({
+  summary: yup.string().required(), 
+  amount: yup.string()
+    .required()
+    .test('amount', 'the amount is not valid', currencyWithAmountIsValid),
+})

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