1
- import React , { useState , useCallback } from 'react' ;
1
+ import React , { useState , useCallback , useRef } from 'react' ;
2
2
import classnames from 'classnames' ;
3
+ import { useFormState } from 'react-use-form-state' ;
3
4
4
5
import './index.css' ;
5
6
6
- const encode = data => {
7
+ const encode = ( data ) => {
7
8
return Object . keys ( data )
8
- . map ( key => encodeURIComponent ( key ) + '=' + encodeURIComponent ( data [ key ] ) )
9
+ . map ( ( key ) => encodeURIComponent ( key ) + '=' + encodeURIComponent ( data [ key ] ) )
9
10
. join ( '&' ) ;
10
11
} ;
11
12
12
- export default props => {
13
- const [ name , setName ] = useState ( '' ) ;
14
- const [ email , setEmail ] = useState ( '' ) ;
15
- const [ message , setMessage ] = useState ( '' ) ;
16
- const [ city , setCity ] = useState ( '' ) ;
13
+ export default ( props ) => {
14
+ const [ formState , { text, email, textarea } ] = useFormState ( ) ;
17
15
const [ feedbackMessage , setFeedbackMessage ] = useState ( '' ) ;
18
-
19
- const onChangeName = useCallback ( e => setName ( e . target . value ) , [ ] ) ;
20
- const onChangeEmail = useCallback ( e => setEmail ( e . target . value ) , [ ] ) ;
21
- const onChangeMessage = useCallback ( e => setMessage ( e . target . value ) , [ ] ) ;
22
- const onChangeCity = useCallback ( e => setCity ( e . target . value ) , [ ] ) ;
16
+ const [ sendingMessage , setSendingMessage ] = useState ( false ) ;
17
+ const formRef = useRef ( ) ;
23
18
24
19
const onSubmit = useCallback (
25
- async e => {
20
+ async ( e ) => {
26
21
e . preventDefault ( ) ;
27
22
23
+ if ( ! isFormValid ( formState ) ) {
24
+ setFeedbackMessage ( 'Please complete all required fields' ) ;
25
+ return ;
26
+ }
27
+
28
+ if ( sendingMessage ) {
29
+ return ;
30
+ }
31
+
32
+ setFeedbackMessage ( 'Sending your message now 🚀' ) ;
33
+ setSendingMessage ( true ) ;
34
+
28
35
try {
29
36
const response = await fetch ( '/' , {
30
37
method : 'POST' ,
31
38
headers : { 'Content-Type' : 'application/x-www-form-urlencoded' } ,
32
39
body : encode ( {
33
40
'form-name' : 'contact' ,
34
- name,
35
- email,
36
- city,
37
- message,
41
+ name : formState . values . name ,
42
+ email : formState . values . email ,
43
+ city : formState . values . city ,
44
+ message : formState . values . message ,
38
45
} ) ,
39
46
} ) ;
40
47
41
- console . log ( 'response' , response ) ;
48
+ if ( response . status !== 200 ) {
49
+ throw new Error ( 'unable to send message' ) ;
50
+ }
42
51
43
52
setFeedbackMessage ( 'Thank you!' ) ;
53
+ formState . clear ( ) ;
54
+ formRef . current . reset ( ) ;
44
55
} catch ( e ) {
45
56
console . error ( 'error' , e ) ;
46
57
setFeedbackMessage ( 'Unable to send the message, please try again' ) ;
58
+ } finally {
59
+ setSendingMessage ( false ) ;
47
60
}
48
61
} ,
49
- [ name , email , city , message ]
62
+ [ formState . values , sendingMessage ]
50
63
) ;
51
64
52
65
return (
@@ -55,69 +68,46 @@ export default props => {
55
68
onSubmit = { onSubmit }
56
69
className = "Form"
57
70
name = "contact"
71
+ ref = { formRef }
58
72
>
59
73
< input type = "hidden" name = "form-name" value = "contact" />
60
74
61
- < Input
62
- component = "input"
63
- type = "name"
64
- name = "name"
65
- value = { name }
66
- onChange = { onChangeName }
67
- required
68
- label = "Name*"
69
- />
70
-
71
- < Input
72
- component = "input"
73
- type = "email"
74
- name = "email"
75
- value = { email }
76
- onChange = { onChangeEmail }
77
- required
78
- label = "Email*"
79
- />
80
-
81
- < Input
82
- component = "input"
83
- type = "text"
84
- name = "city"
85
- value = { city }
86
- onChange = { onChangeCity }
87
- label = "City"
88
- />
89
-
90
- < Input
91
- required
92
- name = "message"
93
- component = "textarea"
94
- value = { message }
95
- onChange = { onChangeMessage }
96
- label = "Message*"
97
- />
75
+ < Input { ...text ( 'name' ) } required label = "Name*" />
76
+
77
+ < Input { ...email ( 'email' ) } required label = "Email*" />
78
+
79
+ < Input { ...text ( 'city' ) } label = "City" />
80
+
81
+ < Input { ...textarea ( 'message' ) } type = "textarea" label = "Message*" />
82
+
83
+ { feedbackMessage && (
84
+ < p className = "Form--feedback-message" > { feedbackMessage } </ p >
85
+ ) }
98
86
99
87
< div className = "Form--submit-container" >
100
- < button type = "submit" > Send</ button >
88
+ < button disabled = { sendingMessage } type = "submit" >
89
+ Send
90
+ </ button >
101
91
</ div >
102
-
103
- { feedbackMessage && < p > { feedbackMessage } </ p > }
104
92
</ form >
105
93
) ;
106
94
} ;
107
95
108
- const Input = props => {
109
- const { component , label, className, ...others } = props ;
96
+ const Input = ( props ) => {
97
+ const { type , label, className, ...others } = props ;
110
98
let input ;
111
99
112
- switch ( component ) {
100
+ switch ( type ) {
101
+ case 'text' :
102
+ case 'email' :
113
103
case 'input' :
114
- input = < input { ...others } /> ;
104
+ input = < input type = { type } { ...others } /> ;
115
105
break ;
116
106
case 'textarea' :
117
- input = < textarea { ...others } /> ;
107
+ input = < textarea type = { type } { ...others } /> ;
118
108
break ;
119
109
default :
120
- throw new Error ( ' Ops' ) ;
110
+ throw new Error ( ` Ops: ${ type } ` ) ;
121
111
}
122
112
123
113
const classes = classnames ( className , {
@@ -131,3 +121,8 @@ const Input = props => {
131
121
</ label >
132
122
) ;
133
123
} ;
124
+
125
+ const isFormValid = ( formState ) =>
126
+ formState . validity . name &&
127
+ formState . validity . email &&
128
+ formState . validity . message ;
0 commit comments