[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.
- [taler-merchant-backoffice] branch master updated (d37369b -> 70bf89a), gnunet, 2021/02/18
- [taler-merchant-backoffice] 02/08: add duration as human readable, gnunet, 2021/02/18
- [taler-merchant-backoffice] 05/08: refactoring route, gnunet, 2021/02/18
- [taler-merchant-backoffice] 01/08: payto as array,
gnunet <=
- [taler-merchant-backoffice] 07/08: record wont compile, gnunet, 2021/02/18
- [taler-merchant-backoffice] 08/08: rever sass-loader since it doesnt work with webpack 4 https://github.com/preactjs/preact-cli/issues/880, gnunet, 2021/02/18
- [taler-merchant-backoffice] 04/08: added copyright and replace default import, gnunet, 2021/02/18
- [taler-merchant-backoffice] 03/08: adding copyright to source files, gnunet, 2021/02/18
- [taler-merchant-backoffice] 06/08: implemented pnpm, gnunet, 2021/02/18