gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] 01/02: lots of fixes in same commit


From: gnunet
Subject: [taler-merchant-backoffice] 01/02: lots of fixes in same commit
Date: Fri, 11 Jun 2021 04:55:31 +0200

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

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

commit c9c04a14be4bf9a70cd1730d2e8b5aa8bd38f032
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Jun 10 23:51:14 2021 -0300

    lots of fixes in same commit
    
    added tooltips in buttons and fix tooltips styles in corner cases
    added a start for required fields
    token -> access token
    fixed query product list
    refactor instance update/create form
    some more comments from christian email
---
 .../src/components/exception/AsyncButton.tsx       |  12 +-
 .../frontend/src/components/exception/login.tsx    |   6 +-
 .../frontend/src/components/form/DatePicker.tsx    |   5 -
 packages/frontend/src/components/form/Input.tsx    |   7 +-
 .../frontend/src/components/form/InputArray.tsx    |  13 +-
 .../frontend/src/components/form/InputDate.tsx     |   8 +-
 .../frontend/src/components/form/InputGroup.tsx    |   8 +-
 .../src/components/form/InputSearchProduct.tsx     |  24 +--
 .../src/components/form/InputSecured.stories.tsx   |   6 +-
 .../frontend/src/components/form/InputSecured.tsx  |   2 +-
 .../frontend/src/components/form/InputStock.tsx    |  27 ++--
 .../src/components/form/InputWithAddon.tsx         |   7 +-
 .../components/form/{Input.tsx => TextField.tsx}   |  25 +--
 packages/frontend/src/components/form/useField.tsx |  10 +-
 .../instance/DefaultInstanceFormFields.tsx         |  88 +++++++++++
 packages/frontend/src/components/menu/index.tsx    |   3 -
 packages/frontend/src/components/modal/index.tsx   |  25 +--
 packages/frontend/src/context/backend.ts           |   1 -
 packages/frontend/src/declaration.d.ts             |   9 ++
 packages/frontend/src/hooks/product.ts             |   2 +-
 packages/frontend/src/i18n/index.tsx               |   5 +-
 .../frontend/src/paths/admin/create/CreatePage.tsx |  72 ++++-----
 .../admin/create/InstanceCreatedSuccessfully.tsx   |   2 +-
 packages/frontend/src/paths/admin/list/Table.tsx   |  85 +++++-----
 .../paths/instance/orders/create/CreatePage.tsx    |   2 +-
 .../orders/create/InventoryProductForm.tsx         |   8 +-
 .../orders/create/NonInventoryProductForm.tsx      |  20 +--
 .../orders/create/OrderCreatedSuccessfully.tsx     |   9 +-
 .../paths/instance/orders/details/DetailPage.tsx   | 171 +++++++++++----------
 .../src/paths/instance/orders/details/Timeline.tsx |   5 +-
 .../src/paths/instance/orders/list/Table.tsx       |   7 +-
 .../src/paths/instance/orders/list/index.tsx       |  51 ++++--
 .../paths/instance/products/create/CreatePage.tsx  |   2 +-
 .../products/create/CreatedSuccessfully.tsx        |   1 +
 .../src/paths/instance/products/list/Table.tsx     |  82 +++++-----
 .../paths/instance/products/update/UpdatePage.tsx  |  21 ++-
 .../paths/instance/reserves/create/CreatePage.tsx  |   2 +-
 .../paths/instance/reserves/details/DetailPage.tsx | 107 ++++++-------
 .../src/paths/instance/reserves/list/Table.tsx     |  12 +-
 .../paths/instance/transfers/create/CreatePage.tsx |   2 +-
 .../src/paths/instance/transfers/list/Table.tsx    |   9 +-
 .../src/paths/instance/transfers/list/index.tsx    |  20 ++-
 .../src/paths/instance/update/UpdatePage.tsx       |  34 +---
 packages/frontend/src/scss/main.scss               |  71 +++++----
 44 files changed, 613 insertions(+), 475 deletions(-)

diff --git a/packages/frontend/src/components/exception/AsyncButton.tsx 
b/packages/frontend/src/components/exception/AsyncButton.tsx
index 95e4e72..3dad3e0 100644
--- a/packages/frontend/src/components/exception/AsyncButton.tsx
+++ b/packages/frontend/src/components/exception/AsyncButton.tsx
@@ -25,12 +25,12 @@ import { useAsync } from "../../hooks/async";
 import { Translate } from "../../i18n";
 
 type Props = {
-  children: ComponentChildren, 
+  children: ComponentChildren,
   disabled: boolean;
   onClick?: () => Promise<void>;
 };
 
