1
- import { Box , Button , Stack , TextField , Typography } from "@mui/material" ;
1
+ import { Box , Button , Stack , Typography } from "@mui/material" ;
2
2
import SignUpSvg from "../../assets/signup.svg?react" ;
3
- import { useState } from "react" ;
4
3
import { useNavigate } from "react-router-dom" ;
5
4
import { useAuth } from "../../contexts/AuthContext" ;
5
+ import CustomTextField from "../../components/CustomTextField" ;
6
+ import { emailValidator , nameValidator , passwordValidator , usernameValidator } from "../../utils/validators" ;
7
+ import { useRef , useState } from "react" ;
6
8
7
9
const SignUp : React . FC = ( ) => {
8
- const [ firstName , setFirstName ] = useState < string > ( "" ) ;
9
- const [ lastName , setLastName ] = useState < string > ( "" ) ;
10
- const [ username , setUsername ] = useState < string > ( "" ) ;
11
- const [ email , setEmail ] = useState < string > ( "" ) ;
12
- const [ password , setPassword ] = useState < string > ( "" ) ;
13
10
const navigate = useNavigate ( ) ;
14
-
15
11
const auth = useAuth ( ) ;
16
12
if ( ! auth ) {
17
13
throw new Error ( "useAuth() must be used within AuthProvider" ) ;
18
14
}
19
15
const { signup } = auth ;
20
16
17
+ const formValues = useRef ( { firstName : "" , lastName : "" , username : "" , email : "" , password : "" } ) ;
18
+ const formValidity = useRef ( { firstName : false , lastName : false , username : false , email : false , password : false } ) ;
19
+ const [ emptyFields , setEmptyFields ] = useState < { [ key : string ] : boolean } > ( {
20
+ firstName : false ,
21
+ lastName : false ,
22
+ username : false ,
23
+ email : false ,
24
+ password : false ,
25
+ } ) ;
26
+
27
+ const handleInputChange = ( field : keyof typeof formValues . current , value : string , isValid : boolean ) => {
28
+ formValues . current [ field ] = value ;
29
+ formValidity . current [ field ] = isValid ;
30
+ setEmptyFields ( ( prevState ) => ( { ...prevState , [ field ] : ! value } ) ) ;
31
+ } ;
32
+
33
+ const handleSignUp = ( event : React . FormEvent < HTMLFormElement > ) => {
34
+ event . preventDefault ( ) ;
35
+
36
+ if ( ! Object . values ( formValidity . current ) . every ( ( isValid ) => isValid ) ) {
37
+ // Mark untouched required fields red
38
+ Object . entries ( formValues . current ) . forEach ( ( [ field , value ] ) => {
39
+ setEmptyFields ( ( prevState ) => ( { ...prevState , [ field ] : ! value } ) ) ;
40
+ } ) ;
41
+ return ;
42
+ }
43
+
44
+ const { firstName, lastName, username, email, password } = formValues . current ;
45
+ signup ( firstName , lastName , username , email , password ) ;
46
+ } ;
47
+
21
48
return (
22
49
< Box
23
50
sx = { {
@@ -44,71 +71,65 @@ const SignUp: React.FC = () => {
44
71
>
45
72
PeerPrep
46
73
</ Typography >
47
- < Stack
74
+ < Stack
75
+ component = "form"
48
76
direction = "column"
49
77
spacing = { 1.5 }
50
78
sx = { ( theme ) => ( {
51
79
marginTop : theme . spacing ( 2 ) ,
52
80
marginBottom : theme . spacing ( 2 ) ,
53
81
} ) }
82
+ onSubmit = { handleSignUp }
83
+ noValidate
54
84
>
55
- < TextField
85
+ < CustomTextField
56
86
label = "First Name"
57
- variant = "outlined"
58
87
size = "small"
59
- onChange = { ( input ) => setFirstName ( input . target . value ) }
60
- slotProps = { {
61
-
62
- } }
88
+ required
89
+ emptyField = { emptyFields . firstName }
90
+ validator = { nameValidator }
91
+ onChange = { ( value , isValid ) => handleInputChange ( "firstName" , value , isValid ) }
63
92
/>
64
- < TextField
93
+ < CustomTextField
65
94
label = "Last Name"
66
- variant = "outlined"
67
95
size = "small"
68
- onChange = { ( input ) => setLastName ( input . target . value ) }
69
- slotProps = { {
70
-
71
- } }
96
+ required
97
+ emptyField = { emptyFields . lastName }
98
+ validator = { nameValidator }
99
+ onChange = { ( value , isValid ) => handleInputChange ( "lastName" , value , isValid ) }
72
100
/>
73
- < TextField
101
+ < CustomTextField
74
102
label = "Username"
75
- variant = "outlined"
76
103
size = "small"
77
- onChange = { ( input ) => setUsername ( input . target . value ) }
78
- slotProps = { {
79
-
80
- } }
104
+ required
105
+ emptyField = { emptyFields . username }
106
+ validator = { usernameValidator }
107
+ onChange = { ( value , isValid ) => handleInputChange ( "username" , value , isValid ) }
81
108
/>
82
- < TextField
109
+ < CustomTextField
83
110
label = "Email"
84
- variant = "outlined"
85
111
size = "small"
86
- onChange = { ( input ) => setEmail ( input . target . value ) }
87
- slotProps = { {
88
-
89
- } }
112
+ required
113
+ emptyField = { emptyFields . email }
114
+ validator = { emailValidator }
115
+ onChange = { ( value , isValid ) => handleInputChange ( "email" , value , isValid ) }
90
116
/>
91
- < TextField
117
+ < CustomTextField
92
118
label = "Password"
93
- variant = "outlined"
94
119
size = "small"
95
- onChange = { ( input ) => setPassword ( input . target . value ) }
96
- slotProps = { {
97
-
98
- } }
120
+ required
121
+ emptyField = { emptyFields . password }
122
+ validator = { passwordValidator }
123
+ onChange = { ( value , isValid ) => handleInputChange ( "password" , value , isValid ) }
99
124
/>
125
+ < Button
126
+ type = "submit"
127
+ variant = "contained"
128
+ sx = { ( theme ) => ( { height : theme . spacing ( 5 ) } ) }
129
+ >
130
+ Sign up
131
+ </ Button >
100
132
</ Stack >
101
- < Button
102
- variant = "contained"
103
- sx = { ( theme ) => ( {
104
- marginTop : theme . spacing ( 1 ) ,
105
- marginBottom : theme . spacing ( 1 ) ,
106
- height : theme . spacing ( 5 ) ,
107
- } ) }
108
- onClick = { ( ) => signup ( firstName , lastName , username , email , password ) }
109
- >
110
- Sign up
111
- </ Button >
112
133
< Stack
113
134
direction = "row"
114
135
spacing = { 0.5 }
0 commit comments