diff --git a/.gitignore b/.gitignore index 9a3c7d5b531..859da7ed174 100644 --- a/.gitignore +++ b/.gitignore @@ -53,6 +53,7 @@ typings/ # dotenv environment variables file .env +.env.development # gatsby files .cache/ @@ -68,9 +69,6 @@ yarn-error.log # Yarn Integrity file .yarn-integrity -# dotenv environment variables file -.env - # next.js build output .next diff --git a/src/common/validation.js b/src/common/validation.js index 94ccabfddac..0807308e092 100644 --- a/src/common/validation.js +++ b/src/common/validation.js @@ -16,6 +16,13 @@ const validation = { return null } }, + name: (input, message) => { + if (!input) { + return message ? message : localize('Name is required') + } else { + return null + } + }, required: (input, message) => { if (!input) { return message ? message : localize('This field is required') diff --git a/src/components/custom/_agreement-label.js b/src/components/custom/_agreement-label.js index 4dad7eab0ba..71c95cc04f1 100644 --- a/src/components/custom/_agreement-label.js +++ b/src/components/custom/_agreement-label.js @@ -52,6 +52,7 @@ const AgreementLabel = ({ handleChangeCheckbox, isChecked, color }) => { translate_text="I agree to the <0>terms and conditions" components={[ ( + + + + + ) diff --git a/src/pages/blog/components/_subscribe.js b/src/pages/blog/components/_subscribe.js new file mode 100644 index 00000000000..e328d717c0e --- /dev/null +++ b/src/pages/blog/components/_subscribe.js @@ -0,0 +1,417 @@ +import React, { useEffect } from 'react' +import PropTypes from 'prop-types' +import styled from 'styled-components' +import { Title, TextWrapper } from './_common' +import paperPlane from 'images/common/blog/paperplanes.png' +import validation from 'common/validation' +import { Input, Button } from 'components/form' +import { Localize, localize } from 'components/localization' +import { Flex } from 'components/containers' +import AgreementLabel from 'components/custom/_agreement-label' +import device from 'themes/device.js' +import { DerivStore } from 'store' + +const SignupFormWrapper = styled(Flex)` + width: 100%; + align-items: initial; + justify-content: initial; + background: var(--color-blue-3); + padding: 40px 80px; + border-radius: 8px; + position: relative; + + @media ${device.tabletL} { + padding: 200px 20px 40px; + } + @media ${device.tabletS} { + width: 100%; + + & > div { + width: 100%; + } + } +` +const PaperPlaneImage = styled.img` + position: absolute; + right: 50px; + bottom: 0; + + @media screen and (max-width: 1330px) and (min-width: 991px) { + position: absolute; + right: 0; + bottom: 0; + width: 240px; + } + + @media ${device.tabletL} { + position: absolute; + top: 20px; + width: 280px; + left: 50%; + transform: translateX(-50%); + } +` +const StyledFormContent = styled.div` + @media ${device.tabletL} { + width: 100%; + max-width: 100%; + + h3, + p { + width: 100%; + max-width: 100%; + } + } +` +const InputWrapper = styled.div` + display: flex; + + > div:last-child { + margin-left: 10px; + } + input { + text-transform: none; + font-size: 12px; + } + input#name { + width: 212px; + } + p { + padding-left: 0; + margin-top: 5px; + } + input#email { + width: 300px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + @media screen and (max-width: 1330px) and (min-width: 991px) { + input#name { + width: 100%; + } + input#email { + width: 200px; + } + } + @media screen and (max-width: 991px) { + > div:last-child { + margin-left: 0; + } + } + @media ${device.tabletL} { + margin-right: 0; + flex-direction: column; + + input { + margin-left: 0 !important; + width: 100% !important; + } + } + @media ${device.tablet} { + margin-right: 0; + width: 100%; + } +` +const InputGroupForm = styled.form` + display: flex; + flex-direction: column; + width: 100%; + margin-top: 24px; + + .link-text { + color: var(--color-grey-19); + font-weight: bold; + } + + @media ${device.tabletL} { + > div { + flex-direction: column; + } + } +` +const EmailButton = styled(Button)` + padding: 9px 28px; + border-radius: 4px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + + @media ${device.tabletL} { + padding: 10px 16px; + white-space: nowrap; + min-width: unset; + margin-left: 0; + height: 40px; + width: auto; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + } +` + +const Subscribe = () => { + const [is_checked, setChecked] = React.useState(false) + const [email, setEmail] = React.useState('') + const [name, setName] = React.useState('') + const [is_submitting, setIsSubmitting] = React.useState(false) + const [submit_status, setSubmitStatus] = React.useState('') + const [email_error_msg, setEmailErrorMsg] = React.useState('') + const [name_error_msg, setNameErrorMsg] = React.useState('') + const [submit_error_msg, setSubmitErrorMsg] = React.useState('') + + const { is_eu_country } = React.useContext(DerivStore) + + useEffect(() => { + addScriptForCIO() + const options = { + headers: new Headers({ 'content-type': 'application/json' }), + mode: 'no-cors', + } + const url = 'https://assets.customer.io/assets/track.js' + fetch(url, options) + .then(() => { + setSubmitStatus(true) + }) + .catch(() => { + setSubmitStatus(false) + }) + }, []) + + const addScriptForCIO = () => { + const addScript = (settings) => { + const script = document.createElement('script') + const { async, text, src, id } = settings + + if (async) script.async = settings['async'] + if (text) script.text = settings['text'] + if (src) script.src = settings['src'] + if (id) script.id = settings['id'] + document.body.appendChild(script) + } + const site_id = process.env.GATSBY_ENV_CIO_SITE_ID + + let cio_url = 'https://assets.customer.io/assets/track.js' + if (is_eu_country) { + cio_url = 'https://assets.customer.io/assets/track-eu.js' + } + + addScript({ + text: ` + var _cio = _cio || []; + var a,b,c;a=function(f){return function(){_cio.push([f]. + concat(Array.prototype.slice.call(arguments,0)))}};b=["load","identify", + "sidentify","track","page"];for(c=0;c { + setChecked(event.currentTarget.checked) + } + + const handleInputNameChange = (e) => { + const { value } = e.target + + setName(value) + handleValidation(value) + } + + const handleInputChange = (e) => { + const { value } = e.target + + setEmail(value) + handleValidation(value) + } + + const handleValidation = (param) => { + const message = typeof param === 'object' ? param.target.value : param + setNameErrorMsg(validateName(message.replace(/\s/g, ''))) + setEmailErrorMsg(validateEmail(message.replace(/\s/g, ''))) + } + + const validateEmail = (email) => { + const error_message = validation.email(email) || submit_error_msg + + if (submit_error_msg) { + setSubmitErrorMsg('') + setSubmitStatus('') + } + + return error_message + } + + const validateName = (name) => { + const error_message = validation.name(name) || submit_error_msg + + if (submit_error_msg) { + setSubmitErrorMsg('') + setSubmitStatus('') + } + + return error_message + } + + const clearEmail = () => { + setEmail('') + setEmailErrorMsg('') + } + + const clearName = () => { + setName('') + setNameErrorMsg('') + } + + const customerioData = () => { + window._cio.identify({ + id: email, + email, + created_at: Math.round(Date.now() / 1000), + name, + }) + } + + const handleEmailSignup = (e) => { + e.preventDefault() + setIsSubmitting(true) + const formattedEmail = email.replace(/\s/g, '') + handleValidation(email) + handleValidation(name) + const has_error_email = validateEmail(formattedEmail) + const has_error_name = validateName(formattedEmail) + + if (has_error_email || has_error_name || email_error_msg || name_error_msg) { + return setIsSubmitting(false) + } + + customerioData(formattedEmail) + submit_status && setSubmitStatus('success') + clearName() + clearEmail() + } + + return ( + + + + Codestin Search App + + {localize( + 'Be among the first to get new content delivered to your inbox once a month by subscribing to our blog updates.', + )} + + + + + + + + + {localize('Subscribe')} + + + {submit_status === true && ( + + )} + {submit_status === 'success' && ( + + + + )} + {submit_status === false && ( + + + + )} + + + + ) +} + +Subscribe.propTypes = { + ebook_utm_code: PropTypes.string, + onSubmit: PropTypes.func, +} + +export default Subscribe diff --git a/src/pages/blog/form/index.js b/src/pages/blog/form/index.js new file mode 100644 index 00000000000..616cbf28f6f --- /dev/null +++ b/src/pages/blog/form/index.js @@ -0,0 +1,29 @@ +import React from 'react' +import styled from 'styled-components' +import Subscribe from '../components/_subscribe' +import Layout from 'components/layout/layout' +import { SEO, Container, Flex } from 'components/containers' +import { localize, WithIntl } from 'components/localization' + +const MainWrapper = styled(Flex)` + background-color: var(--color-white); + flex-direction: column; + overflow: hidden; +` + +const SubscriptionForm = () => { + return ( + + + + + + + + + + + ) +} + +export default WithIntl()(SubscriptionForm) diff --git a/src/pages/blog/index.js b/src/pages/blog/index.js index a895b9b51e0..e47c758e8d2 100644 --- a/src/pages/blog/index.js +++ b/src/pages/blog/index.js @@ -1,10 +1,11 @@ import React from 'react' import { graphql, useStaticQuery } from 'gatsby' import styled from 'styled-components' +import Subscribe from './components/_subscribe' import DVideoBanner from './video-banner' import Hero from './components/_hero' import Layout from 'components/layout/layout' -import { SEO, Flex } from 'components/containers' +import { Container, SEO, Flex } from 'components/containers' import { localize, WithIntl } from 'components/localization' import { Carousel } from 'components/elements' @@ -74,6 +75,11 @@ const DerivBlog = () => { + + + + + ) } diff --git a/src/pages/blog/videos/index.js b/src/pages/blog/videos/index.js index 4653e0f9314..25be55fbb3e 100644 --- a/src/pages/blog/videos/index.js +++ b/src/pages/blog/videos/index.js @@ -1,5 +1,6 @@ import React from 'react' import styled from 'styled-components' +import Subscribe from '../components/_subscribe' import AllVideos from './_all-videos' import { video_data } from './_data' import Layout from 'components/layout/layout' @@ -67,6 +68,11 @@ const VideosPage = () => ( + + + + + )