gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] branch master updated: fix product form on n


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated: fix product form on new order
Date: Tue, 15 Jun 2021 19:33:48 +0200

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

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

The following commit(s) were added to refs/heads/master by this push:
     new d674e28  fix product form on new order
d674e28 is described below

commit d674e28bcd25e8e24697d2b871c1d8218686ec65
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue Jun 15 14:30:43 2021 -0300

    fix product form on new order
---
 CHANGELOG.md                                       |  7 +++
 .../frontend/src/components/form/InputImage.tsx    |  7 ++-
 packages/frontend/src/context/listener.ts          | 35 +++++++++++
 packages/frontend/src/hooks/index.ts               | 40 -------------
 packages/frontend/src/hooks/listener.ts            | 68 ++++++++++++++++++++++
 packages/frontend/src/hooks/product.ts             |  8 ++-
 .../orders/create/NonInventoryProductForm.tsx      | 66 ++++++++++++---------
 .../paths/instance/products/create/CreatePage.tsx  |  2 +-
 .../paths/instance/products/update/UpdatePage.tsx  |  4 +-
 packages/frontend/src/utils/constants.ts           |  4 +-
 10 files changed, 166 insertions(+), 75 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 852efd5..6b78731 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -42,6 +42,13 @@ wallet
  - show transaction with error state
  - add developer mode in settings, this will show debug tab
  - add transaction details, and delete button
+ onDetails
+ - add examples for error and pending
+ - retry button when there is an error
+ - starting the backup UI
+
+
+
 
 ## [Unreleased]
 
diff --git a/packages/frontend/src/components/form/InputImage.tsx 
b/packages/frontend/src/components/form/InputImage.tsx
index 8f10c47..2f598b3 100644
--- a/packages/frontend/src/components/form/InputImage.tsx
+++ b/packages/frontend/src/components/form/InputImage.tsx
@@ -22,6 +22,7 @@ import { ComponentChildren, h } from "preact";
 import { useRef, useState } from "preact/hooks";
 import emptyImage from "../../assets/empty.png";
 import { Translate } from "../../i18n";
