Skip to content

Commit ea00d74

Browse files
authored
Merge pull request #123 from EQWorks/EQ-122-Contact-Update
EQ-122: Update contact page
2 parents 4e87ca0 + c51f32c commit ea00d74

File tree

12 files changed

+1057
-17
lines changed

12 files changed

+1057
-17
lines changed

components/contact/contact-info.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import * as React from 'react'
2+
import styled from 'styled-components'
3+
4+
const SectionStyled = styled.section`
5+
background-color: ${({ theme }) => theme.color.greyBackground};
6+
margin: ${({ theme }) => theme.spacing[12]}px auto 0 auto;
7+
.container {
8+
align-items: flex-start;
9+
display: flex;
10+
flex-wrap: wrap;
11+
justify-content: center;
12+
margin: 0 auto;
13+
max-width: ${({ theme }) => theme.width.page};
14+
padding: ${({ theme }) => theme.spacing[6]}px
15+
${({ theme }) => theme.spacing[2]}px;
16+
.divider {
17+
background-color: ${({ theme }) => theme.color.greyLight};
18+
box-sizing: border-box;
19+
height: 3px;
20+
margin: 0 0 ${({ theme }) => theme.spacing[4]}px 0;
21+
max-width: 200px;
22+
width: 100%;
23+
@media ${({ theme }) => theme.breakpoint.md} {
24+
height: 125px;
25+
margin: 0 ${({ theme }) => theme.spacing[3]}px 0
26+
${({ theme }) => theme.spacing[2]}px;
27+
width: 3px;
28+
}
29+
@media ${({ theme }) => theme.breakpoint.lg} {
30+
margin: 0 ${({ theme }) => theme.spacing[7]}px 0
31+
${({ theme }) => theme.spacing[4]}px;
32+
}
33+
}
34+
.item {
35+
text-align: center;
36+
margin: 0 0 ${({ theme }) => theme.spacing[5]}px 0;
37+
width: 100%;
38+
&:last-child {
39+
margin: 0;
40+
}
41+
@media ${({ theme }) => theme.breakpoint.md} {
42+
padding: 0 ${({ theme }) => theme.spacing[1]}px;
43+
text-align: left;
44+
width: 20%;
45+
}
46+
}
47+
}
48+
`
49+
50+
export default function Section() {
51+
return (
52+
<SectionStyled>
53+
<div className='container'>
54+
<div className='item'>
55+
<p className='font-weight-bold'>Toronto Office</p>
56+
<p>1235 Bay Street, Suite 401</p>
57+
<p>Toronto, ON, M5R&nbsp;3K4</p>
58+
</div>
59+
<div className='divider' />
60+
<div className='item'>
61+
<p className='font-weight-bold'>Sales</p>
62+
<p>sales@eqworks.com</p>
63+
</div>
64+
<div className='item'>
65+
<p className='font-weight-bold'>Media inquiries</p>
66+
<p>press@eqworks.com</p>
67+
</div>
68+
<div className='item'>
69+
<p className='font-weight-bold'>Investor relations</p>
70+
<p>Peter Kanniah</p>
71+
<p>peter.kanniah@eqworks.com</p>
72+
<p>416 260 4326</p>
73+
</div>
74+
</div>
75+
</SectionStyled>
76+
)
77+
}

components/contact/form.js

