feat: show sign-in/sign-up errors under input instead of alert (#904)
This commit is contained in:
@@ -3,7 +3,7 @@ import { WebApplication } from '@/ui_models/application';
|
|||||||
import { AppState } from '@/ui_models/app_state';
|
import { AppState } from '@/ui_models/app_state';
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import { FunctionComponent } from 'preact';
|
import { FunctionComponent } from 'preact';
|
||||||
import { StateUpdater, useEffect, useRef, useState } from 'preact/hooks';
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||||
import { AccountMenuPane } from '.';
|
import { AccountMenuPane } from '.';
|
||||||
import { Button } from '../Button';
|
import { Button } from '../Button';
|
||||||
import { Checkbox } from '../Checkbox';
|
import { Checkbox } from '../Checkbox';
|
||||||
@@ -17,22 +17,22 @@ type Props = {
|
|||||||
setMenuPane: (pane: AccountMenuPane) => void;
|
setMenuPane: (pane: AccountMenuPane) => void;
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
setPassword: StateUpdater<string>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ConfirmPassword: FunctionComponent<Props> = observer(
|
export const ConfirmPassword: FunctionComponent<Props> = observer(
|
||||||
({ application, appState, setMenuPane, email, password, setPassword }) => {
|
({ application, appState, setMenuPane, email, password }) => {
|
||||||
const { notesAndTagsCount } = appState.accountMenu;
|
const { notesAndTagsCount } = appState.accountMenu;
|
||||||
const [confirmPassword, setConfirmPassword] = useState('');
|
const [confirmPassword, setConfirmPassword] = useState('');
|
||||||
const [showPassword, setShowPassword] = useState(false);
|
const [showPassword, setShowPassword] = useState(false);
|
||||||
const [isRegistering, setIsRegistering] = useState(false);
|
const [isRegistering, setIsRegistering] = useState(false);
|
||||||
const [isEphemeral, setIsEphemeral] = useState(false);
|
const [isEphemeral, setIsEphemeral] = useState(false);
|
||||||
const [shouldMergeLocal, setShouldMergeLocal] = useState(true);
|
const [shouldMergeLocal, setShouldMergeLocal] = useState(true);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
|
||||||
const passwordInputRef = useRef<HTMLInputElement>(null);
|
const passwordInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
passwordInputRef?.current?.focus();
|
passwordInputRef.current?.focus();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handlePasswordChange = (e: Event) => {
|
const handlePasswordChange = (e: Event) => {
|
||||||
@@ -50,6 +50,9 @@ export const ConfirmPassword: FunctionComponent<Props> = observer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleKeyDown = (e: KeyboardEvent) => {
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (error.length) {
|
||||||
|
setError('');
|
||||||
|
}
|
||||||
if (e.key === 'Enter') {
|
if (e.key === 'Enter') {
|
||||||
handleConfirmFormSubmit(e);
|
handleConfirmFormSubmit(e);
|
||||||
}
|
}
|
||||||
@@ -59,7 +62,7 @@ export const ConfirmPassword: FunctionComponent<Props> = observer(
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!password) {
|
if (!password) {
|
||||||
passwordInputRef?.current!.focus();
|
passwordInputRef.current?.focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,21 +79,15 @@ export const ConfirmPassword: FunctionComponent<Props> = observer(
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
application.alertService.alert(err).finally(() => {
|
setError(err.message);
|
||||||
setPassword('');
|
|
||||||
handleGoBack();
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setIsRegistering(false);
|
setIsRegistering(false);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
application.alertService
|
setError(STRING_NON_MATCHING_PASSWORDS);
|
||||||
.alert(STRING_NON_MATCHING_PASSWORDS)
|
setConfirmPassword('');
|
||||||
.finally(() => {
|
passwordInputRef.current?.focus();
|
||||||
setConfirmPassword('');
|
|
||||||
passwordInputRef?.current!.focus();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -138,6 +135,7 @@ export const ConfirmPassword: FunctionComponent<Props> = observer(
|
|||||||
ref={passwordInputRef}
|
ref={passwordInputRef}
|
||||||
disabled={isRegistering}
|
disabled={isRegistering}
|
||||||
/>
|
/>
|
||||||
|
{error ? <div className="color-dark-red my-2">{error}</div> : null}
|
||||||
<Button
|
<Button
|
||||||
className="btn-w-full mt-1 mb-3"
|
className="btn-w-full mt-1 mb-3"
|
||||||
label={
|
label={
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export const CreateAccount: FunctionComponent<Props> = observer(
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (emailInputRef.current) {
|
if (emailInputRef.current) {
|
||||||
emailInputRef.current!.focus();
|
emailInputRef.current?.focus();
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -62,12 +62,12 @@ export const CreateAccount: FunctionComponent<Props> = observer(
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!email || email.length === 0) {
|
if (!email || email.length === 0) {
|
||||||
emailInputRef?.current!.focus();
|
emailInputRef.current?.focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!password || password.length === 0) {
|
if (!password || password.length === 0) {
|
||||||
passwordInputRef?.current!.focus();
|
passwordInputRef.current?.focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const SignInPane: FunctionComponent<Props> = observer(
|
|||||||
const { notesAndTagsCount } = appState.accountMenu;
|
const { notesAndTagsCount } = appState.accountMenu;
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [isInvalid, setIsInvalid] = useState(false);
|
const [error, setError] = useState('');
|
||||||
const [isEphemeral, setIsEphemeral] = useState(false);
|
const [isEphemeral, setIsEphemeral] = useState(false);
|
||||||
const [isStrictSignin, setIsStrictSignin] = useState(false);
|
const [isStrictSignin, setIsStrictSignin] = useState(false);
|
||||||
const [isSigningIn, setIsSigningIn] = useState(false);
|
const [isSigningIn, setIsSigningIn] = useState(false);
|
||||||
@@ -44,8 +44,8 @@ export const SignInPane: FunctionComponent<Props> = observer(
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const resetInvalid = () => {
|
const resetInvalid = () => {
|
||||||
if (isInvalid) {
|
if (error.length) {
|
||||||
setIsInvalid(false);
|
setError('');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -56,8 +56,8 @@ export const SignInPane: FunctionComponent<Props> = observer(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePasswordChange = (e: Event) => {
|
const handlePasswordChange = (e: Event) => {
|
||||||
if (isInvalid) {
|
if (error.length) {
|
||||||
setIsInvalid(false);
|
setError('');
|
||||||
}
|
}
|
||||||
if (e.target instanceof HTMLInputElement) {
|
if (e.target instanceof HTMLInputElement) {
|
||||||
setPassword(e.target.value);
|
setPassword(e.target.value);
|
||||||
@@ -91,11 +91,7 @@ export const SignInPane: FunctionComponent<Props> = observer(
|
|||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
if (err.toString().includes('Invalid email or password')) {
|
setError(err.message ?? err.toString());
|
||||||
setIsInvalid(true);
|
|
||||||
} else {
|
|
||||||
application.alertService.alert(err);
|
|
||||||
}
|
|
||||||
setPassword('');
|
setPassword('');
|
||||||
passwordInputRef?.current?.blur();
|
passwordInputRef?.current?.blur();
|
||||||
})
|
})
|
||||||
@@ -141,7 +137,7 @@ export const SignInPane: FunctionComponent<Props> = observer(
|
|||||||
</div>
|
</div>
|
||||||
<div className="px-3 mb-1">
|
<div className="px-3 mb-1">
|
||||||
<InputWithIcon
|
<InputWithIcon
|
||||||
className={`mb-2 ${isInvalid ? 'border-dark-red' : null}`}
|
className={`mb-2 ${error ? 'border-dark-red' : null}`}
|
||||||
icon="email"
|
icon="email"
|
||||||
inputType="email"
|
inputType="email"
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
@@ -153,7 +149,7 @@ export const SignInPane: FunctionComponent<Props> = observer(
|
|||||||
ref={emailInputRef}
|
ref={emailInputRef}
|
||||||
/>
|
/>
|
||||||
<InputWithIcon
|
<InputWithIcon
|
||||||
className={`mb-2 ${isInvalid ? 'border-dark-red' : null}`}
|
className={`mb-2 ${error ? 'border-dark-red' : null}`}
|
||||||
icon="password"
|
icon="password"
|
||||||
inputType={showPassword ? 'text' : 'password'}
|
inputType={showPassword ? 'text' : 'password'}
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
@@ -171,11 +167,7 @@ export const SignInPane: FunctionComponent<Props> = observer(
|
|||||||
}}
|
}}
|
||||||
ref={passwordInputRef}
|
ref={passwordInputRef}
|
||||||
/>
|
/>
|
||||||
{isInvalid ? (
|
{error ? <div className="color-dark-red my-2">{error}</div> : null}
|
||||||
<div className="color-dark-red my-2">
|
|
||||||
Invalid email or password.
|
|
||||||
</div>
|
|
||||||
) : null}
|
|
||||||
<Button
|
<Button
|
||||||
className="btn-w-full mt-1 mb-3"
|
className="btn-w-full mt-1 mb-3"
|
||||||
label={isSigningIn ? 'Signing in...' : 'Sign in'}
|
label={isSigningIn ? 'Signing in...' : 'Sign in'}
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ const MenuPaneSelector: FunctionComponent<PaneSelectorProps> = observer(
|
|||||||
setMenuPane={setMenuPane}
|
setMenuPane={setMenuPane}
|
||||||
email={email}
|
email={email}
|
||||||
password={password}
|
password={password}
|
||||||
setPassword={setPassword}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user