+import { MAX_IMAGE_SIZE as MAX_IMAGE_UPLOAD_SIZE } from 
"../../utils/constants";
 import { InputProps, useField } from "./useField";
 
 export interface Props<T> extends InputProps<T> {
@@ -59,17 +60,17 @@ export function InputImage<T>({ name, readonly, 
placeholder, tooltip, label, hel
               if (!f || f.length != 1) {
                 return onChange(emptyImage)
               }
-              if (f[0].size > 1024 * 1024) {
+              if (f[0].size > MAX_IMAGE_UPLOAD_SIZE) {
                 setSizeError(true)
                 return onChange(emptyImage)
               }
               setSizeError(false)
-              f[0].arrayBuffer().then(b => {
+              return f[0].arrayBuffer().then(b => {
                 const b64 = btoa(
                   new Uint8Array(b)
                     .reduce((data, byte) => data + String.fromCharCode(byte), 
'')
                 )
-                onChange(`data:${f[0].type};base64,${b64}` as any)
+                return onChange(`data:${f[0].type};base64,${b64}` as any)
               })
             }} />
           {help}
diff --git a/packages/frontend/src/context/listener.ts 
b/packages/frontend/src/context/listener.ts
new file mode 100644
index 0000000..659db0a
--- /dev/null
+++ b/packages/frontend/src/context/listener.ts
@@ -0,0 +1,35 @@
+/*
+ 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 { createContext } from 'preact'
+import { useContext } from 'preact/hooks'
+
+interface Type {
+  id: string;
+  token?: string;
+  admin?: boolean;
+  changeToken: (t?:string) => void;
+}
+
+const Context = createContext<Type>({} as any)
+
+export const ListenerContextProvider = Context.Provider
+export const useListenerContext = (): Type => useContext(Context);
diff --git a/packages/frontend/src/hooks/index.ts 
b/packages/frontend/src/hooks/index.ts
index 3a16de7..19d672a 100644
--- a/packages/frontend/src/hooks/index.ts
+++ b/packages/frontend/src/hooks/index.ts
@@ -107,44 +107,4 @@ export function useNotNullLocalStorage(key: string, 
initialValue: string): [stri
   return [storedValue, setValue];
 }
 
-/**
- * returns subscriber and activator
- * subscriber will receive a method (listener) that will be call when the 
activator runs.
- * the result of calling the listener will be sent to @action
- * 
- * @param action from <T> to <R>
- * @returns activator and subscriber, undefined activator means that there is 
not subscriber
- */
-export function useListener<T, R = any>(action: (r: T) => Promise<R>): 
[undefined | (() => Promise<R>), (listener?: () => T) => void] {
-  type RunnerHandler = { toBeRan?: () => Promise<R> }
-  const [state, setState] = useState<RunnerHandler>({})
-
-  /**
-   * subscriber will receive a method that will be call when the activator runs
-   * 
-   * @param listener function to be run when the activator runs
-   */
-  const subscriber = (listener?: () => T) => {
-    if (listener) {
-      setState({
-        toBeRan: () => {
-          const whatWeGetFromTheListener = listener()
-          return action(whatWeGetFromTheListener)
-        }
-      })
-    }
-  }
-
-  /**
-   * activator will call runner if there is someone subscribed
-   */
-  const activator = state.toBeRan ? async () => {
-    if (state.toBeRan) {
-      return state.toBeRan()
-    }
-    return Promise.reject()
-  } : undefined
-
-  return [activator, subscriber]
-}
 
diff --git a/packages/frontend/src/hooks/listener.ts 
b/packages/frontend/src/hooks/listener.ts
new file mode 100644
index 0000000..231ed6c
--- /dev/null
+++ b/packages/frontend/src/hooks/listener.ts
@@ -0,0 +1,68 @@
+/*
+ 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 { useState } from "preact/hooks";
+
+/**
+ * returns subscriber and activator
+ * subscriber will receive a method (listener) that will be call when the 
activator runs.
+ * the result of calling the listener will be sent to @action
+ *
+ * @param action from <T> to <R>
+ * @returns activator and subscriber, undefined activator means that there is 
not subscriber
+ */
+
+export function useListener<T, R = any>(action: (r: T) => Promise<R>): 
[undefined | (() => Promise<R>), (listener?: () => T) => void] {
+  type RunnerHandler = { toBeRan?: () => Promise<R>; };
+  const [state, setState] = useState<RunnerHandler>({});
+
+  /**
+   * subscriber will receive a method that will be call when the activator runs
+   *
+   * @param listener function to be run when the activator runs
+   */
+  const subscriber = (listener?: () => T) => {
+    if (listener) {
+      setState({
+        toBeRan: () => {
+          const whatWeGetFromTheListener = listener();
+          return action(whatWeGetFromTheListener);
+        }
+      });
+    } else {
+      setState({
+        toBeRan: undefined
+      })
+    }
+  };
+
+  /**
+   * activator will call runner if there is someone subscribed
+   */
+  const activator = state.toBeRan ? async () => {
+    if (state.toBeRan) {
+      return state.toBeRan();
+    }
+    return Promise.reject();
+  } : undefined;
+
+  return [activator, subscriber];
+}
diff --git a/packages/frontend/src/hooks/product.ts 
b/packages/frontend/src/hooks/product.ts
index a8b33ba..6bc131d 100644
--- a/packages/frontend/src/hooks/product.ts
+++ b/packages/frontend/src/hooks/product.ts
@@ -134,7 +134,13 @@ export function useInstanceProducts(): 
HttpResponse<(MerchantBackend.Products.Pr
     url: `${baseUrl}/instances/${id}`, token: instanceToken
   };
 
-  const { data: list, error: listError, isValidating: listLoading } = 
useSWR<HttpResponseOk<MerchantBackend.Products.InventorySummaryResponse>, 
HttpError>([`/private/products`, token, url], fetcher);
+  const { data: list, error: listError, isValidating: listLoading } = 
useSWR<HttpResponseOk<MerchantBackend.Products.InventorySummaryResponse>, 
HttpError>([`/private/products`, token, url], fetcher, {
+    refreshInterval: 0,
+    refreshWhenHidden: false,
+    revalidateOnFocus: false,
+    revalidateOnReconnect: false,
+    refreshWhenOffline: false,
+  });
 
   const { data: products, error: productError, setSize, size } = 
useSWRInfinite<HttpResponseOk<MerchantBackend.Products.ProductDetail>, 
HttpError>((pageIndex: number) => {
     if (!list?.data || !list.data.products.length || listError || listLoading) 
return null
diff --git 
a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
 
b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
index 31cf33b..47764ec 100644
--- 
a/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
+++ 
b/packages/frontend/src/paths/instance/orders/create/NonInventoryProductForm.tsx
@@ -23,7 +23,8 @@ import { InputNumber } from 
"../../../../components/form/InputNumber";
 import { InputTaxes } from "../../../../components/form/InputTaxes";
 import { ConfirmModal } from "../../../../components/modal";
 import { MerchantBackend } from "../../../../declaration";
-import { useListener } from "../../../../hooks";
+import { useListener } from "../../../../hooks/listener";
+
 import {
   NonInventoryProductSchema as schema
 } from '../../../../schemas';
@@ -57,24 +58,41 @@ export function NonInventoryProductFrom({ productToEdit, 
onAddProduct }: Props):
         unit: result.unit || ''
       })
     }
-    return Promise.reject()
+    return Promise.resolve()
   })
 
   const i18n = useTranslator()
+
+  console.log('submit form', submitForm)
+
   return <Fragment>
     <div class="buttons">
       <button class="button is-success" onClick={() => 
setShowCreateProduct(true)} ><Translate>add new product</Translate></button>
     </div>
-    {showCreateProduct && <ConfirmModal active
-      description={i18n`Complete information of the product`}
-      onCancel={() => setShowCreateProduct(false)} onConfirm={submitForm}>
-      <ProductForm initial={productToEdit} onSubscribe={addFormSubmitter} />
-    </ConfirmModal>}
+    {showCreateProduct && <div class="modal is-active">
+      <div class="modal-background " onClick={() => 
setShowCreateProduct(false)} />
+      <div class="modal-card">
+        <header class="modal-card-head">
+          <p class="modal-card-title">{i18n`Complete information of the 
product`}</p>
+          <button class="delete " aria-label="close" onClick={() => 
setShowCreateProduct(false)} />
+        </header>
+        <section class="modal-card-body">
+          <ProductForm initial={productToEdit} onSubscribe={addFormSubmitter} 
/>
+        </section>
+        <footer class="modal-card-foot">
+          <div class="buttons is-right" style={{ width: '100%' }}>
+            <button class="button " onClick={() => 
setShowCreateProduct(false)} ><Translate>Cancel</Translate></button>
+            <button class="button is-info " disabled={!submitForm} 
onClick={submitForm} ><Translate>Confirm</Translate></button>
+          </div>
+        </footer>
+      </div>
+      <button class="modal-close is-large " aria-label="close" onClick={() => 
setShowCreateProduct(false)} />
+    </div>}
   </Fragment>
 }
 
 interface ProductProps {
-  onSubscribe: (c: () => Entity | undefined) => void;
+  onSubscribe: (c?: () => Entity | undefined) => void;
   initial?: Partial<Entity>;
 }
 
