Skip to content

Commit 8a4f365

Browse files
committed
ref:#187 14_FormValidation refactor
1 parent cca74be commit 8a4f365

11 files changed

Lines changed: 139 additions & 187 deletions

File tree

hooks/14_FormValidation/Readme.md

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Let's add validation support to this form.
44

5-
For this we will use lc-form-validation library
5+
For this we will use formik, fonk and fonk-formik library
66

77
Summary steps:
88

@@ -101,24 +101,6 @@ const validationSchema: ValidationSchema = {
101101
export const loginFormValidation = createFormikValidation(validationSchema);
102102
```
103103

104-
- Let's create now a class to hold the dataFormErrors.
105-
106-
_./src/pages/loginPage.viewmodel.ts_
107-
108-
```typescript
109-
import { FieldValidationResult } from "lc-form-validation";
110-
111-
export interface LoginFormErrors {
112-
login: FieldValidationResult;
113-
password: FieldValidationResult;
114-
}
115-
116-
export const createDefaultLoginFormErrors = (): LoginFormErrors => ({
117-
login: new FieldValidationResult(),
118-
password: new FieldValidationResult()
119-
});
120-
```
121-
122104
- Now let's go for the component side.
123105

124106
- First let's add the dataFormErrors to the state of the component.
@@ -128,7 +110,6 @@ _./src/pages/loginPage.tsx_
128110
```diff
129111
import { isValidLogin } from "../api/login";
130112
import { NotificationComponent } from "../common";
131-
+ import {LoginFormErrors, createDefaultLoginFormErrors} from './loginPage.viewmodel';
132113
```
133114

134115
_./src/pages/loginPage.tsx_
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
import {LoginEntity} from '../model/login';
1+
import { LoginEntity } from "../model/login";
22

33
// Just a fake loginAPI
4-
export const isValidLogin = (loginInfo : LoginEntity) : boolean =>
5-
(loginInfo.login === 'admin' && loginInfo.password === 'test');
4+
export const isValidLogin = (loginInfo: LoginEntity): Promise<boolean> =>
5+
new Promise((resolve) => {
6+
setTimeout(() => {
7+
// mock call
8+
resolve(loginInfo.login === "admin" && loginInfo.password === "test");
9+
}, 500);
10+
});

hooks/14_FormValidation/src/app.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import * as React from "react";
22
import { HashRouter, Switch, Route } from "react-router-dom";
3-
import { LoginPage } from "./pages/loginPage";
3+
import { LoginContainer } from "./pages/login.container";
44
import { PageB } from "./pages/pageB";
55

66
export const App = () => {
77
return (
88
<>
99
<HashRouter>
1010
<Switch>
11-
<Route exact={true} path="/" component={LoginPage} />
11+
<Route exact={true} path="/" component={LoginContainer} />
1212
<Route path="/pageB" component={PageB} />
1313
</Switch>
1414
</HashRouter>
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
export * from './notification';
2-
export * from './textFieldForm';
2+
export * from './textField.component';
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import * as React from "react";
2+
import { useField } from "formik";
3+
import MuiTextField, { TextFieldProps } from "@material-ui/core/TextField";
4+
5+
export const TextFieldComponent: React.FC<TextFieldProps> = (props) => {
6+
const [field, meta] = useField(props.name);
7+
const textFieldProps = Boolean(field) ? field : props;
8+
const hasError = Boolean(meta && meta.touched && meta.error);
9+
10+
return (
11+
<>
12+
<MuiTextField
13+
{...props}
14+
name={textFieldProps.name}
15+
onChange={textFieldProps.onChange}
16+
onBlur={textFieldProps.onBlur}
17+
value={textFieldProps.value}
18+
error={hasError}
19+
helperText={hasError ? meta.error : ""}
20+
fullWidth={true}
21+
margin="normal"
22+
/>
23+
</>
24+
);
25+
};

hooks/14_FormValidation/src/common/textFieldForm.tsx

Lines changed: 0 additions & 41 deletions
This file was deleted.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import * as React from "react";
2+
import { LoginEntity, createEmptyLogin } from "../model/login";
3+
import { TextFieldComponent } from "../common";
4+
import { Form } from "formik";
5+
import createStyles from "@material-ui/styles/createStyles";
6+
import makeStyles from "@material-ui/styles/makeStyles";
7+
import Button from "@material-ui/core/Button";
8+
import Card from "@material-ui/core/Card";
9+
import CardHeader from "@material-ui/core/CardHeader";
10+
import CardContent from "@material-ui/core/CardContent";
11+
import { loginFormValidation } from "./login.validation";
12+
import { Formik } from "formik";
13+
14+
interface PropsForm {
15+
onLogin: (login: LoginEntity) => void;
16+
}
17+
18+
// https://material-ui.com/styles/api/#makestyles-styles-options-hook
19+
const useFormStyles = makeStyles((theme) =>
20+
createStyles({
21+
formContainer: {
22+
display: "flex",
23+
flexDirection: "column",
24+
justifyContent: "center",
25+
},
26+
card: {
27+
maxWidth: 400,
28+
margin: "0 auto",
29+
},
30+
})
31+
);
32+
33+
export const LoginComponent: React.FC<PropsForm> = (props) => {
34+
const classes = useFormStyles();
35+
const { onLogin } = props;
36+
37+
return (
38+
<Card className={classes.card}>
39+
<CardHeader title="Login" />
40+
<CardContent>
41+
<Formik
42+
onSubmit={onLogin}
43+
initialValues={createEmptyLogin()}
44+
validate={loginFormValidation.validateForm}
45+
>
46+
{() => (
47+
<Form>
48+
<div className={classes.formContainer}>
49+
<TextFieldComponent label="Name" name="login" />
50+
<TextFieldComponent
51+
label="Password"
52+
type="password"
53+
name="password"
54+
/>
55+
<Button type="submit" variant="contained" color="primary">
56+
Login
57+
</Button>
58+
</div>
59+
</Form>
60+
)}
61+
</Formik>
62+
</CardContent>
63+
</Card>
64+
);
65+
};
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import * as React from "react";
2+
import { useHistory } from "react-router-dom";
3+
import { LoginEntity } from "../model/login";
4+
import { isValidLogin } from "../api/login";
5+
import { LoginComponent } from "./login.component";
6+
import { NotificationComponent } from "../common";
7+
8+
interface Props {}
9+
10+
export const LoginContainer: React.FC<Props> = (props) => {
11+
const history = useHistory();
12+
const [isShowAlert, setShowAlert] = React.useState(false);
13+
14+
const loginSucceeded = (isValid: boolean) => {
15+
if (isValid) {
16+
history.push("/pageB");
17+
} else {
18+
setShowAlert(true);
19+
}
20+
};
21+
22+
const handleLogin = (login: LoginEntity) => {
23+
isValidLogin(login).then(loginSucceeded);
24+
};
25+
26+
return (
27+
<>
28+
<LoginComponent onLogin={handleLogin} />
29+
<NotificationComponent
30+
show={isShowAlert}
31+
message="Invalid Form"
32+
onClose={() => setShowAlert(false)}
33+
/>
34+
;
35+
</>
36+
);
37+
};

hooks/14_FormValidation/src/pages/loginPage.validation.ts renamed to hooks/14_FormValidation/src/pages/login.validation.ts

File renamed without changes.

hooks/14_FormValidation/src/pages/loginFormComponent.tsx

Lines changed: 0 additions & 52 deletions
This file was deleted.

0 commit comments

Comments
 (0)