gnunet-svn
[Top][All Lists]
Advanced

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

[taler-merchant-backoffice] 01/08: payto as array


From: gnunet
Subject: [taler-merchant-backoffice] 01/08: payto as array
Date: Thu, 18 Feb 2021 20:07:13 +0100

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

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

commit 929e8f389ea8eec3bb942c111f8e37efffba2d63
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Thu Feb 18 09:46:00 2021 -0300

    payto as array
---
 src/components/hooks/useLang.ts         |  2 +-
 src/components/hooks/useLocalStorage.ts | 26 +++++++-----
 src/components/navbar/index.tsx         |  5 ++-
 src/components/yup/YupField.tsx         | 72 ++++++++++++++++++++++++++++-----
 src/declaration.d.ts                    |  5 ++-
 src/i18n/index.ts                       |  2 +-
 src/routes/instances/CardTable.tsx      | 21 ++++++----
 src/schemas/index.ts                    | 22 +++++-----
 8 files changed, 108 insertions(+), 47 deletions(-)

diff --git a/src/components/hooks/useLang.ts b/src/components/hooks/useLang.ts
index c954495..52898e4 100644
--- a/src/components/hooks/useLang.ts
+++ b/src/components/hooks/useLang.ts
@@ -2,5 +2,5 @@ import { StateUpdater } from "preact/hooks";
 import { useNotNullLocalStorage } from "./useLocalStorage";
 
 export default function useLang(): [string, StateUpdater<string>] {
-  return useNotNullLocalStorage('lang-preference', navigator.language || 
(navigator as any).userLanguage )
+  return useNotNullLocalStorage('lang-preference', typeof window !== 
"undefined" ? navigator.language || (navigator as any).userLanguage : 'en' )
 }
