gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] branch master updated (fee8423 -> e81cf15)


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated (fee8423 -> e81cf15)
Date: Tue, 15 Jun 2021 05:04:46 +0200

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

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

    from fee8423  fix lint
     new bfe7540  storybook samples
     new e81cf15  fix lint

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


Summary of changes:
 packages/frontend/.storybook/main.js               |  40 +++---
 packages/frontend/.storybook/preview.js            |  37 ++++--
 .../src/components/form/InputSearchProduct.tsx     |  53 ++++----
 .../src/components/form/InputSecured.stories.tsx   |   2 +-
 .../src/components/form/InputStock.stories.tsx     |   2 +-
 .../frontend/src/context/{instance.ts => fetch.ts} |  19 +--
 packages/frontend/src/hooks/product.ts             |   2 +
 packages/frontend/src/index.tsx                    |  13 +-
 .../src/paths/admin/create/Create.stories.tsx      |  22 ++--
 .../frontend/src/paths/admin/list/View.stories.tsx |   2 +-
 .../src/paths/instance/details/Details.stories.tsx |  60 +++++++++
 .../instance/orders/create/Create.stories.tsx      |  62 ++++++++++
 .../paths/instance/orders/create/CreatePage.tsx    |  56 ++++-----
 .../orders/create/InventoryProductForm.tsx         |   7 +-
 .../orders/create/NonInventoryProductForm.tsx      |   3 +-
 .../src/paths/instance/orders/create/index.tsx     |  26 +++-
 .../instance/orders/details/Detail.stories.tsx     | 137 +++++++++++++++++++++
 .../paths/instance/orders/details/DetailPage.tsx   | 136 ++++++++++----------
 .../src/paths/instance/orders/details/Timeline.tsx |   2 +-
 .../paths/instance/orders/list/List.stories.tsx    |  87 +++++++++++++
 .../src/paths/instance/orders/list/Table.tsx       |  30 ++---
 .../src/paths/instance/orders/list/index.tsx       |  68 ++++++++--
 .../products}/create/Create.stories.tsx            |  22 ++--
 .../products/list/List.stories.tsx}                |  38 ++++--
 .../instance/products/update/Update.stories.tsx    |  71 +++++++++++
 .../reserves}/create/Create.stories.tsx            |  22 ++--
 .../instance/reserves/details/Details.stories.tsx  | 102 +++++++++++++++
 .../paths/instance/reserves/list/List.stories.tsx  |  97 +++++++++++++++
 .../src/paths/instance/reserves/list/Table.tsx     |   1 -
 .../transfers}/create/Create.stories.tsx           |  25 ++--
 .../paths/instance/transfers/create/CreatePage.tsx |   8 +-
 .../src/paths/instance/transfers/create/index.tsx  |   4 +
 .../paths/instance/transfers/list/List.stories.tsx |  84 +++++++++++++
 .../src/paths/instance/transfers/list/Table.tsx    |  32 +----
 .../src/paths/instance/transfers/list/index.tsx    |   2 +-
 .../src/paths/instance/update/Update.stories.tsx   |  59 +++++++++
 36 files changed, 1153 insertions(+), 280 deletions(-)
 copy packages/frontend/src/context/{instance.ts => fetch.ts} (56%)
 create mode 100644 
packages/frontend/src/paths/instance/details/Details.stories.tsx
 create mode 100644 
packages/frontend/src/paths/instance/orders/create/Create.stories.tsx
 create mode 100644 
packages/frontend/src/paths/instance/orders/details/Detail.stories.tsx
 create mode 100644 
packages/frontend/src/paths/instance/orders/list/List.stories.tsx
 copy packages/frontend/src/paths/{admin => 
instance/products}/create/Create.stories.tsx (64%)
 copy packages/frontend/src/paths/{admin/create/Create.stories.tsx => 
instance/products/list/List.stories.tsx} (51%)
 create mode 100644 
packages/frontend/src/paths/instance/products/update/Update.stories.tsx
 copy packages/frontend/src/paths/{admin => 
instance/reserves}/create/Create.stories.tsx (64%)
 create mode 100644 
packages/frontend/src/paths/instance/reserves/details/Details.stories.tsx
 create mode 100644 
packages/frontend/src/paths/instance/reserves/list/List.stories.tsx
 copy packages/frontend/src/paths/{admin => 
instance/transfers}/create/Create.stories.tsx (57%)
 create mode 100644 
packages/frontend/src/paths/instance/transfers/list/List.stories.tsx
 create mode 100644 
packages/frontend/src/paths/instance/update/Update.stories.tsx

diff --git a/packages/frontend/.storybook/main.js 
b/packages/frontend/.storybook/main.js
index 39d042b..f8e4bbc 100644
--- a/packages/frontend/.storybook/main.js
+++ b/packages/frontend/.storybook/main.js
@@ -30,24 +30,28 @@ module.exports = {
     "@storybook/addon-a11y",
     "@storybook/addon-essentials" //docs, control, actions, viewpot, toolbar, 
background
   ],
-  webpackFinal: async (config, { configType }) => {
-    // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
-    // You can change the configuration based on that.
-    // 'PRODUCTION' is used when building the static version of storybook.
-    // Make whatever fine-grained changes you need
-    // config.module.rules.push({
-    //   test: [/\.pot?$/, /\.mo$/],
-    //   loader: require.resolve('messageformat-po-loader'),
-    //   options: {
-    //     biDiSupport: false,
-    //     defaultCharset: null,
-    //     defaultLocale: 'en',
-    //     forceContext: false,
-    //     pluralFunction: null,
-    //     verbose: false
-    //   }
-    // });
-    // Return the altered config
+  // sb does not yet support new jsx transform by default
+  // https://github.com/storybookjs/storybook/issues/12881
+  // https://github.com/storybookjs/storybook/issues/12952
+  babel: async (options) => ({
+    ...options,
+    presets: [
+      ...options.presets,
+      [
+        '@babel/preset-react', {
+          runtime: 'automatic',
+        },
+        'preset-react-jsx-transform' 
+      ],
+    ],
+  }),
+  webpackFinal: (config) => {
+    // should be removed after storybook 6.3
+    // 
https://github.com/storybookjs/storybook/issues/12853#issuecomment-821576113
+    config.resolve.alias = {
+      react: "preact/compat",
+      "react-dom": "preact/compat",
+    };
     return config;
   },
 }
\ No newline at end of file
diff --git a/packages/frontend/.storybook/preview.js 
b/packages/frontend/.storybook/preview.js
index f511267..ab24c75 100644
--- a/packages/frontend/.storybook/preview.js
+++ b/packages/frontend/.storybook/preview.js
@@ -16,17 +16,31 @@
 
 import "../src/scss/main.scss"
 import { ConfigContextProvider } from '../src/context/config'
+import { InstanceContextProvider } from '../src/context/instance'
 import { TranslationProvider } from '../src/context/translation'
