@comicrelief/component-library 6.10.0 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cypress/integration/components/Organisms/Donate.spec.js +13 -13
- package/cypress/integration/components/Organisms/EmailSignUp.spec.js +47 -132
- package/dist/components/Organisms/Donate/Donate.md +9 -9
- package/dist/components/Organisms/Donate/Form/Form.js +2 -1
- package/dist/components/Organisms/Donate/GivingSelector/GivingSelector.js +17 -71
- package/dist/components/Organisms/Donate/GivingSelector/GivingSelector.style.js +71 -0
- package/dist/components/Organisms/Donate/__snapshots__/Donate.test.js.snap +11 -25
- package/dist/components/Organisms/EmailSignUp/EmailSignUp.md +8 -123
- package/dist/components/Organisms/EmailSignUp/EmailSignUp.style.js +46 -29
- package/dist/components/Organisms/EmailSignUp/EmailSignUp.test.js +24 -69
- package/dist/components/Organisms/EmailSignUp/EmailSignUpForm.js +92 -0
- package/dist/components/Organisms/EmailSignUp/_Confetti.js +116 -0
- package/dist/components/Organisms/EmailSignUp/_EmailSignUp.js +107 -0
- package/dist/components/Organisms/EmailSignUp/_EmailSignUpConfig.js +51 -0
- package/dist/components/Organisms/EmailSignUp/_TextInput.js +51 -0
- package/dist/components/Organisms/EmailSignUp/__snapshots__/EmailSignUp.test.js.snap +249 -406
- package/dist/components/Organisms/Header/Header.md +1 -13
- package/dist/components/Organisms/Membership/Membership.test.js +1 -1
- package/dist/index.js +14 -10
- package/package.json +2 -1
- package/src/components/Organisms/Donate/Donate.md +9 -9
- package/src/components/Organisms/Donate/Form/Form.js +1 -0
- package/src/components/Organisms/Donate/GivingSelector/GivingSelector.js +15 -85
- package/src/components/Organisms/Donate/GivingSelector/GivingSelector.style.js +78 -0
- package/src/components/Organisms/Donate/__snapshots__/Donate.test.js.snap +11 -25
- package/src/components/Organisms/EmailSignUp/EmailSignUp.md +8 -123
- package/src/components/Organisms/EmailSignUp/EmailSignUp.style.js +33 -13
- package/src/components/Organisms/EmailSignUp/EmailSignUp.test.js +35 -69
- package/src/components/Organisms/EmailSignUp/EmailSignUpForm.js +60 -0
- package/src/components/Organisms/EmailSignUp/_Confetti.js +106 -0
- package/src/components/Organisms/EmailSignUp/_EmailSignUp.js +138 -0
- package/src/components/Organisms/EmailSignUp/_EmailSignUpConfig.js +54 -0
- package/src/components/Organisms/EmailSignUp/_TextInput.js +45 -0
- package/src/components/Organisms/EmailSignUp/__snapshots__/EmailSignUp.test.js.snap +249 -406
- package/src/components/Organisms/Header/Header.md +1 -13
- package/src/components/Organisms/Membership/Membership.test.js +33 -33
- package/src/index.js +10 -4
- package/cypress/integration/components/Molecules/HeaderEsuWithIcon.spec.js +0 -69
- package/dist/components/Molecules/HeaderEsuWithIcon/HeaderEsuWithIcon.js +0 -136
- package/dist/components/Molecules/HeaderEsuWithIcon/HeaderEsuWithIcon.md +0 -47
- package/dist/components/Molecules/HeaderEsuWithIcon/HeaderEsuWithIcon.style.js +0 -52
- package/dist/components/Molecules/HeaderEsuWithIcon/HeaderEsuWithIcon.test.js +0 -99
- package/dist/components/Molecules/HeaderEsuWithIcon/__snapshots__/HeaderEsuWithIcon.test.js.snap +0 -1211
- package/dist/components/Molecules/HeaderEsuWithIcon/assets/HeaderIcons.js +0 -25
- package/dist/components/Molecules/HeaderEsuWithIcon/assets/icon--close.svg +0 -5
- package/dist/components/Molecules/HeaderEsuWithIcon/assets/icon--email.svg +0 -5
- package/dist/components/Organisms/EmailSignUp/EmailSignUp.js +0 -182
- package/src/components/Molecules/HeaderEsuWithIcon/HeaderEsuWithIcon.js +0 -135
- package/src/components/Molecules/HeaderEsuWithIcon/HeaderEsuWithIcon.md +0 -47
- package/src/components/Molecules/HeaderEsuWithIcon/HeaderEsuWithIcon.style.js +0 -60
- package/src/components/Molecules/HeaderEsuWithIcon/HeaderEsuWithIcon.test.js +0 -103
- package/src/components/Molecules/HeaderEsuWithIcon/__snapshots__/HeaderEsuWithIcon.test.js.snap +0 -1211
- package/src/components/Molecules/HeaderEsuWithIcon/assets/HeaderIcons.js +0 -15
- package/src/components/Molecules/HeaderEsuWithIcon/assets/icon--close.svg +0 -5
- package/src/components/Molecules/HeaderEsuWithIcon/assets/icon--email.svg +0 -5
- package/src/components/Organisms/EmailSignUp/EmailSignUp.js +0 -197
|
@@ -1,129 +1,14 @@
|
|
|
1
|
-
# Email
|
|
1
|
+
# Email SignUp Form
|
|
2
2
|
|
|
3
|
-
```js
|
|
4
|
-
import RichText from '../../Atoms/RichText/RichText';
|
|
5
|
-
|
|
6
|
-
const title = 'Stay in the know!';
|
|
7
|
-
const topCopy = (
|
|
8
|
-
<RichText
|
|
9
|
-
markup={`<p>Get regular email updates and info on what we're up to!</p>`}
|
|
10
|
-
/>
|
|
11
|
-
);
|
|
12
|
-
const privacyCopy = (
|
|
13
|
-
<RichText
|
|
14
|
-
markup={`<p>Our <a class="link link--white inline" href="/privacy-notice">Privacy Policy</a> describes how we handle and protect your information.<br><br>If you are under 18, please make sure you have your parents’ permission before providing us with any personal details.</p>`}
|
|
15
|
-
/>
|
|
16
|
-
);
|
|
17
|
-
const successCopy = (
|
|
18
|
-
<RichText
|
|
19
|
-
markup={`<p>Thanks! Your first email will be with you shortly</p>`}
|
|
20
|
-
/>
|
|
21
|
-
);
|
|
22
|
-
|
|
23
|
-
const [success, setSuccess] = React.useState(false);
|
|
24
|
-
const [error, setError] = React.useState('');
|
|
25
|
-
|
|
26
|
-
const sendEmail = email => {
|
|
27
|
-
setTimeout(() => setSuccess(!success), 2000);
|
|
28
|
-
console.log(email);
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const validate = ({ email }) => {
|
|
32
|
-
let isValid = false;
|
|
33
|
-
if (email.includes('@')) {
|
|
34
|
-
isValid = true;
|
|
35
|
-
setError('');
|
|
36
|
-
} else {
|
|
37
|
-
setError('invalid email!');
|
|
38
|
-
}
|
|
39
|
-
return isValid;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
<EmailSignUp
|
|
43
|
-
title={title}
|
|
44
|
-
topCopy={topCopy}
|
|
45
|
-
successCopy={successCopy}
|
|
46
|
-
isSuccess={success}
|
|
47
|
-
privacyCopy={privacyCopy}
|
|
48
|
-
errorMsg={error}
|
|
49
|
-
subscribe={sendEmail}
|
|
50
|
-
validate={validate}
|
|
51
|
-
/>;
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
# Email Sign Up Schools
|
|
55
3
|
|
|
56
4
|
```js
|
|
57
|
-
import
|
|
58
|
-
|
|
59
|
-
const title = 'Stay in the know!';
|
|
60
|
-
const topCopy = (
|
|
61
|
-
<RichText
|
|
62
|
-
markup={`<p>Get regular email updates and info on what we're up to!</p>`}
|
|
63
|
-
/>
|
|
64
|
-
);
|
|
65
|
-
const privacyCopy = (
|
|
66
|
-
<RichText
|
|
67
|
-
markup={`<p>Our <a class="link link--white inline" href="/privacy-notice">Privacy Policy</a> describes how we handle and protect your information.<br><br>If you are under 18, please make sure you have your parents’ permission before providing us with any personal details.</p>`}
|
|
68
|
-
/>
|
|
69
|
-
);
|
|
70
|
-
const successCopy = (
|
|
71
|
-
<RichText
|
|
72
|
-
markup={`<p>Thanks! Your first email will be with you shortly</p>`}
|
|
73
|
-
/>
|
|
74
|
-
);
|
|
75
|
-
const selectItems = [
|
|
76
|
-
{ value: '', displayValue: '-- Select age group --' },
|
|
77
|
-
{ value: 'Option one', displayValue: 'The first option' },
|
|
78
|
-
{
|
|
79
|
-
value: 'Option two',
|
|
80
|
-
displayValue: 'The second option'
|
|
81
|
-
},
|
|
82
|
-
{ value: 'Option three', displayValue: 'The third option' },
|
|
83
|
-
{ value: 'Option four', displayValue: 'The fourth option' }
|
|
84
|
-
];
|
|
85
|
-
|
|
86
|
-
const [successSchools, setSuccessSchools] = React.useState(false);
|
|
87
|
-
const [error, setError] = React.useState('');
|
|
88
|
-
|
|
89
|
-
sendEmail = emailAndAge => {
|
|
90
|
-
setTimeout(
|
|
91
|
-
() => setSuccessSchools(!successSchools),
|
|
92
|
-
2000
|
|
93
|
-
);
|
|
94
|
-
console.log(emailAndAge);
|
|
95
|
-
};
|
|
5
|
+
import EmailSignUpForm from './EmailSignUpForm';
|
|
6
|
+
import Text from '../../Atoms/Text/Text';
|
|
96
7
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
} else {
|
|
103
|
-
setError('invalid email!');
|
|
104
|
-
}
|
|
105
|
-
if (isValid === true && typeof age !== 'undefined') {
|
|
106
|
-
if (age) {
|
|
107
|
-
setError('');
|
|
108
|
-
} else {
|
|
109
|
-
isValid = false;
|
|
110
|
-
setError('invalid age!');
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
return isValid;
|
|
114
|
-
};
|
|
8
|
+
<>
|
|
9
|
+
<Text tag="p">This EmailSignUpForm component exists purely to show the EmailSignUp component functioning within the Component Library; applications are to provide their own react-hook-form form and validation, based on these.</Text>
|
|
10
|
+
|
|
11
|
+
<EmailSignUpForm />
|
|
12
|
+
</>
|
|
115
13
|
|
|
116
|
-
<EmailSignUp
|
|
117
|
-
title={title}
|
|
118
|
-
topCopy={topCopy}
|
|
119
|
-
successCopy={successCopy}
|
|
120
|
-
schoolsCopy="Now please select your teaching group so you get the right updates."
|
|
121
|
-
isSuccess={successSchools}
|
|
122
|
-
selectItems={selectItems}
|
|
123
|
-
isSchools
|
|
124
|
-
privacyCopy={privacyCopy}
|
|
125
|
-
errorMsg={error}
|
|
126
|
-
subscribe={sendEmail}
|
|
127
|
-
validate={validate}
|
|
128
|
-
/>;
|
|
129
14
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import styled from 'styled-components';
|
|
2
2
|
|
|
3
3
|
import spacing from '../../../theme/shared/spacing';
|
|
4
|
-
import
|
|
4
|
+
import TextInput from './_TextInput';
|
|
5
5
|
import Text from '../../Atoms/Text/Text';
|
|
6
6
|
|
|
7
7
|
const ESUWrapper = styled.div`
|
|
@@ -9,7 +9,8 @@ const ESUWrapper = styled.div`
|
|
|
9
9
|
flex-direction: column;
|
|
10
10
|
font-size: ${({ theme }) => theme.fontSize('s')};
|
|
11
11
|
color: ${({ theme }) => theme.color('white')};
|
|
12
|
-
background-color: ${({ theme,
|
|
12
|
+
background-color: ${({ theme, backgroundColour }) => theme.color(backgroundColour)};
|
|
13
|
+
padding: ${spacing('m')};
|
|
13
14
|
`;
|
|
14
15
|
|
|
15
16
|
const TopCopyWrapper = styled.div`
|
|
@@ -19,14 +20,8 @@ const TopCopyWrapper = styled.div`
|
|
|
19
20
|
|
|
20
21
|
const ButtonWrapper = styled.div`
|
|
21
22
|
margin-top: ${spacing('md')};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
width: 100%;
|
|
25
|
-
font-size: ${({ theme }) => theme.fontSize('s')};
|
|
26
|
-
@media ${({ theme }) => theme.breakpoint('small')} {
|
|
27
|
-
font-size: ${({ theme }) => theme.fontSize('m')};
|
|
28
|
-
max-width: 180px;
|
|
29
|
-
}
|
|
23
|
+
button {
|
|
24
|
+
background-color: ${({ theme, buttonColour }) => theme.color(buttonColour)};
|
|
30
25
|
}
|
|
31
26
|
`;
|
|
32
27
|
|
|
@@ -34,6 +29,7 @@ const PrivacyCopyWrapper = styled.div`
|
|
|
34
29
|
display: flex;
|
|
35
30
|
flex-direction: column;
|
|
36
31
|
margin-top: ${spacing('md')};
|
|
32
|
+
|
|
37
33
|
p {
|
|
38
34
|
font-size: ${({ theme }) => theme.fontSize('s')};
|
|
39
35
|
line-height: ${({ theme }) => theme.fontSize('xl')};
|
|
@@ -44,14 +40,37 @@ const PrivacyCopyWrapper = styled.div`
|
|
|
44
40
|
}
|
|
45
41
|
`;
|
|
46
42
|
|
|
47
|
-
const
|
|
43
|
+
const FormInner = styled.div`
|
|
48
44
|
display: flex;
|
|
49
45
|
flex-direction: column;
|
|
50
46
|
margin: ${spacing('md')} 0;
|
|
51
47
|
`;
|
|
52
48
|
|
|
53
|
-
const
|
|
49
|
+
const NameWrapper = styled.div`
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
gap: 0;
|
|
53
|
+
|
|
54
|
+
@media ${({ theme }) => theme.breakpoint('medium')} {
|
|
55
|
+
justify-content: start;
|
|
56
|
+
flex-direction: ${({ columnLayout }) => (columnLayout ? 'column' : 'row')};
|
|
57
|
+
gap: ${({ columnLayout }) => (columnLayout ? 0 : spacing('md'))};
|
|
58
|
+
)};
|
|
59
|
+
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const InputField = styled(TextInput)`
|
|
54
64
|
width: 100%;
|
|
65
|
+
margin-bottom: ${spacing('md')};
|
|
66
|
+
|
|
67
|
+
& > span:first-child {
|
|
68
|
+
color: ${({ theme }) => theme.color('white')};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@media ${({ theme }) => theme.breakpoint('medium')} {
|
|
72
|
+
max-width: 290px;
|
|
73
|
+
}
|
|
55
74
|
`;
|
|
56
75
|
|
|
57
76
|
const Title = styled(Text)`
|
|
@@ -63,7 +82,8 @@ export {
|
|
|
63
82
|
TopCopyWrapper,
|
|
64
83
|
PrivacyCopyWrapper,
|
|
65
84
|
ButtonWrapper,
|
|
66
|
-
|
|
85
|
+
FormInner,
|
|
67
86
|
InputField,
|
|
87
|
+
NameWrapper,
|
|
68
88
|
Title
|
|
69
89
|
};
|
|
@@ -1,76 +1,42 @@
|
|
|
1
|
-
import React from
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
1
|
+
import React from "react";
|
|
2
|
+
import "jest-styled-components";
|
|
3
|
+
import renderWithTheme from "../../../hoc/shallowWithTheme";
|
|
4
|
+
import { EmailSignUp, validationSchema } from "./_EmailSignUp";
|
|
5
|
+
import RichText from "../../Atoms/RichText/RichText";
|
|
6
|
+
import { useForm, FormProvider } from "react-hook-form";
|
|
7
|
+
import { yupResolver } from "@hookform/resolvers/yup";
|
|
7
8
|
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const tree = renderWithTheme(
|
|
15
|
-
<>
|
|
16
|
-
<EmailSignUp
|
|
17
|
-
title="sign up letter"
|
|
18
|
-
topCopy={<RichText markup={top} />}
|
|
19
|
-
successCopy={<RichText markup={success} />}
|
|
20
|
-
isSuccess={false}
|
|
21
|
-
errorMsg=""
|
|
22
|
-
buttonColor="teal"
|
|
23
|
-
privacyCopy={<RichText markup={privacy} />}
|
|
24
|
-
subscribe={() => 'Done'}
|
|
25
|
-
validate={() => true}
|
|
26
|
-
/>
|
|
27
|
-
</>
|
|
28
|
-
).toJSON();
|
|
9
|
+
const DummyForm = () => {
|
|
10
|
+
const formMethods = useForm({
|
|
11
|
+
mode: "onBlur",
|
|
12
|
+
resolver: yupResolver(validationSchema),
|
|
13
|
+
});
|
|
14
|
+
const { handleSubmit } = formMethods;
|
|
29
15
|
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
const top =
|
|
17
|
+
"<h1> Top Copy</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>";
|
|
18
|
+
const success =
|
|
19
|
+
"<h1> Success Copy</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>";
|
|
20
|
+
const privacy =
|
|
21
|
+
'check <a href="https://www.comicrelief.com/privacy-notice">Privacy policy</a>';
|
|
32
22
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{ value: 'Option four', displayValue: 'The fourth option' }
|
|
46
|
-
];
|
|
47
|
-
const mockNext = jest.fn();
|
|
48
|
-
const tree = renderWithTheme(
|
|
49
|
-
<>
|
|
50
|
-
<EmailSignUp
|
|
51
|
-
title="sign up letter"
|
|
52
|
-
topCopy={<RichText markup={top} />}
|
|
53
|
-
successCopy={<RichText markup={success} />}
|
|
54
|
-
schoolsCopy="Now please select your teaching group so you get the right updates."
|
|
55
|
-
selectItems={selectItems}
|
|
56
|
-
isSuccess={false}
|
|
57
|
-
isSchools
|
|
58
|
-
errorMsg=""
|
|
59
|
-
buttonColor="teal"
|
|
60
|
-
privacyCopy={<RichText markup={privacy} />}
|
|
61
|
-
subscribe={mockNext}
|
|
62
|
-
validate={() => true}
|
|
63
|
-
/>
|
|
64
|
-
</>
|
|
23
|
+
return (
|
|
24
|
+
<FormProvider {...formMethods}>
|
|
25
|
+
<form onSubmit={handleSubmit(() => true)} noValidate>
|
|
26
|
+
<EmailSignUp
|
|
27
|
+
title="sign up letter"
|
|
28
|
+
topCopy={<RichText markup={top} />}
|
|
29
|
+
successCopy={<RichText markup={success} />}
|
|
30
|
+
privacyCopy={<RichText markup={privacy} />}
|
|
31
|
+
formContext={formMethods}
|
|
32
|
+
/>
|
|
33
|
+
</form>
|
|
34
|
+
</FormProvider>
|
|
65
35
|
);
|
|
66
|
-
|
|
67
|
-
input.value = 'test@test.com';
|
|
36
|
+
};
|
|
68
37
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
tree.root.findAllByType('input')[1].props.onClick();
|
|
72
|
-
});
|
|
38
|
+
it("renders correctly", () => {
|
|
39
|
+
const tree = renderWithTheme(<DummyForm />).toJSON();
|
|
73
40
|
|
|
74
|
-
|
|
75
|
-
expect(treeJson).toMatchSnapshot();
|
|
41
|
+
expect(tree).toMatchSnapshot();
|
|
76
42
|
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useForm, FormProvider } from 'react-hook-form';
|
|
3
|
+
import { yupResolver } from '@hookform/resolvers/yup';
|
|
4
|
+
import RichText from '../../Atoms/RichText/RichText';
|
|
5
|
+
import {
|
|
6
|
+
EmailSignUp,
|
|
7
|
+
buildEsuValidationSchema,
|
|
8
|
+
ESU_FIELDS
|
|
9
|
+
} from './_EmailSignUp';
|
|
10
|
+
|
|
11
|
+
const EmailSignUpForm = () => {
|
|
12
|
+
const validationSchema = buildEsuValidationSchema({});
|
|
13
|
+
const formMethods = useForm({
|
|
14
|
+
mode: 'onBlur',
|
|
15
|
+
resolver: yupResolver(validationSchema)
|
|
16
|
+
});
|
|
17
|
+
const { handleSubmit, trigger } = formMethods;
|
|
18
|
+
|
|
19
|
+
async function handleSubscribe(data) {
|
|
20
|
+
const valid = await trigger([
|
|
21
|
+
ESU_FIELDS.EMAIL,
|
|
22
|
+
ESU_FIELDS.FIRST_NAME,
|
|
23
|
+
ESU_FIELDS.LAST_NAME
|
|
24
|
+
]);
|
|
25
|
+
if (valid) {
|
|
26
|
+
console.log(data);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
const title = 'Stay in the know!';
|
|
30
|
+
const topCopy = (
|
|
31
|
+
<RichText
|
|
32
|
+
markup={"<p>Get regular email updates and info on what we're up to!</p>"}
|
|
33
|
+
/>
|
|
34
|
+
);
|
|
35
|
+
const privacyCopy = (
|
|
36
|
+
<RichText
|
|
37
|
+
markup={
|
|
38
|
+
'<p>Our <a class="link link--white inline" href="/privacy-notice">Privacy Policy</a> describes how we handle and protect your information.<br><br>If you are under 18, please make sure you have your parents’ permission before providing us with any personal details.</p>'
|
|
39
|
+
}
|
|
40
|
+
/>
|
|
41
|
+
);
|
|
42
|
+
const successCopy = (
|
|
43
|
+
<RichText markup="<p>Thanks! Your first email will be with you shortly</p>" />
|
|
44
|
+
);
|
|
45
|
+
return (
|
|
46
|
+
<FormProvider {...formMethods}>
|
|
47
|
+
<form onSubmit={handleSubmit(handleSubscribe)} noValidate>
|
|
48
|
+
<EmailSignUp
|
|
49
|
+
id="default"
|
|
50
|
+
title={title}
|
|
51
|
+
topCopy={topCopy}
|
|
52
|
+
successCopy={successCopy}
|
|
53
|
+
privacyCopy={privacyCopy}
|
|
54
|
+
formContext={formMethods}
|
|
55
|
+
/>
|
|
56
|
+
</form>
|
|
57
|
+
</FormProvider>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
export default EmailSignUpForm;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback, useEffect, useRef, useState
|
|
3
|
+
} from 'react';
|
|
4
|
+
import ReactCanvasConfetti from 'react-canvas-confetti';
|
|
5
|
+
import PropTypes from 'prop-types';
|
|
6
|
+
|
|
7
|
+
function randomInRange(min, max) {
|
|
8
|
+
return Math.random() * (max - min) + min;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const canvasStyles = {
|
|
12
|
+
position: 'fixed',
|
|
13
|
+
pointerEvents: 'none',
|
|
14
|
+
width: '100%',
|
|
15
|
+
height: '100%',
|
|
16
|
+
top: 0,
|
|
17
|
+
left: 0
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
function getAnimationSettings(originXA, originXB) {
|
|
21
|
+
return {
|
|
22
|
+
startVelocity: 30,
|
|
23
|
+
spread: 360,
|
|
24
|
+
ticks: 60,
|
|
25
|
+
zIndex: 0,
|
|
26
|
+
particleCount: 150,
|
|
27
|
+
origin: {
|
|
28
|
+
x: randomInRange(originXA, originXB),
|
|
29
|
+
y: Math.random() - 0.2
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// TODO: Refactor this into an atom
|
|
34
|
+
export default function Confetti({ trigger, duration }) {
|
|
35
|
+
const refAnimationInstance = useRef(null);
|
|
36
|
+
const [intervalId, setIntervalId] = useState();
|
|
37
|
+
|
|
38
|
+
const getInstance = useCallback(instance => {
|
|
39
|
+
refAnimationInstance.current = instance;
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
const nextTickAnimation = useCallback(() => {
|
|
43
|
+
if (refAnimationInstance.current) {
|
|
44
|
+
refAnimationInstance.current(getAnimationSettings(0.1, 0.3));
|
|
45
|
+
refAnimationInstance.current(getAnimationSettings(0.7, 0.9));
|
|
46
|
+
}
|
|
47
|
+
}, []);
|
|
48
|
+
|
|
49
|
+
const startAnimation = useCallback(() => {
|
|
50
|
+
if (!intervalId) {
|
|
51
|
+
setIntervalId(setInterval(nextTickAnimation, 400));
|
|
52
|
+
}
|
|
53
|
+
}, [intervalId, nextTickAnimation]);
|
|
54
|
+
|
|
55
|
+
const pauseAnimation = useCallback(() => {
|
|
56
|
+
clearInterval(intervalId);
|
|
57
|
+
setIntervalId(null);
|
|
58
|
+
}, [intervalId]);
|
|
59
|
+
|
|
60
|
+
const stopAnimation = useCallback(() => {
|
|
61
|
+
clearInterval(intervalId);
|
|
62
|
+
setIntervalId(null);
|
|
63
|
+
if (refAnimationInstance.current) {
|
|
64
|
+
refAnimationInstance.current.reset();
|
|
65
|
+
}
|
|
66
|
+
}, [intervalId]);
|
|
67
|
+
|
|
68
|
+
// eslint-disable-next-line
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
return () => {
|
|
71
|
+
clearInterval(intervalId);
|
|
72
|
+
};
|
|
73
|
+
}, [intervalId]);
|
|
74
|
+
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
let timeOut;
|
|
77
|
+
if (trigger) {
|
|
78
|
+
startAnimation();
|
|
79
|
+
timeOut = setTimeout(() => {
|
|
80
|
+
// This gracefully ends the animation
|
|
81
|
+
pauseAnimation();
|
|
82
|
+
}, duration);
|
|
83
|
+
}
|
|
84
|
+
return () => {
|
|
85
|
+
if (timeOut) {
|
|
86
|
+
// this clears up the animation
|
|
87
|
+
stopAnimation();
|
|
88
|
+
}
|
|
89
|
+
}; // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
|
+
}, [trigger, duration]);
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<ReactCanvasConfetti refConfetti={getInstance} style={canvasStyles} />
|
|
95
|
+
</>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Confetti.defaultProps = {
|
|
100
|
+
duration: 3000
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
Confetti.propTypes = {
|
|
104
|
+
trigger: PropTypes.bool.isRequired,
|
|
105
|
+
duration: PropTypes.number
|
|
106
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import {
|
|
4
|
+
ESUWrapper,
|
|
5
|
+
TopCopyWrapper,
|
|
6
|
+
FormInner,
|
|
7
|
+
PrivacyCopyWrapper,
|
|
8
|
+
InputField,
|
|
9
|
+
ButtonWrapper,
|
|
10
|
+
Title,
|
|
11
|
+
NameWrapper
|
|
12
|
+
} from './EmailSignUp.style';
|
|
13
|
+
import ButtonWithStates from '../../Atoms/ButtonWithStates/ButtonWithStates';
|
|
14
|
+
|
|
15
|
+
import Text from '../../Atoms/Text/Text';
|
|
16
|
+
import { buildEsuValidationSchema, ESU_FIELDS } from './_EmailSignUpConfig';
|
|
17
|
+
import ErrorText from '../../Atoms/ErrorText/ErrorText';
|
|
18
|
+
import Confetti from './_Confetti';
|
|
19
|
+
|
|
20
|
+
const EmailSignUp = ({
|
|
21
|
+
title,
|
|
22
|
+
topCopy,
|
|
23
|
+
successCopy,
|
|
24
|
+
privacyCopy,
|
|
25
|
+
backgroundColour,
|
|
26
|
+
buttonColour,
|
|
27
|
+
formContext,
|
|
28
|
+
columnLayout,
|
|
29
|
+
...rest
|
|
30
|
+
}) => {
|
|
31
|
+
const {
|
|
32
|
+
formState: {
|
|
33
|
+
isValid,
|
|
34
|
+
isSubmitting,
|
|
35
|
+
isSubmitted,
|
|
36
|
+
isSubmitSuccessful,
|
|
37
|
+
errors
|
|
38
|
+
}
|
|
39
|
+
} = formContext;
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<ESUWrapper backgroundColour={backgroundColour} {...rest}>
|
|
43
|
+
<Title tag="h2" size="xxl" weight="400" family="Anton" uppercase>
|
|
44
|
+
{title}
|
|
45
|
+
</Title>
|
|
46
|
+
{!isSubmitted ? (
|
|
47
|
+
<TopCopyWrapper>
|
|
48
|
+
<Text>{topCopy}</Text>
|
|
49
|
+
</TopCopyWrapper>
|
|
50
|
+
) : (
|
|
51
|
+
isSubmitSuccessful && (
|
|
52
|
+
<>
|
|
53
|
+
<Confetti trigger={isSubmitSuccessful} />
|
|
54
|
+
<TopCopyWrapper>
|
|
55
|
+
<Text>{successCopy}</Text>
|
|
56
|
+
</TopCopyWrapper>
|
|
57
|
+
</>
|
|
58
|
+
)
|
|
59
|
+
)}
|
|
60
|
+
{!isSubmitSuccessful && (
|
|
61
|
+
<FormInner>
|
|
62
|
+
<NameWrapper columnLayout={columnLayout}>
|
|
63
|
+
<InputField
|
|
64
|
+
fieldName={ESU_FIELDS.FIRST_NAME}
|
|
65
|
+
id="first-name"
|
|
66
|
+
type="text"
|
|
67
|
+
label="First Name"
|
|
68
|
+
placeholder="Enter your first name"
|
|
69
|
+
formContext={formContext}
|
|
70
|
+
/>
|
|
71
|
+
<InputField
|
|
72
|
+
fieldName={ESU_FIELDS.LAST_NAME}
|
|
73
|
+
id="last-name"
|
|
74
|
+
type="text"
|
|
75
|
+
label="Last Name"
|
|
76
|
+
placeholder="Enter your last name"
|
|
77
|
+
formContext={formContext}
|
|
78
|
+
/>
|
|
79
|
+
</NameWrapper>
|
|
80
|
+
<InputField
|
|
81
|
+
fieldName={ESU_FIELDS.EMAIL}
|
|
82
|
+
id="email"
|
|
83
|
+
type="email"
|
|
84
|
+
label="Email Address"
|
|
85
|
+
placeholder="example@youremail.com"
|
|
86
|
+
formContext={formContext}
|
|
87
|
+
/>
|
|
88
|
+
<ButtonWrapper buttonColour={buttonColour}>
|
|
89
|
+
<ButtonWithStates
|
|
90
|
+
type="submit"
|
|
91
|
+
disabled={!isValid || isSubmitting}
|
|
92
|
+
loading={isSubmitting}
|
|
93
|
+
loadingText="Submitting..."
|
|
94
|
+
data-test="subscribe-button"
|
|
95
|
+
>
|
|
96
|
+
<Text>Subscribe</Text>
|
|
97
|
+
</ButtonWithStates>
|
|
98
|
+
</ButtonWrapper>
|
|
99
|
+
</FormInner>
|
|
100
|
+
)}
|
|
101
|
+
{isSubmitted && !isSubmitSuccessful && (
|
|
102
|
+
<>
|
|
103
|
+
{/*
|
|
104
|
+
Field errors will prevent submission,
|
|
105
|
+
so theoretically this should just be a single error set in the submission callback
|
|
106
|
+
with with RHF's `setError` method, but will neatly display multiple errors.
|
|
107
|
+
*/}
|
|
108
|
+
{Object.values(errors).map(error => (
|
|
109
|
+
<ErrorText>{error.message}</ErrorText>
|
|
110
|
+
))}
|
|
111
|
+
</>
|
|
112
|
+
)}
|
|
113
|
+
|
|
114
|
+
<PrivacyCopyWrapper>
|
|
115
|
+
<Text>{privacyCopy}</Text>
|
|
116
|
+
</PrivacyCopyWrapper>
|
|
117
|
+
</ESUWrapper>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
EmailSignUp.propTypes = {
|
|
122
|
+
title: PropTypes.string.isRequired,
|
|
123
|
+
topCopy: PropTypes.node.isRequired,
|
|
124
|
+
successCopy: PropTypes.node.isRequired,
|
|
125
|
+
privacyCopy: PropTypes.node.isRequired,
|
|
126
|
+
backgroundColour: PropTypes.string,
|
|
127
|
+
buttonColour: PropTypes.string,
|
|
128
|
+
formContext: PropTypes.shape().isRequired,
|
|
129
|
+
columnLayout: PropTypes.bool
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
EmailSignUp.defaultProps = {
|
|
133
|
+
backgroundColour: 'deep_violet_dark',
|
|
134
|
+
buttonColour: 'red',
|
|
135
|
+
columnLayout: false
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export { EmailSignUp, buildEsuValidationSchema, ESU_FIELDS };
|