feat: show sign-in/sign-up errors under input instead of alert (#904)

This commit is contained in:
Aman Harwara
2022-03-02 19:43:52 +05:30
committed by GitHub
parent c184ef2449
commit 6311c68712
4 changed files with 25 additions and 36 deletions

View File

@@ -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={

View File

@@ -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;
} }

View File

@@ -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'}

View File

@@ -74,7 +74,6 @@ const MenuPaneSelector: FunctionComponent<PaneSelectorProps> = observer(
setMenuPane={setMenuPane} setMenuPane={setMenuPane}
email={email} email={email}
password={password} password={password}
setPassword={setPassword}
/> />
); );
} }