1- import React , { useState } from " react" ;
2- import { styled } from " linaria/react" ;
3- import Section from " ../Section" ;
4- import LandingContainer from " ../LandingContainer" ;
5- import { media , tm , tmDark , tmSelectors } from " ../../themes" ;
6- import backgroundImageLight from " ../../assets/email-form/bg-light-big.svg" ;
7- import backgroundImageDark from " ../../assets/email-form/bg-dark-big.svg" ;
8- import Lines from " ../../assets/email-form/lines" ;
9- import CTA from " ../ui/CTA" ;
1+ import React , { useState } from ' react' ;
2+ import { styled } from ' linaria/react' ;
3+ import Section from ' ../Section' ;
4+ import LandingContainer from ' ../LandingContainer' ;
5+ import { media , tm , tmDark , tmSelectors } from ' ../../themes' ;
6+ import backgroundImageLight from ' ../../assets/email-form/bg-light-big.svg' ;
7+ import backgroundImageDark from ' ../../assets/email-form/bg-dark-big.svg' ;
8+ import Lines from ' ../../assets/email-form/lines' ;
9+ import CTA from ' ../ui/CTA' ;
1010
1111// Props interface for the component
1212export interface EmailFormProps {
@@ -83,7 +83,7 @@ const FormContainer = styled.div`
8383` ;
8484
8585const FormTitle = styled . h2 `
86- font-family: " Source Code Pro" , monospace;
86+ font-family: ' Source Code Pro' , monospace;
8787 font-size: 18px;
8888 font-weight: 500;
8989 line-height: 1.35;
@@ -155,7 +155,7 @@ const Input = styled.input`
155155 padding: 0 24px;
156156 background-color: ${ tm ( ( { colors } ) => colors . neutral100 ) } ;
157157 border: 1px solid ${ tm ( ( { colors } ) => colors . neutral700 ) } ;
158- font-family: " Source Code Pro" , monospace;
158+ font-family: ' Source Code Pro' , monospace;
159159 font-size: 16px;
160160 line-height: 30px;
161161 letter-spacing: 0.03em;
@@ -205,18 +205,26 @@ const Input = styled.input`
205205
206206const ErrorMessage = styled . div `
207207 position: absolute;
208- bottom: -24px ;
208+ bottom: -16px ;
209209 left: 0;
210210 color: red;
211- font-size: 14px;
212- font-family: "Source Code Pro", monospace;
211+ font-size: 10px;
212+ font-family: 'Source Code Pro', monospace;
213+ ${ media . xs } {
214+ font-size: 12px;
215+ bottom: -18px;
216+ }
217+ ${ media . laptop } {
218+ font-size: 14px;
219+ bottom: -24px;
220+ }
213221` ;
214222
215223const SuccessMessage = styled . div `
216224 margin-top: 16px;
217225 color: ${ tm ( ( { colors } ) => colors . tipBorderColor ) } ;
218226 font-size: 16px;
219- font-family: " Source Code Pro" , monospace;
227+ font-family: ' Source Code Pro' , monospace;
220228 text-align: center;
221229` ;
222230
@@ -245,56 +253,56 @@ const LinesContainer = styled.div`
245253 }
246254` ;
247255
256+ const validateEmail = ( email : string ) : boolean => {
257+ const emailRegex = / ^ [ a - z A - Z 0 - 9 . ! # $ % & ' * + / = ? ^ _ ` { | } ~ - ] + @ ( [ a - z A - Z 0 - 9 - ] + \. ) + [ a - z A - Z ] { 2 , } $ / ;
258+ return emailRegex . test ( email ) ;
259+ } ;
260+
248261const EmailForm : React . FC < EmailFormProps > = ( { endpoint } ) => {
249- const [ email , setEmail ] = useState ( "" ) ;
250- const [ error , setError ] = useState ( "" ) ;
262+ const [ email , setEmail ] = useState ( '' ) ;
263+ const [ error , setError ] = useState ( '' ) ;
251264 const [ isSubmitting , setIsSubmitting ] = useState ( false ) ;
252265 const [ isSuccess , setIsSuccess ] = useState ( false ) ;
253266
254- const validateEmail = ( e : string ) : boolean => {
255- const emailRegex = / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / ;
256- return emailRegex . test ( e ) ;
257- } ;
258-
259267 const handleSubmit = async ( e : any ) => {
260268 e . preventDefault ( ) ;
261269
262270 // Reset states
263- setError ( "" ) ;
271+ setError ( '' ) ;
264272 setIsSuccess ( false ) ;
265273
266274 // Validate email
267275 if ( ! email . trim ( ) ) {
268- setError ( " Email address is required" ) ;
276+ setError ( ' Email address is required' ) ;
269277 return ;
270278 }
271279
272280 if ( ! validateEmail ( email ) ) {
273- setError ( " Please enter a valid email address" ) ;
281+ setError ( ' Please enter a valid email address' ) ;
274282 return ;
275283 }
276284
277285 setIsSubmitting ( true ) ;
278286
279287 try {
280288 const response = await fetch ( endpoint , {
281- method : " POST" ,
289+ method : ' POST' ,
282290 headers : {
283- " Content-Type" : " application/json" ,
291+ ' Content-Type' : ' application/json' ,
284292 } ,
285293 body : JSON . stringify ( { email } ) ,
286294 } ) ;
287295
288296 if ( ! response . ok ) {
289- throw new Error ( " Failed to submit email" ) ;
297+ throw new Error ( ' Failed to submit email' ) ;
290298 }
291299
292300 // Success
293- setEmail ( "" ) ;
301+ setEmail ( '' ) ;
294302 setIsSuccess ( true ) ;
295303 } catch ( err ) {
296- console . error ( " Error submitting email:" , err ) ;
297- setError ( " Failed to submit. Please try again later." ) ;
304+ console . error ( ' Error submitting email:' , err ) ;
305+ setError ( ' Failed to submit. Please try again later.' ) ;
298306 } finally {
299307 setIsSubmitting ( false ) ;
300308 }
@@ -307,39 +315,32 @@ const EmailForm: React.FC<EmailFormProps> = ({ endpoint }) => {
307315 </ LinesContainer >
308316 < FormSection >
309317 < LandingContainer >
310- < BackgroundImage
311- image = { backgroundImageLight . src }
312- imageDark = { backgroundImageDark . src }
313- />
318+ < BackgroundImage image = { backgroundImageLight . src } imageDark = { backgroundImageDark . src } />
314319 < FormContainer >
315- < FormTitle >
316- Tell me about new product features as they come out
317- </ FormTitle >
320+ < FormTitle > Tell me about new product features as they come out</ FormTitle >
318321 < FormRow >
319322 < InputContainer >
320323 < Input
321- type = " email"
322- placeholder = " email address*"
324+ type = ' email'
325+ placeholder = ' email address*'
323326 value = { email }
324- onChange = { ( e ) => setEmail ( e . target . value ) }
327+ onChange = { ( { target : { value } } : React . ChangeEvent < HTMLInputElement > ) => {
328+ setEmail ( value ) ;
329+
330+ if ( error && ( validateEmail ( value ) || value . trim ( ) === '' ) ) {
331+ setError ( '' ) ;
332+ }
333+ } }
325334 disabled = { isSubmitting }
326- aria-label = " Email address"
335+ aria-label = ' Email address'
327336 />
328337 { error && < ErrorMessage > { error } </ ErrorMessage > }
329338 </ InputContainer >
330- < CTA
331- variant = "lg"
332- disabled = { isSubmitting }
333- onClick = { ( e ) => handleSubmit ( e ) }
334- >
335- { isSubmitting ? "Submitting..." : "Get started" }
339+ < CTA variant = 'lg' disabled = { isSubmitting } onClick = { ( e ) => handleSubmit ( e ) } >
340+ { isSubmitting ? 'Submitting...' : 'Get started' }
336341 </ CTA >
337342 </ FormRow >
338- { isSuccess && (
339- < SuccessMessage >
340- Thank you! You are now subscribed to our updates.
341- </ SuccessMessage >
342- ) }
343+ { isSuccess && < SuccessMessage > Thank you! You are now subscribed to our updates.</ SuccessMessage > }
343344 </ FormContainer >
344345 </ LandingContainer >
345346 </ FormSection >
0 commit comments