Lines changed: 321 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,321 @@
1+
import Checkbox from '@material-ui/core/Checkbox'
2+
import FormControlLabel from '@material-ui/core/FormControlLabel'
3+
import FormGroup from '@material-ui/core/FormGroup'
4+
import FormHelperText from '@material-ui/core/FormHelperText'
5+
import TextField from '@material-ui/core/TextField'
6+
import axios from 'axios'
7+
import * as React from 'react'
8+
import styled from 'styled-components'
9+
10+
const SectionStyled = styled.section`
11+
color: ${({ theme }) => theme.color.black};
12+
margin: ${({ theme }) => theme.spacing[12]}px auto;
13+
max-width: ${({ theme }) => theme.width.article};
14+
padding: 0 ${({ theme }) => theme.spacing[2]}px;
15+
text-align: center;
16+
input[type='submit'] {
17+
background-color: ${({ theme }) => theme.color.blue};
18+
border: none;
19+
color: ${({ theme }) => theme.color.white};
20+
cursor: pointer;
21+
font-size: 0.9em;
22+
padding: ${({ theme }) => theme.spacing[2]}px
23+
${({ theme }) => theme.spacing[7]}px;
24+
text-transform: uppercase;
25+
transition: all 0.25s ease-out;
26+
&:hover {
27+
background-color: ${({ theme }) => theme.color.blueDark};
28+
color: ${({ theme }) => theme.color.white};
29+
}
30+
}
31+
.check-error-text {
32+
margin: 0 auto ${({ theme }) => theme.spacing[2]}px auto;
33+
text-align: center;
34+
}
35+
.message-field {
36+
box-sizing: border-box;
37+
margin: 0 auto ${({ theme }) => theme.spacing[4]}px auto;
38+
width: 100%;
39+
@media ${({ theme }) => theme.breakpoint.sm} {
40+
margin: 0 auto;
41+
padding: 0 ${({ theme }) => theme.spacing[2]}px
42+
${({ theme }) => theme.spacing[6]}px
43+
${({ theme }) => theme.spacing[2]}px;
44+
}
45+
label {
46+
color: ${({ theme }) => theme.color.black};
47+
font-weight: ${({ theme }) => theme.font.bold};
48+
font-size: 0.8em;
49+
text-transform: uppercase;
50+
@media ${({ theme }) => theme.breakpoint.sm} {
51+
padding: 0 0 0 21px;
52+
}
53+
}
54+
}
55+
.MuiFormGroup-root {
56+
.MuiTextField-root {
57+
box-sizing: border-box;
58+
padding: 0 0 ${({ theme }) => theme.spacing[4]}px 0;
59+
width: 100%;
60+
@media ${({ theme }) => theme.breakpoint.sm} {
61+
padding: 0 ${({ theme }) => theme.spacing[2]}px
62+
${({ theme }) => theme.spacing[6]}px
63+
${({ theme }) => theme.spacing[2]}px;
64+
width: 50%;
65+
}
66+
label {
67+
color: ${({ theme }) => theme.color.black};
68+
font-weight: ${({ theme }) => theme.font.bold};
69+
font-size: 0.8em;
70+
text-transform: uppercase;
71+
@media ${({ theme }) => theme.breakpoint.sm} {
72+
padding: 0 0 0 21px;
73+
}
74+
}
75+
}
76+
}
77+
.MuiFormControlLabel-root {
78+
display: block;
79+
box-sizing: border-box;
80+
.MuiFormControlLabel-label {
81+
font-style: italic;
82+
color: ${({ theme }) => theme.color.greyMedium};
83+
}
84+
}
85+
`
86+
87+
export default function Form() {
88+
const [checked, setChecked] = React.useState(false)
89+
const [status, statusSet] = React.useState('')
90+
const [formData, FormDataSet] = React.useState({})
91+
const [formError, formErrorSet] = React.useState({})
92+
93+
const handleChange = (event) => {
94+
formErrorSet((prevData) => ({
95+
...prevData,
96+
consent: !event.target.checked
97+
}))
98+
99+
setChecked(event.target.checked)
100+
}
101+
102+
const updateInput = (event, field) => {
103+
FormDataSet((prevData) => ({
104+
...prevData,
105+
[field]: event.target.value
106+
}))
107+
108+
const fieldError = event.target.value.length > 0 ? false : true
109+
formErrorSet((prevData) => ({
110+
...prevData,
111+
[field]: fieldError
112+
}))
113+
}
114+
115+
const submitForm = (event) => {
116+
event.preventDefault()
117+
118+
const syncErrors = []
119+
if (!formData['first-name'] || formData['first-name'].length < 1) {
120+
formErrorSet((prevData) => ({
121+
...prevData,
122+
'first-name': true
123+
}))
124+
syncErrors.push('first-name')
125+
}
126+
127+
if (!formData['last-name'] || formData['last-name'].length < 1) {
128+
formErrorSet((prevData) => ({
129+
...prevData,
130+
'last-name': true
131+
}))
132+
syncErrors.push('last-name')
133+
}
134+
135+
if (!formData['company'] || formData['company'].length < 1) {
136+
formErrorSet((prevData) => ({
137+
...prevData,
138+
company: true
139+
}))
140+
syncErrors.push('company')
141+
}
142+
143+
if (!formData['job-title'] || formData['job-title'].length < 1) {
144+
formErrorSet((prevData) => ({
145+
...prevData,
146+
'job-title': true
147+
}))
148+
syncErrors.push('job-title')
149+
}
150+
151+
if (
152+
!formData['email'] ||
153+
formData['email'].length < 1 ||
154+
!validateEmail(formData['email'])
155+
) {
156+
formErrorSet((prevData) => ({
157+
...prevData,
158+
email: true
159+
}))
160+
syncErrors.push('email')
161+
}
162+
163+
if (!formData['phone'] || formData['phone'].length < 1) {
164+
formErrorSet((prevData) => ({
165+
...prevData,
166+
phone: true
167+
}))
168+
syncErrors.push('phone')
169+
}
170+
171+
if (!formData['message'] || formData['message'].length < 1) {
172+
formErrorSet((prevData) => ({
173+
...prevData,
174+
message: true
175+
}))
176+
syncErrors.push('message')
177+
}
178+
179+
if (!checked) {
180+
formErrorSet((prevData) => ({
181+
...prevData,
182+
consent: true
183+
}))
184+
syncErrors.push('consent')
185+
}
186+
187+
if (syncErrors.length === 0) {
188+
axios({
189+
url: 'https://formspree.io/f/mqkyorzl',
190+
method: 'post',
191+
headers: {
192+
Accept: 'application/json'
193+
},
194+
data: {
195+
first_name: formData['first-name'],
196+
last_name: formData['last-name'],
197+
company: formData['company'],
198+
job_title: formData['job-title'],
199+
email: formData['email'],
200+
phone: formData['phone'],
201+
message: formData['message'],
202+
consent: formData['consent']
203+
}
204+
}).then((response) => {
205+
if (response.status === 200) {
206+
statusSet('SUCCESS')
207+
} else {
208+
statusSet('ERROR')
209+
}
210+
})
211+
}
212+
}
213+
214+
function validateEmail(email) {
215+
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
216+
return re.test(String(email).toLowerCase())
217+
}
218+
219+
return (
220+
<SectionStyled>
221+
<form autoComplete='off'>
222+
<FormGroup row>
223+
<TextField
224+
error={formError['first-name']}
225+
fullWidth
226+
// helperText={(formError['first-name'] ? 'Required field.' : null)}
227+
label='First Name'
228+
name='first-name'
229+
onBlur={(event) => updateInput(event, 'first-name')}
230+
required
231+
/>
232+
<TextField
233+
error={formError['last-name']}
234+
fullWidth
235+
// helperText={(formError['last-name'] ? 'Required field.' : null)}
236+
label='last Name'
237+
name='last-name'
238+
onBlur={(event) => updateInput(event, 'last-name')}
239+
required
240+
/>
241+
</FormGroup>
242+
243+
<FormGroup row>
244+
<TextField
245+
error={formError['company']}
246+
// helperText={(formError['company'] ? 'Required field.' : null)}
247+
label='Company'
248+
name='company'
249+
onBlur={(event) => updateInput(event, 'company')}
250+
required
251+
/>
252+
<TextField
253+
error={formError['job-title']}
254+
// helperText={(formError['job-title'] ? 'Required field.' : null)}
255+
label='Job Title'
256+
name='job-title'
257+
onBlur={(event) => updateInput(event, 'job-title')}
258+
required
259+
/>
260+
</FormGroup>
261+
262+
<FormGroup row>
263+
<TextField
264+
error={formError['email']}
265+
// helperText={(formError['email'] ? 'Required field.' : null)}
266+
label='Email'
267+
name='email'
268+
onBlur={(event) => updateInput(event, 'email')}
269+
required
270+
type='email'
271+
/>
272+
<TextField
273+
error={formError['phone']}
274+
// helperText={(formError['phone'] ? 'Required field.' : null)}
275+
label='Phone'
276+
name='phone'
277+
onBlur={(event) => updateInput(event, 'phone')}
278+
required
279+
type='tel'
280+
/>
281+
</FormGroup>
282+
283+
<TextField
284+
className='message-field'
285+
error={formError['message']}
286+
// fullWidth
287+
// helperText={(formError['message'] ? 'Required field.' : null)}
288+
label='Your Message'
289+
multiline
290+
name='message'
291+
onBlur={(event) => updateInput(event, 'message')}
292+
required
293+
rowsMax={4}
294+
type='tel'
295+
/>
296+
297+
<FormControlLabel
298+
control={
299+
<Checkbox
300+
checked={checked}
301+
onChange={handleChange}
302+
name='consent'
303+
value='consent'
304+
/>
305+
}
306+
label='I consent to my submitted data being collected and stored.'
307+
/>
308+
<FormHelperText className='check-error-text' error>
309+
{formError['consent'] ? 'Required field.' : <span>&nbsp;</span>}
310+
</FormHelperText>
311+
312+
<input onClick={submitForm} type='submit' value='send »' />
313+
</form>
314+
315+
{status === 'SUCCESS' && (
316+
<p>Thank you for your message. It has been sent.</p>
317+
)}
318+
{status === 'ERROR' && <p>Ooops! There was an error. Please try again</p>}
319+
</SectionStyled>
320+
)
321+
}

0 commit comments

Comments
 (0)