aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/taler-wallet-webextension/src/components/AmountField.tsx33
-rw-r--r--packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/mui/TextField.stories.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/mui/TextField.tsx9
-rw-r--r--packages/taler-wallet-webextension/src/mui/input/FormControl.tsx14
-rw-r--r--packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx6
-rw-r--r--packages/taler-wallet-webextension/src/mui/input/InputBase.tsx16
-rw-r--r--packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx6
-rw-r--r--packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx3
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx147
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx4
15 files changed, 149 insertions, 107 deletions
diff --git a/packages/taler-wallet-webextension/src/components/AmountField.tsx b/packages/taler-wallet-webextension/src/components/AmountField.tsx
index 79c510d2f..1c57be0df 100644
--- a/packages/taler-wallet-webextension/src/components/AmountField.tsx
+++ b/packages/taler-wallet-webextension/src/components/AmountField.tsx
@@ -45,23 +45,20 @@ export function AmountField({
return handler.value;
}
return (
- <Fragment>
- <TextField
- label={label}
- type="number"
- min="0"
- step="0.1"
- variant="filled"
- error={!!handler.error}
- required={required}
- startAdornment={
- <div style={{ padding: "25px 12px 8px 12px" }}>{currency}</div>
- }
- value={handler.value}
- disabled={!handler.onInput}
- onInput={positiveAmount}
- />
- {handler.error && <ErrorText>{handler.error}</ErrorText>}
- </Fragment>
+ <TextField
+ label={label}
+ type="number"
+ min="0"
+ step="0.1"
+ variant="filled"
+ error={handler.error}
+ required={required}
+ startAdornment={
+ <div style={{ padding: "25px 12px 8px 12px" }}>{currency}</div>
+ }
+ value={handler.value}
+ disabled={!handler.onInput}
+ onInput={positiveAmount}
+ />
);
}
diff --git a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx
index 603392b60..4970f590f 100644
--- a/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/InvoiceCreate/views.tsx
@@ -78,7 +78,7 @@ export function ReadyView({
<TextField
label="Subject"
variant="filled"
- error={!!subject.error}
+ error={subject.error}
required
fullWidth
value={subject.value}
diff --git a/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx b/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx
index 93ae343e9..bca806c5d 100644
--- a/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx
+++ b/packages/taler-wallet-webextension/src/cta/TransferCreate/views.tsx
@@ -68,7 +68,7 @@ export function ReadyView({
<TextField
label="Subject"
variant="filled"
- error={!!subject.error}
+ error={subject.error}
required
fullWidth
value={subject.value}
diff --git a/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx b/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx
index a409f09f0..7db6b2964 100644
--- a/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx
+++ b/packages/taler-wallet-webextension/src/mui/TextField.stories.tsx
@@ -56,13 +56,13 @@ const Input = (variant: Props["variant"]): VNode => {
value="disabled"
/>
<TextField
- error
+ error={"Error"}
variant={variant}
label="Something"
{...{ value, onChange }}
/>
<TextField
- error
+ error={"Error"}
disabled
variant={variant}
label="Disabled and Error"
diff --git a/packages/taler-wallet-webextension/src/mui/TextField.tsx b/packages/taler-wallet-webextension/src/mui/TextField.tsx
index 7c6eb40a2..ba05158fa 100644
--- a/packages/taler-wallet-webextension/src/mui/TextField.tsx
+++ b/packages/taler-wallet-webextension/src/mui/TextField.tsx
@@ -30,7 +30,7 @@ export interface Props {
autoFocus?: boolean;
color?: Colors;
disabled?: boolean;
- error?: boolean;
+ error?: string;
fullWidth?: boolean;
helperText?: VNode | string;
id?: string;
@@ -85,7 +85,12 @@ export function TextField({
<FormControl {...props}>
{label && <InputLabel>{label}</InputLabel>}
<Input {...props}>{children}</Input>
- {helperText && <FormHelperText>{helperText}</FormHelperText>}
+ {helperText && (
+ <FormHelperText error={props.error}>{helperText}</FormHelperText>
+ )}
+ {props.error ? (
+ <FormHelperText error="true">{props.error}</FormHelperText>
+ ) : undefined}
</FormControl>
);
}
diff --git a/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
index 8454b0fad..e80e7f8d8 100644
--- a/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/FormControl.tsx
@@ -22,7 +22,7 @@ import { Colors } from "../style";
export interface Props {
color: Colors;
disabled: boolean;
- error: boolean;
+ error?: string;
focused: boolean;
fullWidth: boolean;
hiddenLabel: boolean;
@@ -64,7 +64,7 @@ export const FormControlContext = createContext<FCCProps | null>(null);
export function FormControl({
color = "primary",
disabled = false,
- error = false,
+ error = undefined,
focused: visuallyFocused,
fullWidth = false,
hiddenLabel = false,
@@ -75,9 +75,9 @@ export function FormControl({
children,
}: Partial<Props>): VNode {
const [filled, setFilled] = useState(false);
- const [focusedState, setFocused] = useState(false);
+ const [focusedState, setFocused] = useState(visuallyFocused);
const focused =
- visuallyFocused !== undefined && !disabled ? visuallyFocused : focusedState;
+ focusedState !== undefined && !disabled ? focusedState : false;
const value: FCCProps = {
color,
@@ -124,7 +124,7 @@ export interface FCCProps {
// setAdornedStart,
color: Colors;
disabled: boolean;
- error: boolean;
+ error: string | undefined;
filled: boolean;
focused: boolean;
fullWidth: boolean;
@@ -142,7 +142,7 @@ export interface FCCProps {
const defaultContextValue: FCCProps = {
color: "primary",
disabled: false,
- error: false,
+ error: undefined,
filled: false,
focused: false,
fullWidth: false,
@@ -159,7 +159,7 @@ const defaultContextValue: FCCProps = {
function withoutUndefinedProperties(obj: any): any {
return Object.keys(obj).reduce((acc, key) => {
const _acc: any = acc;
- if (obj[key] !== undefined) _acc[key] = obj[key];
+ if (obj[key] !== undefined && obj[key] !== false) _acc[key] = obj[key];
return _acc;
}, {});
}
diff --git a/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx b/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx
index 739b41e32..5e40ba616 100644
--- a/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/FormHelperText.tsx
@@ -43,7 +43,7 @@ const containedStyle = css`
interface Props {
disabled?: boolean;
- error?: boolean;
+ error?: string;
filled?: boolean;
focused?: boolean;
margin?: "dense";
diff --git a/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx b/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx
index 1d4b5eff5..11404b5c1 100644
--- a/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/FormLabel.tsx
@@ -22,7 +22,7 @@ import { useFormControl } from "./FormControl.js";
export interface Props {
class?: string;
disabled?: boolean;
- error?: boolean;
+ error?: string;
filled?: boolean;
focused?: boolean;
required?: boolean;
@@ -67,9 +67,9 @@ export function FormLabel({
});
return (
<label
- data-focused={fcs.focused}
+ data-focused={!fcs.focused ? undefined : true}
data-error={!fcs.error ? undefined : true}
- data-disabled={fcs.disabled}
+ data-disabled={!fcs.disabled ? undefined : true}
class={[_class, root, theme.typography.body1].join(" ")}
{...rest}
style={{
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx b/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx
index e1c6e7af1..94304f16b 100644
--- a/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/InputBase.tsx
@@ -60,8 +60,8 @@ export function InputBaseRoot({
const fcs = useFormControl({});
return (
<div
- data-disabled={disabled}
- data-focused={focused}
+ data-disabled={!disabled ? undefined : true}
+ data-focused={!focused ? undefined : true}
data-multiline={multiline}
data-hasStart={!!startAdornment}
data-hasEnd={!!endAdornment}
@@ -116,6 +116,12 @@ const componentStyle = css`
duration: theme.transitions.duration.shorter,
})};
}
+ &:not(focus)::placeholder {
+ opacity: 0;
+ }
+ &:focus::placeholder {
+ opacity: ${theme.palette.mode === "light" ? 0.42 : 0.5};
+ }
&:focus {
outline: 0;
}
@@ -292,11 +298,11 @@ export function InputBase({
<Root {...fcs} onClick={handleClick}>
<FormControlContext.Provider value={null}>
<Input
- aria-invalid={fcs.error}
+ aria-invalid={fcs.error ? true : undefined}
// aria-describedby={}
- disabled={fcs.disabled}
+ disabled={fcs.disabled ? true : undefined}
name={name}
- placeholder={placeholder}
+ placeholder={!placeholder ? undefined : placeholder}
readOnly={readOnly}
required={fcs.required}
rows={rows}
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx b/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx
index fa5144ca3..9ab91e7fd 100644
--- a/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/InputFilled.tsx
@@ -27,7 +27,7 @@ export interface Props {
defaultValue?: string;
disabled?: boolean;
disableUnderline?: boolean;
- error?: boolean;
+ error?: string;
fullWidth?: boolean;
id?: string;
margin?: "dense" | "normal" | "none";
@@ -176,7 +176,7 @@ function Root({
return (
<InputBaseRoot
disabled={disabled}
- focused={focused}
+ focused={focused ? true : undefined}
fullWidth={fullWidth}
multiline={multiline}
error={error}
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx b/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx
index 469047afb..35cbd7a41 100644
--- a/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/InputLabel.tsx
@@ -90,7 +90,7 @@ interface InputLabelProps {
color: Colors;
disableAnimation: boolean;
disabled: boolean;
- error: boolean;
+ error?: string;
focused: boolean;
margin: boolean;
required: boolean;
@@ -104,8 +104,8 @@ export function InputLabel(props: Partial<InputLabelProps>): VNode {
<FormLabel
data-form-control={!!fcs}
data-size={fcs.size}
- data-shrink={props.shrink || fcs.filled || fcs.focused}
- data-disable-animation={props.disableAnimation}
+ data-shrink={props.shrink || fcs.filled || fcs.focused ? true : undefined}
+ data-disable-animation={props.disableAnimation ? true : undefined}
data-variant={fcs.variant}
class={root}
{...props}
diff --git a/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx b/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx
index b1152ebec..45614f618 100644
--- a/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx
+++ b/packages/taler-wallet-webextension/src/mui/input/InputStandard.tsx
@@ -28,7 +28,7 @@ export interface Props {
disabled?: boolean;
disableUnderline?: boolean;
endAdornment?: VNode;
- error?: boolean;
+ error?: string;
fullWidth?: boolean;
id?: string;
margin?: "dense" | "normal" | "none";
@@ -128,7 +128,7 @@ function Root({ fullWidth, disabled, focused, error, children }: any): VNode {
return (
<InputBaseRoot
disabled={disabled}
- focused={focused}
+ focused={focused ? true : undefined}
fullWidth={fullWidth}
error={error}
class={[rootStyle, formControlStyle, underlineStyle].join(" ")}
diff --git a/packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx b/packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx
index c0d3a38b0..875dec227 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/stories.tsx
@@ -194,8 +194,9 @@ export const AddingIbanAccount = createExample(ReadyView, {
uri: {
targetType: "iban",
iban: "ASDQWEQWE",
+ bic: "SANDBOX",
isKnown: true,
- targetPath: "/ASDQWEQWE",
+ targetPath: "SANDBOX/ASDQWEQWE",
params: {},
},
},
diff --git a/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx b/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
index 326e078f4..3af0d5505 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManageAccount/views.tsx
@@ -23,7 +23,6 @@ import {
import { styled } from "@linaria/react";
import { Fragment, h, VNode } from "preact";
import { useState } from "preact/hooks";
-import { ErrorMessage } from "../../components/ErrorMessage.js";
import { LoadingError } from "../../components/LoadingError.js";
import { SelectList } from "../../components/SelectList.js";
import {
@@ -41,6 +40,7 @@ import checkIcon from "../../svg/check_24px.svg";
import warningIcon from "../../svg/warning_24px.svg";
import deleteIcon from "../../svg/delete_24px.svg";
import { State } from "./index.js";
+import { ErrorMessage } from "../../components/ErrorMessage.js";
type AccountType = "bitcoin" | "x-taler-bank" | "iban";
type ComponentFormByAccountType = {
@@ -143,9 +143,9 @@ export function ReadyView({
</p>
<p>
<TextField
- label="Account alias"
- variant="standard"
- required
+ label="Alias"
+ variant="filled"
+ placeholder="Easy to remember description"
fullWidth
disabled={accountType.value === ""}
value={alias.value}
@@ -202,6 +202,9 @@ function IbanTable({
<i18n.Translate>Alias</i18n.Translate>
</th>
<th>
+ <i18n.Translate>Bank Id</i18n.Translate>
+ </th>
+ <th>
<i18n.Translate>Int. Account Number</i18n.Translate>
</th>
<th>
@@ -219,7 +222,8 @@ function IbanTable({
return (
<tr key={account.alias}>
<td>{account.alias}</td>
- <td>{p.targetPath}</td>
+ <td>{p.bic}</td>
+ <td>{p.iban}</td>
<td>{p.params["receiver-name"]}</td>
<td class="kyc">
{account.kyc_completed ? (
@@ -415,7 +419,7 @@ function BitcoinAddressAccount({ field }: { field: TextFieldHandler }): VNode {
variant="standard"
fullWidth
value={value}
- error={value !== undefined && !!errors?.value}
+ error={value !== undefined ? errors?.value : undefined}
disabled={!field.onInput}
onChange={(v) => {
setValue(v);
@@ -424,9 +428,6 @@ function BitcoinAddressAccount({ field }: { field: TextFieldHandler }): VNode {
}
}}
/>
- {value !== undefined && errors?.value && (
- <ErrorMessage title={<span>{errors?.value}</span>} />
- )}
</Fragment>
);
}
@@ -456,7 +457,7 @@ function TalerBankAddressAccount({
variant="standard"
fullWidth
value={host}
- error={host !== undefined && !!errors?.host}
+ error={host !== undefined ? errors?.host : undefined}
disabled={!field.onInput}
onChange={(v) => {
setHost(v);
@@ -464,77 +465,109 @@ function TalerBankAddressAccount({
field.onInput(`payto://x-taler-bank/${v}/${account}`);
}
}}
- />{" "}
- {host !== undefined && errors?.host && (
- <ErrorMessage title={<span>{errors?.host}</span>} />
- )}
+ />
<TextField
label="Bank account"
variant="standard"
fullWidth
disabled={!field.onInput}
value={account}
- error={account !== undefined && !!errors?.account}
+ error={account !== undefined ? errors?.account : undefined}
onChange={(v) => {
setAccount(v || "");
if (!errors && field.onInput) {
field.onInput(`payto://x-taler-bank/${host}/${v}`);
}
}}
- />{" "}
- {account !== undefined && errors?.account && (
- <ErrorMessage title={<span>{errors?.account}</span>} />
- )}
+ />
</Fragment>
);
}
+//Taken from libeufin and libeufin took it from the ISO20022 XSD schema
+const bicRegex = /^[A-Z]{6}[A-Z2-9][A-NP-Z0-9]([A-Z0-9]{3})?$/;
+const ibanRegex = /^[A-Z]{2}[0-9]{2}[a-zA-Z0-9]{1,30}$/;
+
function IbanAddressAccount({ field }: { field: TextFieldHandler }): VNode {
const { i18n } = useTranslationContext();
- const [number, setNumber] = useState<string | undefined>(undefined);
+ const [bic, setBic] = useState<string | undefined>(undefined);
+ const [iban, setIban] = useState<string | undefined>(undefined);
const [name, setName] = useState<string | undefined>(undefined);
const errors = undefinedIfEmpty({
- number: !number ? i18n.str`Can't be empty` : undefined,
+ bic: !bic
+ ? undefined
+ : !bicRegex.test(bic)
+ ? i18n.str`Invalid bic`
+ : undefined,
+ iban: !iban
+ ? i18n.str`Can't be empty`
+ : !ibanRegex.test(iban)
+ ? i18n.str`Invalid iban`
+ : undefined,
name: !name ? i18n.str`Can't be empty` : undefined,
});
+
+ function sendUpdateIfNoErrors(
+ bic: string | undefined,
+ iban: string,
+ name: string,
+ ): void {
+ if (!errors && field.onInput) {
+ const path = bic === undefined ? iban : `${bic}/${iban}`;
+ field.onInput(
+ `payto://iban/${path}?receiver-name=${encodeURIComponent(name)}`,
+ );
+ }
+ }
return (
<Fragment>
- <TextField
- label="IBAN number"
- variant="standard"
- fullWidth
- value={number}
- error={number !== undefined && !!errors?.number}
- disabled={!field.onInput}
- onChange={(v) => {
- setNumber(v);
- if (!errors && field.onInput) {
- field.onInput(`payto://iban/${v}?receiver-name=${name}`);
- }
- }}
- />
- {number !== undefined && errors?.number && (
- <ErrorMessage title={<span>{errors?.number}</span>} />
- )}
- <TextField
- label="Account name"
- variant="standard"
- fullWidth
- value={name}
- error={name !== undefined && !!errors?.name}
- disabled={!field.onInput}
- onChange={(v) => {
- setName(v);
- if (!errors && field.onInput) {
- field.onInput(
- `payto://iban/${number}?receiver-name=${encodeURIComponent(v)}`,
- );
- }
- }}
- />
- {name !== undefined && errors?.name && (
- <ErrorMessage title={<span>{errors?.name}</span>} />
- )}
+ <p>
+ <TextField
+ label="BIC"
+ variant="filled"
+ placeholder="BANKID"
+ fullWidth
+ value={bic}
+ error={bic !== undefined ? errors?.bic : undefined}
+ disabled={!field.onInput}
+ onChange={(v) => {
+ setBic(v);
+ sendUpdateIfNoErrors(v, iban || "", name || "");
+ }}
+ />
+ </p>
+ <p>
+ <TextField
+ label="IBAN"
+ variant="filled"
+ placeholder="XX123456"
+ fullWidth
+ required
+ value={iban}
+ error={iban !== undefined ? errors?.iban : undefined}
+ disabled={!field.onInput}
+ onChange={(v) => {
+ setIban(v);
+ sendUpdateIfNoErrors(bic, v, name || "");
+ }}
+ />
+ </p>
+ <p>
+ <TextField
+ label="Receiver name"
+ variant="filled"
+ placeholder="Name of the target bank account owner"
+ fullWidth
+ required
+ value={name}
+ error={name !== undefined ? errors?.name : undefined}
+ disabled={!field.onInput}
+ onChange={(v) => {
+ setName(v);
+ sendUpdateIfNoErrors(bic, iban || "", v);
+ }}
+ />
+ </p>
</Fragment>
);
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index 746d127cf..76bfe014b 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -1343,7 +1343,7 @@ function DepositDetails({
const { i18n } = useTranslationContext();
const r = Amounts.parseOrThrow(transaction.amountRaw);
const e = Amounts.parseOrThrow(transaction.amountEffective);
- const fee = Amounts.sub(r, e).amount;
+ const fee = Amounts.sub(e, r).amount;
const maxFrac = [r, e, fee]
.map((a) => Amounts.maxFractionalDigits(a))
@@ -1366,7 +1366,7 @@ function DepositDetails({
<i18n.Translate>Transaction fees</i18n.Translate>
</td>
<td>
- <Amount value={fee} negative maxFracSize={maxFrac} />
+ <Amount value={fee} maxFracSize={maxFrac} />
</td>
</tr>
)}