gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] 01/02: storybook samples


From: gnunet
Subject: [taler-merchant-backoffice] 01/02: storybook samples
Date: Tue, 15 Jun 2021 05:04:47 +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 bfe7540cc735567939a6f29e9a055486deaf887f
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Mon Jun 14 23:59:54 2021 -0300

    storybook samples
---
 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 +-
 packages/frontend/src/context/fetch.ts             |  40 ++++++
 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   | 130 ++++++++++---------
 .../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    |  28 +----
 .../src/paths/instance/transfers/list/index.tsx    |   2 +-
 .../src/paths/instance/update/Update.stories.tsx   |  59 +++++++++
 36 files changed, 1181 insertions(+), 263 deletions(-)

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/fetch.ts 
b/packages/frontend/src/context/fetch.ts
new file mode 100644
index 0000000..52a4f9c
--- /dev/null
+++ b/packages/frontend/src/context/fetch.ts
@@ -0,0 +1,40 @@
+/*
+ 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, createContext, VNode, ComponentChildren } from 'preact'
+import { useContext } from 'preact/hooks'
+import useSWR, { trigger, useSWRInfinite, cache, mutate } from 'swr';
+
+interface Type {
+  useSWR: typeof useSWR,
+  useSWRInfinite: typeof useSWRInfinite,
+}
+
+const Context = createContext<Type>({} as any)
+
+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..3e689b0
--- /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/esm';
+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..b41bedf 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()
@@ -141,9 +151,6 @@ function ClaimedPage({ id, order }: { id: string; order: 
MerchantBackend.Orders.
                 <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>
@@ -196,31 +203,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 +324,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 +360,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 +456,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..751b14e 100644
--- a/packages/frontend/src/paths/instance/transfers/list/Table.tsx
+++ b/packages/frontend/src/paths/instance/transfers/list/Table.tsx
@@ -29,36 +29,20 @@ 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">
@@ -67,10 +51,6 @@ export function CardTable({ instances, onCreate, onUpdate, 
onDelete, selected, o
 
       <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`}>
@@ -84,8 +64,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]