@@ -92,30 +110,24 @@ export function ProductForm({ onSubscribe, initial }: 
ProductProps) {
     taxes: [],
     ...initial,
   })
-  const [errors, setErrors] = useState<FormErrors<NonInventoryProduct>>({})
+  let errors: FormErrors<Entity> = {}
+  try {
+    schema.validateSync(value, { abortEarly: false })
+  } catch (err) {
+    const yupErrors = err.inner as yup.ValidationError[]
+    errors = yupErrors.reduce((prev, cur) => !cur.path ? prev : ({ ...prev, 
[cur.path]: cur.message }), {})
+  }
 
   const submit = useCallback((): Entity | undefined => {
-    try {
-      const validated = schema.validateSync(value, { abortEarly: false })
-      const result: MerchantBackend.Product = {
-        description: validated.description,
-        image: validated.image,
-        price: validated.price,
-        quantity: validated.quantity,
-        taxes: validated.taxes,
-        unit: validated.unit,
-      }
-      return result
-    } catch (err) {
-      const errors = err.inner as yup.ValidationError[]
-      const pathMessages = errors.reduce((prev, cur) => !cur.path ? prev : ({ 
...prev, [cur.path]: cur.message }), {})
-      setErrors(pathMessages)
-    }
+    return value as MerchantBackend.Product
   }, [value])
 