+import { BackendContextProvider } from '../src/context/backend'
 import { h } from 'preact';
 
 const mockConfig = {
   backendURL: 'http://demo.taler.net',
-  currency: 'KUDOS'
+  currency: 'TESTKUDOS'
+}
+
+const mockInstance = {
+  id: 'instance-id',
+  token: 'instance-token',
+  admin: false,
+}
+
+const mockBackend = {
+  url: 'http://merchant.url/',
+  token: 'default-token',
+  triedToLog: false,
 }
 
 export const parameters = {
   controls: { expanded: true },
-  actions: { argTypesRegex: "^on[A-Z].*" },
+  // actions: { argTypesRegex: "^on.*" },
 }
 
 export const globalTypes = {
@@ -45,11 +59,16 @@ export const globalTypes = {
 };
 
 export const decorators = [
-  (Story, { globals }) => {
-    
-    return <TranslationProvider initial={globals.locale}>
-      <Story />
-    </TranslationProvider>
-  },
-  (Story) => <ConfigContextProvider value={mockConfig}> <Story /> 
</ConfigContextProvider>
+  (Story, { globals }) => <TranslationProvider initial={globals.locale}>
+    <Story />
+  </TranslationProvider>,
+  (Story) => <ConfigContextProvider value={mockConfig}>
+    <Story />
+  </ConfigContextProvider>,
+  (Story) => <InstanceContextProvider value={mockInstance}>
+    <Story />
+  </InstanceContextProvider>,
+  (Story) => <BackendContextProvider value={mockBackend}>
+    <Story />
+  </BackendContextProvider>,
 ];
diff --git a/packages/frontend/src/components/form/InputSearchProduct.tsx 
b/packages/frontend/src/components/form/InputSearchProduct.tsx
index 43f79c9..f9f8f68 100644
--- a/packages/frontend/src/components/form/InputSearchProduct.tsx
+++ b/packages/frontend/src/components/form/InputSearchProduct.tsx
@@ -32,13 +32,14 @@ type Entity = MerchantBackend.Products.ProductDetail & 
WithId
 export interface Props {
   selected?: Entity;
   onChange: (p?: Entity) => void;
+  products: (MerchantBackend.Products.ProductDetail & WithId)[],
 }
 
 interface ProductSearch {
   name: string;
 }
 
-export function InputSearchProduct({ selected, onChange }: Props): VNode {
+export function InputSearchProduct({ selected, onChange, products }: Props): 
VNode {
   const [prodForm, setProdName] = useState<Partial<ProductSearch>>({ name: '' 
})
 
   const errors: FormErrors<ProductSearch> = {
@@ -75,10 +76,14 @@ export function InputSearchProduct({ selected, onChange }: 
Props): VNode {
       addonBefore={<span class="icon" ><i class="mdi mdi-magnify" /></span>}
     >
       <div>
-        <ProductList name={prodForm.name} onSelect={(p) => {
-          setProdName({ name: '' })
-          onChange(p)
-        }} />
+        <ProductList
+          name={prodForm.name}
+          list={products}
+          onSelect={(p) => {
+            setProdName({ name: '' })
+            onChange(p)
+          }}
+        />
       </div>
     </InputWithAddon>
 
@@ -89,29 +94,22 @@ export function InputSearchProduct({ selected, onChange }: 
Props): VNode {
 interface ProductListProps {
   name?: string;
   onSelect: (p: MerchantBackend.Products.ProductDetail & WithId) => void;
+  list: (MerchantBackend.Products.ProductDetail & WithId)[]
 }
 
-function ProductList({ name, onSelect }: ProductListProps) {
-  const result = useInstanceProducts();
-
-  const re = new RegExp(`.*${name}.*`)
-
-  let products = <div />
+function ProductList({ name, onSelect, list }: ProductListProps) {
+  if (!name) {
+    /* FIXME
+      this BR is added to occupy the space that will be added when the 
+      dropdown appears
+    */
+    return <div ><br /></div>
+  }
+  const filtered = list.filter(p => p.id.includes(name) || 
p.description.includes(name))
 
-  if (result.loading) {
-    products = <div class="dropdown-content">
-      <div class="dropdown-item"><Translate>loading...</Translate></div>
-    </div>
-  } else if (result.ok && !!name) {
-    if (!result.data.length) {
-      products = <div class="dropdown-content">
-        <div class="dropdown-item">
-          <Translate>no products found</Translate>
-        </div>
-      </div>
-    } else {
-      const filtered = result.data.filter(p => re.test(p.id) || 
re.test(p.description))
-      products = <div class="dropdown-content">
+  return <div class="dropdown is-active">
+    <div class="dropdown-menu" id="dropdown-menu" role="menu" style={{ 
minWidth: '20rem' }}>
+      <div class="dropdown-content">
         {!filtered.length ?
           <div class="dropdown-item" >
             <Translate>no products found with that description</Translate>
@@ -136,11 +134,6 @@ function ProductList({ name, onSelect }: ProductListProps) 
{
           ))
         }
       </div>
-    }
-  }
-  return <div class="dropdown is-active">
-    <div class="dropdown-menu" id="dropdown-menu" role="menu" style={{ 
minWidth: '20rem' }}>
-      {products}
     </div>
   </div>
 }
diff --git a/packages/frontend/src/components/form/InputSecured.stories.tsx 
b/packages/frontend/src/components/form/InputSecured.stories.tsx
index 7314add..1990eee 100644
--- a/packages/frontend/src/components/form/InputSecured.stories.tsx
+++ b/packages/frontend/src/components/form/InputSecured.stories.tsx
@@ -25,7 +25,7 @@ import { FormProvider } from "./FormProvider";
 import { InputSecured } from './InputSecured';
 
 export default {
-  title: 'Fields/InputSecured',
+  title: 'Components/Form/InputSecured',
   component: InputSecured,
 };
 
diff --git a/packages/frontend/src/components/form/InputStock.stories.tsx 
b/packages/frontend/src/components/form/InputStock.stories.tsx
index cc2654b..6e2275b 100644
--- a/packages/frontend/src/components/form/InputStock.stories.tsx
+++ b/packages/frontend/src/components/form/InputStock.stories.tsx
@@ -26,7 +26,7 @@ import { FormProvider } from "./FormProvider";
 import { InputStock, Stock } from './InputStock'
 
 export default {
-  title: 'Fields/InputStock',
+  title: 'Components/Form/InputStock',
   component: InputStock,
 };
 
diff --git a/packages/frontend/src/context/instance.ts 
b/packages/frontend/src/context/fetch.ts
similarity index 56%
copy from packages/frontend/src/context/instance.ts
copy to packages/frontend/src/context/fetch.ts
index fecf364..52a4f9c 100644
--- a/packages/frontend/src/context/instance.ts
+++ b/packages/frontend/src/context/fetch.ts
@@ -19,17 +19,22 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { createContext } from 'preact'
+import { h, createContext, VNode, ComponentChildren } from 'preact'
 import { useContext } from 'preact/hooks'
+import useSWR, { trigger, useSWRInfinite, cache, mutate } from 'swr';
 
 interface Type {
-  id: string;
-  token?: string;
-  admin?: boolean;
-  changeToken: (t?:string) => void;
+  useSWR: typeof useSWR,
+  useSWRInfinite: typeof useSWRInfinite,
 }
 
 const Context = createContext<Type>({} as any)
 
-export const InstanceContextProvider = Context.Provider
-export const useInstanceContext = (): Type => useContext(Context);
+export const useFetchContext = (): Type => useContext(Context);
+export const FetchContextProvider = ({ children }: { children: 
ComponentChildren }): VNode => {
+  return h(Context.Provider, { value: { useSWR, useSWRInfinite }, children });
+}
+
+export const FetchContextProviderTesting = ({ children, data }: { children: 
ComponentChildren, data:any }): VNode => {
+  return h(Context.Provider, { value: { useSWR: () => data, useSWRInfinite }, 
children });
+}
diff --git a/packages/frontend/src/hooks/product.ts 
b/packages/frontend/src/hooks/product.ts
index cdb1c4e..a8b33ba 100644
--- a/packages/frontend/src/hooks/product.ts
+++ b/packages/frontend/src/hooks/product.ts
@@ -16,6 +16,7 @@
 import { useEffect } from 'preact/hooks';
 import useSWR, { trigger, useSWRInfinite, cache, mutate } from 'swr';
 import { useBackendContext } from '../context/backend';
+// import { useFetchContext } from '../context/fetch';
 import { useInstanceContext } from '../context/instance';
 import { MerchantBackend, WithId } from '../declaration';
 import { fetcher, HttpError, HttpResponse, HttpResponseOk, mutateAll, request 
} from './backend';
@@ -125,6 +126,7 @@ export function useProductAPI(): ProductAPI {
 export function useInstanceProducts(): 
HttpResponse<(MerchantBackend.Products.ProductDetail & WithId)[]> {
   const { url: baseUrl, token: baseToken } = useBackendContext();
   const { token: instanceToken, id, admin } = useInstanceContext();
+  // const { useSWR, useSWRInfinite } = useFetchContext();
 
   const { url, token } = !admin ? {
     url: baseUrl, token: baseToken
diff --git a/packages/frontend/src/index.tsx b/packages/frontend/src/index.tsx
index 5c2df2f..0a77533 100644
--- a/packages/frontend/src/index.tsx
+++ b/packages/frontend/src/index.tsx
@@ -27,6 +27,7 @@ import { Loading } from "./components/exception/loading";
 import { NotificationCard, NotYetReadyAppMenu } from "./components/menu";
 import { BackendContextProvider, useBackendContext } from './context/backend';
 import { ConfigContextProvider } from './context/config';
+import { FetchContextProvider } from './context/fetch';
 import { TranslationProvider } from './context/translation';
 import { useBackendConfig } from "./hooks/backend";
 import { useTranslator } from './i18n';
@@ -35,11 +36,13 @@ import "./scss/main.scss";
 
 export default function Application(): VNode {
   return (
-    <BackendContextProvider>
-      <TranslationProvider>
-        <ApplicationStatusRoutes />
-      </TranslationProvider>
-    </BackendContextProvider>
+    // <FetchContextProvider>
+      <BackendContextProvider>
+        <TranslationProvider>
+          <ApplicationStatusRoutes />
+        </TranslationProvider>
+      </BackendContextProvider>
+    // </FetchContextProvider>
   );
 }
 
diff --git a/packages/frontend/src/paths/admin/create/Create.stories.tsx 
b/packages/frontend/src/paths/admin/create/Create.stories.tsx
index d1d8f39..c128755 100644
--- a/packages/frontend/src/paths/admin/create/Create.stories.tsx
+++ b/packages/frontend/src/paths/admin/create/Create.stories.tsx
@@ -19,20 +19,28 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { h, VNode } from 'preact';
-import { CreatePage } from './CreatePage';
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CreatePage as TestedComponent } from './CreatePage';
 
 
 export default {
-  title: 'Instances/Create',
-  component: CreatePage,
+  title: 'Pages/Instance/Create',
+  component: TestedComponent,
   argTypes: {
     onCreate: { action: 'onCreate' },
     goBack: { action: 'goBack' },
   }
 };
 
-export const Example = (a: any): VNode => <CreatePage {...a} />;
-Example.args = {
-  isLoading: false
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
 }
+
+export const Example = createExample(TestedComponent, {
+});
+// export const Example = (a: any): VNode => <CreatePage {...a} />;
+// Example.args = {
+//   isLoading: false
+// }
diff --git a/packages/frontend/src/paths/admin/list/View.stories.tsx 
b/packages/frontend/src/paths/admin/list/View.stories.tsx
index 0d34142..3da8c2e 100644
--- a/packages/frontend/src/paths/admin/list/View.stories.tsx
+++ b/packages/frontend/src/paths/admin/list/View.stories.tsx
@@ -24,7 +24,7 @@ import { View } from './View';
 
 
 export default {
-  title: 'Instances/View',
+  title: 'Pages/Instance/List',
   component: View,
   argTypes: {
     onSelect: { action: 'onSelect' },
diff --git a/packages/frontend/src/paths/instance/details/Details.stories.tsx 
b/packages/frontend/src/paths/instance/details/Details.stories.tsx
new file mode 100644
index 0000000..21141f7
--- /dev/null
+++ b/packages/frontend/src/paths/instance/details/Details.stories.tsx
@@ -0,0 +1,60 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { h, VNode, FunctionalComponent } from 'preact';
+import { DetailPage as TestedComponent } from './DetailPage';
+
+
+export default {
+  title: 'Pages/Instance/Detail',
+  component: TestedComponent,
+  argTypes: {
+    onUpdate: { action: 'onUpdate' },
+    onBack: { action: 'onBack' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const Example = createExample(TestedComponent, {
+  selected: {
+    accounts: [],
+    name: 'name',
+    auth: {method:'external'},
+    address: {},
+    jurisdiction: {},
+    default_max_deposit_fee: 'TESTKUDOS:2',
+    default_max_wire_fee: 'TESTKUDOS:1',
+    default_pay_delay: {
+      d_ms: 1000000,
+    },
+    default_wire_fee_amortization: 1,
+    default_wire_transfer_delay: {
+      d_ms: 100000,
+    },
+    merchant_pub: 'ASDWQEKASJDKSADJ'
+  }
+});
+
diff --git 
a/packages/frontend/src/paths/instance/orders/create/Create.stories.tsx 
b/packages/frontend/src/paths/instance/orders/create/Create.stories.tsx
new file mode 100644
index 0000000..29f6842
--- /dev/null
+++ b/packages/frontend/src/paths/instance/orders/create/Create.stories.tsx
@@ -0,0 +1,62 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CreatePage as TestedComponent } from './CreatePage';
+
+
+export default {
+  title: 'Pages/Order/Create',
+  component: TestedComponent,
+  argTypes: {
+    onCreate: { action: 'onCreate' },
+    goBack: { action: 'goBack' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const Example = createExample(TestedComponent, {
+  instanceConfig: {
+    default_max_deposit_fee: '',
+    default_max_wire_fee: '',
+    default_pay_delay: {
+      d_ms: 'forever'
+    },
+    default_wire_fee_amortization: 1
+  },
+  instanceInventory: [{
+    id: 't-shirt-1',
+    description: 'a m size t-shirt',
+    price: 'TESTKUDOS:1',
+    total_stock: -1
+  },{
+    id: 't-shirt-2',
+    description: 'a xl size t-shirt'
+  } as any,{
+    id: 't-shirt-3',
+    description: 'a s size t-shirt'
+  } as any]
+});
diff --git a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx 
b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
index ae32dac..768a1cb 100644
--- a/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/instance/orders/create/CreatePage.tsx
@@ -31,25 +31,42 @@ import { InputGroup } from 
"../../../../components/form/InputGroup";
 import { InputLocation } from "../../../../components/form/InputLocation";
 import { ProductList } from "../../../../components/product/ProductList";
 import { useConfigContext } from "../../../../context/config";
-import { MerchantBackend, WithId } from "../../../../declaration";
-import { useInstanceDetails } from "../../../../hooks/instance";
+import { Duration, MerchantBackend, WithId } from "../../../../declaration";
 import { Translate, useTranslator } from "../../../../i18n";
 import { OrderCreateSchema as schema } from '../../../../schemas/index';
-import { multiplyPrice, rate, subtractPrices, sumPrices } from 
"../../../../utils/amount";
+import { multiplyPrice, rate, sumPrices } from "../../../../utils/amount";
 import { InventoryProductForm } from "./InventoryProductForm";
 import { NonInventoryProductFrom } from "./NonInventoryProductForm";
 
 interface Props {
   onCreate: (d: MerchantBackend.Orders.PostOrderRequest) => void;
   onBack?: () => void;
+  instanceConfig: InstanceConfig;
+  instanceInventory: (MerchantBackend.Products.ProductDetail & WithId)[],
 }
+interface InstanceConfig {
+  default_max_wire_fee: string;
+  default_max_deposit_fee: string;
+  default_wire_fee_amortization: number;
+  default_pay_delay: Duration;
+}
+
+function with_defaults(config: InstanceConfig): Partial<Entity> {
+  const defaultPayDeadline = !config.default_pay_delay || 
config.default_pay_delay.d_ms === "forever" ? 
+    undefined : 
+    add(new Date(), { seconds: config.default_pay_delay.d_ms / 1000 })
 
-function with_defaults(): Partial<Entity> {
   return {
     inventoryProducts: {},
     products: [],
     pricing: {} as any,
-    payments: {} as any,
+    payments: {
+      max_wire_fee: config.default_max_wire_fee,
+      max_fee: config.default_max_deposit_fee,
+      wire_fee_amortization: config.default_wire_fee_amortization,
+      pay_deadline: defaultPayDeadline,
+      refund_deadline: defaultPayDeadline,
+    } as Partial<Payments>,
     extra: ''
   };
 }
@@ -86,8 +103,8 @@ interface Entity {
   extra: string;
 }
 
-export function CreatePage({ onCreate, onBack }: Props): VNode {
-  const [value, valueHandler] = useState(with_defaults())
+export function CreatePage({ onCreate, onBack, instanceConfig, 
instanceInventory }: Props): VNode {
+  const [value, valueHandler] = useState(with_defaults(instanceConfig))
   // const [errors, setErrors] = useState<FormErrors<Entity>>({})
 
   const inventoryList = Object.values(value.inventoryProducts || {})
@@ -196,30 +213,6 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
     })
   }, [value.pricing?.order_price])
 
-  const details_response = useInstanceDetails()
-
-  const dmwf = !details_response.ok ? undefined : 
details_response.data.default_max_wire_fee;
-  const dmdf = !details_response.ok ? undefined : 
details_response.data.default_max_deposit_fee;
-  const dwfa = !details_response.ok ? undefined : 
details_response.data.default_wire_fee_amortization;
-  const dpd = !details_response.ok ? undefined : 
details_response.data.default_pay_delay;
-  useEffect(() => {
-    if (details_response.ok) {
-      valueHandler(v => {
-        const defaultPayDeadline = !dpd || dpd.d_ms === "forever" ? undefined 
: add(new Date(), { seconds: dpd.d_ms / 1000 })
-        return ({
-          ...v, payments: {
-            ...v.payments,
-            max_wire_fee: dmwf,
-            max_fee: dmdf,
-            wire_fee_amortization: dwfa,
-            pay_deadline: defaultPayDeadline,
-            refund_deadline: defaultPayDeadline,
-          }
-        })
-      })
-    }
-  }, [details_response.ok, dmwf, dmdf, dwfa, dpd])
-
   const i18n = useTranslator()
 
   return <div>
@@ -239,6 +232,7 @@ export function CreatePage({ onCreate, onBack }: Props): 
VNode {
             <InventoryProductForm
               currentProducts={value.inventoryProducts || {}}
               onAddProduct={addProductToTheInventoryList}
+              inventory={instanceInventory}
             />
 
             {inventoryList.length > 0 &&
diff --git 
a/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx 
b/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx
index b97b39a..0fc5338 100644
--- 
a/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx
+++ 
b/packages/frontend/src/paths/instance/orders/create/InventoryProductForm.tsx
@@ -29,10 +29,11 @@ type Form = {
 
 interface Props {
   currentProducts: ProductMap,
-  onAddProduct: (product: MerchantBackend.Products.ProductDetail & WithId, 
quantity: number) => void
+  onAddProduct: (product: MerchantBackend.Products.ProductDetail & WithId, 
quantity: number) => void,
+  inventory: (MerchantBackend.Products.ProductDetail & WithId)[],
 }
 
-export function InventoryProductForm({ currentProducts, onAddProduct }: 
Props): VNode {
+export function InventoryProductForm({ currentProducts, onAddProduct, 
inventory }: Props): VNode {
   const initialState = { quantity: 1 }
   const [state, setState] = useState<Partial<Form>>(initialState)
   const [errors, setErrors] = useState<FormErrors<Form>>({})
@@ -74,7 +75,7 @@ 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 }))}  />
+    <InputSearchProduct selected={state.product} onChange={(p) => setState(v 
=> ({ ...v, product: p }))} products={inventory}  />
     { 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" disabled={!state.product} 
onClick={submit}><Translate>Add</Translate></button>
diff --git 
a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
 
b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
index 756ec23..31cf33b 100644
--- 
a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
+++ 
b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
@@ -60,12 +60,13 @@ export function NonInventoryProductFrom({ productToEdit, 
onAddProduct }: Props):
     return Promise.reject()
   })
 
+  const i18n = useTranslator()
   return <Fragment>
     <div class="buttons">
       <button class="button is-success" onClick={() => 
setShowCreateProduct(true)} ><Translate>add new product</Translate></button>
     </div>
     {showCreateProduct && <ConfirmModal active
-      description="alskdj alsk jdalksjd laksjd lkasjd"
+      description={i18n`Complete information of the product`}
       onCancel={() => setShowCreateProduct(false)} onConfirm={submitForm}>
       <ProductForm initial={productToEdit} onSubscribe={addFormSubmitter} />
     </ConfirmModal>}
diff --git a/packages/frontend/src/paths/instance/orders/create/index.tsx 
b/packages/frontend/src/paths/instance/orders/create/index.tsx
index ee0577a..71f5b7f 100644
--- a/packages/frontend/src/paths/instance/orders/create/index.tsx
+++ b/packages/frontend/src/paths/instance/orders/create/index.tsx
@@ -21,9 +21,13 @@
 
 import { Fragment, h, VNode } from 'preact';
 import { useState } from 'preact/hooks';
+import { Loading } from '../../../../components/exception/loading';
 import { NotificationCard } from '../../../../components/menu';
 import { MerchantBackend } from '../../../../declaration';
+import { HttpError } from '../../../../hooks/backend';
+import { useInstanceDetails } from '../../../../hooks/instance';
 import { useOrderAPI } from '../../../../hooks/order';
+import { useInstanceProducts } from '../../../../hooks/product';
 import { Notification } from '../../../../utils/types';
 import { CreatePage } from './CreatePage';
 import { OrderCreatedSuccessfully } from './OrderCreatedSuccessfully';
@@ -35,11 +39,26 @@ export type Entity = {
 interface Props {
   onBack?: () => void;
   onConfirm: () => void;
+  onUnauthorized: () => VNode;
+  onNotFound: () => VNode;
+  onLoadError: (error: HttpError) => VNode;
 }
-export default function OrderCreate({ onConfirm, onBack }: Props): VNode {
+export default function OrderCreate({ onConfirm, onBack, onLoadError, 
onNotFound, onUnauthorized }: Props): VNode {
   const { createOrder } = useOrderAPI()
   const [notif, setNotif] = useState<Notification | undefined>(undefined)
 
+  const detailsResult = useInstanceDetails()
+  const inventoryResult = useInstanceProducts()
+
+  if (detailsResult.clientError && detailsResult.isUnauthorized) return 
onUnauthorized()
+  if (detailsResult.clientError && detailsResult.isNotfound) return 
onNotFound()
+  if (detailsResult.loading) return <Loading />
+  if (!detailsResult.ok) return onLoadError(detailsResult)
+
+  if (inventoryResult.clientError && inventoryResult.isUnauthorized) return 
onUnauthorized()
+  if (inventoryResult.clientError && inventoryResult.isNotfound) return 
onNotFound()
+  if (inventoryResult.loading) return <Loading />
+  if (!inventoryResult.ok) return onLoadError(inventoryResult)
 
   return <Fragment>
     
@@ -55,6 +74,9 @@ export default function OrderCreate({ onConfirm, onBack }: 
Props): VNode {
             description: error.message
           })
         })
-      }} />
+      }} 
+      instanceConfig={detailsResult.data}
+      instanceInventory={inventoryResult.data}
+      />
   </Fragment>
 }
\ No newline at end of file
diff --git 
a/packages/frontend/src/paths/instance/orders/details/Detail.stories.tsx 
b/packages/frontend/src/paths/instance/orders/details/Detail.stories.tsx
new file mode 100644
index 0000000..4e43a54
--- /dev/null
+++ b/packages/frontend/src/paths/instance/orders/details/Detail.stories.tsx
@@ -0,0 +1,137 @@
+/*
+ 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 { addDays } from 'date-fns';
+import { h, VNode, FunctionalComponent } from 'preact';
+import { MerchantBackend } from '../../../../declaration';
+import { DetailPage as TestedComponent } from './DetailPage';
+
+
+export default {
+  title: 'Pages/Order/Detail',
+  component: TestedComponent,
+  argTypes: {
+    onRefund: { action: 'onRefund' },
+    onBack: { action: 'onBack' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+const defaultContractTerm = {
+  amount: 'TESTKUDOS:10',
+  timestamp: {
+    t_ms: new Date().getTime(),
+  },
+  auditors: [],
+  exchanges: [],
+  max_fee: 'TESTKUDOS:1',
+  max_wire_fee: 'TESTKUDOS:1',
+  merchant: {
+
+  } as any,
+  merchant_base_url: 'http://merchant.url/',
+  order_id: '2021.165-03GDFC26Y1NNG',
+  products: [],
+  summary: 'text summary',
+  wire_fee_amortization: 1,
+  wire_transfer_deadline: {
+    t_ms: 'never',
+  },
+  refund_deadline: { t_ms: 'never' },
+  merchant_pub: 'ASDASDASDSd',
+  nonce: 'QWEQWEQWE',
+  pay_deadline: {
+    t_ms: 'never',
+  },
+  wire_method: 'x-taler-bank',
+  h_wire: 'asd',
+} as MerchantBackend.ContractTerms
+
+// contract_terms: defaultContracTerm,
+export const Claimed = createExample(TestedComponent, {
+  id: '2021.165-03GDFC26Y1NNG',
+  selected: {
+    order_status: 'claimed',
+    contract_terms: defaultContractTerm
+  },
+});
+
+export const PaidNotRefundable = createExample(TestedComponent, {
+  id: '2021.165-03GDFC26Y1NNG',
+  selected: {
+    order_status: 'paid',
+    contract_terms: defaultContractTerm,
+    refunded: false,
+    deposit_total: 'TESTKUDOS:10',
+    exchange_ec: 0,
+    order_status_url: 'http://merchant.backend/status',
+    exchange_hc: 0,
+    refund_amount: 'TESTKUDOS:0',
+    refund_details: [],
+    refund_pending: false,
+    wire_details: [],
+    wire_reports: [],
+    wired: false,
+  }
+});
+
+export const PaidRefundable = createExample(TestedComponent, {
+  id: '2021.165-03GDFC26Y1NNG',
+  selected: {
+    order_status: 'paid',
+    contract_terms: {
+      ...defaultContractTerm,
+      refund_deadline: {
+        t_ms: addDays(new Date(), 2).getTime()
+      }
+    },
+    refunded: false,
+    deposit_total: 'TESTKUDOS:10',
+    exchange_ec: 0,
+    order_status_url: 'http://merchant.backend/status',
+    exchange_hc: 0,
+    refund_amount: 'TESTKUDOS:0',
+    refund_details: [],
+    refund_pending: false,
+    wire_details: [],
+    wire_reports: [],
+    wired: false,
+  }
+});
+
+export const Unpaid = createExample(TestedComponent, {
+  id: '2021.165-03GDFC26Y1NNG',
+  selected: {
+    order_status: 'unpaid',
+    order_status_url: 'http://merchant.backend/status',
+    creation_time: {
+      t_ms: new Date().getTime()
+    },
+    summary: 'text summary',
+    taler_pay_uri: 'pay uri',
+    total_amount: 'TESTKUDOS:10',
+  }
+});
diff --git a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx 
b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
index bfc7c7f..9f2bce3 100644
--- a/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
+++ b/packages/frontend/src/paths/instance/orders/details/DetailPage.tsx
@@ -84,31 +84,41 @@ function ContractTerms({ value }: { value: CT }) {
 
 function ClaimedPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.CheckPaymentClaimedResponse }) {
   const events: Event[] = []
-  events.push({
-    when: new Date(order.contract_terms.timestamp.t_ms),
-    description: 'order created',
-    type: 'start'
-  })
-  events.push({
-    when: new Date(order.contract_terms.pay_deadline.t_ms),
-    description: 'pay deadline',
-    type: 'deadline'
-  })
-  events.push({
-    when: new Date(order.contract_terms.refund_deadline.t_ms),
-    description: 'refund deadline',
-    type: 'deadline'
-  })
-  events.push({
-    when: new Date(order.contract_terms.wire_transfer_deadline.t_ms),
-    description: 'wire deadline',
-    type: 'deadline'
-  })
-  if (order.contract_terms.delivery_date) events.push({
-    when: new Date(order.contract_terms.delivery_date?.t_ms),
-    description: 'delivery',
-    type: 'delivery'
-  })
+  if (order.contract_terms.timestamp.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.timestamp.t_ms),
+      description: 'order created',
+      type: 'start'
+    })
+  }
+  if (order.contract_terms.pay_deadline.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.pay_deadline.t_ms),
+      description: 'pay deadline',
+      type: 'deadline'
+    })
+  }
+  if (order.contract_terms.refund_deadline.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.refund_deadline.t_ms),
+      description: 'refund deadline',
+      type: 'deadline'
+    })
+  }
+  if (order.contract_terms.wire_transfer_deadline.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.wire_transfer_deadline.t_ms),
+      description: 'wire deadline',
+      type: 'deadline'
+    })
+  }
+  if (order.contract_terms.delivery_date && 
order.contract_terms.delivery_date.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.delivery_date?.t_ms),
+      description: 'delivery',
+      type: 'delivery'
+    })
+  }
 
   const [value, valueHandler] = useState<Partial<Claimed>>(order)
   const i18n = useTranslator()
@@ -138,15 +148,6 @@ function ClaimedPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.
                     </h1>
                   </div>
                 </div>
-                <div class="level-right">
-                  <div class="level-item">
-                    <h1 class="title">
-                      <button class="button is-info" onClick={() => {
-                        if (order.contract_terms.fulfillment_url) 
copyToClipboard(order.contract_terms.fulfillment_url)
-                      }}><Translate>copy url</Translate></button>
-                    </h1>
-                  </div>
-                </div>
               </div>
 
               <div class="level">
@@ -196,31 +197,42 @@ function ClaimedPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.
 }
 function PaidPage({ id, order, onRefund }: { id: string; order: 
MerchantBackend.Orders.CheckPaymentPaidResponse, onRefund: (id: string) => void 
}) {
   const events: Event[] = []
-  events.push({
-    when: new Date(order.contract_terms.timestamp.t_ms),
-    description: 'order created',
-    type: 'start'
-  })
-  events.push({
-    when: new Date(order.contract_terms.pay_deadline.t_ms),
-    description: 'pay deadline',
-    type: 'deadline'
-  })
-  events.push({
-    when: new Date(order.contract_terms.refund_deadline.t_ms),
-    description: 'refund deadline',
-    type: 'deadline'
-  })
-  events.push({
-    when: new Date(order.contract_terms.wire_transfer_deadline.t_ms),
-    description: 'wire deadline',
-    type: 'deadline'
-  })
-  if (order.contract_terms.delivery_date) events.push({
-    when: new Date(order.contract_terms.delivery_date?.t_ms),
-    description: 'delivery',
-    type: 'delivery'
-  })
+  if (order.contract_terms.timestamp.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.timestamp.t_ms),
+      description: 'order created',
+      type: 'start'
+    })
+  }
+  if (order.contract_terms.pay_deadline.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.pay_deadline.t_ms),
+      description: 'pay deadline',
+      type: 'deadline'
+    })
+
+  }
+  if (order.contract_terms.refund_deadline.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.refund_deadline.t_ms),
+      description: 'refund deadline',
+      type: 'deadline'
+    })
+  }
+  if (order.contract_terms.wire_transfer_deadline.t_ms !== 'never') {
+    events.push({
+      when: new Date(order.contract_terms.wire_transfer_deadline.t_ms),
+      description: 'wire deadline',
+      type: 'deadline'
+    })
+  }
+  if (order.contract_terms.delivery_date && 
order.contract_terms.delivery_date.t_ms !== 'never') {
+    if (order.contract_terms.delivery_date) events.push({
+      when: new Date(order.contract_terms.delivery_date?.t_ms),
+      description: 'delivery',
+      type: 'delivery'
+    })
+  }
   order.refund_details.reduce(mergeRefunds, []).forEach(e => {
     events.push({
       when: new Date(e.timestamp.t_ms),
@@ -306,7 +318,7 @@ function PaidPage({ id, order, onRefund }: { id: string; 
order: MerchantBackend.
                   <div class="level-item">
                     <h1 class="title">
                       <div class="buttons">
-                        <span class="has-tooltip-left" 
data-tooltip={refundable ? i18n`refund order`: i18n`not refundable`}>
+                        <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>
@@ -342,7 +354,7 @@ function PaidPage({ id, order, onRefund }: { id: string; 
order: MerchantBackend.
               <div class="column is-8" >
                 <div class="title"><Translate>Payment details</Translate></div>
                 <FormProvider<Paid> object={value} valueHandler={valueHandler} 
>
-                  <InputCurrency<Paid> name="deposit_total" readonly 
label={i18n`Deposit total`} />
+                  {/* <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`} />
                   <TextField<Paid> name="order_status_url" label={i18n`Status 
URL`} >
@@ -438,7 +450,7 @@ export function DetailPage({ id, selected, onRefund, onBack 
}: Props): VNode {
   return <Fragment>
     {DetailByStatus()}
     {showRefund && <RefundModal
-      id={id}
+      order={selected}
       onCancel={() => setShowRefund(undefined)}
       onConfirm={(value) => {
         onRefund(showRefund, value)
diff --git a/packages/frontend/src/paths/instance/orders/details/Timeline.tsx 
b/packages/frontend/src/paths/instance/orders/details/Timeline.tsx
index 16adbcb..34271a4 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">
-    {state.map((e,i) => {
+    {events.map((e,i) => {
       return <div key={i} class="timeline-item">
         {(() => {
           switch (e.type) {
diff --git a/packages/frontend/src/paths/instance/orders/list/List.stories.tsx 
b/packages/frontend/src/paths/instance/orders/list/List.stories.tsx
new file mode 100644
index 0000000..e791f20
--- /dev/null
+++ b/packages/frontend/src/paths/instance/orders/list/List.stories.tsx
@@ -0,0 +1,87 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CardTable as TestedComponent } from './Table';
+
+
+export default {
+  title: 'Pages/Order/List',
+  component: TestedComponent,
+  argTypes: {
+    onCreate: { action: 'onCreate' },
+    goBack: { action: 'goBack' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const Example = createExample(TestedComponent, {
+  orders: [{
+    id: '123',
+    amount: 'TESTKUDOS:10',
+    paid: false,
+    refundable: true,
+    row_id: 1,
+    summary: 'summary',
+    timestamp: {
+      t_ms: new Date().getTime()
+    },
+    order_id: '123'
+  },{
+    id: '234',
+    amount: 'TESTKUDOS:12',
+    paid: true,
+    refundable: true,
+    row_id: 2,
+    summary: 'summary with long text, very very long text that someone want to 
add as a description of the order',
+    timestamp: {
+      t_ms: new Date().getTime()
+    },
+    order_id: '234'
+  },{
+    id: '456',
+    amount: 'TESTKUDOS:1',
+    paid: false,
+    refundable: false,
+    row_id: 3,
+    summary: 'summary with long text, very very long text that someone want to 
add as a description of the order',
+    timestamp: {
+      t_ms: new Date().getTime()
+    },
+    order_id: '456'
+  },{
+    id: '234',
+    amount: 'TESTKUDOS:12',
+    paid: false,
+    refundable: false,
+    row_id: 4,
+    summary: 'summary with long text, very very long text that someone want to 
add as a description of the order',
+    timestamp: {
+      t_ms: new Date().getTime()
+    },
+    order_id: '234'
+  }]
+});
diff --git a/packages/frontend/src/paths/instance/orders/list/Table.tsx 
b/packages/frontend/src/paths/instance/orders/list/Table.tsx
index 41c7293..02a5428 100644
--- a/packages/frontend/src/paths/instance/orders/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/orders/list/Table.tsx
@@ -29,7 +29,6 @@ import { InputGroup } from 
"../../../../components/form/InputGroup";
 import { InputSelector } from "../../../../components/form/InputSelector";
 import { ConfirmModal } from "../../../../components/modal";
 import { MerchantBackend, WithId } from "../../../../declaration";
-import { useOrderDetails } from "../../../../hooks/order";
 import { Translate, useTranslator } from "../../../../i18n";
 import { RefundSchema as RefundSchema } from "../../../../schemas";
 import { mergeRefunds, subtractPrices, sumPrices } from 
"../../../../utils/amount";
@@ -37,8 +36,8 @@ import { AMOUNT_ZERO_REGEX } from 
"../../../../utils/constants";
 
 type Entity = MerchantBackend.Orders.OrderHistoryEntry & WithId
 interface Props {
-  instances: Entity[];
-  onRefund: (id: string, value: MerchantBackend.Orders.RefundRequest) => void;
+  orders: Entity[];
+  onRefund: (value: Entity) => void;
   onCopyURL: (id: string) => void;
   onCreate: () => void;
   onSelect: (order: Entity) => void;
@@ -49,11 +48,9 @@ interface Props {
 }
 
 
-export function CardTable({ instances, onCreate, onRefund, onCopyURL, 
onSelect, onLoadMoreAfter, onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: 
Props): VNode {
+export function CardTable({ orders, onCreate, onRefund, onCopyURL, onSelect, 
onLoadMoreAfter, onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: Props): VNode 
{
   const [rowSelection, rowSelectionHandler] = useState<string[]>([])
 
-  const [showRefund, setShowRefund] = useState<string | undefined>(undefined)
-
   const i18n = useTranslator()
 
   return <div class="card has-table">
@@ -74,8 +71,8 @@ export function CardTable({ instances, onCreate, onRefund, 
onCopyURL, onSelect,
     <div class="card-content">
       <div class="b-table has-pagination">
         <div class="table-wrapper has-mobile-cards">
-          {instances.length > 0 ?
-            <Table instances={instances} onSelect={onSelect} onRefund={(order) 
=> setShowRefund(order.id)}
+          {orders.length > 0 ?
+            <Table instances={orders} onSelect={onSelect} onRefund={onRefund}
               onCopyURL={o => onCopyURL(o.id)}
               rowSelection={rowSelection} 
rowSelectionHandler={rowSelectionHandler}
               onLoadMoreAfter={onLoadMoreAfter} 
onLoadMoreBefore={onLoadMoreBefore}
@@ -86,14 +83,6 @@ export function CardTable({ instances, onCreate, onRefund, 
onCopyURL, onSelect,
         </div>
       </div>
     </div>
-    {showRefund && <RefundModal
-      id={showRefund}
-      onCancel={() => setShowRefund(undefined)}
-      onConfirm={(value) => {
-        onRefund(showRefund, value)
-        setShowRefund(undefined)
-      }}
-    />}
   </div>
 }
 interface TableProps {
@@ -160,12 +149,11 @@ function EmptyTable(): VNode {
 
 interface RefundModalProps {
   onCancel: () => void;
-  id: string;
   onConfirm: (value: MerchantBackend.Orders.RefundRequest) => void;
+  order: MerchantBackend.Orders.MerchantOrderStatusResponse
 }
 
-export function RefundModal({ id, onCancel, onConfirm }: RefundModalProps): 
VNode {
-  const result = useOrderDetails(id)
+export function RefundModal({ order, onCancel, onConfirm }: RefundModalProps): 
VNode {
   type State = { mainReason?: string, description?: string, refund?: string }
   const [form, setValue] = useState<State>({})
   const i18n = useTranslator();
@@ -186,10 +174,10 @@ export function RefundModal({ id, onCancel, onConfirm }: 
RefundModalProps): VNod
     }
   }
 
-  const refunds = (result.ok && result.data.order_status === 'paid' ? 
result.data.refund_details : [])
+  const refunds = (order.order_status === 'paid' ? order.refund_details : [])
     .reduce(mergeRefunds, [])
   const totalRefunded = refunds.map(r => r.amount).reduce((p, c) => 
sumPrices(c, p), ':0')
-  const orderPrice = (result.ok && result.data.order_status === 'paid' ? 
result.data.contract_terms.amount : undefined)
+  const orderPrice = (order.order_status === 'paid' ? 
order.contract_terms.amount : undefined)
   const totalRefundable = !orderPrice ? undefined : (refunds.length ? 
subtractPrices(orderPrice, totalRefunded) : orderPrice)
 
   const isRefundable = totalRefundable && 
!AMOUNT_ZERO_REGEX.test(totalRefundable)
diff --git a/packages/frontend/src/paths/instance/orders/list/index.tsx 
b/packages/frontend/src/paths/instance/orders/list/index.tsx
index 8bfe23d..34d156a 100644
--- a/packages/frontend/src/paths/instance/orders/list/index.tsx
+++ b/packages/frontend/src/paths/instance/orders/list/index.tsx
@@ -25,11 +25,12 @@ import { useState } from 'preact/hooks';
 import { Loading } from '../../../../components/exception/loading';
 import { DatePicker } from '../../../../components/form/DatePicker';
 import { NotificationCard } from '../../../../components/menu';
+import { MerchantBackend } from '../../../../declaration';
 import { HttpError } from '../../../../hooks/backend';
-import { InstanceOrderFilter, useInstanceOrders, useOrderAPI } from 
'../../../../hooks/order';
+import { InstanceOrderFilter, useInstanceOrders, useOrderAPI, useOrderDetails 
} from '../../../../hooks/order';
 import { Translate, useTranslator } from '../../../../i18n';
 import { Notification } from '../../../../utils/types';
-import { CardTable } from './Table';
+import { CardTable, RefundModal } from './Table';
 
 interface Props {
   onUnauthorized: () => VNode;
@@ -43,6 +44,7 @@ interface Props {
 export default function ({ onUnauthorized, onLoadError, onCreate, onSelect, 
onNotFound }: Props): VNode {
   const [filter, setFilter] = useState<InstanceOrderFilter>({})
   const [pickDate, setPickDate] = useState(false)
+  const [orderToBeRefunded, setOrderToBeRefunded] = 
useState<MerchantBackend.Orders.OrderHistoryEntry | undefined>(undefined)
 
   const setNewDate = (date: Date) => setFilter(prev => ({ ...prev, date }))
 
@@ -159,26 +161,76 @@ export default function ({ onUnauthorized, onLoadError, 
onCreate, onSelect, onNo
       dateReceiver={setNewDate}
     />
 
-    <CardTable instances={result.data.orders.map(o => ({ ...o, id: o.order_id 
}))}
+    <CardTable orders={result.data.orders.map(o => ({ ...o, id: o.order_id }))}
       onCreate={onCreate}
       onSelect={(order) => onSelect(order.id)}
       onCopyURL={(id) => getPaymentURL(id).then((resp) => 
copyToClipboard(resp.data))}
-      onRefund={(id, value) => refundOrder(id, value)
+      onRefund={(value) => setOrderToBeRefunded(value)}
+      onLoadMoreBefore={result.loadMorePrev} 
hasMoreBefore={!result.isReachingStart}
+      onLoadMoreAfter={result.loadMore} hasMoreAfter={!result.isReachingEnd}
+    />
+    {orderToBeRefunded && <RefundModalForTable
+      id={orderToBeRefunded.order_id}
+      onCancel={() => setOrderToBeRefunded(undefined)}
+      onConfirm={(value) => refundOrder(orderToBeRefunded.order_id, value)
         .then(() => setNotif({
           message: i18n`refund created successfully`,
           type: "SUCCESS"
-        })).catch((error) => setNotif({
+        }))
+        .catch((error) => setNotif({
           message: i18n`could not create the refund`,
           type: "ERROR",
           description: error.message
         }))
+        .then(() => setOrderToBeRefunded(undefined))
       }
-      onLoadMoreBefore={result.loadMorePrev} 
hasMoreBefore={!result.isReachingStart}
-      onLoadMoreAfter={result.loadMore} hasMoreAfter={!result.isReachingEnd}
-    />
+      onLoadError={(error) => {
+        setNotif({
+          message: i18n`could not create the refund`,
+          type: "ERROR",
+          description: error.message
+        })
+        setOrderToBeRefunded(undefined)
+        return <div />
+      }}
+      onUnauthorized={onUnauthorized}
+      onNotFound={() => {
+        setNotif({
+          message: i18n`could not get the order to refund`,
+          type: "ERROR",
+          // description: error.message
+        })
+        setOrderToBeRefunded(undefined)
+        return <div />
+      }}
+    />}
   </section>
 }
 
+interface RefundProps {
+  id: string;
+  onUnauthorized: () => VNode;
+  onLoadError: (error: HttpError) => VNode;
+  onNotFound: () => VNode;
+  onCancel: () => void;
+  onConfirm: (m: MerchantBackend.Orders.RefundRequest) => void;
+}
+
+function RefundModalForTable({ id, onUnauthorized, onLoadError, onNotFound, 
onConfirm, onCancel }: RefundProps) {
+  const result = useOrderDetails(id);
+
+  if (result.clientError && result.isUnauthorized) return onUnauthorized()
+  if (result.clientError && result.isNotfound) return onNotFound()
+  if (result.loading) return <Loading />
+  if (!result.ok) return onLoadError(result)
+
+  return <RefundModal
+    order={result.data}
+    onCancel={onCancel}
+    onConfirm={onConfirm}
+  />
+}
+
 async function copyToClipboard(text: string) {
   return navigator.clipboard.writeText(text)
 }
diff --git a/packages/frontend/src/paths/admin/create/Create.stories.tsx 
b/packages/frontend/src/paths/instance/products/create/Create.stories.tsx
similarity index 64%
copy from packages/frontend/src/paths/admin/create/Create.stories.tsx
copy to packages/frontend/src/paths/instance/products/create/Create.stories.tsx
index d1d8f39..1d9ea53 100644
--- a/packages/frontend/src/paths/admin/create/Create.stories.tsx
+++ b/packages/frontend/src/paths/instance/products/create/Create.stories.tsx
@@ -19,20 +19,24 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { h, VNode } from 'preact';
-import { CreatePage } from './CreatePage';
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CreatePage as TestedComponent } from './CreatePage';
 
 
 export default {
-  title: 'Instances/Create',
-  component: CreatePage,
+  title: 'Pages/Product/Create',
+  component: TestedComponent,
   argTypes: {
     onCreate: { action: 'onCreate' },
-    goBack: { action: 'goBack' },
-  }
+    onBack: { action: 'onBack' },
+  },
 };
 
-export const Example = (a: any): VNode => <CreatePage {...a} />;
-Example.args = {
-  isLoading: false
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
 }
+
+export const Example = createExample(TestedComponent, {
+});
diff --git a/packages/frontend/src/paths/admin/create/Create.stories.tsx 
b/packages/frontend/src/paths/instance/products/list/List.stories.tsx
similarity index 51%
copy from packages/frontend/src/paths/admin/create/Create.stories.tsx
copy to packages/frontend/src/paths/instance/products/list/List.stories.tsx
index d1d8f39..beae83b 100644
--- a/packages/frontend/src/paths/admin/create/Create.stories.tsx
+++ b/packages/frontend/src/paths/instance/products/list/List.stories.tsx
@@ -19,20 +19,40 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { h, VNode } from 'preact';
-import { CreatePage } from './CreatePage';
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CardTable as TestedComponent } from './Table';
 
 
 export default {
-  title: 'Instances/Create',
-  component: CreatePage,
+  title: 'Pages/Product/List',
+  component: TestedComponent,
   argTypes: {
     onCreate: { action: 'onCreate' },
-    goBack: { action: 'goBack' },
-  }
+    onSelect: { action: 'onSelect' },
+    onDelete: { action: 'onDelete' },
+    onUpdate: { action: 'onUpdate' },
+  },
 };
 
-export const Example = (a: any): VNode => <CreatePage {...a} />;
-Example.args = {
-  isLoading: false
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
 }
+
+
+export const Example = createExample(TestedComponent, {
+  instances: [{
+    id: 'orderid',
+    description: 'description1',
+    description_i18n: {} as any,
+    image: '',
+    price: 'TESTKUDOS:10',
+    taxes: [],
+    total_lost: 10,
+    total_sold: 5,
+    total_stock: 15,
+    unit: 'bar',
+    address: {}
+  }]
+});
diff --git 
a/packages/frontend/src/paths/instance/products/update/Update.stories.tsx 
b/packages/frontend/src/paths/instance/products/update/Update.stories.tsx
new file mode 100644
index 0000000..3a57f7f
--- /dev/null
+++ b/packages/frontend/src/paths/instance/products/update/Update.stories.tsx
@@ -0,0 +1,71 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { h, VNode, FunctionalComponent } from 'preact';
+import { UpdatePage as TestedComponent } from './UpdatePage';
+
+
+export default {
+  title: 'Pages/Product/Update',
+  component: TestedComponent,
+  argTypes: {
+    onUpdate: { action: 'onUpdate' },
+    onBack: { action: 'onBack' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const WithManagedStock = createExample(TestedComponent, {
+  product: {
+    product_id: '20102-ASDAS-QWE',
+    description: 'description1',
+    description_i18n: {} as any,
+    image: '',
+    price: 'TESTKUDOS:10',
+    taxes: [],
+    total_lost: 10,
+    total_sold: 5,
+    total_stock: 15,
+    unit: 'bar',
+    address: {}
+  }
+});
+
+export const WithInfiniteStock = createExample(TestedComponent, {
+  product: {
+    product_id: '20102-ASDAS-QWE',
+    description: 'description1',
+    description_i18n: {} as any,
+    image: '',
+    price: 'TESTKUDOS:10',
+    taxes: [],
+    total_lost: 10,
+    total_sold: 5,
+    total_stock: -1,
+    unit: 'bar',
+    address: {}
+  }
+});
diff --git a/packages/frontend/src/paths/admin/create/Create.stories.tsx 
b/packages/frontend/src/paths/instance/reserves/create/Create.stories.tsx
similarity index 64%
copy from packages/frontend/src/paths/admin/create/Create.stories.tsx
copy to packages/frontend/src/paths/instance/reserves/create/Create.stories.tsx
index d1d8f39..e138770 100644
--- a/packages/frontend/src/paths/admin/create/Create.stories.tsx
+++ b/packages/frontend/src/paths/instance/reserves/create/Create.stories.tsx
@@ -19,20 +19,24 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { h, VNode } from 'preact';
-import { CreatePage } from './CreatePage';
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CreatePage as TestedComponent } from './CreatePage';
 
 
 export default {
-  title: 'Instances/Create',
-  component: CreatePage,
+  title: 'Pages/Reserve/Create',
+  component: TestedComponent,
   argTypes: {
     onCreate: { action: 'onCreate' },
-    goBack: { action: 'goBack' },
-  }
+    onBack: { action: 'onBack' },
+  },
 };
 
-export const Example = (a: any): VNode => <CreatePage {...a} />;
-Example.args = {
-  isLoading: false
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
 }
+
+export const Example = createExample(TestedComponent, {
+});
diff --git 
a/packages/frontend/src/paths/instance/reserves/details/Details.stories.tsx 
b/packages/frontend/src/paths/instance/reserves/details/Details.stories.tsx
new file mode 100644
index 0000000..c62442a
--- /dev/null
+++ b/packages/frontend/src/paths/instance/reserves/details/Details.stories.tsx
@@ -0,0 +1,102 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { h, VNode, FunctionalComponent } from 'preact';
+import { DetailPage as TestedComponent } from './DetailPage';
+
+
+export default {
+  title: 'Pages/Reserve/Detail',
+  component: TestedComponent,
+  argTypes: {
+    onUpdate: { action: 'onUpdate' },
+    onBack: { action: 'onBack' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const Funded = createExample(TestedComponent, {
+  id:'THISISTHERESERVEID',
+  selected: {
+    active: true,
+    committed_amount: 'TESTKUDOS:10',
+    creation_time: {
+      t_ms: new Date().getTime(),
+    },
+    exchange_initial_amount: 'TESTKUDOS:10',
+    expiration_time: {
+      t_ms: new Date().getTime()
+    },
+    merchant_initial_amount: 'TESTKUDOS:10',
+    pickup_amount: 'TESTKUDOS:10',
+    payto_uri: 'payto://x-taler-bank/bank.taler:8080/account',
+    exchange_url: 'http://exchange.taler/',
+  }
+});
+
+export const NotYetFunded = createExample(TestedComponent, {
+  id:'THISISTHERESERVEID',
+  selected: {
+    active: true,
+    committed_amount: 'TESTKUDOS:10',
+    creation_time: {
+      t_ms: new Date().getTime(),
+    },
+    exchange_initial_amount: 'TESTKUDOS:0',
+    expiration_time: {
+      t_ms: new Date().getTime()
+    },
+    merchant_initial_amount: 'TESTKUDOS:10',
+    pickup_amount: 'TESTKUDOS:10',
+    payto_uri: 'payto://x-taler-bank/bank.taler:8080/account',
+    exchange_url: 'http://exchange.taler/',
+  }
+});
+
+export const FundedWithEmptyTips = createExample(TestedComponent, {
+  id:'THISISTHERESERVEID',
+  selected: {
+    active: true,
+    committed_amount: 'TESTKUDOS:10',
+    creation_time: {
+      t_ms: new Date().getTime(),
+    },
+    exchange_initial_amount: 'TESTKUDOS:10',
+    expiration_time: {
+      t_ms: new Date().getTime()
+    },
+    merchant_initial_amount: 'TESTKUDOS:10',
+    pickup_amount: 'TESTKUDOS:10',
+    payto_uri: 'payto://x-taler-bank/bank.taler:8080/account',
+    exchange_url: 'http://exchange.taler/',
+    tips:[{
+      reason: 'asdasd',
+      tip_id: '123',
+      total_amount: 'TESTKUDOS:1'
+    }]
+  }
+});
+
diff --git 
a/packages/frontend/src/paths/instance/reserves/list/List.stories.tsx 
b/packages/frontend/src/paths/instance/reserves/list/List.stories.tsx
new file mode 100644
index 0000000..b941066
--- /dev/null
+++ b/packages/frontend/src/paths/instance/reserves/list/List.stories.tsx
@@ -0,0 +1,97 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CardTable as TestedComponent } from './Table';
+
+
+export default {
+  title: 'Pages/Reserve/List',
+  component: TestedComponent,
+  argTypes: {
+    onCreate: { action: 'onCreate' },
+    onDelete: { action: 'onDelete' },
+    onNewTip: { action: 'onNewTip' },
+    onSelect: { action: 'onSelect' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const AllFunded = createExample(TestedComponent, {
+  instances: [{
+    id: 'reseverId',
+    active: true,
+    committed_amount: 'TESTKUDOS:10',
+    creation_time: {
+      t_ms: new Date().getTime(),
+    },
+    exchange_initial_amount: 'TESTKUDOS:10',
+    expiration_time: {
+      t_ms: new Date().getTime()
+    },
+    merchant_initial_amount: 'TESTKUDOS:10',
+    pickup_amount: 'TESTKUDOS:10',
+    reserve_pub: 'WEQWDASDQWEASDADASDQWEQWEASDAS'
+  },{
+    id: 'reseverId2',
+    active: true,
+    committed_amount: 'TESTKUDOS:13',
+    creation_time: {
+      t_ms: new Date().getTime(),
+    },
+    exchange_initial_amount: 'TESTKUDOS:10',
+    expiration_time: {
+      t_ms: new Date().getTime()
+    },
+    merchant_initial_amount: 'TESTKUDOS:10',
+    pickup_amount: 'TESTKUDOS:10',
+    reserve_pub: 'WEQWDASDQWEASDADASDQWEQWEASDAS'
+  }]
+});
+
+export const Empty = createExample(TestedComponent, {
+  instances: []
+});
+
+
+
+export const OneNotYetFunded = createExample(TestedComponent, {
+  instances: [{
+    id: 'reseverId',
+    active: true,
+    committed_amount: 'TESTKUDOS:0',
+    creation_time: {
+      t_ms: new Date().getTime(),
+    },
+    exchange_initial_amount: 'TESTKUDOS:0',
+    expiration_time: {
+      t_ms: new Date().getTime()
+    },
+    merchant_initial_amount: 'TESTKUDOS:10',
+    pickup_amount: 'TESTKUDOS:10',
+    reserve_pub: 'WEQWDASDQWEASDADASDQWEQWEASDAS'
+  }]
+});
diff --git a/packages/frontend/src/paths/instance/reserves/list/Table.tsx 
b/packages/frontend/src/paths/instance/reserves/list/Table.tsx
index 6bca85b..243910d 100644
--- a/packages/frontend/src/paths/instance/reserves/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/reserves/list/Table.tsx
@@ -32,7 +32,6 @@ interface Props {
   onSelect: (id: Entity) => void;
   onDelete: (id: Entity) => void;
   onCreate: () => void;
-  selected?: boolean;
 }
 
 export function CardTable({ instances, onCreate, onSelect, onNewTip, onDelete 
}: Props): VNode {
diff --git a/packages/frontend/src/paths/admin/create/Create.stories.tsx 
b/packages/frontend/src/paths/instance/transfers/create/Create.stories.tsx
similarity index 57%
copy from packages/frontend/src/paths/admin/create/Create.stories.tsx
copy to packages/frontend/src/paths/instance/transfers/create/Create.stories.tsx
index d1d8f39..535cb1e 100644
--- a/packages/frontend/src/paths/admin/create/Create.stories.tsx
+++ b/packages/frontend/src/paths/instance/transfers/create/Create.stories.tsx
@@ -19,20 +19,25 @@
 * @author Sebastian Javier Marchano (sebasjm)
 */
 
-import { h, VNode } from 'preact';
-import { CreatePage } from './CreatePage';
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CreatePage as TestedComponent } from './CreatePage';
 
 
 export default {
-  title: 'Instances/Create',
-  component: CreatePage,
+  title: 'Pages/Transfer/Create',
+  component: TestedComponent,
   argTypes: {
-    onCreate: { action: 'onCreate' },
-    goBack: { action: 'goBack' },
-  }
+    onUpdate: { action: 'onUpdate' },
+    onBack: { action: 'onBack' },
+  },
 };
 
-export const Example = (a: any): VNode => <CreatePage {...a} />;
-Example.args = {
-  isLoading: false
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
 }
+
+export const Example = createExample(TestedComponent, {
+  accounts: ['payto://x-taler-bank/account1','payto://x-taler-bank/account2']
+});
diff --git 
a/packages/frontend/src/paths/instance/transfers/create/CreatePage.tsx 
b/packages/frontend/src/paths/instance/transfers/create/CreatePage.tsx
index 861268f..f6e3b4f 100644
--- a/packages/frontend/src/paths/instance/transfers/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/instance/transfers/create/CreatePage.tsx
@@ -39,19 +39,17 @@ type Entity = MerchantBackend.Transfers.TransferInformation
 interface Props {
   onCreate: (d: Entity) => Promise<void>;
   onBack?: () => void;
+  accounts: string[],
 }
 
-export function CreatePage({ onCreate, onBack }: Props): VNode {
+export function CreatePage({ accounts, onCreate, onBack }: Props): VNode {
   const i18n = useTranslator()
   const { currency } = useConfigContext()
 
-  const instance = useInstanceDetails()
-  const accounts = !instance.ok ? [] : instance.data.accounts.map(a => 
a.payto_uri)
-
   const [state, setState] = useState<Partial<Entity>>({
     wtid: '',
     // payto_uri: ,
-    exchange_url: 'http://exchange.taler:8081/',
+    // exchange_url: 'http://exchange.taler:8081/',
     credit_amount: ``,
   });
 
diff --git a/packages/frontend/src/paths/instance/transfers/create/index.tsx 
b/packages/frontend/src/paths/instance/transfers/create/index.tsx
index a9e56a5..d95929a 100644
--- a/packages/frontend/src/paths/instance/transfers/create/index.tsx
+++ b/packages/frontend/src/paths/instance/transfers/create/index.tsx
@@ -23,6 +23,7 @@ import { Fragment, h, VNode } from 'preact';
 import { useState } from 'preact/hooks';
 import { NotificationCard } from '../../../../components/menu';
 import { MerchantBackend } from '../../../../declaration';
+import { useInstanceDetails } from '../../../../hooks/instance';
 import { useTransferAPI } from '../../../../hooks/transfer';
 import { useTranslator } from '../../../../i18n';
 import { Notification } from '../../../../utils/types';
@@ -38,11 +39,14 @@ export default function CreateTransfer({onConfirm, 
onBack}:Props): VNode {
   const { informTransfer } = useTransferAPI()
   const [notif, setNotif] = useState<Notification | undefined>(undefined)
   const i18n = useTranslator()
+  const instance = useInstanceDetails()
+  const accounts = !instance.ok ? [] : instance.data.accounts.map(a => 
a.payto_uri)
 
   return <>
     <NotificationCard notification={notif} />
     <CreatePage
       onBack={onBack}
+      accounts={accounts}
       onCreate={(request: MerchantBackend.Transfers.TransferInformation) => {
         return informTransfer(request).then(() => onConfirm()).catch((error) 
=> {
           setNotif({
diff --git 
a/packages/frontend/src/paths/instance/transfers/list/List.stories.tsx 
b/packages/frontend/src/paths/instance/transfers/list/List.stories.tsx
new file mode 100644
index 0000000..030ebe2
--- /dev/null
+++ b/packages/frontend/src/paths/instance/transfers/list/List.stories.tsx
@@ -0,0 +1,84 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { h, VNode, FunctionalComponent } from 'preact';
+import { CardTable as TestedComponent } from './Table';
+
+
+export default {
+  title: 'Pages/Transfer/List',
+  component: TestedComponent,
+  argTypes: {
+    onCreate: { action: 'onCreate' },
+    onDelete: { action: 'onDelete' },
+    onNewTip: { action: 'onNewTip' },
+    onSelect: { action: 'onSelect' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const Example = createExample(TestedComponent, {
+  transfers: [{
+    exchange_url: 'http://exchange.url/',
+    id: 'transferid',
+    credit_amount: 'TESTKUDOS:10',
+    payto_uri: 'payto//x-taler-bank/bank:8080/account',
+    transfer_serial_id: 123123123,
+    wtid: '!@KJELQKWEJ!L@K#!J@',
+    confirmed: true,
+    execution_time: {
+      t_ms: new Date().getTime()
+    },
+    verified: false,
+  },{
+    exchange_url: 'http://exchange.url/',
+    id: 'transferid',
+    credit_amount: 'TESTKUDOS:10',
+    payto_uri: 'payto//x-taler-bank/bank:8080/account',
+    transfer_serial_id: 123123123,
+    wtid: '!@KJELQKWEJ!L@K#!J@',
+    confirmed: true,
+    execution_time: {
+      t_ms: new Date().getTime()
+    },
+    verified: false,
+  },{
+    exchange_url: 'http://exchange.url/',
+    id: 'transferid',
+    credit_amount: 'TESTKUDOS:10',
+    payto_uri: 'payto//x-taler-bank/bank:8080/account',
+    transfer_serial_id: 123123123,
+    wtid: '!@KJELQKWEJ!L@K#!J@',
+    confirmed: true,
+    execution_time: {
+      t_ms: new Date().getTime()
+    },
+    verified: false,
+  }]
+});
+export const Empty = createExample(TestedComponent, {
+  transfers: []
+});
diff --git a/packages/frontend/src/paths/instance/transfers/list/Table.tsx 
b/packages/frontend/src/paths/instance/transfers/list/Table.tsx
index 3794b01..128e71f 100644
--- a/packages/frontend/src/paths/instance/transfers/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/transfers/list/Table.tsx
@@ -29,49 +29,25 @@ import { Actions, buildActions } from 
"../../../../utils/table"
 type Entity = MerchantBackend.Transfers.TransferDetails & WithId
 
 interface Props {
-  instances: Entity[];
+  transfers: Entity[];
   onUpdate: (id: string) => void;
   onDelete: (id: Entity) => void;
   onCreate: () => void;
   accounts: string[];
-  selected?: boolean;
   onLoadMoreBefore?: () => void;
   hasMoreBefore?: boolean;
   hasMoreAfter?: boolean;
   onLoadMoreAfter?: () => void;
 }
 
-export function CardTable({ instances, onCreate, onUpdate, onDelete, selected, 
onLoadMoreAfter, onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: Props): VNode 
{
-  const [actionQueue, actionQueueHandler] = useState<Actions<Entity>[]>([]);
+export function CardTable({ transfers, onCreate, onUpdate, onDelete, 
onLoadMoreAfter, onLoadMoreBefore, hasMoreAfter, hasMoreBefore }: Props): VNode 
{
   const [rowSelection, rowSelectionHandler] = useState<string[]>([])
 
-  useEffect(() => {
-    if (actionQueue.length > 0 && !selected && actionQueue[0].type == 
'DELETE') {
-      onDelete(actionQueue[0].element)
-      actionQueueHandler(actionQueue.slice(1))
-    }
-  }, [actionQueue, selected, onDelete])
-
-  useEffect(() => {
-    if (actionQueue.length > 0 && !selected && actionQueue[0].type == 
'UPDATE') {
-      onUpdate(actionQueue[0].element.id)
-      actionQueueHandler(actionQueue.slice(1))
-    }
-  }, [actionQueue, selected, onUpdate])
-
   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-bank" 
/></span><Translate>Transfers</Translate></p>
-
-      <div class="card-header-icon" aria-label="more options">
-
-        <button class={rowSelection.length > 0 ? "button is-danger" : 
"is-hidden"}
-          type="button" onClick={(): void => 
actionQueueHandler(buildActions(instances, rowSelection, 'DELETE'))} >
-          <Translate>Delete</Translate>
-        </button>
-      </div>
       <div class="card-header-icon" aria-label="more options">
         <span class="has-tooltip-left" data-tooltip={i18n`add new transfer`}>
           <button class="button is-info" type="button" onClick={onCreate}>
@@ -84,8 +60,8 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected, o
     <div class="card-content">
       <div class="b-table has-pagination">
         <div class="table-wrapper has-mobile-cards">
-          {instances.length > 0 ?
-            <Table instances={instances} onUpdate={onUpdate}
+          {transfers.length > 0 ?
+            <Table instances={transfers} onUpdate={onUpdate}
               onDelete={onDelete} rowSelection={rowSelection}
               rowSelectionHandler={rowSelectionHandler}
               onLoadMoreAfter={onLoadMoreAfter} 
onLoadMoreBefore={onLoadMoreBefore}
diff --git a/packages/frontend/src/paths/instance/transfers/list/index.tsx 
b/packages/frontend/src/paths/instance/transfers/list/index.tsx
index 5effb5f..7ad5479 100644
--- a/packages/frontend/src/paths/instance/transfers/list/index.tsx
+++ b/packages/frontend/src/paths/instance/transfers/list/index.tsx
@@ -126,7 +126,7 @@ interface ViewProps extends Props {
 }
 
 function View({ transfers, onCreate, accounts, onLoadMoreBefore, 
onLoadMoreAfter }: ViewProps) {
-  return <CardTable instances={transfers.map(o => ({ ...o, id: 
String(o.transfer_serial_id) }))}
+  return <CardTable transfers={transfers.map(o => ({ ...o, id: 
String(o.transfer_serial_id) }))}
     accounts={accounts}
     onCreate={onCreate}
     onDelete={() => null}
diff --git a/packages/frontend/src/paths/instance/update/Update.stories.tsx 
b/packages/frontend/src/paths/instance/update/Update.stories.tsx
new file mode 100644
index 0000000..d0c18dd
--- /dev/null
+++ b/packages/frontend/src/paths/instance/update/Update.stories.tsx
@@ -0,0 +1,59 @@
+/*
+ This file is part of GNU Taler
+ (C) 2021 Taler Systems S.A.
+
+ GNU Taler is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+/**
+*
+* @author Sebastian Javier Marchano (sebasjm)
+*/
+
+import { h, VNode, FunctionalComponent } from 'preact';
+import { UpdatePage as TestedComponent } from './UpdatePage';
+
+
+export default {
+  title: 'Pages/Instance/Update',
+  component: TestedComponent,
+  argTypes: {
+    onUpdate: { action: 'onUpdate' },
+    onBack: { action: 'onBack' },
+  },
+};
+
+function createExample<Props>(Component: FunctionalComponent<Props>, props: 
Partial<Props>) {
+  const r = (args: any) => <Component {...args} />
+  r.args = props
+  return r
+}
+
+export const Example = createExample(TestedComponent, {
+  selected: {
+    accounts: [],
+    name: 'name',
+    auth: {method:'external'},
+    address: {},
+    jurisdiction: {},
+    default_max_deposit_fee: 'TESTKUDOS:2',
+    default_max_wire_fee: 'TESTKUDOS:1',
+    default_pay_delay: {
+      d_ms: 1000000,
+    },
+    default_wire_fee_amortization: 1,
+    default_wire_transfer_delay: {
+      d_ms: 100000,
+    },
+    merchant_pub: 'ASDWQEKASJDKSADJ'
+  }
+});

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