-export function AsyncButton({ onClick, disabled, children }: Props) {
+export function AsyncButton({ onClick, disabled, children, ...rest }: Props) {
   const { isSlow, isLoading, request, cancel } = useAsync(onClick);
 
   if (isSlow) {
@@ -40,7 +40,9 @@ export function AsyncButton({ onClick, disabled, children }: 
Props) {
     return <button class="button"><Translate>Loading...</Translate></button>;
   }
 
-  return <button class="button is-success" onClick={request} 
disabled={disabled}>
-    {children}
-  </button>;
+  return <span {...rest}>
+    <button class="button is-success" onClick={request} disabled={disabled}>
+      {children}
+    </button>
+  </span>;
 }
diff --git a/packages/frontend/src/components/exception/login.tsx 
b/packages/frontend/src/components/exception/login.tsx
index e7c9802..fca81ae 100644
--- a/packages/frontend/src/components/exception/login.tsx
+++ b/packages/frontend/src/components/exception/login.tsx
@@ -55,7 +55,7 @@ export function LoginModal({ onConfirm, withMessage }: 
Props): VNode {
           <p class="modal-card-title">{i18n`Login required`}</p>
         </header>
         <section class="modal-card-body" style={{ border: '1px solid', 
borderTop: 0, borderBottom: 0 }}>
-          {i18n`Please enter your auth token.`}
+          <Translate>Please enter your access token.</Translate>
           <div class="field is-horizontal">
             <div class="field-label is-normal">
               <label class="label">URL</label>
@@ -74,12 +74,12 @@ export function LoginModal({ onConfirm, withMessage }: 
Props): VNode {
           </div>
           <div class="field is-horizontal">
             <div class="field-label is-normal">
-              <label class="label">Token</label>
+              <label class="label"><Translate>Access Token</Translate></label>
             </div>
             <div class="field-body">
               <div class="field">
                 <p class="control is-expanded">
-                  <input class="input" type="text" placeholder={"set new 
token"} name="token"
+                  <input class="input" type="text" placeholder={"set new 
access token"} name="token"
                     onKeyPress={e => e.keyCode === 13 ? onConfirm(url, token ? 
`secret-token:${token}` : undefined) : null}
                     value={token} 
                     onInput={(e): void => setToken(e?.currentTarget.value)}
diff --git a/packages/frontend/src/components/form/DatePicker.tsx 
b/packages/frontend/src/components/form/DatePicker.tsx
index 89d302b..084b7b0 100644
--- a/packages/frontend/src/components/form/DatePicker.tsx
+++ b/packages/frontend/src/components/form/DatePicker.tsx
@@ -261,11 +261,6 @@ export class DatePicker extends Component<Props, State> {
 
             </div>}
 
-            {/* {!selectYearMode && <div class="datePicker--actions">
-              <button onClick={this.closeDatePicker}>CANCEL</button>
-              <button onClick={this.passDateToParent}>OK</button>
-            </div>} */}
-
           </div>
         </div>
 
diff --git a/packages/frontend/src/components/form/Input.tsx 
b/packages/frontend/src/components/form/Input.tsx
index 200bf54..ab5554c 100644
--- a/packages/frontend/src/components/form/Input.tsx
+++ b/packages/frontend/src/components/form/Input.tsx
@@ -39,7 +39,7 @@ const TextInput = ({ inputType, error, ...rest }: any) => 
inputType === 'multili
   <input {...rest} class={error ? "input is-danger" : "input"} 
type={inputType} />;
 
 export function Input<T>({ name, readonly, placeholder, tooltip, label, 
expand, help, children, inputType, inputExtra, side, fromStr = 
defaultFromString, toStr = defaultToString }: Props<keyof T>): VNode {
-  const { error, value, onChange } = useField<T>(name);
+  const { error, value, onChange, required } = useField<T>(name);
   return <div class="field is-horizontal">
     <div class="field-label is-normal">
       <label class="label">
@@ -51,7 +51,7 @@ export function Input<T>({ name, readonly, placeholder, 
tooltip, label, expand,
     </div>
     <div class="field-body is-flex-grow-3">
       <div class="field">
-        <p class={expand ? "control is-expanded" : "control"}>
+        <p class={expand ? "control is-expanded has-icons-right" : "control 
has-icons-right"}>
           <TextInput error={error} {...inputExtra}
             inputType={inputType}
             placeholder={placeholder} readonly={readonly}
@@ -59,6 +59,9 @@ export function Input<T>({ name, readonly, placeholder, 
tooltip, label, expand,
             onChange={(e: h.JSX.TargetedEvent<HTMLInputElement>): void => 
onChange(fromStr(e.currentTarget.value))} />
           {help}
           {children}
+          { required && <span class="icon is-danger is-right">
+            <i class="mdi mdi-star"></i>
+          </span> }
         </p>
         {error && <p class="help is-danger">{error}</p>}
       </div>
diff --git a/packages/frontend/src/components/form/InputArray.tsx 
b/packages/frontend/src/components/form/InputArray.tsx
index cbe5c50..5314eba 100644
--- a/packages/frontend/src/components/form/InputArray.tsx
+++ b/packages/frontend/src/components/form/InputArray.tsx
@@ -20,7 +20,7 @@
 */
 import { h, VNode } from "preact";
 import { useState } from "preact/hooks";
-import { useTranslator } from "../../i18n";
+import { Translate, useTranslator } from "../../i18n";
 import { InputProps, useField } from "./useField";
 
 export interface Props<T> extends InputProps<T> {
@@ -63,24 +63,23 @@ export function InputArray<T>({ name, readonly, 
placeholder, tooltip, label, hel
               placeholder={placeholder} readonly={readonly} disabled={readonly}
               name={String(name)} value={currentValue}
               onChange={(e): void => setCurrentValue(e.currentTarget.value)} />
-            {help}
           </p>
           <p class="control">
-            <button class="button is-info" onClick={(): void => {
+            <button class="button is-info" disabled={!currentValue} 
onClick={(): void => {
               const v = fromStr(currentValue)
               if (!isValid(v)) {
                 setLocalError(i18n`The value ${v} is invalid for a payment 
url`)
                 return;
               }
               setLocalError(null)
-
               onChange([v, ...array] as any);
               setCurrentValue('');
-            }}>add</button>
+            }}><Translate>add</Translate></button>
           </p>
         </div>
-        {error && <p class="help is-danger"> {help} </p>}
-        {array.map((v,i) => <div key={i} class="tags has-addons mt-3 mb-0">
+        {help}
+        {error && <p class="help is-danger"> {error} </p>}
+        {array.map((v, i) => <div key={i} class="tags has-addons mt-3 mb-0">
           <span class="tag is-medium is-info mb-0" style={{ maxWidth: '90%' 
}}>{v}</span>
           <a class="tag is-medium is-danger is-delete mb-0" onClick={() => {
             onChange(array.filter(f => f !== v) as any);
diff --git a/packages/frontend/src/components/form/InputDate.tsx 
b/packages/frontend/src/components/form/InputDate.tsx
index 3986433..654d608 100644
--- a/packages/frontend/src/components/form/InputDate.tsx
+++ b/packages/frontend/src/components/form/InputDate.tsx
@@ -78,10 +78,12 @@ export function InputDate<T>({ name, readonly, label, 
placeholder, help, tooltip
         {error && <p class="help is-danger">{error}</p>}
       </div>
 
-      { !readonly && <button class="button is-info mr-3" onClick={() => 
onChange(undefined as any)} ><Translate>clear</Translate></button> }
-      {withTimestampSupport &&
+      {!readonly && <span data-tooltip={withTimestampSupport ? i18n`change 
value to unknown date` : i18n`change value to empty`}>
+        <button class="button is-info mr-3" onClick={() => onChange(undefined 
as any)} ><Translate>clear</Translate></button>
+      </span>}
+      {withTimestampSupport && <span data-tooltip={i18n`change value to 
never`}>
         <button class="button is-info" onClick={() => onChange({ t_ms: 'never' 
} as any)}><Translate>never</Translate></button>
-      }
+      </span>}
     </div>
     <DatePicker
       opened={opened}
diff --git a/packages/frontend/src/components/form/InputGroup.tsx 
b/packages/frontend/src/components/form/InputGroup.tsx
index 58e4260..0720cfb 100644
--- a/packages/frontend/src/components/form/InputGroup.tsx
+++ b/packages/frontend/src/components/form/InputGroup.tsx
@@ -25,8 +25,8 @@ import { useGroupField } from "./useGroupField";
 export interface Props<T> {
   name: T;
   children: ComponentChildren;
-  label: string;
-  tooltip?: string;
+  label: ComponentChildren;
+  tooltip?: ComponentChildren;
   alternative?: ComponentChildren;
 }
 
@@ -51,14 +51,10 @@ export function InputGroup<T>({ name, label, children, 
tooltip, alternative }: P
       </button>
     </header>
     {active ? <div class="card-content">
-      <div class="content">
         {children}
-      </div>
     </div> : (
       alternative ? <div class="card-content">
-        <div class="content">
           {alternative}
-        </div>
       </div> : undefined
     )}
   </div>;
diff --git a/packages/frontend/src/components/form/InputSearchProduct.tsx 
b/packages/frontend/src/components/form/InputSearchProduct.tsx
index 87ae722..43f79c9 100644
--- a/packages/frontend/src/components/form/InputSearchProduct.tsx
+++ b/packages/frontend/src/components/form/InputSearchProduct.tsx
@@ -114,18 +114,24 @@ function ProductList({ name, onSelect }: 
ProductListProps) {
       products = <div class="dropdown-content">
         {!filtered.length ?
           <div class="dropdown-item" >
-            <Translate>no results</Translate>
+            <Translate>no products found with that description</Translate>
           </div> :
           filtered.map(p => (
             <div key={p.id} class="dropdown-item" onClick={() => onSelect(p)} 
style={{ cursor: 'pointer' }}>
-              <table>
-                <tr>
-                  <td style={{ width: 32 }}>
-                    <div class="image" style={{ minWidth: 32 }}><img 
src={p.image} style={{ width: 32, height: 32 }} /></div>
-                  </td>
-                  <td><b>{p.id}</b>: {p.description}</td>
-                </tr>
-              </table>
+              <article class="media">
+                <div class="media-left">
+                  <div class="image" style={{ minWidth: 64 }}><img 
src={p.image ? p.image : emptyImage} style={{ width: 64, height: 64 }} /></div>
+                </div>
+                <div class="media-content">
+                  <div class="content">
+                    <p>
+                      <strong>{p.id}</strong> <small>{p.price}</small>
+                      <br />
+                      {p.description}
+                    </p>
+                  </div>
+                </div>
+              </article>
             </div>
           ))
         }
diff --git a/packages/frontend/src/components/form/InputSecured.stories.tsx 
b/packages/frontend/src/components/form/InputSecured.stories.tsx
index 136d412..7314add 100644
--- a/packages/frontend/src/components/form/InputSecured.stories.tsx
+++ b/packages/frontend/src/components/form/InputSecured.stories.tsx
@@ -35,14 +35,14 @@ export const InitialValueEmpty = (): VNode => {
   const [state, setState] = useState<Partial<T>>({ auth_token: '' })
   return <FormProvider<T> object={state} errors={{}} valueHandler={setState}>
     Initial value: ''
-    <InputSecured<T> name="auth_token" label="Token" />
+    <InputSecured<T> name="auth_token" label="Access token" />
   </FormProvider>
 }
 
 export const InitialValueToken = (): VNode => {
   const [state, setState] = useState<Partial<T>>({ auth_token: 'token' })
   return <FormProvider<T> object={state} errors={{}} valueHandler={setState}>
-    <InputSecured<T> name="auth_token" label="Token" />
+    <InputSecured<T> name="auth_token" label="Access token" />
   </FormProvider>
 }
 
@@ -50,6 +50,6 @@ export const InitialValueNull = (): VNode => {
   const [state, setState] = useState<Partial<T>>({ auth_token: null })
   return <FormProvider<T> object={state} errors={{}} valueHandler={setState}>
     Initial value: ''
-    <InputSecured<T> name="auth_token" label="Token" />
+    <InputSecured<T> name="auth_token" label="Access token" />
   </FormProvider>
 }
diff --git a/packages/frontend/src/components/form/InputSecured.tsx 
b/packages/frontend/src/components/form/InputSecured.tsx
index 64737e3..7d8d655 100644
--- a/packages/frontend/src/components/form/InputSecured.tsx
+++ b/packages/frontend/src/components/form/InputSecured.tsx
@@ -57,7 +57,7 @@ export function InputSecured<T>({ name, readonly, 
placeholder, tooltip, label, h
             <div class="field has-addons">
               <button class="button" onClick={(): void => { 
setActive(!active); }} >
                 <div class="icon is-left"><i class="mdi mdi-lock-reset" 
/></div>
-                <span><Translate>Manage token</Translate></span>
+                <span><Translate>Manage access token</Translate></span>
               </button>
               <TokenStatus prev={initial} post={value} />
             </div>
diff --git a/packages/frontend/src/components/form/InputStock.tsx 
b/packages/frontend/src/components/form/InputStock.tsx
index ce3add8..b323012 100644
--- a/packages/frontend/src/components/form/InputStock.tsx
+++ b/packages/frontend/src/components/form/InputStock.tsx
@@ -103,23 +103,25 @@ export function InputStock<T>({ name, readonly, 
placeholder, tooltip, label, hel
 
   const stockAddedErrors: FormErrors<typeof addedStock> = {
     lost: currentStock + addedStock.incoming < addedStock.lost ?
-      i18n`lost cannot be greater that current + incoming (max ${currentStock 
+ addedStock.incoming})`
+      i18n`lost cannot be greater than current and incoming (max 
${currentStock + addedStock.incoming})`
       : undefined
   }
 
-  const stockUpdateDescription = stockAddedErrors.lost ? '' : (
-    !!addedStock.incoming || !!addedStock.lost ?
-      i18n`current stock will change from ${currentStock} to ${currentStock + 
addedStock.incoming - addedStock.lost}` :
-      i18n`current stock will stay at ${currentStock}`
-  )
+  // const stockUpdateDescription = stockAddedErrors.lost ? '' : (
+  //   !!addedStock.incoming || !!addedStock.lost ?
+  //     i18n`current stock will change from ${currentStock} to ${currentStock 
+ addedStock.incoming - addedStock.lost}` :
+  //     i18n`current stock will stay at ${currentStock}`
+  // )
 
   return <Fragment>
     <div class="card">
       <header class="card-header">
-        {label}
-        {tooltip && <span class="icon" data-tooltip={tooltip}>
-          <i class="mdi mdi-information" />
-        </span>}
+        <p class="card-header-title">
+          {label}
+          {tooltip && <span class="icon" data-tooltip={tooltip}>
+            <i class="mdi mdi-information" />
+          </span>}
+        </p>
       </header>
       <div class="card-content">
         <FormProvider<Entity> name="stock" errors={errors} object={formValue} 
valueHandler={valueHandler}>
@@ -130,14 +132,15 @@ export function InputStock<T>({ name, readonly, 
placeholder, tooltip, label, hel
               <InputNumber name="lost" label={i18n`Lost`} />
             </FormProvider>
 
-            <div class="field is-horizontal">
+            {/* <div class="field is-horizontal">
               <div class="field-label is-normal" />
               <div class="field-body is-flex-grow-3">
                 <div class="field">
                   {stockUpdateDescription}
                 </div>
               </div>
-            </div>
+            </div> */}
+
           </Fragment> : <InputNumber<Entity> name="current"
             label={i18n`Current`}
             side={
diff --git a/packages/frontend/src/components/form/InputWithAddon.tsx 
b/packages/frontend/src/components/form/InputWithAddon.tsx
index 83b6c2e..22a4960 100644
--- a/packages/frontend/src/components/form/InputWithAddon.tsx
+++ b/packages/frontend/src/components/form/InputWithAddon.tsx
@@ -38,7 +38,7 @@ const defaultToString = (f?: any): string => f || ''
 const defaultFromString = (v: string): any => v as any
 
 export function InputWithAddon<T>({ name, readonly, addonBefore, children, 
expand, label, placeholder, help, tooltip, inputType, inputExtra, side, 
addonAfter, toStr = defaultToString, fromStr = defaultFromString }: Props<keyof 
T>): VNode {
-  const { error, value, onChange } = useField<T>(name);
+  const { error, value, onChange, required } = useField<T>(name);
 
   return <div class="field is-horizontal">
     <div class="field-label is-normal">
@@ -55,11 +55,14 @@ export function InputWithAddon<T>({ name, readonly, 
addonBefore, children, expan
           {addonBefore && <div class="control">
             <a class="button is-static">{addonBefore}</a>
           </div>}
-          <p class={expand ? "control is-expanded" : "control"}>
+          <p class={`control${expand ? " is-expanded" :""}${required ? " 
has-icons-right" : ''}`}>
             <input {...(inputExtra || {})} class={error ? "input is-danger" : 
"input"} type={inputType}
               placeholder={placeholder} readonly={readonly}
               name={String(name)} value={toStr(value)}
               onChange={(e): void => onChange(fromStr(e.currentTarget.value))} 
/>
+            {required && <span class="icon is-danger is-right">
+              <i class="mdi mdi-star"></i>
+            </span>}
             {help}
             {children}
           </p>
diff --git a/packages/frontend/src/components/form/Input.tsx 
b/packages/frontend/src/components/form/TextField.tsx
similarity index 56%
copy from packages/frontend/src/components/form/Input.tsx
copy to packages/frontend/src/components/form/TextField.tsx
index 200bf54..50ea26a 100644
--- a/packages/frontend/src/components/form/Input.tsx
+++ b/packages/frontend/src/components/form/TextField.tsx
@@ -24,22 +24,12 @@ import { useField, InputProps } from "./useField";
 interface Props<T> extends InputProps<T> {
   inputType?: 'text' | 'number' | 'multiline' | 'password';
   expand?: boolean;
-  toStr?: (v?: any) => string;
-  fromStr?: (s: string) => any;
-  inputExtra?: any,
   side?: ComponentChildren;
-  children?: ComponentChildren;
+  children: ComponentChildren;
 }
 
-const defaultToString = (f?: any): string => f || ''
-const defaultFromString = (v: string): any => v as any
-
-const TextInput = ({ inputType, error, ...rest }: any) => inputType === 
'multiline' ?
-  <textarea {...rest} class={error ? "textarea is-danger" : "textarea"} 
rows="3" /> :
-  <input {...rest} class={error ? "input is-danger" : "input"} 
type={inputType} />;
-
-export function Input<T>({ name, readonly, placeholder, tooltip, label, 
expand, help, children, inputType, inputExtra, side, fromStr = 
defaultFromString, toStr = defaultToString }: Props<keyof T>): VNode {
-  const { error, value, onChange } = useField<T>(name);
+export function TextField<T>({ name, tooltip, label, expand, help, children, 
side}: Props<keyof T>): VNode {
+  const { error } = useField<T>(name);
   return <div class="field is-horizontal">
     <div class="field-label is-normal">
       <label class="label">
@@ -51,14 +41,9 @@ export function Input<T>({ name, readonly, placeholder, 
tooltip, label, expand,
     </div>
     <div class="field-body is-flex-grow-3">
       <div class="field">
-        <p class={expand ? "control is-expanded" : "control"}>
-          <TextInput error={error} {...inputExtra}
-            inputType={inputType}
-            placeholder={placeholder} readonly={readonly}
-            name={String(name)} value={toStr(value)}
-            onChange={(e: h.JSX.TargetedEvent<HTMLInputElement>): void => 
onChange(fromStr(e.currentTarget.value))} />
+        <p class={expand ? "control is-expanded has-icons-right" : "control 
has-icons-right"}>
+          {children}          
           {help}
-          {children}
         </p>
         {error && <p class="help is-danger">{error}</p>}
       </div>
diff --git a/packages/frontend/src/components/form/useField.tsx 
b/packages/frontend/src/components/form/useField.tsx
index 969291c..c552711 100644
--- a/packages/frontend/src/components/form/useField.tsx
+++ b/packages/frontend/src/components/form/useField.tsx
@@ -24,6 +24,7 @@ import { useFormContext } from "./FormProvider";
 
 interface Use<V> {
   error?: string;
+  required: boolean;
   value: any;
   initial: any;
   onChange: (v: V) => void;
@@ -47,9 +48,10 @@ export function useField<T>(name: keyof T): Use<T[typeof 
name]> {
   const value = readField(object, String(name))
   const initial = readField(initialObject, String(name))
   const isDirty = value !== initial
-
+  const hasError = readField(errors, String(name))
   return {
-    error: isDirty ? readField(errors, String(name)) : undefined,
+    error: isDirty ? hasError : undefined,
+    required: !isDirty && hasError, 
     value,
     initial,
     onChange: updateField(name) as any,
@@ -76,9 +78,9 @@ const setValueDeeper = (object: any, names: string[], value: 
any): any => {
 
 export interface InputProps<T> {
   name: T;
-  label: string;
+  label: ComponentChildren;
   placeholder?: string;
-  tooltip?: string;
+  tooltip?: ComponentChildren;
   readonly?: boolean;
   help?: ComponentChildren;
 }
\ No newline at end of file
diff --git 
a/packages/frontend/src/components/instance/DefaultInstanceFormFields.tsx 
b/packages/frontend/src/components/instance/DefaultInstanceFormFields.tsx
new file mode 100644
index 0000000..2b98383
--- /dev/null
+++ b/packages/frontend/src/components/instance/DefaultInstanceFormFields.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/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { Fragment, h } from "preact";
+import { Input } from "../form/Input";
+import { InputCurrency } from "../form/InputCurrency";
+import { InputDuration } from "../form/InputDuration";
+import { InputGroup } from "../form/InputGroup";
+import { InputLocation } from "../form/InputLocation";
+import { InputPayto } from "../form/InputPayto";
+import { InputWithAddon } from "../form/InputWithAddon";
+import { useBackendContext } from "../../context/backend";
+import { useTranslator } from "../../i18n";
+import { Entity } from "../../paths/admin/create/CreatePage";
+
+export function DefaultInstanceFormFields({ readonlyId, showId }: { 
readonlyId?: boolean; showId: boolean }) {
+  const i18n = useTranslator();
+  const backend = useBackendContext();
+  return <Fragment>
+    { showId && <InputWithAddon<Entity> name="id" label={i18n`ID`} 
addonBefore={`${backend.url}/private/instances/`} readonly={readonlyId} 
tooltip={i18n`display name identification`} /> }
+
+    <Input<Entity> name="name" label={i18n`Name`} tooltip={i18n`descriptive 
name`} />
+
+    <InputPayto<Entity> name="payto_uris" label={i18n`Account address`} 
help="x-taler-bank/bank.taler:5882/blogger" tooltip={i18n`where the money will 
be sent`} />
+
+    <InputCurrency<Entity> name="default_max_deposit_fee" label={i18n`Default 
max deposit fee`} tooltip={i18n`max deposit fee when an order has not 
overridden it`} />
+
+    <InputCurrency<Entity> name="default_max_wire_fee" label={i18n`Default max 
wire fee`} tooltip={i18n`max wire fee when the order has not overridden it`} />
+
+    <Input<Entity> name="default_wire_fee_amortization" label={i18n`Default 
wire fee amortization`} tooltip={i18n`max wire fee amortization when the order 
has not overridden it`} />
+
+    <InputGroup name="address" label={i18n`Address`} tooltip={i18n`physical 
location of merchant`}>
+      <InputLocation name="address" />
+    </InputGroup>
+
+    <InputGroup name="jurisdiction" label={i18n`Jurisdiction`} 
tooltip={i18n`legal location of merchant`}>
+      <InputLocation name="jurisdiction" />
+    </InputGroup>
+
+    <InputDuration<Entity> name="default_pay_delay" label={i18n`Default 
payment delay`} tooltip={i18n`max time to pay if the order does not override 
it`} />
+
+    <InputDuration<Entity> name="default_wire_transfer_delay" 
label={i18n`Default wire transfer delay`} tooltip={i18n`min time to wait the 
transfer if the merchant does not override it`} />
+
+  </Fragment>;
+}
+/*
+            <InputWithAddon<Entity> name="id" label={i18n`Identifier`} 
addonBefore={`${backend.url}/private/instances/`} readonly={!!forceId} 
tooltip={i18n`Name of the instance in URLs. The 'default' instance is special 
in that it is used to administer other instances.`} />
+
+            <Input<Entity> name="name" label={i18n`Business name`} 
tooltip={i18n`Legal name of the business represented by this instance.`} />
+
+            <InputPayto<Entity> name="payto_uris" label={i18n`Bank account 
URI`} help="x-taler-bank/bank.taler:5882/blogger" tooltip={i18n`URI specifying 
bank account for crediting revenue.`} />
+
+            <InputCurrency<Entity> name="default_max_deposit_fee" 
label={i18n`Default max deposit fee`} tooltip={i18n`Maximum deposit fees this 
merchant is willing to pay per order by default.`} />
+
+            <InputCurrency<Entity> name="default_max_wire_fee" 
label={i18n`Default max wire fee`} tooltip={i18n`Maximum wire fees this 
merchant is willing to pay per wire transfer by default.`} />
+
+            <Input<Entity> name="default_wire_fee_amortization" 
label={i18n`Default wire fee amortization`} tooltip={i18n`Number of orders 
excess wire transfer fees will be divided by to compute per order surcharge.`} 
/>
+
+            <InputGroup name="address" label={i18n`Address`} 
tooltip={i18n`Physical location of the merchant.`}>
+              <InputLocation name="address" />
+            </InputGroup>
+
+            <InputGroup name="jurisdiction" label={i18n`Jurisdiction`} 
tooltip={i18n`Jurisdiction for legal disputes with the merchant.`}>
+              <InputLocation name="jurisdiction" />
+            </InputGroup>
+
+            <InputDuration<Entity> name="default_pay_delay" 
label={i18n`Default payment delay`} tooltip={i18n`Time customers have to pay an 
order before the offer expires by default.`} />
+
+            <InputDuration<Entity> name="default_wire_transfer_delay" 
label={i18n`Default wire transfer delay`} tooltip={i18n`Maximum time an 
exchange is allowed to delay wiring funds to the merchant, enabling it to 
aggregate smaller payments into larger wire transfers and reducing wire fees.`} 
/>
+*/
\ No newline at end of file
diff --git a/packages/frontend/src/components/menu/index.tsx 
b/packages/frontend/src/components/menu/index.tsx
index 31826ed..3a7ccab 100644
--- a/packages/frontend/src/components/menu/index.tsx
+++ b/packages/frontend/src/components/menu/index.tsx
@@ -27,15 +27,12 @@ import { Sidebar } from "./SideBar";
 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_details: return `${id}: Detail of the 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.reserves_details: return `${id}: Detail of a reserve`
     case InstancePaths.reserves_new: return `${id}: New reserve`
     case InstancePaths.reserves_list: return `${id}: Reserves`
     case InstancePaths.transfers_list: return `${id}: Transfers`
diff --git a/packages/frontend/src/components/modal/index.tsx 
b/packages/frontend/src/components/modal/index.tsx
index 8f6b722..9874a19 100644
--- a/packages/frontend/src/components/modal/index.tsx
+++ b/packages/frontend/src/components/modal/index.tsx
@@ -44,7 +44,7 @@ export function ConfirmModal({ active, description, onCancel, 
onConfirm, childre
     <div class="modal-background " onClick={onCancel} />
     <div class="modal-card">
       <header class="modal-card-head">
-        {!description ? null : <p class="modal-card-title  
has-text-white-ter">{description}</p>}
+        {!description ? null : <p class="modal-card-title">{description}</p>}
         <button class="delete " aria-label="close" onClick={onCancel} />
       </header>
       <section class="modal-card-body">
@@ -125,6 +125,7 @@ interface UpdateTokenModalProps {
   onClear: () => void;
 }
 
+//FIXME: merge UpdateTokenModal with SetTokenNewInstanceModal
 export function UpdateTokenModal({ onCancel, onClear, onConfirm, oldToken }: 
UpdateTokenModalProps): VNode {
   type State = { old_token: string, new_token: string, repeat_token: string }
   const [form, setValue] = useState<Partial<State>>({
@@ -134,7 +135,7 @@ export function UpdateTokenModal({ onCancel, onClear, 
onConfirm, oldToken }: Upd
 
   const hasInputTheCorrectOldToken = oldToken && oldToken !== form.old_token
   const errors = {
-    old_token: hasInputTheCorrectOldToken ? i18n`is not the same as the 
current token` : undefined,
+    old_token: hasInputTheCorrectOldToken ? i18n`is not the same as the 
current access token` : undefined,
     new_token: !form.new_token ? i18n`cannot be empty` : (form.new_token === 
form.old_token ? i18n`cannot be the same as the old token` : undefined),
     repeat_token: form.new_token !== form.repeat_token ? i18n`is not the same` 
: undefined
   }
@@ -143,7 +144,7 @@ export function UpdateTokenModal({ onCancel, onClear, 
onConfirm, oldToken }: Upd
 
   const instance = useInstanceContext()
 
-  const text = i18n`You are updating the authorization token from instance 
with id ${instance.id}`
+  const text = i18n`You are updating the access token from instance with id 
${instance.id}`
 
   return <ClearConfirmModal description={text}
     onCancel={onCancel}
@@ -154,11 +155,11 @@ export function UpdateTokenModal({ onCancel, onClear, 
onConfirm, oldToken }: Upd
       <div class="column" />
       <div class="column is-four-fifths" >
         <FormProvider errors={errors} object={form} valueHandler={setValue}>
-          {oldToken && <Input<State> name="old_token" label={i18n`Old token`} 
tooltip={i18n`token currently in use`} inputType="password" />}
-          <Input<State> name="new_token" label={i18n`New token`} 
tooltip={i18n`next token to be used`} inputType="password" />
-          <Input<State> name="repeat_token" label={i18n`Repeat token`} 
tooltip={i18n`confirm the same token`} inputType="password" />
+          {oldToken && <Input<State> name="old_token" label={i18n`Old access 
token`} tooltip={i18n`access token currently in use`} inputType="password" />}
+          <Input<State> name="new_token" label={i18n`New access token`} 
tooltip={i18n`next access token to be used`} inputType="password" />
+          <Input<State> name="repeat_token" label={i18n`Repeat access token`} 
tooltip={i18n`confirm the same access token`} inputType="password" />
         </FormProvider>
-        <p><Translate>Clearing the auth token will mean public access to the 
instance</Translate></p>
+        <p><Translate>Clearing the access token will mean public access to the 
instance</Translate></p>
       </div>
       <div class="column" />
     </div>
@@ -173,13 +174,13 @@ export function SetTokenNewInstanceModal({ onCancel, 
onClear, onConfirm }: Updat
   const i18n = useTranslator()
 
   const errors = {
-    new_token: !form.new_token ? i18n`cannot be empty` : (form.new_token === 
form.old_token ? i18n`cannot be the same as the old token` : undefined),
+    new_token: !form.new_token ? i18n`cannot be empty` : (form.new_token === 
form.old_token ? i18n`cannot be the same as the old access token` : undefined),
     repeat_token: form.new_token !== form.repeat_token ? i18n`is not the same` 
: undefined
   }
 
   const hasErrors = Object.keys(errors).some(k => (errors as any)[k] !== 
undefined)
 
-  const text = i18n`You are setting the authorization token for the new 
instance`
+  const text = i18n`You are setting the access token for the new instance`
 
   return <ClearConfirmModal description={text}
     onCancel={onCancel}
@@ -190,10 +191,10 @@ export function SetTokenNewInstanceModal({ onCancel, 
onClear, onConfirm }: Updat
       <div class="column" />
       <div class="column is-four-fifths" >
         <FormProvider errors={errors} object={form} valueHandler={setValue}>
-          <Input<State> name="new_token" label={i18n`New token`} 
tooltip={i18n`next token to be used`} inputType="password" />
-          <Input<State> name="repeat_token" label={i18n`Repeat token`} 
tooltip={i18n`confirm the same token`} inputType="password" />
+          <Input<State> name="new_token" label={i18n`New access token`} 
tooltip={i18n`next access token to be used`} inputType="password" />
+          <Input<State> name="repeat_token" label={i18n`Repeat access token`} 
tooltip={i18n`confirm the same access token`} inputType="password" />
         </FormProvider>
-        <p><Translate>Clearing the auth token will mean public access to the 
instance</Translate></p>
+        <p><Translate>Clearing the access token will mean public access to the 
instance</Translate></p>
       </div>
       <div class="column" />
     </div>
diff --git a/packages/frontend/src/context/backend.ts 
b/packages/frontend/src/context/backend.ts
index c1b2c14..9355859 100644
--- a/packages/frontend/src/context/backend.ts
+++ b/packages/frontend/src/context/backend.ts
@@ -49,7 +49,6 @@ export function useBackendContextState(): BackendContextType {
   const [url, triedToLog, changeBackend, resetBackend] = useBackendURL();
   const [token, _updateToken] = useBackendDefaultToken();
   const updateToken = (t?:string) => {
-    // console.log("update token", t)
     _updateToken(t)
   }
 
diff --git a/packages/frontend/src/declaration.d.ts 
b/packages/frontend/src/declaration.d.ts
index 21199f4..82bc694 100644
--- a/packages/frontend/src/declaration.d.ts
+++ b/packages/frontend/src/declaration.d.ts
@@ -685,6 +685,15 @@ export namespace MerchantBackend {
             // The order was neither claimed nor paid.
             order_status: "unpaid";
 
+            // when was the order created
+            creation_time: Timestamp;
+
+            // Order summary text.
+            summary: string;
+
+            // Total amount of the order (to be paid by the customer).
+            total_amount: Amount;
+
             // URI that the wallet must process to complete the payment.
             taler_pay_uri: string;
 
diff --git a/packages/frontend/src/hooks/product.ts 
b/packages/frontend/src/hooks/product.ts
index 6dd2d13..cdb1c4e 100644
--- a/packages/frontend/src/hooks/product.ts
+++ b/packages/frontend/src/hooks/product.ts
@@ -138,7 +138,7 @@ export function useInstanceProducts(): 
HttpResponse<(MerchantBackend.Products.Pr
     if (!list?.data || !list.data.products.length || listError || listLoading) 
return null
     return [`/private/products/${list.data.products[pageIndex].product_id}`, 
token, url]
   }, fetcher, {
-
+    revalidateAll: true,
   })
 
   useEffect(() => {
diff --git a/packages/frontend/src/i18n/index.tsx 
b/packages/frontend/src/i18n/index.tsx
index 5be1a3b..63c8e19 100644
--- a/packages/frontend/src/i18n/index.tsx
+++ b/packages/frontend/src/i18n/index.tsx
@@ -21,7 +21,7 @@
 /**
  * Imports
  */
-import { Component, ComponentChild, ComponentChildren, h, Fragment, VNode } 
from "preact";
+import { ComponentChild, ComponentChildren, h, Fragment, VNode } from "preact";
 
 import { useTranslationContext } from "../context/translation";
 
@@ -40,11 +40,10 @@ export function useTranslator() {
 }
 
 
-
 /**
  * Convert template strings to a msgid
  */
-function toI18nString(stringSeq: ReadonlyArray<string>): string {
+ function toI18nString(stringSeq: ReadonlyArray<string>): string {
   let s = "";
   for (let i = 0; i < stringSeq.length; i++) {
     s += stringSeq[i];
diff --git a/packages/frontend/src/paths/admin/create/CreatePage.tsx 
b/packages/frontend/src/paths/admin/create/CreatePage.tsx
index 488d137..82286de 100644
--- a/packages/frontend/src/paths/admin/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/admin/create/CreatePage.tsx
@@ -24,22 +24,13 @@ import { useState } from "preact/hooks";
 import * as yup from 'yup';
 import { AsyncButton } from "../../../components/exception/AsyncButton";
 import { FormErrors, FormProvider } from 
"../../../components/form/FormProvider";
-import { Input } from "../../../components/form/Input";
-import { InputCurrency } from "../../../components/form/InputCurrency";
-import { InputDuration } from "../../../components/form/InputDuration";
-import { InputGroup } from "../../../components/form/InputGroup";
-import { InputLocation } from "../../../components/form/InputLocation";
-import { InputPayto } from "../../../components/form/InputPayto";
-import { InputSecured } from "../../../components/form/InputSecured";
-import { InputWithAddon } from "../../../components/form/InputWithAddon";
-import { SetTokenNewInstanceModal, UpdateTokenModal } from 
"../../../components/modal";
-import { useBackendContext } from "../../../context/backend";
-import { useInstanceContext } from "../../../context/instance";
+import { SetTokenNewInstanceModal } from "../../../components/modal";
 import { MerchantBackend } from "../../../declaration";
 import { Translate, useTranslator } from "../../../i18n";
 import { InstanceCreateSchema as schema } from '../../../schemas';
+import { DefaultInstanceFormFields } from 
"../../../components/instance/DefaultInstanceFormFields";
 
-type Entity = MerchantBackend.Instances.InstanceConfigurationMessage & { 
auth_token?: string }
+export type Entity = MerchantBackend.Instances.InstanceConfigurationMessage & 
{ auth_token?: string }
 
 interface Props {
   onCreate: (d: Entity) => Promise<void>;
@@ -50,9 +41,9 @@ interface Props {
 function with_defaults(id?: string): Partial<Entity> {
   return {
     id,
-    default_pay_delay: { d_ms: 1000 * 60 * 5 },
+    default_pay_delay: { d_ms: 1000 * 60 * 60 }, // one hour
     default_wire_fee_amortization: 1,
-    default_wire_transfer_delay: { d_ms: 2000 * 60 * 5 },
+    default_wire_transfer_delay: { d_ms: 1000 * 2 * 60 * 60 * 24 }, // one day
   };
 }
 export function CreatePage({ onCreate, onBack, forceId }: Props): VNode {
@@ -78,13 +69,13 @@ export function CreatePage({ onCreate, onBack, forceId }: 
Props): VNode {
     // schema.validateSync(value, { abortEarly: false })
     return onCreate(schema.cast(value) as Entity);
   }
-  const backend = useBackendContext()
 
   function updateToken(token: string | null) {
     valueHandler(old => ({ ...old, auth_token: token === null ? undefined : 
token }))
   }
 
   const i18n = useTranslator()
+
   return <div>
     <div class="columns">
       <div class="column" />
@@ -108,44 +99,37 @@ export function CreatePage({ onCreate, onBack, forceId }: 
Props): VNode {
       <div class="column" />
     </div>
 
+    <section class="hero is-hero-bar">
+      <div class="hero-body">
+        <div class="level">
+          <div class="level-item has-text-centered">
+            <h1 class="title">
+              <button class="button is-danger" onClick={() => 
updateIsTokenDialogActive(true)} >
+                <div class="icon is-centered"><i class="mdi mdi-lock-reset" 
/></div>
+                <span><Translate>Set access token</Translate></span>
+              </button>
+            </h1>
+          </div>
+        </div>
+      </div></section>
+
+
     <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} >
-
-            <InputWithAddon<Entity> name="id" label={i18n`Identifier`} 
addonBefore={`${backend.url}/private/instances/`} readonly={!!forceId} 
tooltip={i18n`Name of the instance in URLs. The 'default' instance is special 
in that it is used to administer other instances.`} />
-
-            <Input<Entity> name="name" label={i18n`Business name`} 
tooltip={i18n`Legal name of the business represented by this instance.`} />
+        <div class="column is-four-fifths">
 
-            <InputPayto<Entity> name="payto_uris" label={i18n`Bank account 
URI`} help="x-taler-bank/bank.taler:5882/blogger" tooltip={i18n`URI specifying 
bank account for crediting revenue.`} />
-
-            <InputCurrency<Entity> name="default_max_deposit_fee" 
label={i18n`Default max deposit fee`} tooltip={i18n`Maximum deposit fees this 
merchant is willing to pay per order by default.`} />
-
-            <InputCurrency<Entity> name="default_max_wire_fee" 
label={i18n`Default max wire fee`} tooltip={i18n`Maximum wire fees this 
merchant is willing to pay per wire transfer by default.`} />
-
-            <Input<Entity> name="default_wire_fee_amortization" 
label={i18n`Default wire fee amortization`} tooltip={i18n`Number of orders 
excess wire transfer fees will be divided by to compute per order surcharge.`} 
/>
-
-            <InputGroup name="address" label={i18n`Address`} 
tooltip={i18n`Physical location of the merchant.`}>
-              <InputLocation name="address" />
-            </InputGroup>
-
-            <InputGroup name="jurisdiction" label={i18n`Jurisdiction`} 
tooltip={i18n`Jurisdiction for legal disputes with the merchant.`}>
-              <InputLocation name="jurisdiction" />
-            </InputGroup>
-
-            <InputDuration<Entity> name="default_pay_delay" 
label={i18n`Default payment delay`} tooltip={i18n`Time customers have to pay an 
order before the offer expires by default.`} />
+          <FormProvider<Entity> errors={errors} object={value} 
valueHandler={valueHandler} >
 
-            <InputDuration<Entity> name="default_wire_transfer_delay" 
label={i18n`Default wire transfer delay`} tooltip={i18n`Maximum time an 
exchange is allowed to delay wiring funds to the merchant, enabling it to 
aggregate smaller payments into larger wire transfers and reducing wire fees.`} 
/>
+            <DefaultInstanceFormFields readonlyId={!!forceId} showId={true} />
 
           </FormProvider>
 
           <div class="buttons is-right mt-5">
-            {onBack && <button class="button" onClick={onBack} 
><Translate>Cancel</Translate></button>}
-            {isTokenSet ?
-              <AsyncButton onClick={submit} disabled={hasErrors} 
><Translate>Confirm</Translate></AsyncButton> :
-              <button class="button" onClick={() => 
updateIsTokenDialogActive(true)} ><Translate>Set token</Translate></button>
-            }
+            {onBack && <button class="button" 
onClick={onBack}><Translate>Cancel</Translate></button>}
+            <AsyncButton onClick={submit} disabled={!isTokenSet && hasErrors} 
data-tooltip={
+              hasErrors ? i18n`Need to complete fields first, check fields 
marked with a star` : 'confirm operation'
+            }><Translate>Confirm</Translate></AsyncButton>
           </div>
 
         </div>
diff --git 
a/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx 
b/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx
index 45aec1c..00b3f20 100644
--- a/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx
+++ b/packages/frontend/src/paths/admin/create/InstanceCreatedSuccessfully.tsx
@@ -49,7 +49,7 @@ export function InstanceCreatedSuccessfully({ entity, 
onConfirm }: { entity: Ent
     </div>
     <div class="field is-horizontal">
       <div class="field-label is-normal">
-        <label class="label">Token</label>
+        <label class="label">Access token</label>
       </div>
       <div class="field-body is-flex-grow-3">
         <div class="field">
diff --git a/packages/frontend/src/paths/admin/list/Table.tsx 
b/packages/frontend/src/paths/admin/list/Table.tsx
index 1f512c0..4210a92 100644
--- a/packages/frontend/src/paths/admin/list/Table.tsx
+++ b/packages/frontend/src/paths/admin/list/Table.tsx
@@ -22,7 +22,7 @@
 import { h, VNode } from "preact";
 import { StateUpdater, useEffect, useState } from "preact/hooks";
 import { MerchantBackend } from "../../../declaration";
-import { Translate } from "../../../i18n";
+import { Translate, useTranslator } from "../../../i18n";
 
 interface Props {
   instances: MerchantBackend.Instances.Instance[];
@@ -50,6 +50,7 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected }:
     }
   }, [actionQueue, selected, onUpdate])
 
+  const i18n = useTranslator()
 
   return <div class="card has-table">
     <header class="card-header">
@@ -63,9 +64,11 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected }:
         </button>
       </div>
       <div class="card-header-icon" aria-label="more options">
-        <button class="button is-info" type="button" onClick={onCreate}>
-          <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
-        </button>
+        <span class="has-tooltip-left" data-tooltip={i18n`add new instance`}>
+          <button class="button is-info" type="button" onClick={onCreate}>
+            <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
+          </button>
+        </span>
       </div>
 
     </header>
@@ -96,48 +99,48 @@ function toggleSelected<T>(id: T): (prev: T[]) => T[] {
 function Table({ rowSelection, rowSelectionHandler, instances, onUpdate, 
onDelete }: TableProps): VNode {
   return (
     <div class="table-container">
-    <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
-      <thead>
-        <tr>
-          <th class="is-checkbox-cell">
-            <label class="b-checkbox checkbox">
-              <input type="checkbox" checked={rowSelection.length === 
instances.length} onClick={(): void => rowSelectionHandler(rowSelection.length 
=== instances.length ? [] : instances.map(i => i.id))} />
-              <span class="check" />
-            </label>
-          </th>
-          <th><Translate>ID</Translate></th>
-          <th><Translate>Name</Translate></th>
-          <th />
-        </tr>
-      </thead>
-      <tbody>
-        {instances.map(i => {
-          return <tr key={i.id}>
-            <td class="is-checkbox-cell">
+      <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
+        <thead>
+          <tr>
+            <th class="is-checkbox-cell">
               <label class="b-checkbox checkbox">
-                <input type="checkbox" checked={rowSelection.indexOf(i.id) != 
-1} onClick={(): void => rowSelectionHandler(toggleSelected(i.id))} />
+                <input type="checkbox" checked={rowSelection.length === 
instances.length} onClick={(): void => rowSelectionHandler(rowSelection.length 
=== instances.length ? [] : instances.map(i => i.id))} />
                 <span class="check" />
               </label>
-            </td>
-            <td><a href={`/orders?instance=${i.id}`} >{i.id}</a></td>
-            <td >{i.name}</td>
-            <td class="is-actions-cell right-sticky">
-              <div class="buttons is-right">
-                <button class="button is-small is-success jb-modal" 
type="button" onClick={(): void => onUpdate(i.id)}>
-                  <Translate>Edit</Translate>
-                </button>
-                <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onDelete(i)}>
-                  <Translate>Delete</Translate>
-                </button>
-              </div>
-            </td>
+            </th>
+            <th><Translate>ID</Translate></th>
+            <th><Translate>Name</Translate></th>
+            <th />
           </tr>
-        })}
-
-      </tbody>
-    </table>
+        </thead>
+        <tbody>
+          {instances.map(i => {
+            return <tr key={i.id}>
+              <td class="is-checkbox-cell">
+                <label class="b-checkbox checkbox">
+                  <input type="checkbox" checked={rowSelection.indexOf(i.id) 
!= -1} onClick={(): void => rowSelectionHandler(toggleSelected(i.id))} />
+                  <span class="check" />
+                </label>
+              </td>
+              <td><a href={`/orders?instance=${i.id}`} >{i.id}</a></td>
+              <td >{i.name}</td>
+              <td class="is-actions-cell right-sticky">
+                <div class="buttons is-right">
+                  <button class="button is-small is-success jb-modal" 
type="button" onClick={(): void => onUpdate(i.id)}>
+                    <Translate>Edit</Translate>
+                  </button>
+                  <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onDelete(i)}>
+                    <Translate>Delete</Translate>
+                  </button>
+                </div>
+              </td>
+            </tr>
+          })}
+
+        </tbody>
+      </table>
     </div>
-    )
+  )
 }
 
 function EmptyTable(): VNode {
diff --git a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx 
b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
index 1b47564..ae32dac 100644
--- a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
@@ -257,7 +257,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
               with a total price of {totalPriceProducts}
             </p>
           } tooltip={i18n`Add products without inventory management to the 
order.`}>
-            <NonInventoryProductFrom value={editingProduct} onAddProduct={(p) 
=> {
+            <NonInventoryProductFrom productToEdit={editingProduct} 
onAddProduct={(p) => {
               setEditingProduct(undefined)
               return addNewProduct(p)
             }} />
diff --git 
a/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx 
b/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx
index 6cf48f8..b97b39a 100644
--- 
a/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx
+++ 
b/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx
@@ -39,12 +39,14 @@ export function InventoryProductForm({ currentProducts, 
onAddProduct }: Props):
 
   const i18n = useTranslator()
 
+  const productWithInfiniteStock = state.product && state.product.total_stock 
=== -1
+
   const submit = (): void => {
     if (!state.product) {
       setErrors({ product: i18n`You must enter a valid product identifier.` });
       return;
     }
-    if (state.product.total_stock === -1) {
+    if (productWithInfiniteStock) {
       onAddProduct(state.product, 1)
     } else {
       if (!state.quantity || state.quantity <= 0) {
@@ -73,9 +75,9 @@ export function InventoryProductForm({ currentProducts, 
onAddProduct }: Props):
 
   return <FormProvider<Form> errors={errors} object={state} 
valueHandler={setState}>
     <InputSearchProduct selected={state.product} onChange={(p) => setState(v 
=> ({ ...v, product: p }))}  />
-    <InputNumber<Form> name="quantity" label={i18n`Quantity`} 
tooltip={i18n`how many products will be added`} />
+    { state.product && !productWithInfiniteStock && <InputNumber<Form> 
name="quantity" label={i18n`Quantity`} tooltip={i18n`how many products will be 
added`} /> }
     <div class="buttons is-right mt-5">
-      <button class="button is-success" 
onClick={submit}><Translate>Add</Translate></button>
+      <button class="button is-success" disabled={!state.product} 
onClick={submit}><Translate>Add</Translate></button>
     </div>
   </FormProvider>
 }
diff --git 
a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
 
b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
index 967f1cb..756ec23 100644
--- 
a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
+++ 
b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
@@ -28,22 +28,22 @@ import {
   NonInventoryProductSchema as schema
 } from '../../../../schemas';
 import * as yup from 'yup';
-import { useTranslator } from "../../../../i18n";
+import { Translate, useTranslator } from "../../../../i18n";
 
 type Entity = MerchantBackend.Product
 
 interface Props {
   onAddProduct: (p: Entity) => Promise<void>;
-  value?: Entity;
+  productToEdit?: Entity;
 }
-export function NonInventoryProductFrom({ value, onAddProduct }: Props): VNode 
{
+export function NonInventoryProductFrom({ productToEdit, onAddProduct }: 
Props): VNode {
   const [showCreateProduct, setShowCreateProduct] = useState(false)
 
-  const editing = !!value
+  const isEditing = !!productToEdit
 
   useEffect(() => {
-    setShowCreateProduct(editing)
-  }, [editing])
+    setShowCreateProduct(isEditing)
+  }, [isEditing])
 
   const [submitForm, addFormSubmitter] = 
useListener<Partial<MerchantBackend.Product> | undefined>((result) => {
     if (result) {
@@ -62,10 +62,12 @@ export function NonInventoryProductFrom({ value, 
onAddProduct }: Props): VNode {
 
   return <Fragment>
     <div class="buttons">
-      <button class="button is-success" onClick={() => 
setShowCreateProduct(true)} >add new product</button>
+      <button class="button is-success" onClick={() => 
setShowCreateProduct(true)} ><Translate>add new product</Translate></button>
     </div>
-    {showCreateProduct && <ConfirmModal active onCancel={() => 
setShowCreateProduct(false)} onConfirm={submitForm}>
-      <ProductForm initial={value} onSubscribe={addFormSubmitter} />
+    {showCreateProduct && <ConfirmModal active
+      description="alskdj alsk jdalksjd laksjd lkasjd"
+      onCancel={() => setShowCreateProduct(false)} onConfirm={submitForm}>
+      <ProductForm initial={productToEdit} onSubscribe={addFormSubmitter} />
     </ConfirmModal>}
   </Fragment>
 }
diff --git 
a/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx
 
b/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx
index db0be90..14c5d68 100644
--- 
a/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx
+++ 
b/packages/frontend/src/paths/instance/orders/create/OrderCreatedSuccessfully.tsx
@@ -17,6 +17,7 @@ import { h, VNode } from "preact";
 import { useEffect, useState } from "preact/hooks";
 import { CreatedSuccessfully } from 
"../../../../components/notifications/CreatedSuccessfully";
 import { useOrderAPI } from "../../../../hooks/order";
+import { Translate } from "../../../../i18n";
 import { Entity } from "./index";
 
 interface Props {
@@ -38,7 +39,7 @@ export function OrderCreatedSuccessfully({ entity, onConfirm, 
onCreateAnother }:
   return <CreatedSuccessfully onConfirm={onConfirm} 
onCreateAnother={onCreateAnother}>
     <div class="field is-horizontal">
       <div class="field-label is-normal">
-        <label class="label">Amount</label>
+        <label class="label"><Translate>Amount</Translate></label>
       </div>
       <div class="field-body is-flex-grow-3">
         <div class="field">
@@ -50,7 +51,7 @@ export function OrderCreatedSuccessfully({ entity, onConfirm, 
onCreateAnother }:
     </div>
     <div class="field is-horizontal">
       <div class="field-label is-normal">
-        <label class="label">Summary</label>
+        <label class="label"><Translate>Summary</Translate></label>
       </div>
       <div class="field-body is-flex-grow-3">
         <div class="field">
@@ -62,7 +63,7 @@ export function OrderCreatedSuccessfully({ entity, onConfirm, 
onCreateAnother }:
     </div>
     <div class="field is-horizontal">
       <div class="field-label is-normal">
-        <label class="label">Order ID</label>
+        <label class="label"><Translate>Order ID</Translate></label>
       </div>
       <div class="field-body is-flex-grow-3">
         <div class="field">
@@ -74,7 +75,7 @@ export function OrderCreatedSuccessfully({ entity, onConfirm, 
onCreateAnother }:
     </div>
     <div class="field is-horizontal">
       <div class="field-label is-normal">
-        <label class="label">Payment URL</label>
+        <label class="label"><Translate>Payment URL</Translate></label>
       </div>
       <div class="field-body is-flex-grow-3">
         <div class="field">
diff --git a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx 
b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
index be05b43..9f148b6 100644
--- a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
+++ b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
@@ -19,6 +19,7 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
+import { AmountJson, Amounts } from "@gnu-taler/taler-util";
 import { format } from "date-fns";
 import { Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
@@ -29,7 +30,7 @@ import { InputDate } from 
"../../../../components/form/InputDate";
 import { InputDuration } from "../../../../components/form/InputDuration";
 import { InputGroup } from "../../../../components/form/InputGroup";
 import { InputLocation } from "../../../../components/form/InputLocation";
-import { NotificationCard } from "../../../../components/menu";
+import { TextField } from "../../../../components/form/TextField";
 import { ProductList } from "../../../../components/product/ProductList";
 import { MerchantBackend } from "../../../../declaration";
 import { Translate, useTranslator } from "../../../../i18n";
@@ -52,6 +53,35 @@ type Unpaid = 
MerchantBackend.Orders.CheckPaymentUnpaidResponse
 type Claimed = MerchantBackend.Orders.CheckPaymentClaimedResponse
 
 
+function ContractTerms({ value }: { value: CT }) {
+  const i18n = useTranslator()
+
+  return <InputGroup name="contract_terms" label={i18n`Contract Terms`}>
+    <FormProvider<CT> object={value} valueHandler={null} >
+      <Input<CT> readonly name="summary" label={i18n`Summary`} 
tooltip={i18n`human-readable description of the whole purchase`} />
+      <InputCurrency<CT> readonly name="amount" label={i18n`Amount`} 
tooltip={i18n`total price for the transaction`} />
+      {value.fulfillment_url &&
+        <Input<CT> readonly name="fulfillment_url" label={i18n`Fulfillment 
URL`} tooltip={i18n`URL for this purchase`} />
+      }
+      <Input<CT> readonly name="max_fee" label={i18n`Max fee`} 
tooltip={i18n`maximum total deposit fee accepted by the merchant for this 
contract`} />
+      <Input<CT> readonly name="max_wire_fee" label={i18n`Max wire fee`} 
tooltip={i18n`maximum wire fee accepted by the merchant`} />
+      <Input<CT> readonly name="wire_fee_amortization" label={i18n`Wire fee 
amortization`} tooltip={i18n`over how many customer transactions does the 
merchant expect to amortize wire fees on average`} />
+      <InputDate<CT> readonly name="timestamp" label={i18n`Created at`} 
tooltip={i18n`time when this contract was generated`} />
+      <InputDate<CT> readonly name="refund_deadline" label={i18n`Refund 
deadline`} tooltip={i18n`after this deadline has passed no refunds will be 
accepted`} />
+      <InputDate<CT> readonly name="pay_deadline" label={i18n`Payment 
deadline`} tooltip={i18n`after this deadline, the merchant won't accept 
payments for the contract`} />
+      <InputDate<CT> readonly name="wire_transfer_deadline" label={i18n`Wire 
transfer deadline`} tooltip={i18n`transfer deadline for the exchange`} />
+      <InputDate<CT> readonly name="delivery_date" label={i18n`Delivery date`} 
tooltip={i18n`time indicating when the order should be delivered`} />
+      {value.delivery_date &&
+        <InputGroup name="delivery_location" label={i18n`Location`} 
tooltip={i18n`where the order will be delivered`} >
+          <InputLocation name="payments.delivery_location" />
+        </InputGroup>
+      }
+      <InputDuration<CT> readonly name="auto_refund" label={i18n`Auto-refund 
delay`} tooltip={i18n`how long the wallet should try to get an automatic refund 
for the purchase`} />
+      <Input<CT> readonly name="extra" label={i18n`Extra info`} 
tooltip={i18n`extra data that is only interpreted by the merchant frontend`} />
+    </FormProvider>
+  </InputGroup>
+}
+
 function ClaimedPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.CheckPaymentClaimedResponse }) {
   const events: Event[] = []
   events.push({
@@ -126,11 +156,8 @@ function ClaimedPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.
                       whiteSpace: 'nowrap',
                       overflow: 'hidden',
                       textOverflow: 'ellipsis',
-                      // maxWidth: '100%',
                     }}>
-                      {/* <a href={order.order_status_url} rel="nofollow" 
target="new">{order.order_status_url}</a> */}
-                      <p><Translate>pay at</Translate>:  <b>missing value, 
there is no order_status_url</b></p>
-                      <p><Translate>created at</Translate>: {format(new 
Date(order.contract_terms.timestamp.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p>
+                      <p><b><Translate>claimed at</Translate>:</b> {format(new 
Date(order.contract_terms.timestamp.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p>
                     </div>
                   </div>
                 </div>
@@ -155,18 +182,12 @@ function ClaimedPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.
             </div>
           </section>
 
-          {order.contract_terms.products.length > 0 &&
-            <section class="section">
-              <div class="columns">
-                <div class="column is-12" >
-                  <div class="title"><Translate>Product list</Translate></div>
-                  <ProductList list={order.contract_terms.products} />
-                </div>
-                <div class="column" />
-              </div>
-            </section>
-          }
+          {order.contract_terms.products.length ? <Fragment>
+            <div class="title"><Translate>Product list</Translate></div>
+            <ProductList list={order.contract_terms.products} />
+          </Fragment> : undefined}
 
+          {value.contract_terms && <ContractTerms value={value.contract_terms} 
/>}
         </div>
         <div class="column" />
       </div>
@@ -207,19 +228,43 @@ function PaidPage({ id, order, onRefund }: { id: string; 
order: MerchantBackend.
       type: 'refund',
     })
   })
-  order.wire_details.forEach(e => {
-    events.push({
-      when: new Date(e.execution_time.t_ms),
-      description: `wired`,
-      type: 'wired',
-    })
-  })
-  if (order.contract_terms.wire_transfer_deadline.t_ms !== 'never' &&
-    order.contract_terms.wire_transfer_deadline.t_ms < new Date().getTime()) 
events.push({
-      when: new Date(order.contract_terms.wire_transfer_deadline.t_ms - 1000 * 
10),
-      description: `wired (faked)`,
-      type: 'wired',
-    })
+  if (order.wire_details && order.wire_details.length) {
+    if (order.wire_details.length > 1) {
+      let last: MerchantBackend.Orders.TransactionWireTransfer | null = null
+      let first: MerchantBackend.Orders.TransactionWireTransfer | null = null
+      let total: AmountJson | null = null
+
+      order.wire_details.forEach(w => {
+        if (last === null || last.execution_time.t_ms < w.execution_time.t_ms) 
{
+          last = w
+        }
+        if (first === null || first.execution_time.t_ms > 
w.execution_time.t_ms) {
+          first = w
+        }
+        total = total === null ? Amounts.parseOrThrow(w.amount) : 
Amounts.add(total, Amounts.parseOrThrow(w.amount)).amount
+      })
+      events.push({
+        when: new Date(last!.execution_time.t_ms),
+        description: `wired ${Amounts.stringify(total!)}`,
+        type: 'wired-range',
+      })
+      events.push({
+        when: new Date(first!.execution_time.t_ms),
+        description: `wire transfer started...`,
+        type: 'wired-range',
+      })
+    } else {
+      order.wire_details.forEach(e => {
+        events.push({
+          when: new Date(e.execution_time.t_ms),
+          description: `wired ${e.amount}`,
+          type: 'wired',
+        })
+      })
+
+    }
+
+  }
 
   const [value, valueHandler] = useState<Partial<Paid>>(order)
 
@@ -261,10 +306,9 @@ function PaidPage({ id, order, onRefund }: { id: string; 
order: MerchantBackend.
                   <div class="level-item">
                     <h1 class="title">
                       <div class="buttons">
-                        {refundable && <button class="button is-danger" 
onClick={() => onRefund(id)}><Translate>refund</Translate></button>}
-                        <button class="button is-info" onClick={() => {
-                          if (order.contract_terms.fulfillment_url) 
copyToClipboard(order.contract_terms.fulfillment_url)
-                        }}><Translate>copy url</Translate></button>
+                        <span class="has-tooltip-left" 
data-tooltip={refundable ? i18n`refund order`: i18n`not refundable`}>
+                          <button class="button is-danger" 
disabled={!refundable} onClick={() => 
onRefund(id)}><Translate>refund</Translate></button>
+                        </span>
                       </div>
                     </h1>
                   </div>
@@ -301,53 +345,23 @@ function PaidPage({ id, order, onRefund }: { id: string; 
order: MerchantBackend.
                   <InputCurrency<Paid> name="deposit_total" readonly 
label={i18n`Deposit total`} />
                   {order.refunded && <InputCurrency<Paid> name="refund_amount" 
readonly label={i18n`Refunded amount`} />}
                   <Input<Paid> name="order_status" readonly label={i18n`Order 
status`} />
-                  {order.order_status_url && <Input<Paid> 
name="order_status_url" readonly label={i18n`Status URL`} />}
+                  <TextField<Paid> name="order_status_url" label={i18n`Status 
URL`} >
+                    <a target="_blank" href={order.order_status_url}>
+                      {order.order_status_url}
+                    </a>
+                  </TextField>
                 </FormProvider>
               </div>
             </div>
           </section>
 
-          {value.contract_terms && <section class="section">
-            <div class="columns">
-              <div class="column is-12" >
-                <div class="title"><Translate>Contract Terms</Translate></div>
-                <FormProvider<CT> object={value.contract_terms} 
valueHandler={null} >
-                  <Input<CT> readonly name="summary" label={i18n`Summary`} 
tooltip={i18n`human-readable description of the whole purchase`} />
-                  <InputCurrency<CT> readonly name="amount" 
label={i18n`Amount`} tooltip={i18n`total price for the transaction`} />
-                  {value.contract_terms.fulfillment_url &&
-                    <Input<CT> readonly name="fulfillment_url" 
label={i18n`Fulfillment URL`} tooltip={i18n`URL for this purchase`} />
-                  }
-                  <Input<CT> readonly name="max_fee" label={i18n`Max fee`} 
tooltip={i18n`maximum total deposit fee accepted by the merchant for this 
contract`} />
-                  <Input<CT> readonly name="max_wire_fee" label={i18n`Max wire 
fee`} tooltip={i18n`maximum wire fee accepted by the merchant`} />
-                  <Input<CT> readonly name="wire_fee_amortization" 
label={i18n`Wire fee amortization`} tooltip={i18n`over how many customer 
transactions does the merchant expect to amortize wire fees on average`} />
-                  <InputDate<CT> readonly name="timestamp" label={i18n`Created 
at`} tooltip={i18n`time when this contract was generated`} />
-                  <InputDate<CT> readonly name="refund_deadline" 
label={i18n`Refund deadline`} tooltip={i18n`after this deadline has passed no 
refunds will be accepted`} />
-                  <InputDate<CT> readonly name="pay_deadline" 
label={i18n`Payment deadline`} tooltip={i18n`after this deadline, the merchant 
won't accept payments for the contract`} />
-                  <InputDate<CT> readonly name="wire_transfer_deadline" 
label={i18n`Wire transfer deadline`} tooltip={i18n`transfer deadline for the 
exchange`} />
-                  <InputDate<CT> readonly name="delivery_date" 
label={i18n`Delivery date`} tooltip={i18n`time indicating when the order should 
be delivered`} />
-                  {value.contract_terms.delivery_date &&
-                    <InputGroup name="delivery_location" 
label={i18n`Location`} tooltip={i18n`where the order will be delivered`} >
-                      <InputLocation name="payments.delivery_location" />
-                    </InputGroup>
-                  }
-                  <InputDuration<CT> readonly name="auto_refund" 
label={i18n`Auto-refund delay`} tooltip={i18n`how long the wallet should try to 
get an automatic refund for the purchase`} />
-                  <Input<CT> readonly name="extra" label={i18n`Extra info`} 
tooltip={i18n`extra data that is only interpreted by the merchant frontend`} />
-                </FormProvider>
-              </div>
-              <div class="column" />
-            </div>
-          </section>}
 
-          {order.contract_terms.products.length ? <section class="section">
-            <div class="columns">
-              <div class="column is-12" >
-                <div class="title"><Translate>Product list</Translate></div>
-                <ProductList list={order.contract_terms.products} />
-              </div>
-              <div class="column" />
-            </div>
-          </section> : undefined}
+          {order.contract_terms.products.length ? <Fragment>
+            <div class="title"><Translate>Product list</Translate></div>
+            <ProductList list={order.contract_terms.products} />
+          </Fragment> : undefined}
 
+          {value.contract_terms && <ContractTerms value={value.contract_terms} 
/>}
         </div>
         <div class="column" />
       </div>
@@ -380,10 +394,9 @@ function UnpaidPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.C
                 whiteSpace: 'nowrap',
                 overflow: 'hidden',
                 textOverflow: 'ellipsis',
-                // maxWidth: '100%',
               }}>
-                <p><Translate>pay at</Translate>: <a 
href={order.order_status_url} rel="nofollow" 
target="new">{order.order_status_url}</a></p>
-                <p><Translate>created at</Translate>: <b>missing value, there 
is no contract term yet</b></p>
+                <p><b><Translate>pay at</Translate>:</b> <a 
href={order.order_status_url} rel="nofollow" 
target="new">{order.order_status_url}</a></p>
+                <p><b><Translate>created at</Translate>:</b> {format(new 
Date(order.creation_time.t_ms), 'yyyy-MM-dd HH:mm:ss')}</p>
               </div>
             </div>
           </div>
@@ -394,8 +407,10 @@ function UnpaidPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.C
     <section class="section is-main-section">
       <div class="columns">
         <div class="column" />
-        <div class="column is-6">
+        <div class="column is-four-fifths">
           <FormProvider<Unpaid> object={value} valueHandler={valueHandler} >
+            <Input<Unpaid> readonly name="summary" label={i18n`Summary`} 
tooltip={i18n`human-readable description of the whole purchase`} />
+            <InputCurrency<Unpaid> readonly name="total_amount" 
label={i18n`Amount`} tooltip={i18n`total price for the transaction`} />
             <Input<Unpaid> name="order_status" readonly label={i18n`Order 
status`} />
             <Input<Unpaid> name="order_status_url" readonly label={i18n`Order 
status URL`} />
             <Input<Unpaid> name="taler_pay_uri" readonly label={i18n`Payment 
URI`} />
@@ -432,7 +447,7 @@ export function DetailPage({ id, selected, onRefund, onBack 
}: Props): VNode {
     />}
     <div class="columns">
       <div class="column" />
-      <div class="column is-two-thirds">
+      <div class="column is-four-fifths">
         <div class="buttons is-right mt-5">
           <button class="button" 
onClick={onBack}><Translate>Back</Translate></button>
         </div>
diff --git a/packages/frontend/src/paths/instance/orders/details/Timeline.tsx 
b/packages/frontend/src/paths/instance/orders/details/Timeline.tsx
index d4f17c4..16adbcb 100644
--- a/packages/frontend/src/paths/instance/orders/details/Timeline.tsx
+++ b/packages/frontend/src/paths/instance/orders/details/Timeline.tsx
@@ -47,7 +47,7 @@ export function Timeline({ events:e }: Props) {
     }
   })
   return <div class="timeline">
-    {events.map((e,i) => {
+    {state.map((e,i) => {
       return <div key={i} class="timeline-item">
         {(() => {
           switch (e.type) {
@@ -55,6 +55,7 @@ export function Timeline({ events:e }: Props) {
             case "delivery": return <div class="timeline-marker is-icon "><i 
class="mdi mdi-delivery" /></div>
             case "start": return <div class="timeline-marker is-icon 
is-success"><i class="mdi mdi-flag " /></div>
             case "wired": return <div class="timeline-marker is-icon 
is-success"><i class="mdi mdi-cash" /></div>
+            case "wired-range": return <div class="timeline-marker is-icon 
is-success"><i class="mdi mdi-cash" /></div>
             case "refund": return <div class="timeline-marker is-icon 
is-danger"><i class="mdi mdi-cash" /></div>
             case "now": return <div class="timeline-marker is-icon is-info"><i 
class="mdi mdi-clock" /></div>
           }
@@ -71,5 +72,5 @@ export function Timeline({ events:e }: Props) {
 export interface Event {
   when: Date;
   description: string;
-  type: 'start' | 'refund' | 'wired' | 'deadline' | 'delivery' | 'now'
+  type: 'start' | 'refund' | 'wired' | 'wired-range' |'deadline' | 'delivery' 
| 'now'
 }
diff --git a/packages/frontend/src/paths/instance/orders/list/Table.tsx 
b/packages/frontend/src/paths/instance/orders/list/Table.tsx
index 4057ca2..41c7293 100644
--- a/packages/frontend/src/paths/instance/orders/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/orders/list/Table.tsx
@@ -31,7 +31,7 @@ import { ConfirmModal } from "../../../../components/modal";
 import { MerchantBackend, WithId } from "../../../../declaration";
 import { useOrderDetails } from "../../../../hooks/order";
 import { Translate, useTranslator } from "../../../../i18n";
-import { AuthorizeTipSchema, RefundSchema as RefundSchema } from 
"../../../../schemas";
+import { RefundSchema as RefundSchema } from "../../../../schemas";
 import { mergeRefunds, subtractPrices, sumPrices } from 
"../../../../utils/amount";
 import { AMOUNT_ZERO_REGEX } from "../../../../utils/constants";
 
@@ -54,6 +54,7 @@ export function CardTable({ instances, onCreate, onRefund, 
onCopyURL, onSelect,
 
   const [showRefund, setShowRefund] = useState<string | undefined>(undefined)
 
+  const i18n = useTranslator()
 
   return <div class="card has-table">
     <header class="card-header">
@@ -62,9 +63,11 @@ export function CardTable({ instances, onCreate, onRefund, 
onCopyURL, onSelect,
       <div class="card-header-icon" aria-label="more options" />
 
       <div class="card-header-icon" aria-label="more options">
+      <span class="has-tooltip-left" data-tooltip={i18n`add new order`}>
         <button class="button is-info" type="button" onClick={onCreate}>
           <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
         </button>
+        </span>
       </div>
 
     </header>
@@ -114,7 +117,7 @@ function Table({ instances, onSelect, onRefund, onCopyURL, 
onLoadMoreAfter, onLo
         <tr>
           <th style={{ minWidth: 100 }}><Translate>Date</Translate></th>
           <th style={{ minWidth: 100 }}><Translate>Amount</Translate></th>
-          <th style={{ minWidth: 500 }}><Translate>Summary</Translate></th>
+          <th style={{ minWidth: 400 }}><Translate>Summary</Translate></th>
           <th style={{ minWidth: 50 }} />
         </tr>
       </thead>
diff --git a/packages/frontend/src/paths/instance/orders/list/index.tsx 
b/packages/frontend/src/paths/instance/orders/list/index.tsx
index c85db0b..8bfe23d 100644
--- a/packages/frontend/src/paths/instance/orders/list/index.tsx
+++ b/packages/frontend/src/paths/instance/orders/list/index.tsx
@@ -41,7 +41,7 @@ interface Props {
 
 
 export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, 
onNotFound }: Props): VNode {
-  const [filter, setFilter] = useState<InstanceOrderFilter>({ })
+  const [filter, setFilter] = useState<InstanceOrderFilter>({})
   const [pickDate, setPickDate] = useState(false)
 
   const setNewDate = (date: Date) => setFilter(prev => ({ ...prev, date }))
@@ -66,7 +66,7 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
 
   async function testIfOrderExistAndSelect() {
     if (!orderId) {
-      setErrorOrderId('Enter an order id')
+      setErrorOrderId(i18n`Enter an order id`)
       return;
     }
     try {
@@ -74,11 +74,12 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
       onSelect(orderId)
       setErrorOrderId(undefined)
     } catch {
-      setErrorOrderId('order not found')
+      setErrorOrderId(i18n`order not found`)
     }
   }
 
   const i18n = useTranslator()
+  const dateTooltip = i18n`jump to order closer to a given date`
 
   return <section class="section is-main-section">
     <NotificationCard notification={notif} />
@@ -91,11 +92,11 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
               <input class={errorOrderId ? "input is-danger" : "input"} 
type="text" value={orderId} onChange={e => setOrderId(e.currentTarget.value)} 
placeholder={i18n`order id`} />
               {errorOrderId && <p class="help is-danger">{errorOrderId}</p>}
             </div>
-            <div class="control">
-              <a class="button" onClick={testIfOrderExistAndSelect}>
+            <span class="has-tooltip-bottom" data-tooltip={i18n`view order 
details`}>
+              <button class="button" onClick={testIfOrderExistAndSelect}>
                 <span class="icon"><i class="mdi mdi-arrow-right" /></span>
-              </a>
-            </div>
+              </button>
+            </span>
           </div>
         </div>
       </div>
@@ -104,10 +105,26 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
       <div class="column">
         <div class="tabs">
           <ul>
-            <li class={isAllActive}><a onClick={() => 
setFilter({})}><Translate>All</Translate></a></li>
-            <li class={isPaidActive}><a onClick={() => setFilter({ paid: 'yes' 
})}><Translate>Paid</Translate></a></li>
-            <li class={isRefundedActive}><a onClick={() => setFilter({ 
refunded: 'yes' })}><Translate>Refunded</Translate></a></li>
-            <li class={isNotWiredActive}><a onClick={() => setFilter({ wired: 
'no' })}><Translate>Not wired</Translate></a></li>
+            <li class={isAllActive}>
+              <div class="has-tooltip-right" data-tooltip={i18n`remove all 
filters`}>
+                <a onClick={() => setFilter({})}><Translate>All</Translate></a>
+              </div>
+            </li>
+            <li class={isPaidActive}>
+              <div class="has-tooltip-right" data-tooltip={i18n`filter paid 
orders`}>
+                <a onClick={() => setFilter({ paid: 'yes' 
})}><Translate>Paid</Translate></a>
+              </div>
+            </li>
+            <li class={isRefundedActive}>
+              <div class="has-tooltip-right" data-tooltip={i18n`filter 
refunded orders`}>
+                <a onClick={() => setFilter({ refunded: 'yes' 
})}><Translate>Refunded</Translate></a>
+              </div>
+            </li>
+            <li class={isNotWiredActive}>
+              <div class="has-tooltip-left" data-tooltip={i18n`filter not yet 
wired orders`}>
+                <a onClick={() => setFilter({ wired: 'no' })}><Translate>Not 
wired</Translate></a>
+              </div>
+            </li>
           </ul>
         </div>
       </div>
@@ -120,12 +137,16 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
               </a>
             </div>}
             <div class="control">
-              <input class="input" type="text" readonly value={!filter.date ? 
'' : format(filter.date, 'yyyy/MM/dd')} placeholder={i18n`date (YYYY/MM/DD)`} />
+              <span class="has-tooltip-top" data-tooltip={dateTooltip}>
+                <input class="input" type="text" readonly value={!filter.date 
? '' : format(filter.date, 'yyyy/MM/dd')} placeholder={i18n`date (YYYY/MM/DD)`} 
onClick={() => { setPickDate(true) }} />
+              </span>
             </div>
             <div class="control">
-              <a class="button" onClick={() => { setPickDate(true) }}>
-                <span class="icon"><i class="mdi mdi-calendar" /></span>
-              </a>
+              <span class="has-tooltip-left" data-tooltip={dateTooltip}>
+                <a class="button" onClick={() => { setPickDate(true) }}>
+                  <span class="icon"><i class="mdi mdi-calendar" /></span>
+                </a>
+              </span>
             </div>
           </div>
         </div>
diff --git 
a/packages/frontend/src/paths/instance/products/create/CreatePage.tsx 
b/packages/frontend/src/paths/instance/products/create/CreatePage.tsx
index e6e6f1e..78c0f0d 100644
--- a/packages/frontend/src/paths/instance/products/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/instance/products/create/CreatePage.tsx
@@ -45,7 +45,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
     <section class="section is-main-section">
       <div class="columns">
         <div class="column" />
-        <div class="column is-two-thirds">
+        <div class="column is-four-fifths">
           <ProductForm onSubscribe={addFormSubmitter} />
 
           <div class="buttons is-right mt-5">
diff --git 
a/packages/frontend/src/paths/instance/products/create/CreatedSuccessfully.tsx 
b/packages/frontend/src/paths/instance/products/create/CreatedSuccessfully.tsx
index dc39d84..b567504 100644
--- 
a/packages/frontend/src/paths/instance/products/create/CreatedSuccessfully.tsx
+++ 
b/packages/frontend/src/paths/instance/products/create/CreatedSuccessfully.tsx
@@ -16,6 +16,7 @@
 import { h, VNode } from "preact";
 import { CreatedSuccessfully as Template } from 
"../../../../components/notifications/CreatedSuccessfully";
 import { Entity } from "./index";
+import emptyImage from "../../assets/empty.png";
 
 interface Props {
   entity: Entity;
diff --git a/packages/frontend/src/paths/instance/products/list/Table.tsx 
b/packages/frontend/src/paths/instance/products/list/Table.tsx
index 878506d..1b4a7b3 100644
--- a/packages/frontend/src/paths/instance/products/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/products/list/Table.tsx
@@ -28,6 +28,7 @@ import { InputNumber } from 
"../../../../components/form/InputNumber"
 import { MerchantBackend, WithId } from "../../../../declaration"
 import emptyImage from "../../../../assets/empty.png";
 import { Translate, useTranslator } from "../../../../i18n"
+import { Amounts } from "@gnu-taler/taler-util"
 
 type Entity = MerchantBackend.Products.ProductDetail & WithId
 
@@ -35,23 +36,23 @@ interface Props {
   instances: Entity[];
   onDelete: (id: Entity) => void;
   onSelect: (product: Entity) => void;
-  onUpdate: (id: string, data: MerchantBackend.Products.ProductPatchDetail) => 
void;
+  onUpdate: (id: string, data: MerchantBackend.Products.ProductPatchDetail) => 
Promise<void>;
   onCreate: () => void;
   selected?: boolean;
 }
 
 export function CardTable({ instances, onCreate, onSelect, onUpdate, onDelete 
}: Props): VNode {
   const [rowSelection, rowSelectionHandler] = useState<string | 
undefined>(undefined)
-
+  const i18n = useTranslator()
   return <div class="card has-table">
     <header class="card-header">
       <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-shopping" /></span><Translate>Products</Translate></p>
-
-      <div class="card-header-icon" aria-label="more options" />
       <div class="card-header-icon" aria-label="more options">
-        <button class="button is-info" type="button" onClick={onCreate}>
-          <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
-        </button>
+        <span class="has-tooltip-left" data-tooltip={i18n`add new product`}>
+          <button class="button is-info" type="button" onClick={onCreate}>
+            <span class="icon is-small"  ><i class="mdi mdi-plus mdi-36px" 
/></span>
+          </button>
+        </span>
       </div>
 
     </header>
@@ -71,12 +72,13 @@ interface TableProps {
   rowSelection: string | undefined;
   instances: Entity[];
   onSelect: (id: Entity) => void;
-  onUpdate: (id: string, data: MerchantBackend.Products.ProductPatchDetail) => 
void;
+  onUpdate: (id: string, data: MerchantBackend.Products.ProductPatchDetail) => 
Promise<void>;
   onDelete: (id: Entity) => void;
   rowSelectionHandler: StateUpdater<string | undefined>;
 }
 
 function Table({ rowSelection, rowSelectionHandler, instances, onSelect, 
onUpdate, onDelete }: TableProps): VNode {
+  const i18n = useTranslator()
   return (
     <div class="table-container">
       <table class="table is-fullwidth is-striped is-hoverable is-fullwidth">
@@ -108,30 +110,38 @@ function Table({ rowSelection, rowSelectionHandler, 
instances, onSelect, onUpdat
               stockInfo = <label title={restStockInfo}>{totalStock} 
{i.unit}</label>
             }
 
+            const isFree = Amounts.parseOrThrow(i.price).value === 0
+
             return <Fragment key={i.id}><tr key="info">
               <td onClick={() => rowSelection !== i.id && 
rowSelectionHandler(i.id)} style={{ cursor: 'pointer' }} >
                 <img src={i.image ? i.image : emptyImage} style={{ border: 
'solid black 1px', width: 100, height: 100 }} />
               </td>
               <td onClick={() => rowSelection !== i.id && 
rowSelectionHandler(i.id)} style={{ cursor: 'pointer' }} >{i.description}</td>
-              <td onClick={() => rowSelection !== i.id && 
rowSelectionHandler(i.id)} style={{ cursor: 'pointer' }} >{i.price} / 
{i.unit}</td>
+              <td onClick={() => rowSelection !== i.id && 
rowSelectionHandler(i.id)} style={{ cursor: 'pointer' }} >
+                {isFree ? i18n`free` : `${i.price} / ${i.unit}`}
+              </td>
               <td onClick={() => rowSelection !== i.id && 
rowSelectionHandler(i.id)} style={{ cursor: 'pointer' }} >{sum(i.taxes)}</td>
               <td onClick={() => rowSelection !== i.id && 
rowSelectionHandler(i.id)} style={{ cursor: 'pointer' }} >{difference(i.price, 
sum(i.taxes))}</td>
               <td onClick={() => rowSelection !== i.id && 
rowSelectionHandler(i.id)} style={{ cursor: 'pointer' }} >{stockInfo}</td>
               <td onClick={() => rowSelection !== i.id && 
rowSelectionHandler(i.id)} style={{ cursor: 'pointer' }} >{i.total_sold} 
{i.unit}</td>
               <td class="is-actions-cell right-sticky">
                 <div class="buttons is-right">
-                  <button class="button is-small is-success jb-modal" 
type="button" onClick={(): void => onSelect(i)}>
-                    Update
-                  </button>
-                  <button class="button is-small is-danger jb-modal" 
type="button" onClick={(): void => onDelete(i)}>
-                    Delete
-                  </button>
+                  <span class="has-tooltip-bottom" data-tooltip={i18n`go to 
product update page`}>
+                    <button class="button is-small is-success " type="button" 
onClick={(): void => onSelect(i)}>
+                      <Translate>Update</Translate>
+                    </button>
+                  </span>
+                  <span class="has-tooltip-left" data-tooltip={i18n`remove 
this product from the database`}>
+                    <button class="button is-small is-danger" type="button" 
onClick={(): void => onDelete(i)}>
+                      <Translate>Delete</Translate>
+                    </button>
+                  </span>
                 </div>
               </td>
             </tr>
               {rowSelection === i.id && <tr key="form">
                 <td colSpan={10} >
-                  <FastProductUpdateForm product={i} onUpdate={(prod) => 
onUpdate(i.id, prod)} onCancel={() => rowSelectionHandler(undefined)} />
+                  <FastProductUpdateForm product={i} onUpdate={(prod) => 
onUpdate(i.id, prod).then(r => rowSelectionHandler(undefined))} onCancel={() => 
rowSelectionHandler(undefined)} />
                 </td>
               </tr>}
             </Fragment>
@@ -144,7 +154,7 @@ function Table({ rowSelection, rowSelectionHandler, 
instances, onSelect, onUpdat
 
 interface FastProductUpdateFormProps {
   product: Entity;
-  onUpdate: (data: MerchantBackend.Products.ProductPatchDetail) => void;
+  onUpdate: (data: MerchantBackend.Products.ProductPatchDetail) => 
Promise<void>;
   onCancel: () => void;
 }
 interface FastProductUpdate {
@@ -152,9 +162,12 @@ interface FastProductUpdate {
   lost: number;
   price: string;
 }
+interface UpdatePrice {
+  price: string;
+}
 
 function FastProductWithInfiniteStockUpdateForm({ product, onUpdate, onCancel 
}: FastProductUpdateFormProps) {
-  const [value, valueHandler] = useState<{ price: string }>({ price: 
product.price })
+  const [value, valueHandler] = useState<UpdatePrice>({ price: product.price })
   const i18n = useTranslator()
 
   return <Fragment>
@@ -164,14 +177,12 @@ function FastProductWithInfiniteStockUpdateForm({ 
product, onUpdate, onCancel }:
 
     <div class="buttons is-right mt-5">
       <button class="button" onClick={onCancel} 
><Translate>Cancel</Translate></button>
-      <button class="button is-info" onClick={() => {
-
-        return onUpdate({
+      <span class="has-tooltip-left" data-tooltip={i18n`update product with 
new price`}>
+        <button class="button is-info" onClick={() => onUpdate({
           ...product,
           price: value.price,
-        })
-
-      }}><Translate>Confirm</Translate></button>
+        })}><Translate>Confirm</Translate></button>
+      </span>
     </div>
 
   </Fragment>
@@ -190,12 +201,6 @@ function FastProductWithManagedStockUpdateForm({ product, 
onUpdate, onCancel }:
       : undefined
   }
 
-  const stockUpdateDescription = errors.lost ? '' : (
-    !!value.incoming || !!value.lost ?
-      `current stock will change from ${currentStock} to ${currentStock + 
value.incoming - value.lost}` :
-      `current stock will stay at ${currentStock}`
-  )
-
   const hasErrors = Object.keys(errors).some(k => (errors as any)[k] !== 
undefined)
   const i18n = useTranslator()
 
@@ -203,29 +208,20 @@ function FastProductWithManagedStockUpdateForm({ product, 
onUpdate, onCancel }:
     <FormProvider<FastProductUpdate> name="added" errors={errors} 
object={value} valueHandler={valueHandler as any} >
       <InputNumber<FastProductUpdate> name="incoming" label={i18n`Incoming`} 
tooltip={i18n`add more elements to the inventory`} />
       <InputNumber<FastProductUpdate> name="lost" label={i18n`Lost`} 
tooltip={i18n`report elements lost in the inventory`} />
-      <div class="field is-horizontal">
-        <div class="field-label is-normal" />
-        <div class="field-body is-flex-grow-3">
-          <div class="field">
-            {stockUpdateDescription}
-          </div>
-        </div>
-      </div>
       <InputCurrency<FastProductUpdate> name="price" label={i18n`Price`} 
tooltip={i18n`new price for the product`} />
     </FormProvider>
 
     <div class="buttons is-right mt-5">
       <button class="button" onClick={onCancel} 
><Translate>Cancel</Translate></button>
-      <button class="button is-info" disabled={hasErrors} onClick={() => {
-
-        return onUpdate({
+      <span class="has-tooltip-left" data-tooltip={hasErrors ? i18n`the are 
value with errors` : i18n`update product with new stock and price`}>
+        <button class="button is-info" disabled={hasErrors} onClick={() => 
onUpdate({
           ...product,
           total_stock: product.total_stock + value.incoming,
           total_lost: product.total_lost + value.lost,
           price: value.price,
         })
-
-      }}><Translate>Confirm</Translate></button>
+        }><Translate>Confirm</Translate></button>
+      </span>
     </div>
 
   </Fragment>
diff --git 
a/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx 
b/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx
index e0a2b16..1dfca99 100644
--- a/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx
+++ b/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx
@@ -26,7 +26,7 @@ import { MerchantBackend, WithId } from 
"../../../../declaration";
 import { useListener } from "../../../../hooks";
 import { Translate } from "../../../../i18n";
 
-type Entity = MerchantBackend.Products.ProductDetail & { product_id: string}
+type Entity = MerchantBackend.Products.ProductDetail & { product_id: string }
 
 interface Props {
   onUpdate: (d: Entity) => Promise<void>;
@@ -41,17 +41,30 @@ export function UpdatePage({ product, onUpdate, onBack }: 
Props): VNode {
   })
 
   return <div>
-    <section class="section is-main-section">
+    <section class="section">
+      <section class="hero is-hero-bar">
+        <div class="hero-body">
+
+          <div class="level">
+            <div class="level-left">
+              <div class="level-item">
+                <span class="is-size-4"><Translate>Product 
id:</Translate><b>{product.product_id}</b></span>
+              </div>
+            </div>
+          </div>
+        </div>
+      </section>
+      <hr />
+
       <div class="columns">
         <div class="column" />
-        <div class="column is-two-thirds">
+        <div class="column is-four-fifths">
           <ProductForm initial={product} onSubscribe={addFormSubmitter} 
alreadyExist />
 
           <div class="buttons is-right mt-5">
             {onBack && <button class="button" onClick={onBack} 
><Translate>Cancel</Translate></button>}
             <AsyncButton onClick={submitForm} 
disabled={!submitForm}><Translate>Confirm</Translate></AsyncButton>
           </div>
-
         </div>
         <div class="column" />
       </div>
diff --git 
a/packages/frontend/src/paths/instance/reserves/create/CreatePage.tsx 
b/packages/frontend/src/paths/instance/reserves/create/CreatePage.tsx
index 8669242..cdaf475 100644
--- a/packages/frontend/src/paths/instance/reserves/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/instance/reserves/create/CreatePage.tsx
@@ -133,7 +133,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
     <section class="section is-main-section">
       <div class="columns">
         <div class="column" />
-        <div class="column is-two-thirds">
+        <div class="column is-four-fifths">
 
           <div class="tabs is-toggle is-fullwidth is-small">
             <ul>
diff --git 
a/packages/frontend/src/paths/instance/reserves/details/DetailPage.tsx 
b/packages/frontend/src/paths/instance/reserves/details/DetailPage.tsx
index 08942f6..06fbf20 100644
--- a/packages/frontend/src/paths/instance/reserves/details/DetailPage.tsx
+++ b/packages/frontend/src/paths/instance/reserves/details/DetailPage.tsx
@@ -20,22 +20,16 @@
 */
 
 import { Amounts } from "@gnu-taler/taler-util";
-import { format, isAfter } from "date-fns";
+import { format } from "date-fns";
 import { Fragment, h, VNode } from "preact";
-import { useState } from "preact/hooks";
 import { FormProvider } from "../../../../components/form/FormProvider";
 import { Input } from "../../../../components/form/Input";
 import { InputCurrency } from "../../../../components/form/InputCurrency";
 import { InputDate } from "../../../../components/form/InputDate";
-import { InputDuration } from "../../../../components/form/InputDuration";
-import { InputGroup } from "../../../../components/form/InputGroup";
-import { InputLocation } from "../../../../components/form/InputLocation";
-import { NotificationCard } from "../../../../components/menu";
-import { ProductList } from "../../../../components/product/ProductList";
+import { TextField } from "../../../../components/form/TextField";
 import { MerchantBackend } from "../../../../declaration";
 import { useTipDetails } from "../../../../hooks/tips";
 import { Translate, useTranslator } from "../../../../i18n";
-import { mergeRefunds } from "../../../../utils/amount";
 
 type Entity = MerchantBackend.Tips.ReserveDetail;
 type CT = MerchantBackend.ContractTerms
@@ -49,59 +43,60 @@ interface Props {
 export function DetailPage({ id, selected, onBack }: Props): VNode {
   const i18n = useTranslator()
   const didExchangeAckTransfer = 
Amounts.isNonZero(Amounts.parseOrThrow(selected.exchange_initial_amount))
-  return <div class="section main-section">
-    <FormProvider object={{ ...selected, id }} valueHandler={null} >
-      <InputDate<Entity> name="creation_time" label={i18n`Created at`} 
readonly />
-      <InputDate<Entity> name="expiration_time" label={i18n`Valid until`} 
readonly />
-      <InputCurrency<Entity> name="merchant_initial_amount" 
label={i18n`Created balance`} readonly />
-      <Input<Entity> name="exchange_url" label={i18n`Exchange URL`} readonly />
-
-      {didExchangeAckTransfer && <Fragment>
-        <InputCurrency<Entity> name="exchange_initial_amount" 
label={i18n`Exchange balance`} readonly />
-        <InputCurrency<Entity> name="pickup_amount" label={i18n`Picked up`} 
readonly />
-        <InputCurrency<Entity> name="committed_amount" label={i18n`Committed`} 
readonly />
-      </Fragment>
-      }
-      <Input<Entity> name="payto_uri" label={i18n`Account address`} readonly />
-      <Input name="id" label={i18n`Subject`} readonly />
-    </FormProvider>
-
-    {didExchangeAckTransfer ? <Fragment>
-      <div class="card has-table">
-        <header class="card-header">
-          <p class="card-header-title">
-            <span class="icon"><i class="mdi mdi-cash-register" /></span>
-            <Translate>Tips</Translate>
-          </p>
-
-        </header>
-        <div class="card-content">
-          <div class="b-table has-pagination">
-            <div class="table-wrapper has-mobile-cards">
-              {selected.tips && selected.tips.length > 0 ? <Table 
tips={selected.tips} /> : <EmptyTable />}
-            </div></div>
-        </div>
-      </div>
-    </Fragment> : <Fragment>
-      <p class="is-size-5"><Translate>Now you should transfer to the exchange 
into the account address indicated above and the transaction must carry the 
subject message.</Translate></p>
-
-      <p class="is-size-5"><Translate>For example :</Translate></p>
-      <pre>
-        
{selected.payto_uri}?message={id}&amount={selected.merchant_initial_amount}
-      </pre>
-    </Fragment>
-    }
-
-    <div class="columns">
-      <div class="column" />
-      <div class="column is-two-thirds">
+  return <div class="columns">
+    <div class="column" />
+    <div class="column is-four-fifths">
+      <div class="section main-section">
+        <FormProvider object={{ ...selected, id }} valueHandler={null} >
+          <InputDate<Entity> name="creation_time" label={i18n`Created at`} 
readonly />
+          <InputDate<Entity> name="expiration_time" label={i18n`Valid until`} 
readonly />
+          <InputCurrency<Entity> name="merchant_initial_amount" 
label={i18n`Created balance`} readonly />
+          <TextField<Entity> name="exchange_url" label={i18n`Exchange URL`} 
readonly >
+            <a target="_blank" 
href={selected.exchange_url}>{selected.exchange_url}</a>
+          </TextField>
+
+          {didExchangeAckTransfer && <Fragment>
+            <InputCurrency<Entity> name="exchange_initial_amount" 
label={i18n`Exchange balance`} readonly />
+            <InputCurrency<Entity> name="pickup_amount" label={i18n`Picked 
up`} readonly />
+            <InputCurrency<Entity> name="committed_amount" 
label={i18n`Committed`} readonly />
+          </Fragment>
+          }
+          <Input<Entity> name="payto_uri" label={i18n`Account address`} 
readonly />
+          <Input name="id" label={i18n`Subject`} readonly />
+        </FormProvider>
+
+        {didExchangeAckTransfer ? <Fragment>
+          <div class="card has-table">
+            <header class="card-header">
+              <p class="card-header-title">
+                <span class="icon"><i class="mdi mdi-cash-register" /></span>
+                <Translate>Tips</Translate>
+              </p>
+
+            </header>
+            <div class="card-content">
+              <div class="b-table has-pagination">
+                <div class="table-wrapper has-mobile-cards">
+                  {selected.tips && selected.tips.length > 0 ? <Table 
tips={selected.tips} /> : <EmptyTable />}
+                </div></div>
+            </div>
+          </div>
+        </Fragment> : <Fragment>
+          <p class="is-size-5"><Translate>Now you should transfer to the 
exchange into the account address indicated above and the transaction must 
carry the subject message.</Translate></p>
+          <p class="is-size-5"><Translate>For example :</Translate></p>
+          <pre>
+            
{selected.payto_uri}?message={id}&amount={selected.merchant_initial_amount}
+          </pre>
+        </Fragment>
+        }
+
         <div class="buttons is-right mt-5">
           <button class="button" 
onClick={onBack}><Translate>Back</Translate></button>
         </div>
+
       </div>
-      <div class="column" />
     </div>
-
+    <div class="column" />
   </div>
 }
 
diff --git a/packages/frontend/src/paths/instance/reserves/list/Table.tsx 
b/packages/frontend/src/paths/instance/reserves/list/Table.tsx
index c53dd2a..6bca85b 100644
--- a/packages/frontend/src/paths/instance/reserves/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/reserves/list/Table.tsx
@@ -22,7 +22,7 @@
 import { format } from "date-fns"
 import { Fragment, h, VNode } from "preact"
 import { MerchantBackend, WithId } from "../../../../declaration"
-import { Translate } from "../../../../i18n"
+import { Translate, useTranslator } from "../../../../i18n"
 
 type Entity = MerchantBackend.Tips.ReserveStatusEntry & WithId
 
@@ -47,6 +47,7 @@ export function CardTable({ instances, onCreate, onSelect, 
onNewTip, onDelete }:
     return prev
   }, new Array<Array<Entity>>([], []))
 
+  const i18n = useTranslator()
 
   return <Fragment>
     {withoutFunds.length > 0 && <div class="card has-table">
@@ -67,9 +68,12 @@ export function CardTable({ instances, onCreate, onSelect, 
onNewTip, onDelete }:
         <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-cash" /></span><Translate>Reserves ready</Translate></p>
         <div class="card-header-icon" aria-label="more options" />
         <div class="card-header-icon" aria-label="more options">
-          <button class="button is-info" type="button" onClick={onCreate}>
-            <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
-          </button>
+          <span class="has-tooltip-left" data-tooltip={i18n`add new reserve`}>
+
+            <button class="button is-info" type="button" onClick={onCreate}>
+              <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
+            </button>
+          </span>
         </div>
       </header>
       <div class="card-content">
diff --git 
a/packages/frontend/src/paths/instance/transfers/create/CreatePage.tsx 
b/packages/frontend/src/paths/instance/transfers/create/CreatePage.tsx
index 748722f..861268f 100644
--- a/packages/frontend/src/paths/instance/transfers/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/instance/transfers/create/CreatePage.tsx
@@ -77,7 +77,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
     <section class="section is-main-section">
       <div class="columns">
         <div class="column" />
-        <div class="column is-two-thirds">
+        <div class="column is-four-fifths">
 
           <FormProvider object={state} valueHandler={setState} errors={errors}>
             <Input<Entity> name="wtid" label={i18n`Transfer ID`} help="" 
tooltip={i18n`unique identifier of the wire transfer, usually 52 random 
characters long`} />
diff --git a/packages/frontend/src/paths/instance/transfers/list/Table.tsx 
b/packages/frontend/src/paths/instance/transfers/list/Table.tsx
index ad7248f..3794b01 100644
--- a/packages/frontend/src/paths/instance/transfers/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/transfers/list/Table.tsx
@@ -59,6 +59,7 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected, o
     }
   }, [actionQueue, selected, onUpdate])
 
+  const i18n = useTranslator()
 
   return <div class="card has-table">
     <header class="card-header">
@@ -72,9 +73,11 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected, o
         </button>
       </div>
       <div class="card-header-icon" aria-label="more options">
-        <button class="button is-info" type="button" onClick={onCreate}>
-          <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
-        </button>
+        <span class="has-tooltip-left" data-tooltip={i18n`add new transfer`}>
+          <button class="button is-info" type="button" onClick={onCreate}>
+            <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
+          </button>
+        </span>
       </div>
 
     </header>
diff --git a/packages/frontend/src/paths/instance/transfers/list/index.tsx 
b/packages/frontend/src/paths/instance/transfers/list/index.tsx
index 5486451..5effb5f 100644
--- a/packages/frontend/src/paths/instance/transfers/list/index.tsx
+++ b/packages/frontend/src/paths/instance/transfers/list/index.tsx
@@ -74,7 +74,7 @@ export default function ListTransfer({ onUnauthorized, 
onLoadError, onCreate, on
   return <section class="section is-main-section">
     <div class="columns">
       <div class="column" />
-      <div class="column is-6">
+      <div class="column is-10">
         <FormProvider object={form} valueHandler={setForm as any}>
           <InputSelector name="payto_uri" label={i18n`Address`}
             values={accounts}
@@ -87,9 +87,21 @@ export default function ListTransfer({ onUnauthorized, 
onLoadError, onCreate, on
     </div>
     <div class="tabs">
       <ul>
-        <li class={isAllTransfers}><a onClick={() => 
setFilter(undefined)}><Translate>All</Translate></a></li>
-        <li class={isVerifiedTransfers}><a onClick={() => 
setFilter('yes')}><Translate>Verified</Translate></a></li>
-        <li class={isNonVerifiedTransfers}><a onClick={() => 
setFilter('no')}><Translate>Non Verified</Translate></a></li>
+        <li class={isAllTransfers}>
+          <div class="has-tooltip-right" data-tooltip={i18n`remove all 
filters`}>
+            <a onClick={() => 
setFilter(undefined)}><Translate>All</Translate></a>
+          </div>
+        </li>
+        <li class={isVerifiedTransfers}>
+          <div class="has-tooltip-right" data-tooltip={i18n`remove all 
filters`}>
+            <a onClick={() => 
setFilter('yes')}><Translate>Verified</Translate></a>
+          </div>
+        </li>
+        <li class={isNonVerifiedTransfers}>
+          <div class="has-tooltip-right" data-tooltip={i18n`remove all 
filters`}>
+            <a onClick={() => setFilter('no')}><Translate>Non 
Verified</Translate></a>
+          </div>
+        </li>
       </ul>
     </div>
     <View
diff --git a/packages/frontend/src/paths/instance/update/UpdatePage.tsx 
b/packages/frontend/src/paths/instance/update/UpdatePage.tsx
index 3fe17ff..5367e5d 100644
--- a/packages/frontend/src/paths/instance/update/UpdatePage.tsx
+++ b/packages/frontend/src/paths/instance/update/UpdatePage.tsx
@@ -36,6 +36,7 @@ import { useInstanceContext } from 
"../../../context/instance";
 import { MerchantBackend } from "../../../declaration";
 import { Translate, useTranslator } from "../../../i18n";
 import { InstanceUpdateSchema as schema } from '../../../schemas';
+import { DefaultInstanceFormFields } from 
"../../../components/instance/DefaultInstanceFormFields";
 
 
 type Entity = MerchantBackend.Instances.InstanceReconfigurationMessage & { 
auth_token?: string }
@@ -101,8 +102,6 @@ export function UpdatePage({ onUpdate, onChangeAuth, 
selected, onBack }: Props):
   }
   const [active, setActive] = useState(false);
 
-  const i18n = useTranslator()
-
   return <div>
     <section class="section">
 
@@ -112,7 +111,7 @@ export function UpdatePage({ onUpdate, onChangeAuth, 
selected, onBack }: Props):
           <div class="level">
             <div class="level-left">
               <div class="level-item">
-                <span class="is-size-4">Instance id: <b>{id}</b></span>
+                <span class="is-size-4"><Translate>Instance id</Translate>: 
<b>{id}</b></span>
               </div>
             </div>
             <div class="level-right">
@@ -120,7 +119,7 @@ export function UpdatePage({ onUpdate, onChangeAuth, 
selected, onBack }: Props):
                 <h1 class="title">
                   <button class="button is-danger" onClick={(): void => { 
setActive(!active); }} >
                     <div class="icon is-left"><i class="mdi mdi-lock-reset" 
/></div>
-                    <span><Translate>Manage token</Translate></span>
+                    <span><Translate>Manage access token</Translate></span>
                   </button>
                 </h1>
               </div>
@@ -142,42 +141,25 @@ export function UpdatePage({ onUpdate, onChangeAuth, 
selected, onBack }: Props):
         <div class="column" />
       </div>
       <hr />
+
       <div class="columns">
         <div class="column" />
         <div class="column is-four-fifths">
           <FormProvider<Entity> errors={errors} object={value} 
valueHandler={valueHandler} >
 
-            <Input<Entity> name="name" label={i18n`Name`} 
tooltip={i18n`display name of this instance`} />
-
-            <InputPayto<Entity> name="payto_uris" label={i18n`Account 
address`} help="x-taler-bank/bank.taler:5882/blogger" />
-
-            <InputCurrency<Entity> name="default_max_deposit_fee" 
label={i18n`Default max deposit fee`} />
-
-            <InputCurrency<Entity> name="default_max_wire_fee" 
label={i18n`Default max wire fee`} />
-
-            <Input<Entity> name="default_wire_fee_amortization" 
inputType="number" label={i18n`Default wire fee amortization`} />
-
-            <InputGroup name="address" label={i18n`Address`}>
-              <InputLocation name="address" />
-            </InputGroup>
-
-            <InputGroup name="jurisdiction" label={i18n`Jurisdiction`}>
-              <InputLocation name="jurisdiction" />
-            </InputGroup>
-
-            <InputDuration<Entity> name="default_pay_delay" 
label={i18n`Default payment delay`} />
-
-            <InputDuration<Entity> name="default_wire_transfer_delay" 
label={i18n`Default wire transfer delay`} />
+            <DefaultInstanceFormFields showId={false} />
 
           </FormProvider>
 
           <div class="buttons is-right mt-4">
-            <button class="button" onClick={onBack} 
><Translate>Cancel</Translate></button>
+            <button class="button" onClick={onBack} data-tooltip="cancel 
operation"><Translate>Cancel</Translate></button>
+
             <AsyncButton onClick={submit} disabled={hasErrors} 
><Translate>Confirm</Translate></AsyncButton>
           </div>
         </div>
         <div class="column" />
       </div>
+
     </section>
 
   </div >
diff --git a/packages/frontend/src/scss/main.scss 
b/packages/frontend/src/scss/main.scss
index 08e2f79..100cadc 100644
--- a/packages/frontend/src/scss/main.scss
+++ b/packages/frontend/src/scss/main.scss
@@ -13,14 +13,14 @@
  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)
  */
- 
- /* Theme style (colors & sizes) */
- @import "theme-default";
+
+/* Theme style (colors & sizes) */
+@import "theme-default";
 
 /* Core Libs & Lib configs */
 @import "libs/all";
@@ -83,28 +83,28 @@ $tooltip-color: red;
 }
 
 .toast > .message {
-  white-space:pre-wrap;
-  opacity:80%;
+  white-space: pre-wrap;
+  opacity: 80%;
 }
 
 div {
   &.is-loading {
-      position: relative;
-      pointer-events: none;
-      opacity: 0.5;
-      &:after {
-          // @include loader;
-          position: absolute;
-          top: calc(50% - 2.5em);
-          left: calc(50% - 2.5em);
-          width: 5em;
-          height: 5em;
-          border-width: 0.25em;
-      }
+    position: relative;
+    pointer-events: none;
+    opacity: 0.5;
+    &:after {
+      // @include loader;
+      position: absolute;
+      top: calc(50% - 2.5em);
+      left: calc(50% - 2.5em);
+      width: 5em;
+      height: 5em;
+      border-width: 0.25em;
+    }
   }
 }
 
-input[type=checkbox]:indeterminate + .check {
+input[type="checkbox"]:indeterminate + .check {
   background: red !important;
 }
 
@@ -115,7 +115,7 @@ input[type=checkbox]:indeterminate + .check {
 }
 
 .right-sticky .buttons {
-  flex-wrap: nowrap  
+  flex-wrap: nowrap;
 }
 
 .table.is-striped tbody tr:not(.is-selected):nth-child(even) .right-sticky {
@@ -132,13 +132,12 @@ tr:hover .right-sticky {
 .content-full-size {
   height: calc(100% - 3rem);
   position: absolute;
-  width: calc(100% - 14rem); 
-  display:flex;
+  width: calc(100% - 14rem);
+  display: flex;
 }
 
 .content-full-size .column .card {
   min-width: 200px;
-
 }
 
 @include touch {
@@ -146,7 +145,7 @@ tr:hover .right-sticky {
     height: 100%;
     position: absolute;
     width: 100%;
-  }  
+  }
 }
 
 .column.is-half {
@@ -158,9 +157,21 @@ input:read-only {
   cursor: initial;
 }
 
-span.icon[data-tooltip]:before {
-  z-index: 1000;
-  max-width: 250px;
-  transform: inherit;
-  // white-space: normal;
+[data-tooltip]:before {
+  max-width: 15rem;
+  width: max-content;
+  text-align: left;
+  transition: opacity 0.1s linear 1s;
+  // transform: inherit !important;
+  white-space: pre-wrap !important;
+  font-weight: normal;
+  // position: relative;
+}
+
+.icon[data-tooltip]:before {
+  transition: none;
+}
+
+span[data-tooltip] {
+  border-bottom: none;
 }

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