diff --git a/src/components/hooks/useLocalStorage.ts 
b/src/components/hooks/useLocalStorage.ts
index 7c9fc4a..888ef78 100644
--- a/src/components/hooks/useLocalStorage.ts
+++ b/src/components/hooks/useLocalStorage.ts
@@ -2,16 +2,18 @@ import { StateUpdater, useState } from "preact/hooks";
 
 export function useLocalStorage(key: string, initialValue?: string): [string | 
undefined, StateUpdater<string | undefined>] {
   const [storedValue, setStoredValue] = useState<string | undefined>((): 
string | undefined => {
-    return window.localStorage.getItem(key) || initialValue;
+    return typeof window !== "undefined" ? window.localStorage.getItem(key) || 
initialValue : initialValue;
   });
 
   const setValue = (value?: string | ((val?: string) => string | undefined)) 
=> {
     const valueToStore = value instanceof Function ? value(storedValue) : 
value;
     setStoredValue(valueToStore);
-    if (!valueToStore) {
-      window.localStorage.removeItem(key)
-    } else {
-      window.localStorage.setItem(key, valueToStore);
+    if (typeof window !== "undefined") {
+      if (!valueToStore) {
+        window.localStorage.removeItem(key)
+      } else {
+        window.localStorage.setItem(key, valueToStore);
+      }
     }
   };
 
@@ -20,17 +22,19 @@ export function useLocalStorage(key: string, initialValue?: 
string): [string | u
 
 export function useNotNullLocalStorage(key: string, initialValue: string): 
[string, StateUpdater<string>] {
   const [storedValue, setStoredValue] = useState<string>((): string => {
-    return window.localStorage.getItem(key) || initialValue;
+    return typeof window !== "undefined" ? window.localStorage.getItem(key) || 
initialValue : initialValue;
   });
 
   const setValue = (value: string | ((val: string) => string)) => {
     const valueToStore = value instanceof Function ? value(storedValue) : 
value;
     setStoredValue(valueToStore);
-    if (!valueToStore) {
-      window.localStorage.removeItem(key)
-    } else {
-      window.localStorage.setItem(key, valueToStore);
-    }
+    if (typeof window !== "undefined") {
+      if (!valueToStore) {
+        window.localStorage.removeItem(key)
+      } else {
+        window.localStorage.setItem(key, valueToStore);
+      }
+      }
   };
 
   return [storedValue, setValue];
diff --git a/src/components/navbar/index.tsx b/src/components/navbar/index.tsx
index 4423617..91f4a92 100644
--- a/src/components/navbar/index.tsx
+++ b/src/components/navbar/index.tsx
@@ -2,7 +2,8 @@ import { h, VNode } from 'preact';
 import { useState } from 'preact/hooks';
 import LoginPage from '../auth/LoginPage';
 import i18n from '../../i18n'
-import logo from '../../assets/logo.jpeg'
+// TODO: Fix compilation problem
+// import * as logo from '../../assets/logo.jpeg';
 
 interface Props {
   lang: string;
@@ -14,7 +15,7 @@ export default function NavigationBar({ lang, setLang }: 
Props): VNode {
   return (<nav class="navbar is-fixed-top" role="navigation" aria-label="main 
navigation">
     <div class="navbar-brand">
       <a class="navbar-item" href="https://taler.net";>
-        <img src={logo} style={{height: 50, maxHeight: 50}} />
+        <img src="https://taler.net/static/images/logo-2020.jpg"; 
style={{height: 50, maxHeight: 50}} />
       </a>
 
       <a role="button" class="navbar-burger" aria-label="menu" 
aria-expanded="false" data-target="navbarBasicExample">
diff --git a/src/components/yup/YupField.tsx b/src/components/yup/YupField.tsx
index 9549539..2344db0 100644
--- a/src/components/yup/YupField.tsx
+++ b/src/components/yup/YupField.tsx
@@ -1,7 +1,6 @@
 import { h, VNode } from "preact";
-import { Localizer, Text, useText } from "preact-i18n";
+import { Text, useText } from "preact-i18n";
 import { useState } from "preact/hooks";
-import { KeyValue } from "../../declaration";
 import { useBackendConfig } from "../hooks/backend";
 import useBackend from "../hooks/useBackend";
 
@@ -31,15 +30,17 @@ export default function YupField(name: string, field: 
string, errors: any, objec
     onChange: updateField(field)
   }
   const [backend] = useBackend()
-  const {data} = useBackendConfig()
-  
+  const { data } = useBackendConfig()
+  const currency = data?.currency || ''
+
   switch (info.meta?.type) {
     case 'group': return <YupObjectInput name={name}
       info={info} errors={errors}
       value={object && object[field]}
       onChange={(updater: any): void => valueHandler((prev: any) => ({ 
...prev, [field]: updater(prev[field]) }))}
     />
-    case 'amount': return <YupInputWithAddon {...values} addon={data?.currency 
|| ''} />;
+    case 'array': return <YupInputArray {...values} />;
+    case 'amount': return <YupInputWithAddon {...values} addon={currency} 
onChange={(v: string): void => values.onChange(`${currency}:${v}`)} 
value={values.value?.split(':')[1]} />;
     case 'url': return <YupInputWithAddon {...values} 
addon={`${backend.url}/private/instances/`} />;
     case 'secured': return <YupInputSecured {...values} />;
     case 'duration': return <YupInput {...values} value={object && 
object[field]?.d_ms} />;
@@ -57,9 +58,9 @@ function YupObjectInput({ name, info, value, errors, onChange 
}: Props2): VNode
       </p>
       <button class="card-header-icon" aria-label="more options" onClick={(): 
void => setActive(!active)}>
         <span class="icon">
-          { active ? 
+          {active ?
             <i class="mdi mdi-arrow-up" /> :
-            <i class="mdi mdi-arrow-down" /> }
+            <i class="mdi mdi-arrow-down" />}
         </span>
       </button>
     </header>
@@ -90,7 +91,7 @@ function YupInput({ name, readonly, value, errors, onChange 
}: Props): VNode {
       <div class="field">
         <p class="control">
           <input class={errors[name] ? "input is-danger" : "input"} type="text"
-            placeholder={dict['placeholder']} readonly={readonly}
+            placeholder={dict.placeholder} readonly={readonly}
             name={name} value={value}
             onChange={(e): void => onChange(e.currentTarget.value)} />
           <Text id={`fields.instance.${name}.help`} />
@@ -103,6 +104,57 @@ function YupInput({ name, readonly, value, errors, 
onChange }: Props): VNode {
   </div>
 }
 
+function YupInputArray({ name, readonly, value, errors, onChange }: Props): 
VNode {
+  const dict = useText({
+    placeholder: `fields.instance.${name}.placeholder`,
+    tooltip: `fields.instance.${name}.tooltip`,
+  })
+  const array = value as unknown as string[] || []
+  const [currentValue, setCurrentValue] = useState('')
+
+  return <div class="field is-horizontal">
+    <div class="field-label is-normal">
+      <label class="label">
+        <Text id={`fields.instance.${name}.label`} />
+        {dict.tooltip && <span class="icon" data-tooltip={dict.tooltip}>
+          <i class="mdi mdi-information" />
+        </span>}
+      </label>
+    </div>
+    <div class="field-body">
+      <div class="field">
+        <div class="field has-addons">
+          <p class="control">
+            <button class="button is-info" onClick={(): void => {
+              onChange([currentValue, ...array])
+              setCurrentValue('')
+            }} >add</button>
+          </p>
+          <p class="control">
+            <input class={errors[name] ? "input is-danger" : "input"} 
type="text"
+              placeholder={dict.placeholder} readonly={readonly}
+              name={name} value={currentValue}
+              onChange={(e): void => setCurrentValue(e.currentTarget.value)} />
+            <Text id={`fields.instance.${name}.help`} />
+          </p>
+        </div>
+        {errors[name] ? <p class="help is-danger">
+          <Text id={`validation.${errors[name].type}`} 
fields={errors[name].params}>{errors[name].message}</Text>
+        </p> : null}
+        {array.map(v => <div class="tags has-addons">
+          <span class="tag is-medium is-info">{v}</span>
+          <a class="tag is-medium is-danger is-delete" onClick={() => {
+            onChange(array.filter(f => f !== v))
+            setCurrentValue(v)
+          }} />
+        </div>
+        )}
+      </div>
+
+    </div>
+  </div>
+}
+
 function YupInputWithAddon({ name, readonly, value, errors, onChange, addon }: 
Props & { addon: string }): VNode {
   const dict = useText({
     placeholder: `fields.instance.${name}.placeholder`,
@@ -126,7 +178,7 @@ function YupInputWithAddon({ name, readonly, value, errors, 
onChange, addon }: P
           </div>
           <p class="control is-expanded">
             <input class={errors[name] ? "input is-danger" : "input"} 
type="text"
-              placeholder={dict['placeholder']} readonly={readonly}
+              placeholder={dict.placeholder} readonly={readonly}
               name={name} value={value}
               onChange={(e): void => onChange(e.currentTarget.value)} />
             <Text id={`fields.instance.${name}.help`} />
@@ -145,7 +197,7 @@ function YupInputSecured({ name, readonly, value, errors, 
onChange }: Props): VN
   })
 
   const [active, setActive] = useState(false)
-  
+
   return <div class="field is-horizontal">
     <div class="field-label is-normal">
       <label class="label">
diff --git a/src/declaration.d.ts b/src/declaration.d.ts
index 2cc71c8..89645e2 100644
--- a/src/declaration.d.ts
+++ b/src/declaration.d.ts
@@ -5,9 +5,10 @@ declare module "*.css" {
     export default mapping;
 }
 declare module "*.jpeg" {
-    const mapping: Record<string, string>;
-    export default mapping;
+    const value: any;
+    export = value;
 }
+
 declare module "*.scss" {
     const mapping: Record<string, string>;
     export default mapping;
diff --git a/src/i18n/index.ts b/src/i18n/index.ts
index c0d1acc..9f9b39c 100644
--- a/src/i18n/index.ts
+++ b/src/i18n/index.ts
@@ -151,7 +151,7 @@ export default {
         },
         payto_uris: {
           label: 'Bank accounts',
-          placeholder: 'comma separated values',
+          tooltip: 'Bank account URI',
           help: 'payto://x-taler-bank/bank.taler:5882/blogger',
         },
         default_max_deposit_fee: {
diff --git a/src/routes/instances/CardTable.tsx 
b/src/routes/instances/CardTable.tsx
index d7129f3..fa1d60b 100644
--- a/src/routes/instances/CardTable.tsx
+++ b/src/routes/instances/CardTable.tsx
@@ -49,15 +49,20 @@ export default function CardTable({ instances, onCreate, 
onSelect, selected }: P
   return <div class="card has-table">
     <header class="card-header">
       <p class="card-header-title"><span class="icon"><i class="mdi 
mdi-account-multiple" /></span><Text id="text.instances" /></p>
-      
-      <button class={rowSelection.length > 0 ? "card-header-icon" : 
"is-hidden"} 
-        type="button" onClick={(): void => 
actionQueueHandler(buildActions(instances, rowSelection, 'DELETE'))} >
 
-        <span class="icon"><i class="mdi mdi-trash-can" /></span>
-      </button>
-      <button class="card-header-icon" type="button" onClick={onCreate}>
-        <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" /></span>
-      </button>
+      <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'))} >
+          <span class="icon"><i class="mdi mdi-trash-can" /></span>
+        </button>
+      </div>
+      <div class="card-header-icon" aria-label="more options">
+        <button class="button is-info" type="button" onClick={onCreate}>
+          <span class="icon is-small" ><i class="mdi mdi-plus mdi-36px" 
/></span>
+        </button>
+      </div>
+
     </header>
     <div class="card-content">
       <div class="b-table has-pagination">
diff --git a/src/schemas/index.ts b/src/schemas/index.ts
index c3ad791..c16b881 100644
--- a/src/schemas/index.ts
+++ b/src/schemas/index.ts
@@ -12,13 +12,8 @@ yup.setLocale({
   },
 });
 
-function stringToArray(this: yup.AnySchema, current: any, original: string): 
string[] {
-  if (this.isType(current)) return current;
-  return original.split(',').filter(s => s.length > 0)
-}
-
 function listOfPayToUrisAreValid(values?: (string | undefined)[]): boolean {
-  return !!values && values.filter(v => v && PAYTO_REGEX.test(v)).length > 0;
+  return !!values && values.every(v => v && PAYTO_REGEX.test(v));
 }
 
 function numberToDuration(this: yup.AnySchema, current: any, original: 
string): Duration {
@@ -33,10 +28,13 @@ function currencyWithAmountIsValid(value?: string): boolean 
{
 const InstanceSchema = yup.object().shape({
   id: yup.string().required().meta({type: 'url'}),
   name: yup.string().required(),
-  auth_token: yup.string().min(8).max(20).optional().meta({type: 'secured'}),
+  auth_token: yup.string()
+    .min(8).max(20)
+    .optional()
+    .meta({type: 'secured'}),
   payto_uris: yup.array().of(yup.string())
     .min(1)
-    .transform(stringToArray)
+    .meta({type: 'array'})
     .test('payto', '{path} is not valid', listOfPayToUrisAreValid),
   default_max_deposit_fee: yup.string()
     .required()
@@ -75,13 +73,13 @@ const InstanceSchema = yup.object().shape({
   default_pay_delay: yup.object()
     .shape({ d_ms: yup.number() })
     .required()
-    .meta({ type: 'duration' })
-    .transform(numberToDuration),
+    .meta({ type: 'duration' }),
+    // .transform(numberToDuration),
   default_wire_transfer_delay: yup.object()
     .shape({ d_ms: yup.number() })
     .required()
-    .meta({ type: 'duration' })
-    .transform(numberToDuration),
+    .meta({ type: 'duration' }),
+    // .transform(numberToDuration),
 })
 
 export const InstanceUpdateSchema = InstanceSchema.clone().omit(['id']);

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