From fa133c40edb633c63d37619682ba0771d4481ed9 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Fri, 28 Aug 2020 02:24:00 +0300 Subject: fix input validation errors --- src/containers/Registration/Registration.tsx | 103 ++++++++++++++++----------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 9bcea8e..7d2a758 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -1,10 +1,13 @@ import React, { useState, useRef } from 'react'; import { useHistory } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; -import TextField from '@material-ui/core/TextField'; -import Button from '@material-ui/core/Button'; -import CheckCircleIcon from '@material-ui/icons/CheckCircle'; -import InputAdornment from '@material-ui/core/InputAdornment'; +import { + TextField, + Button, + InputAdornment, + IconButton +} from '@material-ui/core'; +import { CheckCircle, Visibility, VisibilityOff } from '@material-ui/icons'; import { post } from '../../requests'; import { useAuth } from '../../hooks/useAuth'; @@ -35,18 +38,20 @@ const useStyles = makeStyles(theme => ({ } })); -const inputStyle = { WebkitBoxShadow: '0 0 0 1000px snow inset' }; - +interface ValidationStates { + validUsername: boolean | undefined; + validEmail: boolean | undefined; + validPassword: boolean | undefined; + showPassword: boolean; +} const Registration: React.FC = () => { - const errorOutputs = { - usernameError: 'Username is required', - emailError: 'Invalid email address', - passwordError: 'Should be at least 6 characters' - }; - const [errorPassword, setErrorPassword] = useState(false); - const [errorEmail, setErrorEmail] = useState(false); - const [errorUsername, setErrorUsername] = useState(false); + const [values, setValues] = useState({ + validUsername: undefined, + validEmail: undefined, + validPassword: undefined, + showPassword: false + }); const classes = useStyles(); const usernameRef = useRef(); @@ -55,11 +60,15 @@ const Registration: React.FC = () => { const { login } = useAuth(); const history = useHistory(); + const checkFromValidation = () => { + return values.validUsername && values.validEmail && values.validPassword; + }; + const handleSubmit = () => { const username = usernameRef.current?.value?.toLowerCase(); const password = passwordRef.current?.value; const email = emailRef.current?.value; - if (username && password) { + if (username && password && checkFromValidation()) { post('/users', { username, password, email }) .then(() => login(username, password)) .then(() => history.push(`/profile/${username}`)); @@ -70,14 +79,20 @@ const Registration: React.FC = () => { history.push('/login'); }; - const handleLoginChange = (e: React.ChangeEvent) => { - setErrorUsername(e.currentTarget.value.length === 0); + const handleClickShowPassword = () => { + setValues({ ...values, showPassword: !values.showPassword }); + }; + const handleMouseDownPassword = (event: React.MouseEvent) => { + event.preventDefault(); + }; + const handleUsernameChange = (e: React.ChangeEvent) => { + setValues({ ...values, validUsername: e.currentTarget.value.length > 0 }); }; const handleEmailChange = (e: React.ChangeEvent) => { - setErrorEmail(!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value)); + setValues({ ...values, validEmail: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value) }); }; const handlePasswordChange = (e: React.ChangeEvent) => { - setErrorPassword(e.currentTarget.value.length < 6); + setValues({ ...values, validPassword: e.currentTarget.value.length > 6 }); }; return ( @@ -87,46 +102,54 @@ const Registration: React.FC = () => { + {values.validUsername && values.validUsername !== undefined && } + + ) + }} /> - + {values.validEmail && values.validEmail !== undefined && } - ), - inputProps: { - style: inputStyle - } + ) }} /> - + + {values.showPassword ? : } + + {values.validPassword && values.validPassword !== undefined && } - ), - inputProps: { - style: inputStyle - } + ) }} /> -- cgit v1.2.3 From 4bbebc183e75e287e28d5b4369699d1bc40c0cd1 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Fri, 28 Aug 2020 18:40:23 +0300 Subject: feat: submit Form on button click --- src/containers/Registration/Registration.tsx | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 7d2a758..20bc283 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -1,4 +1,4 @@ -import React, { useState, useRef } from 'react'; +import React, {useState, useRef, FormEvent} from 'react'; import { useHistory } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; import { @@ -64,11 +64,13 @@ const Registration: React.FC = () => { return values.validUsername && values.validEmail && values.validPassword; }; - const handleSubmit = () => { + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); const username = usernameRef.current?.value?.toLowerCase(); const password = passwordRef.current?.value; const email = emailRef.current?.value; if (username && password && checkFromValidation()) { + console.log('yes'); post('/users', { username, password, email }) .then(() => login(username, password)) .then(() => history.push(`/profile/${username}`)); @@ -98,7 +100,7 @@ const Registration: React.FC = () => { return ( <>
Sign Up
-
+ { ) }} /> - +
Already have an account?
-- cgit v1.2.3 From b7be53c172869679cdfa65a44591c7bd9c5b9302 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Fri, 28 Aug 2020 18:46:47 +0300 Subject: separate validation state into 2 states and remove CheckCircle icon --- src/containers/Registration/Registration.tsx | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 20bc283..0746deb 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -38,20 +38,19 @@ const useStyles = makeStyles(theme => ({ } })); -interface ValidationStates { +interface errors { validUsername: boolean | undefined; validEmail: boolean | undefined; validPassword: boolean | undefined; - showPassword: boolean; } const Registration: React.FC = () => { - const [values, setValues] = useState({ + const [values, setValues] = useState({ validUsername: undefined, validEmail: undefined, validPassword: undefined, - showPassword: false }); + const [showPassword, setShowPassword] = useState(false); const classes = useStyles(); const usernameRef = useRef(); @@ -82,7 +81,7 @@ const Registration: React.FC = () => { }; const handleClickShowPassword = () => { - setValues({ ...values, showPassword: !values.showPassword }); + setShowPassword(prevState => !prevState); }; const handleMouseDownPassword = (event: React.MouseEvent) => { event.preventDefault(); @@ -108,13 +107,6 @@ const Registration: React.FC = () => { helperText={!values.validUsername && 'This field is required'} required onChange={handleUsernameChange} - InputProps={{ - endAdornment: ( - - {values.validUsername && values.validUsername !== undefined && } - - ) - }} /> { error={!values.validEmail} helperText={!values.validEmail && 'Invalid email address'} onChange={handleEmailChange} - InputProps={{ - endAdornment: ( - - {values.validEmail && values.validEmail !== undefined && } - - ) - }} /> { required error={!values.validPassword} helperText={!values.validPassword && 'Should be at least 6 characters'} - type={values.showPassword ? 'text' : 'password'} + type={showPassword ? 'text' : 'password'} onChange={handlePasswordChange} InputProps={{ endAdornment: ( @@ -147,7 +132,7 @@ const Registration: React.FC = () => { onClick={handleClickShowPassword} onMouseDown={handleMouseDownPassword} > - {values.showPassword ? : } + {showPassword ? : } {values.validPassword && values.validPassword !== undefined && } -- cgit v1.2.3 From 9c571fa6e99d3c5e271c5763d86bf4cdd702aebb Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Fri, 28 Aug 2020 18:47:40 +0300 Subject: change state name --- src/containers/Registration/Registration.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 0746deb..47b5947 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -38,14 +38,14 @@ const useStyles = makeStyles(theme => ({ } })); -interface errors { +interface ErrorStates { validUsername: boolean | undefined; validEmail: boolean | undefined; validPassword: boolean | undefined; } const Registration: React.FC = () => { - const [values, setValues] = useState({ + const [values, setValues] = useState({ validUsername: undefined, validEmail: undefined, validPassword: undefined, -- cgit v1.2.3 From da1854e8fd34245e2e9e4fd941320f08b1cc40e1 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Fri, 28 Aug 2020 18:55:34 +0300 Subject: add useMemo for check validity of the form --- src/containers/Registration/Registration.tsx | 41 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 47b5947..3269f6e 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -1,4 +1,4 @@ -import React, {useState, useRef, FormEvent} from 'react'; +import React, {useState, useRef, FormEvent, useMemo} from 'react'; import { useHistory } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; import { @@ -39,16 +39,16 @@ const useStyles = makeStyles(theme => ({ })); interface ErrorStates { - validUsername: boolean | undefined; - validEmail: boolean | undefined; - validPassword: boolean | undefined; + username: boolean | undefined; + email: boolean | undefined; + password: boolean | undefined; } const Registration: React.FC = () => { const [values, setValues] = useState({ - validUsername: undefined, - validEmail: undefined, - validPassword: undefined, + username: undefined, + email: undefined, + password: undefined, }); const [showPassword, setShowPassword] = useState(false); @@ -59,16 +59,16 @@ const Registration: React.FC = () => { const { login } = useAuth(); const history = useHistory(); - const checkFromValidation = () => { - return values.validUsername && values.validEmail && values.validPassword; - }; + const isValid = useMemo(() => { + return values.username && values.email && values.password; + },[values]); const handleSubmit = (event: FormEvent) => { event.preventDefault(); const username = usernameRef.current?.value?.toLowerCase(); const password = passwordRef.current?.value; const email = emailRef.current?.value; - if (username && password && checkFromValidation()) { + if (username && password && isValid) { console.log('yes'); post('/users', { username, password, email }) .then(() => login(username, password)) @@ -87,13 +87,13 @@ const Registration: React.FC = () => { event.preventDefault(); }; const handleUsernameChange = (e: React.ChangeEvent) => { - setValues({ ...values, validUsername: e.currentTarget.value.length > 0 }); + setValues({ ...values, username: e.currentTarget.value.length > 0 }); }; const handleEmailChange = (e: React.ChangeEvent) => { - setValues({ ...values, validEmail: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value) }); + setValues({ ...values, email: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value) }); }; const handlePasswordChange = (e: React.ChangeEvent) => { - setValues({ ...values, validPassword: e.currentTarget.value.length > 6 }); + setValues({ ...values, password: e.currentTarget.value.length > 6 }); }; return ( @@ -103,24 +103,24 @@ const Registration: React.FC = () => { { > {showPassword ? : } - {values.validPassword && values.validPassword !== undefined && } ) }} -- cgit v1.2.3 From 987c4ecc67dc3cd41d0db04727c942efe35d5c82 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Fri, 28 Aug 2020 19:21:11 +0300 Subject: change onChange to onBlur event --- src/containers/Registration/Registration.tsx | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 3269f6e..e250397 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -79,21 +79,29 @@ const Registration: React.FC = () => { const handleLogin = () => { history.push('/login'); }; - const handleClickShowPassword = () => { setShowPassword(prevState => !prevState); }; const handleMouseDownPassword = (event: React.MouseEvent) => { event.preventDefault(); }; - const handleUsernameChange = (e: React.ChangeEvent) => { - setValues({ ...values, username: e.currentTarget.value.length > 0 }); + const handleUsernameChange = (e: React.FocusEvent) => { + setValues({ + ...values, + username: e.currentTarget.value.length > 0 + }); }; - const handleEmailChange = (e: React.ChangeEvent) => { - setValues({ ...values, email: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value) }); + const handleEmailChange = (e: React.FocusEvent) => { + setValues({ + ...values, + email: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value) + }); }; - const handlePasswordChange = (e: React.ChangeEvent) => { - setValues({ ...values, password: e.currentTarget.value.length > 6 }); + const handlePasswordChange = (e: React.FocusEvent) => { + setValues({ + ...values, + password: e.currentTarget.value.length > 6 + }); }; return ( @@ -106,14 +114,14 @@ const Registration: React.FC = () => { error={!values.username} helperText={!values.username && 'This field is required'} required - onChange={handleUsernameChange} + onBlur={handleUsernameChange} /> { error={!values.password} helperText={!values.password && 'Should be at least 6 characters'} type={showPassword ? 'text' : 'password'} - onChange={handlePasswordChange} + onBlur={handlePasswordChange} InputProps={{ endAdornment: ( -- cgit v1.2.3 From be765bb98e19fdc755418cdf4d2eb19d0aa15ecd Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Fri, 28 Aug 2020 19:41:42 +0300 Subject: fix eslint errors --- src/containers/Registration/Registration.tsx | 42 +++++++++++++++------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index e250397..955d900 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -1,4 +1,9 @@ -import React, {useState, useRef, FormEvent, useMemo} from 'react'; +import React, { + useState, + useRef, + FormEvent, + useMemo +} from 'react'; import { useHistory } from 'react-router-dom'; import { makeStyles } from '@material-ui/core/styles'; import { @@ -7,7 +12,7 @@ import { InputAdornment, IconButton } from '@material-ui/core'; -import { CheckCircle, Visibility, VisibilityOff } from '@material-ui/icons'; +import { Visibility, VisibilityOff } from '@material-ui/icons'; import { post } from '../../requests'; import { useAuth } from '../../hooks/useAuth'; @@ -46,9 +51,9 @@ interface ErrorStates { const Registration: React.FC = () => { const [values, setValues] = useState({ - username: undefined, - email: undefined, - password: undefined, + username: false, + email: false, + password: false }); const [showPassword, setShowPassword] = useState(false); @@ -60,16 +65,15 @@ const Registration: React.FC = () => { const history = useHistory(); const isValid = useMemo(() => { - return values.username && values.email && values.password; - },[values]); + return !values.username && !values.email && !values.password; + }, [values]); - const handleSubmit = (event: FormEvent) => { + const handleSubmit = (event:FormEvent) => { event.preventDefault(); const username = usernameRef.current?.value?.toLowerCase(); const password = passwordRef.current?.value; const email = emailRef.current?.value; if (username && password && isValid) { - console.log('yes'); post('/users', { username, password, email }) .then(() => login(username, password)) .then(() => history.push(`/profile/${username}`)); @@ -88,19 +92,19 @@ const Registration: React.FC = () => { const handleUsernameChange = (e: React.FocusEvent) => { setValues({ ...values, - username: e.currentTarget.value.length > 0 + username: e.currentTarget.value.length === 0 }); }; const handleEmailChange = (e: React.FocusEvent) => { setValues({ ...values, - email: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value) + email: !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value) }); }; const handlePasswordChange = (e: React.FocusEvent) => { setValues({ ...values, - password: e.currentTarget.value.length > 6 + password: e.currentTarget.value.length < 6 }); }; @@ -111,24 +115,24 @@ const Registration: React.FC = () => { { ) }} /> - +
Already have an account?
-- cgit v1.2.3 From 421a1e8d73714dce004e7682dfa3c52ccdb0f71f Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Fri, 28 Aug 2020 20:15:25 +0300 Subject: convert username input to lowercase --- src/containers/Registration/Registration.tsx | 55 +++++++++++++++------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 955d900..ff9af60 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -44,13 +44,13 @@ const useStyles = makeStyles(theme => ({ })); interface ErrorStates { - username: boolean | undefined; - email: boolean | undefined; - password: boolean | undefined; + username: boolean; + email: boolean; + password: boolean; } const Registration: React.FC = () => { - const [values, setValues] = useState({ + const [errors, setErrors] = useState({ username: false, email: false, password: false @@ -65,10 +65,10 @@ const Registration: React.FC = () => { const history = useHistory(); const isValid = useMemo(() => { - return !values.username && !values.email && !values.password; - }, [values]); + return !errors.username && !errors.email && !errors.password; + }, [errors]); - const handleSubmit = (event:FormEvent) => { + const handleSubmit = (event: FormEvent) => { event.preventDefault(); const username = usernameRef.current?.value?.toLowerCase(); const password = passwordRef.current?.value; @@ -89,25 +89,29 @@ const Registration: React.FC = () => { const handleMouseDownPassword = (event: React.MouseEvent) => { event.preventDefault(); }; - const handleUsernameChange = (e: React.FocusEvent) => { - setValues({ - ...values, - username: e.currentTarget.value.length === 0 + const handleUsernameChange = (event: React.FocusEvent) => { + setErrors({ + ...errors, + username: event.currentTarget.value.length === 0 }); }; - const handleEmailChange = (e: React.FocusEvent) => { - setValues({ - ...values, - email: !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e.currentTarget.value) + const handleEmailChange = (event: React.FocusEvent) => { + setErrors({ + ...errors, + email: !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(event.currentTarget.value) }); }; - const handlePasswordChange = (e: React.FocusEvent) => { - setValues({ - ...values, - password: e.currentTarget.value.length < 6 + const handlePasswordChange = (event: React.FocusEvent) => { + setErrors({ + ...errors, + password: event.currentTarget.value.length < 6 }); }; + const handleToLowerCase = (e: React.ChangeEvent) => { + e.target.value = ("" + e.target.value).toLowerCase(); + }; + return ( <>
Sign Up
@@ -115,24 +119,25 @@ const Registration: React.FC = () => { Date: Fri, 28 Aug 2020 20:19:25 +0300 Subject: fix eslint errors --- src/containers/Registration/Registration.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index ff9af60..709d04e 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -109,7 +109,7 @@ const Registration: React.FC = () => { }; const handleToLowerCase = (e: React.ChangeEvent) => { - e.target.value = ("" + e.target.value).toLowerCase(); + e.target.value = e.target.value.toString().toLowerCase(); }; return ( -- cgit v1.2.3 From ae005b8444aacc4071512f38031043156b6854c4 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Sat, 29 Aug 2020 00:22:27 +0300 Subject: hide error state onFocue input --- src/containers/Registration/Registration.tsx | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 709d04e..e7c8874 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -44,16 +44,16 @@ const useStyles = makeStyles(theme => ({ })); interface ErrorStates { - username: boolean; - email: boolean; - password: boolean; + username: boolean | undefined; + email: boolean | undefined; + password: boolean | undefined; } const Registration: React.FC = () => { const [errors, setErrors] = useState({ - username: false, - email: false, - password: false + username: undefined, + email: undefined, + password: undefined }); const [showPassword, setShowPassword] = useState(false); @@ -112,6 +112,13 @@ const Registration: React.FC = () => { e.target.value = e.target.value.toString().toLowerCase(); }; + const handleFocus = (value: string) => () => { + setErrors({ + ...errors, + [value]: undefined + }); + }; + return ( <>
Sign Up
@@ -124,6 +131,7 @@ const Registration: React.FC = () => { required onBlur={handleUsernameChange} onInput={handleToLowerCase} + onFocus={handleFocus('username')} /> { error={errors.email} helperText={errors.email && 'Invalid email address'} onBlur={handleEmailChange} + onFocus={handleFocus('email')} /> { helperText={errors.password && 'Should be at least 6 characters'} type={showPassword ? 'text' : 'password'} onBlur={handlePasswordChange} + onFocus={handleFocus('password')} InputProps={{ endAdornment: ( -- cgit v1.2.3 From e3d230ffcc344b9027b19a136525f105149f0982 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Sat, 29 Aug 2020 02:20:22 +0300 Subject: add fixed height for inputs to avoid jumping errorText --- src/containers/Registration/Registration.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index e7c8874..422cf92 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -40,6 +40,9 @@ const useStyles = makeStyles(theme => ({ marginLeft: 10, color: 'green', cursor: 'pointer' + }, + textField: { + height: 70 } })); @@ -132,6 +135,7 @@ const Registration: React.FC = () => { onBlur={handleUsernameChange} onInput={handleToLowerCase} onFocus={handleFocus('username')} + className={classes.textField} /> { helperText={errors.email && 'Invalid email address'} onBlur={handleEmailChange} onFocus={handleFocus('email')} + className={classes.textField} /> { ) }} + className={classes.textField} /> -- cgit v1.2.3 From 935daf265d21f0c2ec34ce79ff468474c0a728d1 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 29 Aug 2020 14:29:13 +0300 Subject: chore: install formik and yup --- package-lock.json | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 5 ++- 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 9b4ef60..34a0fb0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1771,6 +1771,12 @@ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==" }, + "@types/yup": { + "version": "0.29.6", + "resolved": "https://registry.npmjs.org/@types/yup/-/yup-0.29.6.tgz", + "integrity": "sha512-YPDo5L5uHyxQ4UkyJST+33stD8Z6IT9fvmKyaPAGxkZ6q19foEi6sQGkmqBvzSyRPdstFEeJiS2rKuTn8rfO5g==", + "dev": true + }, "@typescript-eslint/eslint-plugin": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.1.0.tgz", @@ -4292,6 +4298,11 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, + "deepmerge": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.2.1.tgz", + "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==" + }, "default-gateway": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", @@ -5860,6 +5871,11 @@ } } }, + "fn-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fn-name/-/fn-name-3.0.0.tgz", + "integrity": "sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA==" + }, "follow-redirects": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", @@ -5928,6 +5944,32 @@ "mime-types": "^2.1.12" } }, + "formik": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/formik/-/formik-2.1.5.tgz", + "integrity": "sha512-bWpo3PiqVDYslvrRjTq0Isrm0mFXHiO33D8MS6t6dWcqSFGeYF52nlpCM2xwOJ6tRVRznDkL+zz/iHPL4LDuvQ==", + "requires": { + "deepmerge": "^2.1.1", + "hoist-non-react-statics": "^3.3.0", + "lodash": "^4.17.14", + "lodash-es": "^4.17.14", + "react-fast-compare": "^2.0.1", + "scheduler": "^0.18.0", + "tiny-warning": "^1.0.2", + "tslib": "^1.10.0" + }, + "dependencies": { + "scheduler": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.18.0.tgz", + "integrity": "sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + } + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -8089,6 +8131,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, + "lodash-es": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz", + "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==" + }, "lodash._reinterpolate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", @@ -10447,6 +10494,11 @@ "react-is": "^16.8.1" } }, + "property-expr": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.4.tgz", + "integrity": "sha512-sFPkHQjVKheDNnPvotjQmm3KD3uk1fWKUN7CrpdbwmUx3CrG3QiM8QpTSimvig5vTXmTvjz7+TDvXOI9+4rkcg==" + }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -10906,6 +10958,11 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz", "integrity": "sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==" }, + "react-fast-compare": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", + "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" + }, "react-icons": { "version": "3.10.0", "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-3.10.0.tgz", @@ -12935,6 +12992,11 @@ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" }, + "synchronous-promise": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/synchronous-promise/-/synchronous-promise-2.0.13.tgz", + "integrity": "sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA==" + }, "table": { "version": "5.4.6", "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", @@ -13247,6 +13309,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" }, + "toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=" + }, "tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -14719,6 +14786,30 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "yup": { + "version": "0.29.3", + "resolved": "https://registry.npmjs.org/yup/-/yup-0.29.3.tgz", + "integrity": "sha512-RNUGiZ/sQ37CkhzKFoedkeMfJM0vNQyaz+wRZJzxdKE7VfDeVKH8bb4rr7XhRLbHJz5hSjoDNwMEIaKhuMZ8gQ==", + "requires": { + "@babel/runtime": "^7.10.5", + "fn-name": "~3.0.0", + "lodash": "^4.17.15", + "lodash-es": "^4.17.11", + "property-expr": "^2.0.2", + "synchronous-promise": "^2.0.13", + "toposort": "^2.0.2" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", + "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + } + } } } } diff --git a/package.json b/package.json index abfcc76..472dabc 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "axios": "^0.19.2", "bluebird": "^3.7.2", "compressorjs": "^1.0.6", + "formik": "^2.1.5", "lodash": "^4.17.15", "notistack": "^0.9.17", "react": "^16.13.1", @@ -20,7 +21,8 @@ "react-virtualized": "^9.21.2", "swr": "^0.3.0", "typeface-roboto": "0.0.75", - "which-types": "^1.6.1" + "which-types": "^1.6.1", + "yup": "^0.29.3" }, "scripts": { "start": "react-scripts start", @@ -49,6 +51,7 @@ "@types/react-dom": "^16.9.8", "@types/react-router-dom": "^5.1.5", "@types/react-virtualized": "^9.21.10", + "@types/yup": "^0.29.6", "@typescript-eslint/eslint-plugin": "^3.1.0", "@typescript-eslint/parser": "^3.1.0", "eslint": "^6.8.0", -- cgit v1.2.3 From 868e380262dcef15d9645ceb912d18701ecb61fb Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 29 Aug 2020 14:29:28 +0300 Subject: feat: use yup and formik --- src/containers/Registration/Registration.tsx | 203 +++++++++++---------------- 1 file changed, 84 insertions(+), 119 deletions(-) diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index 422cf92..b5c56e6 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -1,10 +1,7 @@ -import React, { - useState, - useRef, - FormEvent, - useMemo -} from 'react'; +import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; +import { Formik, Form, Field } from 'formik'; +import * as Yup from 'yup'; import { makeStyles } from '@material-ui/core/styles'; import { TextField, @@ -16,6 +13,22 @@ import { Visibility, VisibilityOff } from '@material-ui/icons'; import { post } from '../../requests'; import { useAuth } from '../../hooks/useAuth'; +interface Fields { + username: string; + email: string; + password: string; +} + +const validationSchema = Yup.object({ + username: Yup.string() + .required('This field is required'), + email: Yup.string() + .email('Invalid email address') + .required('This field is required'), + password: Yup.string() + .min(6, 'Should be at least 6 characters') + .required('This field is required'), +}); const useStyles = makeStyles(theme => ({ root: { @@ -42,137 +55,89 @@ const useStyles = makeStyles(theme => ({ cursor: 'pointer' }, textField: { - height: 70 + height: theme.spacing(8) } })); -interface ErrorStates { - username: boolean | undefined; - email: boolean | undefined; - password: boolean | undefined; -} - const Registration: React.FC = () => { - const [errors, setErrors] = useState({ - username: undefined, - email: undefined, - password: undefined - }); - const [showPassword, setShowPassword] = useState(false); - const classes = useStyles(); - const usernameRef = useRef(); - const emailRef = useRef(); - const passwordRef = useRef(); const { login } = useAuth(); const history = useHistory(); - - const isValid = useMemo(() => { - return !errors.username && !errors.email && !errors.password; - }, [errors]); - - const handleSubmit = (event: FormEvent) => { - event.preventDefault(); - const username = usernameRef.current?.value?.toLowerCase(); - const password = passwordRef.current?.value; - const email = emailRef.current?.value; - if (username && password && isValid) { - post('/users', { username, password, email }) - .then(() => login(username, password)) - .then(() => history.push(`/profile/${username}`)); - } - }; + const [showPassword, setShowPassword] = useState(false); const handleLogin = () => { history.push('/login'); }; - const handleClickShowPassword = () => { - setShowPassword(prevState => !prevState); - }; - const handleMouseDownPassword = (event: React.MouseEvent) => { - event.preventDefault(); - }; - const handleUsernameChange = (event: React.FocusEvent) => { - setErrors({ - ...errors, - username: event.currentTarget.value.length === 0 - }); - }; - const handleEmailChange = (event: React.FocusEvent) => { - setErrors({ - ...errors, - email: !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(event.currentTarget.value) - }); - }; - const handlePasswordChange = (event: React.FocusEvent) => { - setErrors({ - ...errors, - password: event.currentTarget.value.length < 6 - }); - }; - const handleToLowerCase = (e: React.ChangeEvent) => { - e.target.value = e.target.value.toString().toLowerCase(); - }; + const handleSubmit = ({ username, email, password }: Fields) => { + post('/users', { username, email, password }) + .then(() => login(username, password)) + .then(() => history.push(`/profile/${username}`)); + } - const handleFocus = (value: string) => () => { - setErrors({ - ...errors, - [value]: undefined - }); + const handleClickShowPassword = () => { + setShowPassword(prevState => !prevState); }; return ( <>
Sign Up
-
- - - - - {showPassword ? : } - - - ) - }} - className={classes.textField} - /> - - + + {({ values, errors, touched, isSubmitting }) => ( +
+ + + + + {showPassword ? : } + + + ) + }} + className={classes.textField} + /> + + + )} +
Already have an account?
Date: Sat, 29 Aug 2020 15:30:48 +0300 Subject: feat: use Formik in Login form --- src/containers/Login/Login.tsx | 104 +++++++++++++++++---------- src/containers/Registration/Registration.tsx | 17 ++--- 2 files changed, 72 insertions(+), 49 deletions(-) diff --git a/src/containers/Login/Login.tsx b/src/containers/Login/Login.tsx index bec0db5..9814d01 100644 --- a/src/containers/Login/Login.tsx +++ b/src/containers/Login/Login.tsx @@ -1,14 +1,24 @@ -import React, { useState, useRef } from 'react'; +import React, { useState } from 'react'; import { useHistory } from 'react-router-dom'; +import { Formik, Form, Field } from 'formik'; import { makeStyles } from '@material-ui/core/styles'; import { TextField, Button, FormControlLabel, - Switch + Switch, + InputAdornment, + IconButton } from '@material-ui/core'; +import { Visibility, VisibilityOff } from '@material-ui/icons'; import { useAuth } from '../../hooks/useAuth'; +interface Fields { + username: string; + password: string; + remember: boolean; +} + const useStyles = makeStyles(theme => ({ root: { '& > *': { @@ -37,54 +47,76 @@ const useStyles = makeStyles(theme => ({ const Login: React.FC = () => { const [error, setError] = useState(false); - const [remember, setRemember] = useState(true); + const [showPassword, setShowPassword] = useState(false); const classes = useStyles(); - const nameRef = useRef(); - const passwordRef = useRef(); const { login } = useAuth(); const history = useHistory(); - const handleCheck = () => { - setRemember(!remember); - }; - - const handleSubmit = async () => { - const name = nameRef.current?.value?.toLowerCase(); - const password = passwordRef.current?.value; - if (name && password) { - login(name, password, remember).then(success => { - if (success) history.push(`/profile/${name}`); + const handleSubmit = async ({ username, password, remember }: Fields) => { + console.log({ username, password, remember }) + if (username && password) { + login(username, password, remember).then(success => { + if (success) history.push(`/profile/${username}`); else setError(true); }); - } + } else setError(true); }; - const handleRegistration = () => { history.push('/registration'); }; + const toggleShowPassword = () => { + setShowPassword(prevState => !prevState); + }; + return ( <>
Sign In
-
- - - } - label="Remember me" - /> - - + + {({ values, touched, isSubmitting }) => ( +
+ + + + {showPassword ? : } + + + ) + }} + /> + } + /> + + + )} +
{'Don\'t have an account?'}
({ color: 'green', cursor: 'pointer' }, - textField: { - height: theme.spacing(8) - } })); const Registration: React.FC = () => { @@ -75,7 +73,7 @@ const Registration: React.FC = () => { .then(() => history.push(`/profile/${username}`)); } - const handleClickShowPassword = () => { + const toggleShowPassword = () => { setShowPassword(prevState => !prevState); }; @@ -88,7 +86,7 @@ const Registration: React.FC = () => { onSubmit={handleSubmit} > {({ values, errors, touched, isSubmitting }) => ( -
+ { error={touched.username && !!errors.username} helperText={touched.username && errors.username} required - className={classes.textField} as={TextField} /> { error={touched.email && !!errors.email} helperText={touched.email && errors.email} required - className={classes.textField} as={TextField} /> { InputProps={{ endAdornment: ( - + {showPassword ? : } ) }} - className={classes.textField} /> -- cgit v1.2.3 From 9ec578406ad78f3ded1332ecd331c89c32059784 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 29 Aug 2020 15:33:50 +0300 Subject: style: remove object-curly-newline eslint rule --- .eslintrc.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.json b/.eslintrc.json index 75a787c..479e04f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -21,6 +21,7 @@ "no-cond-assign": 0, "no-nested-ternary": 0, "linebreak-style": 0, + "object-curly-newline": 0, "react/prop-types": 0, "react/no-children-prop": 0, "react/no-danger": 0, -- cgit v1.2.3 From b7aed6ed7df2cea67924d34154671afb75edb7c2 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 29 Aug 2020 15:34:17 +0300 Subject: fix: resovle eslint errors --- src/containers/Login/Login.tsx | 9 ++------- src/containers/Registration/Registration.tsx | 8 ++++---- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/containers/Login/Login.tsx b/src/containers/Login/Login.tsx index 9814d01..3d58c63 100644 --- a/src/containers/Login/Login.tsx +++ b/src/containers/Login/Login.tsx @@ -53,7 +53,6 @@ const Login: React.FC = () => { const history = useHistory(); const handleSubmit = async ({ username, password, remember }: Fields) => { - console.log({ username, password, remember }) if (username && password) { login(username, password, remember).then(success => { if (success) history.push(`/profile/${username}`); @@ -76,7 +75,7 @@ const Login: React.FC = () => { initialValues={{ username: '', password: '', remember: true }} onSubmit={handleSubmit} > - {({ values, touched, isSubmitting }) => ( + {({ values, isSubmitting }) => (
{ InputProps={{ endAdornment: ( - + {showPassword ? : } diff --git a/src/containers/Registration/Registration.tsx b/src/containers/Registration/Registration.tsx index fb2dc8c..a3aedb3 100644 --- a/src/containers/Registration/Registration.tsx +++ b/src/containers/Registration/Registration.tsx @@ -28,7 +28,7 @@ const validationSchema = Yup.object({ .required('This field is required'), password: Yup.string() .min(6, 'Should be at least 6 characters') - .required('This field is required'), + .required('This field is required') }); const useStyles = makeStyles(theme => ({ @@ -54,7 +54,7 @@ const useStyles = makeStyles(theme => ({ marginLeft: 10, color: 'green', cursor: 'pointer' - }, + } })); const Registration: React.FC = () => { @@ -71,7 +71,7 @@ const Registration: React.FC = () => { post('/users', { username, email, password }) .then(() => login(username, password)) .then(() => history.push(`/profile/${username}`)); - } + }; const toggleShowPassword = () => { setShowPassword(prevState => !prevState); @@ -118,7 +118,7 @@ const Registration: React.FC = () => { InputProps={{ endAdornment: ( - + {showPassword ? : } -- cgit v1.2.3 From 3c4f51295ec4ccbed37d2faf8fd751608fc48843 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sat, 29 Aug 2020 15:34:29 +0300 Subject: chore: v1.2.5 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 34a0fb0..d80d20f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "which", - "version": "1.2.4", + "version": "1.2.5", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 472dabc..2bb2500 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "which", - "version": "1.2.4", + "version": "1.2.5", "homepage": "https://which-ecosystem.github.io/", "dependencies": { "@material-ui/core": "^4.10.1", -- cgit v1.2.3