using util to parse uri, some more fixs

This commit is contained in:
Sebastian 2022-10-26 16:04:12 -03:00
parent b4bad2deaf
commit af29a02e5b
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
4 changed files with 100 additions and 28 deletions

View File

@ -14,6 +14,7 @@
"jed": "1.1.1", "jed": "1.1.1",
"preact": "10.6.5", "preact": "10.6.5",
"preact-router": "3.2.1", "preact-router": "3.2.1",
"@gnu-taler/taler-util": "workspace:*",
"qrcode-generator": "^1.4.4", "qrcode-generator": "^1.4.4",
"react": "npm:@preact/compat@^17.1.2", "react": "npm:@preact/compat@^17.1.2",
"swr": "1.3.0" "swr": "1.3.0"

View File

@ -31,6 +31,7 @@ import { QR } from "../../components/QR.js";
import { useLocalStorage, useNotNullLocalStorage } from "../../hooks/index.js"; import { useLocalStorage, useNotNullLocalStorage } from "../../hooks/index.js";
import { Translate, useTranslator } from "../../i18n/index.js"; import { Translate, useTranslator } from "../../i18n/index.js";
import "../../scss/main.scss"; import "../../scss/main.scss";
import { parsePaytoUri } from "@gnu-taler/taler-util";
/** /**
* If the first argument does not look like a placeholder, return it. * If the first argument does not look like a placeholder, return it.
@ -113,6 +114,7 @@ interface TransactionRequestType {
interface CredentialsRequestType { interface CredentialsRequestType {
username: string; username: string;
password: string; password: string;
repeatPassword: string;
} }
/** /**
@ -336,14 +338,16 @@ type RawPaytoInputType = string;
type RawPaytoInputTypeOpt = RawPaytoInputType | undefined; type RawPaytoInputTypeOpt = RawPaytoInputType | undefined;
function useRawPaytoInputType( function useRawPaytoInputType(
state?: RawPaytoInputType, state?: RawPaytoInputType,
): [RawPaytoInputTypeOpt, StateUpdater<RawPaytoInputTypeOpt>] { ): [RawPaytoInputTypeOpt, StateUpdater<RawPaytoInputTypeOpt>, boolean] {
const ret = useLocalStorage("raw-payto-input-state", state); const ret = useLocalStorage("raw-payto-input-state", state);
const [dirty, setDirty] = useState(false);
const retObj: RawPaytoInputTypeOpt = ret[0]; const retObj: RawPaytoInputTypeOpt = ret[0];
const retSetter: StateUpdater<RawPaytoInputTypeOpt> = function (val) { const retSetter: StateUpdater<RawPaytoInputTypeOpt> = function (val) {
const newVal = val instanceof Function ? val(retObj) : val; const newVal = val instanceof Function ? val(retObj) : val;
setDirty(true);
ret[1](newVal); ret[1](newVal);
}; };
return [retObj, retSetter]; return [retObj, retSetter, dirty];
} }
/** /**
@ -1012,12 +1016,24 @@ function BankFrame(Props: any): VNode {
</Fragment> </Fragment>
); );
} }
function ShowInputErrorLabel({
isDirty,
message,
}: {
message: string | undefined;
isDirty: boolean;
}): VNode {
if (message && isDirty)
return <p class="informational informational-fail">{message}</p>;
return <Fragment />;
}
function PaytoWireTransfer(Props: any): VNode { function PaytoWireTransfer(Props: any): VNode {
const currency = useContext(CurrencyContext); const currency = useContext(CurrencyContext);
const [pageState, pageStateSetter] = useContext(PageContext); // NOTE: used for go-back button? const [pageState, pageStateSetter] = useContext(PageContext); // NOTE: used for go-back button?
const [submitData, submitDataSetter] = useWireTransferRequestType(); const [submitData, submitDataSetter] = useWireTransferRequestType();
const [rawPaytoInput, rawPaytoInputSetter] = useRawPaytoInputType(); const [rawPaytoInput, rawPaytoInputSetter, rawPaytoInputDirty] =
useRawPaytoInputType();
const i18n = useTranslator(); const i18n = useTranslator();
const { focus, backendState } = Props; const { focus, backendState } = Props;
const amountRegex = "^[0-9]+(.[0-9]+)?$"; const amountRegex = "^[0-9]+(.[0-9]+)?$";
@ -1159,6 +1175,14 @@ function PaytoWireTransfer(Props: any): VNode {
</div> </div>
); );
const errors = undefinedIfEmpty({
rawPaytoInput: !rawPaytoInput
? i18n`Missing payto address`
: !parsePaytoUri(rawPaytoInput)
? i18n`Payto does not follow the pattern`
: undefined,
});
return ( return (
<div> <div>
<p>{i18n`Transfer money to account identified by payto:// URI:`}</p> <p>{i18n`Transfer money to account identified by payto:// URI:`}</p>
@ -1168,17 +1192,21 @@ function PaytoWireTransfer(Props: any): VNode {
<input <input
name="address" name="address"
type="text" type="text"
size={90} size={50}
ref={ref} ref={ref}
id="address" id="address"
value={rawPaytoInput} value={rawPaytoInput}
required required
placeholder={i18n`payto address`} placeholder={i18n`payto address`}
pattern={`payto://iban/[A-Z][A-Z][0-9]+?message=[a-zA-Z0-9 ]+&amount=${currency}:[0-9]+(.[0-9]+)?`} // pattern={`payto://iban/[A-Z][A-Z][0-9]+?message=[a-zA-Z0-9 ]+&amount=${currency}:[0-9]+(.[0-9]+)?`}
onInput={(e): void => { onInput={(e): void => {
rawPaytoInputSetter(e.currentTarget.value); rawPaytoInputSetter(e.currentTarget.value);
}} }}
/> />
<ShowInputErrorLabel
message={errors?.rawPaytoInput}
isDirty={rawPaytoInputDirty}
/>
<br /> <br />
<div class="hint"> <div class="hint">
Hint: Hint:
@ -1192,6 +1220,7 @@ function PaytoWireTransfer(Props: any): VNode {
<input <input
class="pure-button pure-button-primary" class="pure-button pure-button-primary"
type="submit" type="submit"
disabled={!!errors}
value={i18n`Send`} value={i18n`Send`}
onClick={async () => { onClick={async () => {
// empty string evaluates to false. // empty string evaluates to false.
@ -1593,6 +1622,11 @@ function RegistrationButton(Props: any): VNode {
return <span />; return <span />;
} }
function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
? obj
: undefined;
}
/** /**
* Collect and submit login data. * Collect and submit login data.
*/ */
@ -1604,6 +1638,16 @@ function LoginForm(Props: any): VNode {
useEffect(() => { useEffect(() => {
ref.current?.focus(); ref.current?.focus();
}, []); }, []);
const errors = undefinedIfEmpty({
username: !(submitData && submitData.username)
? i18n`Missing username`
: undefined,
password: !(submitData && submitData.password)
? i18n`Missing password`
: undefined,
});
return ( return (
<div class="login-div"> <div class="login-div">
<form action="javascript:void(0);" class="login-form"> <form action="javascript:void(0);" class="login-form">
@ -1649,6 +1693,7 @@ function LoginForm(Props: any): VNode {
<button <button
type="submit" type="submit"
class="pure-button pure-button-primary" class="pure-button pure-button-primary"
disabled={!!errors}
onClick={() => { onClick={() => {
if (typeof submitData === "undefined") { if (typeof submitData === "undefined") {
console.log("login data is undefined", submitData); console.log("login data is undefined", submitData);
@ -1691,7 +1736,19 @@ function RegistrationForm(Props: any): VNode {
const [pageState, pageStateSetter] = useContext(PageContext); const [pageState, pageStateSetter] = useContext(PageContext);
const [submitData, submitDataSetter] = useCredentialsRequestType(); const [submitData, submitDataSetter] = useCredentialsRequestType();
const i18n = useTranslator(); const i18n = useTranslator();
// https://stackoverflow.com/questions/36683770/how-to-get-the-value-of-an-input-field-using-reactjs
const errors = !submitData
? undefined
: undefinedIfEmpty({
username: !submitData.username ? i18n`Missing username` : undefined,
password: !submitData.password ? i18n`Missing password` : undefined,
repeatPassword: !submitData.repeatPassword
? i18n`Missing password`
: submitData.repeatPassword !== submitData.password
? i18n`Password don't match`
: undefined,
});
return ( return (
<Fragment> <Fragment>
<h1 class="nav">{i18n`Welcome to ${UI_BANK_NAME}!`}</h1> <h1 class="nav">{i18n`Welcome to ${UI_BANK_NAME}!`}</h1>
@ -1735,6 +1792,24 @@ function RegistrationForm(Props: any): VNode {
})); }));
}} }}
/> />
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
<label for="register-repeat">{i18n`Repeat Password:`}</label>
</p>
<input
type="password"
style={{ marginBottom: 8 }}
name="register-repeat"
id="register-repeat"
placeholder="Same password"
value={submitData && submitData.repeatPassword}
required
onInput={(e): void => {
submitDataSetter((submitData: any) => ({
...submitData,
repeatPassword: e.currentTarget.value,
}));
}}
/>
<br /> <br />
{/* {/*
<label for="phone">{i18n`Phone number:`}</label> <label for="phone">{i18n`Phone number:`}</label>
@ -1755,28 +1830,10 @@ function RegistrationForm(Props: any): VNode {
*/} */}
<button <button
class="pure-button pure-button-primary btn-register" class="pure-button pure-button-primary btn-register"
disabled={!!errors}
onClick={() => { onClick={() => {
console.log("maybe submitting the registration.."); console.log("maybe submitting the registration..");
console.log(submitData); if (!submitData) return;
if (typeof submitData === "undefined") {
console.log(`submit data ${submitData} is undefined`);
return;
}
if (
typeof submitData.password === "undefined" ||
typeof submitData.username === "undefined"
) {
console.log("username or password is undefined");
return;
}
if (
submitData.password.length === 0 ||
submitData.username.length === 0
) {
console.log("username or password are the empty string");
return;
}
console.log("submitting the registration..");
registrationCall( registrationCall(
{ ...submitData }, { ...submitData },
Props.backendStateSetter, // will store BE URL, if OK. Props.backendStateSetter, // will store BE URL, if OK.
@ -1790,7 +1847,11 @@ function RegistrationForm(Props: any): VNode {
* strings due to a non lively update of the <input> fields * strings due to a non lively update of the <input> fields
* after setting to undefined. * after setting to undefined.
*/ */
submitDataSetter({ username: "", password: "" }); submitDataSetter({
username: "",
password: "",
repeatPassword: "",
});
}} }}
> >
{i18n`Register`} {i18n`Register`}
@ -1799,6 +1860,11 @@ function RegistrationForm(Props: any): VNode {
<button <button
class="pure-button pure-button-secondary btn-cancel" class="pure-button pure-button-secondary btn-cancel"
onClick={() => { onClick={() => {
submitDataSetter({
username: "",
password: "",
repeatPassword: "",
});
pageStateSetter((prevState: PageStateType) => ({ pageStateSetter((prevState: PageStateType) => ({
...prevState, ...prevState,
tryRegister: false, tryRegister: false,

View File

@ -120,7 +120,7 @@ input {
.large-amount { .large-amount {
font-weight: bold; font-weight: bold;
font-size: x-large; font-size: xxx-large;
} }
.currency { .currency {
@ -259,3 +259,6 @@ html {
.hint { .hint {
scale: 0.7; scale: 0.7;
} }
h1.nav {
text-align: center;
}

View File

@ -96,6 +96,7 @@ importers:
specifiers: specifiers:
'@creativebulma/bulma-tooltip': ^1.2.0 '@creativebulma/bulma-tooltip': ^1.2.0
'@gnu-taler/pogen': ^0.0.5 '@gnu-taler/pogen': ^0.0.5
'@gnu-taler/taler-util': workspace:*
'@typescript-eslint/eslint-plugin': ^5.41.0 '@typescript-eslint/eslint-plugin': ^5.41.0
'@typescript-eslint/parser': ^5.41.0 '@typescript-eslint/parser': ^5.41.0
bulma: ^0.9.4 bulma: ^0.9.4
@ -116,6 +117,7 @@ importers:
swr: 1.3.0 swr: 1.3.0
typescript: ^4.4.4 typescript: ^4.4.4
dependencies: dependencies:
'@gnu-taler/taler-util': link:../taler-util
date-fns: 2.29.3 date-fns: 2.29.3
jed: 1.1.1 jed: 1.1.1
preact: 10.6.5 preact: 10.6.5