fix: show error message on login and registration form, prevent saving password on localstorage
This commit is contained in:
parent
2c04459a58
commit
ac2f680f68
@ -213,32 +213,6 @@ function useWireTransferRequestType(
|
|||||||
return [retObj, retSetter];
|
return [retObj, retSetter];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores in the state a object containing a 'username'
|
|
||||||
* and 'password' field, in order to avoid losing the
|
|
||||||
* handle of the data entered by the user in <input> fields.
|
|
||||||
*/
|
|
||||||
type CredentialsRequestTypeOpt = CredentialsRequestType | undefined;
|
|
||||||
function useCredentialsRequestType(
|
|
||||||
state?: CredentialsRequestType,
|
|
||||||
): [CredentialsRequestTypeOpt, StateUpdater<CredentialsRequestTypeOpt>] {
|
|
||||||
const ret = hooks.useLocalStorage(
|
|
||||||
"credentials-request-state",
|
|
||||||
JSON.stringify(state),
|
|
||||||
);
|
|
||||||
const retObj: CredentialsRequestTypeOpt = ret[0]
|
|
||||||
? JSON.parse(ret[0])
|
|
||||||
: ret[0];
|
|
||||||
const retSetter: StateUpdater<CredentialsRequestTypeOpt> = function (val) {
|
|
||||||
const newVal =
|
|
||||||
val instanceof Function
|
|
||||||
? JSON.stringify(val(retObj))
|
|
||||||
: JSON.stringify(val);
|
|
||||||
ret[1](newVal);
|
|
||||||
};
|
|
||||||
return [retObj, retSetter];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request preparators.
|
* Request preparators.
|
||||||
*
|
*
|
||||||
@ -597,7 +571,7 @@ async function createWithdrawalCall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function loginCall(
|
async function loginCall(
|
||||||
req: CredentialsRequestType,
|
req: { username: string; password: string },
|
||||||
/**
|
/**
|
||||||
* FIXME: figure out if the two following
|
* FIXME: figure out if the two following
|
||||||
* functions can be retrieved from the state.
|
* functions can be retrieved from the state.
|
||||||
@ -629,7 +603,7 @@ async function loginCall(
|
|||||||
* the page's (to indicate a successful login or a problem).
|
* the page's (to indicate a successful login or a problem).
|
||||||
*/
|
*/
|
||||||
async function registrationCall(
|
async function registrationCall(
|
||||||
req: CredentialsRequestType,
|
req: { username: string; password: string },
|
||||||
/**
|
/**
|
||||||
* FIXME: figure out if the two following
|
* FIXME: figure out if the two following
|
||||||
* functions can be retrieved somewhat from
|
* functions can be retrieved somewhat from
|
||||||
@ -882,11 +856,7 @@ function ShowInputErrorLabel({
|
|||||||
isDirty: boolean;
|
isDirty: boolean;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
if (message && isDirty)
|
if (message && isDirty)
|
||||||
return (
|
return <div style={{ marginTop: 8, color: "red" }}>{message}</div>;
|
||||||
<div class="informational informational-fail" style={{ marginTop: 8 }}>
|
|
||||||
{message}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
return <Fragment />;
|
return <Fragment />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1488,24 +1458,6 @@ function PaymentOptions({ currency }: { currency?: string }): VNode {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function RegistrationButton(Props: any): VNode {
|
|
||||||
const { backendStateSetter, pageStateSetter } = Props;
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
if (bankUiSettings.allowRegistrations)
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
class="pure-button pure-button-secondary btn-cancel"
|
|
||||||
onClick={() => {
|
|
||||||
route("/register");
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{i18n.str`Register`}
|
|
||||||
</button>
|
|
||||||
);
|
|
||||||
|
|
||||||
return <span />;
|
|
||||||
}
|
|
||||||
|
|
||||||
function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
|
function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
|
||||||
return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
|
return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
|
||||||
? obj
|
? obj
|
||||||
@ -1514,20 +1466,20 @@ function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
|
|||||||
/**
|
/**
|
||||||
* Collect and submit login data.
|
* Collect and submit login data.
|
||||||
*/
|
*/
|
||||||
function LoginForm(Props: any): VNode {
|
function LoginForm(): VNode {
|
||||||
const { backendStateSetter, pageStateSetter } = Props;
|
const [backendState, backendStateSetter] = useBackendState();
|
||||||
const [submitData, submitDataSetter] = useCredentialsRequestType();
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
|
const [username, setUsername] = useState<string | undefined>();
|
||||||
|
const [password, setPassword] = useState<string | undefined>();
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const ref = useRef<HTMLInputElement>(null);
|
const ref = useRef<HTMLInputElement>(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ref.current?.focus();
|
ref.current?.focus();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const errors = !submitData
|
const errors = undefinedIfEmpty({
|
||||||
? undefined
|
username: !username ? i18n.str`Missing username` : undefined,
|
||||||
: undefinedIfEmpty({
|
password: !password ? i18n.str`Missing password` : undefined,
|
||||||
username: !submitData.username ? i18n.str`Missing username` : undefined,
|
|
||||||
password: !submitData.password ? i18n.str`Missing password` : undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -1544,16 +1496,17 @@ function LoginForm(Props: any): VNode {
|
|||||||
type="text"
|
type="text"
|
||||||
name="username"
|
name="username"
|
||||||
id="username"
|
id="username"
|
||||||
value={submitData && submitData.username}
|
value={username ?? ""}
|
||||||
placeholder="Username"
|
placeholder="Username"
|
||||||
required
|
required
|
||||||
onInput={(e): void => {
|
onInput={(e): void => {
|
||||||
submitDataSetter((submitData: any) => ({
|
setUsername(e.currentTarget.value);
|
||||||
...submitData,
|
|
||||||
username: e.currentTarget.value,
|
|
||||||
}));
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<ShowInputErrorLabel
|
||||||
|
message={errors?.username}
|
||||||
|
isDirty={username !== undefined}
|
||||||
|
/>
|
||||||
<p class="passFieldLabel loginFieldLabel formFieldLabel">
|
<p class="passFieldLabel loginFieldLabel formFieldLabel">
|
||||||
<label for="password">{i18n.str`Password:`}</label>
|
<label for="password">{i18n.str`Password:`}</label>
|
||||||
</p>
|
</p>
|
||||||
@ -1561,50 +1514,48 @@ function LoginForm(Props: any): VNode {
|
|||||||
type="password"
|
type="password"
|
||||||
name="password"
|
name="password"
|
||||||
id="password"
|
id="password"
|
||||||
value={submitData && submitData.password}
|
value={password ?? ""}
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
required
|
required
|
||||||
onInput={(e): void => {
|
onInput={(e): void => {
|
||||||
submitDataSetter((submitData: any) => ({
|
setPassword(e.currentTarget.value);
|
||||||
...submitData,
|
|
||||||
password: e.currentTarget.value,
|
|
||||||
}));
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<ShowInputErrorLabel
|
||||||
|
message={errors?.password}
|
||||||
|
isDirty={password !== undefined}
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="pure-button pure-button-primary"
|
class="pure-button pure-button-primary"
|
||||||
disabled={!!errors}
|
disabled={!!errors}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (typeof submitData === "undefined") {
|
if (!username || !password) return;
|
||||||
console.log("login data is undefined", submitData);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!submitData.password || !submitData.username) {
|
|
||||||
console.log(
|
|
||||||
"username or password is the empty string",
|
|
||||||
submitData,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loginCall(
|
loginCall(
|
||||||
// Deep copy, to avoid the cleanup
|
{ username, password },
|
||||||
// below make data disappear.
|
|
||||||
{ ...submitData },
|
|
||||||
backendStateSetter,
|
backendStateSetter,
|
||||||
pageStateSetter,
|
pageStateSetter,
|
||||||
);
|
);
|
||||||
submitDataSetter({
|
setUsername(undefined);
|
||||||
password: "",
|
setPassword(undefined);
|
||||||
repeatPassword: "",
|
|
||||||
username: "",
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{i18n.str`Login`}
|
{i18n.str`Login`}
|
||||||
</button>
|
</button>
|
||||||
{RegistrationButton(Props)}
|
|
||||||
|
{bankUiSettings.allowRegistrations ? (
|
||||||
|
<button
|
||||||
|
class="pure-button pure-button-secondary btn-cancel"
|
||||||
|
onClick={() => {
|
||||||
|
route("/register");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n.str`Register`}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<div />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -1615,21 +1566,20 @@ function LoginForm(Props: any): VNode {
|
|||||||
* Collect and submit registration data.
|
* Collect and submit registration data.
|
||||||
*/
|
*/
|
||||||
function RegistrationForm(): VNode {
|
function RegistrationForm(): VNode {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
|
|
||||||
const [backendState, backendStateSetter] = useBackendState();
|
const [backendState, backendStateSetter] = useBackendState();
|
||||||
const { pageState, pageStateSetter } = usePageContext();
|
const { pageState, pageStateSetter } = usePageContext();
|
||||||
const [submitData, submitDataSetter] = useCredentialsRequestType();
|
const [username, setUsername] = useState<string | undefined>();
|
||||||
|
const [password, setPassword] = useState<string | undefined>();
|
||||||
|
const [repeatPassword, setRepeatPassword] = useState<string | undefined>();
|
||||||
|
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const errors = !submitData
|
const errors = undefinedIfEmpty({
|
||||||
? undefined
|
username: !username ? i18n.str`Missing username` : undefined,
|
||||||
: undefinedIfEmpty({
|
password: !password ? i18n.str`Missing password` : undefined,
|
||||||
username: !submitData.username ? i18n.str`Missing username` : undefined,
|
repeatPassword: !repeatPassword
|
||||||
password: !submitData.password ? i18n.str`Missing password` : undefined,
|
|
||||||
repeatPassword: !submitData.repeatPassword
|
|
||||||
? i18n.str`Missing password`
|
? i18n.str`Missing password`
|
||||||
: submitData.repeatPassword !== submitData.password
|
: repeatPassword !== password
|
||||||
? i18n.str`Password don't match`
|
? i18n.str`Password don't match`
|
||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
@ -1650,16 +1600,15 @@ function RegistrationForm(): VNode {
|
|||||||
name="register-un"
|
name="register-un"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Username"
|
placeholder="Username"
|
||||||
value={submitData && submitData.username}
|
value={username ?? ""}
|
||||||
required
|
|
||||||
onInput={(e): void => {
|
onInput={(e): void => {
|
||||||
submitDataSetter((submitData: any) => ({
|
setUsername(e.currentTarget.value);
|
||||||
...submitData,
|
|
||||||
username: e.currentTarget.value,
|
|
||||||
}));
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<br />
|
<ShowInputErrorLabel
|
||||||
|
message={errors?.username}
|
||||||
|
isDirty={username !== undefined}
|
||||||
|
/>
|
||||||
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
||||||
<label for="register-pw">{i18n.str`Password:`}</label>
|
<label for="register-pw">{i18n.str`Password:`}</label>
|
||||||
</p>
|
</p>
|
||||||
@ -1668,15 +1617,16 @@ function RegistrationForm(): VNode {
|
|||||||
name="register-pw"
|
name="register-pw"
|
||||||
id="register-pw"
|
id="register-pw"
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
value={submitData && submitData.password}
|
value={password ?? ""}
|
||||||
required
|
required
|
||||||
onInput={(e): void => {
|
onInput={(e): void => {
|
||||||
submitDataSetter((submitData: any) => ({
|
setPassword(e.currentTarget.value);
|
||||||
...submitData,
|
|
||||||
password: e.currentTarget.value,
|
|
||||||
}));
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<ShowInputErrorLabel
|
||||||
|
message={errors?.password}
|
||||||
|
isDirty={username !== undefined}
|
||||||
|
/>
|
||||||
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
|
||||||
<label for="register-repeat">{i18n.str`Repeat Password:`}</label>
|
<label for="register-repeat">{i18n.str`Repeat Password:`}</label>
|
||||||
</p>
|
</p>
|
||||||
@ -1686,57 +1636,31 @@ function RegistrationForm(): VNode {
|
|||||||
name="register-repeat"
|
name="register-repeat"
|
||||||
id="register-repeat"
|
id="register-repeat"
|
||||||
placeholder="Same password"
|
placeholder="Same password"
|
||||||
value={submitData && submitData.repeatPassword}
|
value={repeatPassword ?? ""}
|
||||||
required
|
required
|
||||||
onInput={(e): void => {
|
onInput={(e): void => {
|
||||||
submitDataSetter((submitData: any) => ({
|
setRepeatPassword(e.currentTarget.value);
|
||||||
...submitData,
|
|
||||||
repeatPassword: e.currentTarget.value,
|
|
||||||
}));
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
<ShowInputErrorLabel
|
||||||
|
message={errors?.repeatPassword}
|
||||||
|
isDirty={username !== undefined}
|
||||||
|
/>
|
||||||
<br />
|
<br />
|
||||||
{/*
|
|
||||||
<label for="phone">{i18n.str`Phone number:`}</label>
|
|
||||||
// FIXME: add input validation (must start with +, otherwise only numbers)
|
|
||||||
<input
|
|
||||||
name="phone"
|
|
||||||
id="phone"
|
|
||||||
type="phone"
|
|
||||||
placeholder="+CC-123456789"
|
|
||||||
value={submitData && submitData.phone}
|
|
||||||
required
|
|
||||||
onInput={(e): void => {
|
|
||||||
submitDataSetter((submitData: any) => ({
|
|
||||||
...submitData,
|
|
||||||
phone: e.currentTarget.value,
|
|
||||||
}))}} />
|
|
||||||
<br />
|
|
||||||
*/}
|
|
||||||
<button
|
<button
|
||||||
class="pure-button pure-button-primary btn-register"
|
class="pure-button pure-button-primary btn-register"
|
||||||
disabled={!!errors}
|
disabled={!!errors}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log("maybe submitting the registration..");
|
if (!username || !password) return;
|
||||||
if (!submitData) return;
|
|
||||||
registrationCall(
|
registrationCall(
|
||||||
{ ...submitData },
|
{ username, password },
|
||||||
backendStateSetter, // will store BE URL, if OK.
|
backendStateSetter, // will store BE URL, if OK.
|
||||||
pageStateSetter,
|
pageStateSetter,
|
||||||
);
|
);
|
||||||
console.log("Clearing the input data");
|
|
||||||
/**
|
setUsername(undefined);
|
||||||
* FIXME: clearing the data should be done by setting
|
setPassword(undefined);
|
||||||
* it to undefined, instead of the empty strings, just
|
setRepeatPassword(undefined);
|
||||||
* like done in the login function. Now set to the empty
|
|
||||||
* strings due to a non lively update of the <input> fields
|
|
||||||
* after setting to undefined.
|
|
||||||
*/
|
|
||||||
submitDataSetter({
|
|
||||||
username: "",
|
|
||||||
password: "",
|
|
||||||
repeatPassword: "",
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{i18n.str`Register`}
|
{i18n.str`Register`}
|
||||||
@ -1745,11 +1669,9 @@ function RegistrationForm(): VNode {
|
|||||||
<button
|
<button
|
||||||
class="pure-button pure-button-secondary btn-cancel"
|
class="pure-button pure-button-secondary btn-cancel"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
submitDataSetter({
|
setUsername(undefined);
|
||||||
username: "",
|
setPassword(undefined);
|
||||||
password: "",
|
setRepeatPassword(undefined);
|
||||||
repeatPassword: "",
|
|
||||||
});
|
|
||||||
route("/account");
|
route("/account");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user