summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-12-07 10:53:06 -0300
committerSebastian <sebasjm@gmail.com>2022-12-07 16:08:15 -0300
commitac2f680f6805534fdebad41755d7e112a00cd15a (patch)
treebc6d1811ef213a00dc83989832eff8c1028b8f4b
parent2c04459a58c04fe7a6c6dc657c1d3fb58132a933 (diff)
downloadwallet-core-ac2f680f6805534fdebad41755d7e112a00cd15a.tar.gz
wallet-core-ac2f680f6805534fdebad41755d7e112a00cd15a.tar.bz2
wallet-core-ac2f680f6805534fdebad41755d7e112a00cd15a.zip
fix: show error message on login and registration form, prevent saving password on localstorage
-rw-r--r--packages/demobank-ui/src/pages/home/index.tsx240
1 files changed, 81 insertions, 159 deletions
diff --git a/packages/demobank-ui/src/pages/home/index.tsx b/packages/demobank-ui/src/pages/home/index.tsx
index 884113e85..9927f965c 100644
--- a/packages/demobank-ui/src/pages/home/index.tsx
+++ b/packages/demobank-ui/src/pages/home/index.tsx
@@ -214,32 +214,6 @@ function useWireTransferRequestType(
}
/**
- * 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.
*
* These functions aim at sanitizing the input received
@@ -597,7 +571,7 @@ async function createWithdrawalCall(
}
async function loginCall(
- req: CredentialsRequestType,
+ req: { username: string; password: string },
/**
* FIXME: figure out if the two following
* 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).
*/
async function registrationCall(
- req: CredentialsRequestType,
+ req: { username: string; password: string },
/**
* FIXME: figure out if the two following
* functions can be retrieved somewhat from
@@ -882,11 +856,7 @@ function ShowInputErrorLabel({
isDirty: boolean;
}): VNode {
if (message && isDirty)
- return (
- <div class="informational informational-fail" style={{ marginTop: 8 }}>
- {message}
- </div>
- );
+ return <div style={{ marginTop: 8, color: "red" }}>{message}</div>;
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 {
return Object.keys(obj).some((k) => (obj as any)[k] !== undefined)
? obj
@@ -1514,21 +1466,21 @@ function undefinedIfEmpty<T extends object>(obj: T): T | undefined {
/**
* Collect and submit login data.
*/
-function LoginForm(Props: any): VNode {
- const { backendStateSetter, pageStateSetter } = Props;
- const [submitData, submitDataSetter] = useCredentialsRequestType();
+function LoginForm(): VNode {
+ const [backendState, backendStateSetter] = useBackendState();
+ const { pageState, pageStateSetter } = usePageContext();
+ const [username, setUsername] = useState<string | undefined>();
+ const [password, setPassword] = useState<string | undefined>();
const { i18n } = useTranslationContext();
const ref = useRef<HTMLInputElement>(null);
useEffect(() => {
ref.current?.focus();
}, []);
- const errors = !submitData
- ? undefined
- : undefinedIfEmpty({
- username: !submitData.username ? i18n.str`Missing username` : undefined,
- password: !submitData.password ? i18n.str`Missing password` : undefined,
- });
+ const errors = undefinedIfEmpty({
+ username: !username ? i18n.str`Missing username` : undefined,
+ password: !password ? i18n.str`Missing password` : undefined,
+ });
return (
<div class="login-div">
@@ -1544,16 +1496,17 @@ function LoginForm(Props: any): VNode {
type="text"
name="username"
id="username"
- value={submitData && submitData.username}
+ value={username ?? ""}
placeholder="Username"
required
onInput={(e): void => {
- submitDataSetter((submitData: any) => ({
- ...submitData,
- username: e.currentTarget.value,
- }));
+ setUsername(e.currentTarget.value);
}}
/>
+ <ShowInputErrorLabel
+ message={errors?.username}
+ isDirty={username !== undefined}
+ />
<p class="passFieldLabel loginFieldLabel formFieldLabel">
<label for="password">{i18n.str`Password:`}</label>
</p>
@@ -1561,50 +1514,48 @@ function LoginForm(Props: any): VNode {
type="password"
name="password"
id="password"
- value={submitData && submitData.password}
+ value={password ?? ""}
placeholder="Password"
required
onInput={(e): void => {
- submitDataSetter((submitData: any) => ({
- ...submitData,
- password: e.currentTarget.value,
- }));
+ setPassword(e.currentTarget.value);
}}
/>
+ <ShowInputErrorLabel
+ message={errors?.password}
+ isDirty={password !== undefined}
+ />
<br />
<button
type="submit"
class="pure-button pure-button-primary"
disabled={!!errors}
onClick={() => {
- if (typeof submitData === "undefined") {
- console.log("login data is undefined", submitData);
- return;
- }
- if (!submitData.password || !submitData.username) {
- console.log(
- "username or password is the empty string",
- submitData,
- );
- return;
- }
+ if (!username || !password) return;
loginCall(
- // Deep copy, to avoid the cleanup
- // below make data disappear.
- { ...submitData },
+ { username, password },
backendStateSetter,
pageStateSetter,
);
- submitDataSetter({
- password: "",
- repeatPassword: "",
- username: "",
- });
+ setUsername(undefined);
+ setPassword(undefined);
}}
>
{i18n.str`Login`}
</button>
- {RegistrationButton(Props)}
+
+ {bankUiSettings.allowRegistrations ? (
+ <button
+ class="pure-button pure-button-secondary btn-cancel"
+ onClick={() => {
+ route("/register");
+ }}
+ >
+ {i18n.str`Register`}
+ </button>
+ ) : (
+ <div />
+ )}
</div>
</form>
</div>
@@ -1615,24 +1566,23 @@ function LoginForm(Props: any): VNode {
* Collect and submit registration data.
*/
function RegistrationForm(): VNode {
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
-
const [backendState, backendStateSetter] = useBackendState();
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 errors = !submitData
- ? undefined
- : undefinedIfEmpty({
- username: !submitData.username ? i18n.str`Missing username` : undefined,
- password: !submitData.password ? i18n.str`Missing password` : undefined,
- repeatPassword: !submitData.repeatPassword
- ? i18n.str`Missing password`
- : submitData.repeatPassword !== submitData.password
- ? i18n.str`Password don't match`
- : undefined,
- });
+ const errors = undefinedIfEmpty({
+ username: !username ? i18n.str`Missing username` : undefined,
+ password: !password ? i18n.str`Missing password` : undefined,
+ repeatPassword: !repeatPassword
+ ? i18n.str`Missing password`
+ : repeatPassword !== password
+ ? i18n.str`Password don't match`
+ : undefined,
+ });
return (
<Fragment>
@@ -1650,16 +1600,15 @@ function RegistrationForm(): VNode {
name="register-un"
type="text"
placeholder="Username"
- value={submitData && submitData.username}
- required
+ value={username ?? ""}
onInput={(e): void => {
- submitDataSetter((submitData: any) => ({
- ...submitData,
- username: e.currentTarget.value,
- }));
+ setUsername(e.currentTarget.value);
}}
/>
- <br />
+ <ShowInputErrorLabel
+ message={errors?.username}
+ isDirty={username !== undefined}
+ />
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
<label for="register-pw">{i18n.str`Password:`}</label>
</p>
@@ -1668,15 +1617,16 @@ function RegistrationForm(): VNode {
name="register-pw"
id="register-pw"
placeholder="Password"
- value={submitData && submitData.password}
+ value={password ?? ""}
required
onInput={(e): void => {
- submitDataSetter((submitData: any) => ({
- ...submitData,
- password: e.currentTarget.value,
- }));
+ setPassword(e.currentTarget.value);
}}
/>
+ <ShowInputErrorLabel
+ message={errors?.password}
+ isDirty={username !== undefined}
+ />
<p class="unameFieldLabel registerFieldLabel formFieldLabel">
<label for="register-repeat">{i18n.str`Repeat Password:`}</label>
</p>
@@ -1686,57 +1636,31 @@ function RegistrationForm(): VNode {
name="register-repeat"
id="register-repeat"
placeholder="Same password"
- value={submitData && submitData.repeatPassword}
+ value={repeatPassword ?? ""}
required
onInput={(e): void => {
- submitDataSetter((submitData: any) => ({
- ...submitData,
- repeatPassword: e.currentTarget.value,
- }));
+ setRepeatPassword(e.currentTarget.value);
}}
/>
+ <ShowInputErrorLabel
+ message={errors?.repeatPassword}
+ isDirty={username !== undefined}
+ />
<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
class="pure-button pure-button-primary btn-register"
disabled={!!errors}
onClick={() => {
- console.log("maybe submitting the registration..");
- if (!submitData) return;
+ if (!username || !password) return;
registrationCall(
- { ...submitData },
+ { username, password },
backendStateSetter, // will store BE URL, if OK.
pageStateSetter,
);
- console.log("Clearing the input data");
- /**
- * FIXME: clearing the data should be done by setting
- * it to undefined, instead of the empty strings, just
- * 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: "",
- });
+
+ setUsername(undefined);
+ setPassword(undefined);
+ setRepeatPassword(undefined);
}}
>
{i18n.str`Register`}
@@ -1745,11 +1669,9 @@ function RegistrationForm(): VNode {
<button
class="pure-button pure-button-secondary btn-cancel"
onClick={() => {
- submitDataSetter({
- username: "",
- password: "",
- repeatPassword: "",
- });
+ setUsername(undefined);
+ setPassword(undefined);
+ setRepeatPassword(undefined);
route("/account");
}}
>