diff --git a/README.md b/README.md index 5a14922c2dcfce233562b1b292fdc162c061488a..39b360a1e7a8a396baf2b0b094867eaf1f0081a9 100644 --- a/README.md +++ b/README.md @@ -48,3 +48,4 @@ yarn start [react calendar app](https://codesandbox.io/s/kkyvoj97pv?from-embed=&file=/src/index.js) +[Typescript cheatsheet](https://github.com/typescript-cheatsheets/react/blob/main/README.md#hooks) \ No newline at end of file diff --git a/package.json b/package.json index 99e22163dac6a4904005dfcd5ffbd20c7c02e327..abb1f096451196acb1e304f828b55ade781b56e4 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "private": true, "dependencies": { + "@hookform/devtools": "^2.2.1", "@material-ui/core": "^4.11.3", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", @@ -16,6 +17,7 @@ "eslint-config-airbnb-typescript": "^12.3.1", "react": "^17.0.1", "react-dom": "^17.0.1", + "react-hook-form": "^6.15.5", "react-router-dom": "^5.2.0", "react-scripts": "4.0.3", "typescript": "^4.1.2" diff --git a/src/components/AuthUser/SignInForm/SignInForm.tsx b/src/components/AuthUser/SignInForm/SignInForm.tsx index 344b6bfe2b02c9faee2b32f3d7babef32ca63a02..866b5df7501ad014e5db4d4382992c9139d47bf4 100644 --- a/src/components/AuthUser/SignInForm/SignInForm.tsx +++ b/src/components/AuthUser/SignInForm/SignInForm.tsx @@ -1,8 +1,8 @@ -import React, { useState } from 'react'; +import React, { FC } from 'react'; +import { useForm, Controller } from 'react-hook-form'; import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; -import TextField from '@material-ui/core/TextField'; -import Button from '@material-ui/core/Button'; -import { isEmailValid } from './emailValidator'; +import { TextField, Button } from '@material-ui/core'; +import { DevTool } from '@hookform/devtools'; const useStyles = makeStyles((theme: Theme) => createStyles({ @@ -20,69 +20,99 @@ const useStyles = makeStyles((theme: Theme) => }, }), ); - -export const SignInForm: React.FC = () => { - interface formData { +// TODO: real time form validation +export const SignInForm: FC = () => { + interface FormData { email: string; password: string; - errors: Array<string>; } - const defaultValues: formData = { + const defaultValues: FormData = { email: '', password: '', - errors: [], }; - const [formValues, setFormValues] = useState<formData>(defaultValues); - const handleSubmit = (event: React.FormEvent): void => { - event.preventDefault(); - const errors: Array<string> = []; - if (!isEmailValid(formValues.email)) errors.push('email'); - }; + const { control, register, errors, handleSubmit } = useForm<FormData>({ + mode: 'onChange', + reValidateMode: 'onChange', + defaultValues, + }); + const onSubmit: any = (values: FormData) => { + // Send data + }; const classes = useStyles(); - return ( - <form className={classes.form} onSubmit={handleSubmit} data-testid="Form"> - <TextField - variant="outlined" - margin="normal" - required - fullWidth - id="email" - label="Email Address" - name="email" - autoComplete="email" - autoFocus - onChange={(event) => - setFormValues({ ...formValues, email: String(event.target.value) }) - } - /> - <TextField - variant="outlined" - margin="normal" - required - fullWidth - name="password" - label="Password" - type="password" - id="password" - autoComplete="current-password" - onChange={(event) => - setFormValues({ ...formValues, password: String(event.target.value) }) - } - /> - <Button - type="submit" - fullWidth - variant="contained" - color="primary" - data-testid="Submit" - className={classes.submit} + <> + <form + className={classes.form} + onSubmit={handleSubmit(onSubmit)} + data-testid="Form" > - Sign In - </Button> - </form> + <Controller + name="email" + control={control} + defaultValues + rules={{ + required: true, + pattern: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, + }} + render={() => ( + <TextField + variant="outlined" + margin="normal" + required + fullWidth + id="email" + label="Email Address" + name="email" + autoComplete="email" + autoFocus + error={Boolean(errors.email)} + helperText={errors.email && 'Incorrect entry.'} + /> + )} + /> + + <Controller + name="password" + control={control} + defaultValues + rules={{ + required: true, + min: 8, + max: 60, + }} + render={() => ( + <TextField + variant="outlined" + margin="normal" + required + fullWidth + name="password" + label="Password" + type="password" + id="password" + autoComplete="password" + autoFocus + error={Boolean(errors.password)} + helperText={errors.password && 'Incorrect entry.'} + /> + )} + /> + + <Button + type="submit" + fullWidth + variant="contained" + color="primary" + data-testid="Submit" + className={classes.submit} + > + Sign In + </Button> + </form> + <DevTool control={control} /> {/* set up the dev tool */} + </> ); }; diff --git a/yarn.lock b/yarn.lock index 28d326ad701ecc03222f109d83b70ff5c6c57cb4..e7c9c40b88a418938ffeceadf8a7c415a7cc6727 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1512,7 +1512,7 @@ "@emotion/utils" "0.11.3" "@emotion/weak-memoize" "0.2.5" -"@emotion/core@^10.0.14", "@emotion/core@^10.0.16": +"@emotion/core@^10.0.14", "@emotion/core@^10.0.16", "@emotion/core@^10.0.28": version "10.1.1" resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.1.1.tgz#c956c1365f2f2481960064bcb8c4732e5fb612c3" integrity sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA== @@ -1576,7 +1576,7 @@ "@emotion/serialize" "^0.11.15" "@emotion/utils" "0.11.3" -"@emotion/styled@^10.0.14": +"@emotion/styled@^10.0.14", "@emotion/styled@^10.0.27": version "10.0.27" resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-10.0.27.tgz#12cb67e91f7ad7431e1875b1d83a94b814133eaf" integrity sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q== @@ -1805,6 +1805,18 @@ dependencies: "@hapi/hoek" "^9.0.0" +"@hookform/devtools@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@hookform/devtools/-/devtools-2.2.1.tgz#2d88414d375199e193c2611b770b194b7752a623" + integrity sha512-VQh4kqwUOpz9LCDzIP0aJ4qnD/ob8Gp09L8gDy++9XtL66z6g8kbCynUvBrJm4qbCNdH0M7/Spm3AUjJqUuFlA== + dependencies: + "@emotion/core" "^10.0.28" + "@emotion/styled" "^10.0.27" + "@types/lodash" "^4.14.152" + little-state-machine "^3.0.1" + lodash "^4.17.15" + react-simple-animate "^3.3.8" + "@hutson/parse-repository-url@^3.0.0": version "3.0.2" resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" @@ -2731,7 +2743,7 @@ dependencies: "@types/node" "*" -"@types/lodash@^4.14.92": +"@types/lodash@^4.14.152", "@types/lodash@^4.14.92": version "4.14.168" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008" integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q== @@ -11423,6 +11435,11 @@ listr2@^3.2.2: through "^2.3.8" wrap-ansi "^7.0.0" +little-state-machine@^3.0.1: + version "3.1.4" + resolved "https://registry.yarnpkg.com/little-state-machine/-/little-state-machine-3.1.4.tgz#b29c396f732976cc327a612ef9a7a53f3f3520ab" + integrity sha512-gYlLCj6oUME0NG34/2O0Ljy52qYYyYDJ5yiAuq2ijbaRlBKIqtQQkKkEYn0KfjYXCE693j+bdY22EyZin25Bhw== + load-cfg@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/load-cfg/-/load-cfg-2.1.0.tgz#230ef6950466df59be934363988d35eee48ce8b9" @@ -15135,6 +15152,11 @@ react-helmet-async@^1.0.4: react-fast-compare "^3.2.0" shallowequal "^1.1.0" +react-hook-form@^6.15.5: + version "6.15.5" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-6.15.5.tgz#c2578f9ce6a6df7b33015587d40cd880dc13e2db" + integrity sha512-so2jEPYKdVk1olMo+HQ9D9n1hVzaPPFO4wsjgSeZ964R7q7CHsYRbVF0PGBi83FcycA5482WHflasdwLIUVENg== + react-hot-loader@^4.12.21: version "4.13.0" resolved "https://registry.yarnpkg.com/react-hot-loader/-/react-hot-loader-4.13.0.tgz#c27e9408581c2a678f5316e69c061b226dc6a202" @@ -15288,6 +15310,11 @@ react-scripts@4.0.3: optionalDependencies: fsevents "^2.1.3" +react-simple-animate@^3.3.8: + version "3.3.11" + resolved "https://registry.yarnpkg.com/react-simple-animate/-/react-simple-animate-3.3.11.tgz#04bb03ffe707e4e7cab4e22a03a93f20415b39de" + integrity sha512-kt2SKJ4Gw3klTmRbik/9R741fPiVRVlxkXvV0c3uu8NqOtdc5ITis62WcdiKH6U5QhCjXNfLW9lrbQ4cAYujyA== + react-simple-code-editor@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/react-simple-code-editor/-/react-simple-code-editor-0.10.0.tgz#73e7ac550a928069715482aeb33ccba36efe2373"