+  const hasErrors = Object.keys(errors).some(k => (errors as any)[k] !== 
undefined)
+
   useEffect(() => {
-    onSubscribe(submit)
-  }, [submit])
+    console.log('has errors', hasErrors)
+    onSubscribe(hasErrors ? undefined : submit)
+  }, [submit, hasErrors])
 
   const i18n = useTranslator()
 
diff --git 
a/packages/frontend/src/paths/instance/products/create/CreatePage.tsx 
b/packages/frontend/src/paths/instance/products/create/CreatePage.tsx
index 2498d6a..0f2411b 100644
--- a/packages/frontend/src/paths/instance/products/create/CreatePage.tsx
+++ b/packages/frontend/src/paths/instance/products/create/CreatePage.tsx
@@ -23,7 +23,7 @@ import { h, VNode } from "preact";
 import { AsyncButton } from "../../../../components/exception/AsyncButton";
 import { ProductForm } from "../../../../components/product/ProductForm";
 import { MerchantBackend } from "../../../../declaration";
-import { useListener } from "../../../../hooks";
+import { useListener } from "../../../../hooks/listener";
 import { Translate, useTranslator } from "../../../../i18n";
 
 type Entity = MerchantBackend.Products.ProductAddDetail & { product_id: string}
diff --git 
a/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx 
b/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx
index 0c665be..32d67c0 100644
--- a/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx
+++ b/packages/frontend/src/paths/instance/products/update/UpdatePage.tsx
@@ -23,7 +23,7 @@ import { h, VNode } from "preact";
 import { AsyncButton } from "../../../../components/exception/AsyncButton";
 import { ProductForm } from "../../../../components/product/ProductForm";
 import { MerchantBackend, WithId } from "../../../../declaration";
-import { useListener } from "../../../../hooks";
+import { useListener } from "../../../../hooks/listener";
 import { Translate, useTranslator } from "../../../../i18n";
 
 type Entity = MerchantBackend.Products.ProductDetail & { product_id: string }
@@ -41,7 +41,7 @@ export function UpdatePage({ product, onUpdate, onBack }: 
Props): VNode {
   })
 
   const i18n = useTranslator()
-  
+
   return <div>
     <section class="section">
       <section class="hero is-hero-bar">
diff --git a/packages/frontend/src/utils/constants.ts 
b/packages/frontend/src/utils/constants.ts
index 1f654c0..403adb9 100644
--- a/packages/frontend/src/utils/constants.ts
+++ b/packages/frontend/src/utils/constants.ts
@@ -40,4 +40,6 @@ export const PAGE_SIZE = 20
 export const MAX_RESULT_SIZE = PAGE_SIZE * 2 - 1;
 
 // how much we will wait for all request, in seconds
-export const DEFAULT_REQUEST_TIMEOUT = 10;
\ No newline at end of file
+export const DEFAULT_REQUEST_TIMEOUT = 10;
+
+export const MAX_IMAGE_SIZE = 1024 * 1024;
\ No newline at end of file

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