11/** @jsxImportSource @emotion /react */
22
3- import { Fragment , useState , type ReactNode , type SyntheticEvent , type HTMLAttributes } from 'react'
3+ import { Fragment , useState , type ReactNode , type HTMLAttributes , useTransition } from 'react'
4+
5+ import { subscribeToButtondown } from '../app/actions'
46
57import { useMediaQuery } from '../lib/media'
68import { Button } from './primitives/Button'
79import { Field } from './primitives/Field'
810import { Stack } from './primitives/Stack'
9-
10- const validEmail = ( email : string ) =>
11- / ^ [ a - z A - Z 0 - 9 . ! # $ % & ' * + \/ = ? ^ _ ` { | } ~ - ] + @ [ a - z A - Z 0 - 9 ] (?: [ a - z A - Z 0 - 9 - ] { 0 , 61 } [ a - z A - Z 0 - 9 ] ) ? (?: \. [ a - z A - Z 0 - 9 ] (?: [ a - z A - Z 0 - 9 - ] { 0 , 61 } [ a - z A - Z 0 - 9 ] ) ? ) * $ / . test (
12- email
13- )
14-
15- const signupURL = 'https://signup.keystonejs.cloud/api/newsletter-signup'
11+ import { usePathname } from 'next/navigation'
1612
1713type SubscriptFormProps = {
1814 autoFocus ?: boolean
@@ -21,89 +17,112 @@ type SubscriptFormProps = {
2117} & HTMLAttributes < HTMLFormElement >
2218
2319export function SubscribeForm ( { autoFocus, stacked, children, ...props } : SubscriptFormProps ) {
24- const [ email , setEmail ] = useState ( '' )
25- const [ loading , setLoading ] = useState ( false )
20+ const pathname = usePathname ( )
21+ const mq = useMediaQuery ( )
22+ const [ isPending , startTransition ] = useTransition ( )
23+
2624 const [ error , setError ] = useState < string | null > ( null )
2725 const [ formSubmitted , setFormSubmitted ] = useState ( false )
28- const mq = useMediaQuery ( )
2926
30- const onSubmit = ( event : SyntheticEvent ) => {
31- event . preventDefault ( )
32- setError ( null )
33- // Check if user wants to subscribe.
34- // and there's a valid email address.
35- // Basic validation check on the email?
36- setLoading ( true )
37- if ( validEmail ( email ) ) {
38- // if good add email to mailing list
39- // and redirect to dashboard.
40- return fetch ( signupURL , {
41- method : 'POST' ,
42- headers : {
43- 'Content-Type' : 'application/json' ,
44- } ,
45- body : JSON . stringify ( {
46- email,
47- source : '@keystone-6/website' ,
48- } ) ,
49- } )
50- . then ( res => {
51- if ( res . status !== 200 ) {
52- // We explicitly set the status in our endpoint
53- // any status that isn't 200 we assume is a failure
54- // which we want to surface to the user
55- res . json ( ) . then ( ( { error } ) => {
56- setError ( error )
57- setLoading ( false )
58- } )
59- } else {
60- setFormSubmitted ( true )
61- }
62- } )
63- . catch ( err => {
64- // network errors or failed parse
65- setError ( err . toString ( ) )
66- setLoading ( false )
67- } )
68- } else {
69- setLoading ( false )
70- // if email fails validation set error message
71- setError ( 'Please enter a valid email' )
72- return
73- }
27+ // Augment the server action with the pathname
28+ const subscribeToButtondownWithPathname = subscribeToButtondown . bind ( null , pathname )
29+
30+ async function submitAction ( formData : FormData ) {
31+ startTransition ( async ( ) => {
32+ const response = await subscribeToButtondownWithPathname ( formData )
33+ if ( response . error ) return setError ( response . error )
34+ if ( response . success ) return setFormSubmitted ( true )
35+ } )
7436 }
7537
7638 return ! formSubmitted ? (
7739 < Fragment >
7840 { children }
79- < form onSubmit = { onSubmit } { ...props } >
41+ < form action = { submitAction } { ...props } >
8042 < Stack
8143 orientation = { stacked ? 'vertical' : 'horizontal' }
8244 block = { stacked }
45+ gap = { 5 }
8346 css = { {
8447 justifyItems : stacked ? 'baseline' : undefined ,
8548 } }
8649 >
50+ < label
51+ htmlFor = "email"
52+ css = { {
53+ position : 'absolute' ,
54+ width : '1px' ,
55+ height : '1px' ,
56+ padding : 0 ,
57+ margin : '-1px' ,
58+ overflow : 'hidden' ,
59+ clip : 'rect(0, 0, 0, 0)' ,
60+ whiteSpace : 'nowrap' ,
61+ borderWidth : '0' ,
62+ } }
63+ >
64+ Email address
65+ </ label >
8766 < Field
8867 type = "email"
8968 autoComplete = "off"
9069 autoFocus = { autoFocus }
9170 placeholder = "Your email address"
92- value = { email }
93- onChange = { e => setEmail ( e . target . value ) }
9471 css = { mq ( {
9572 maxWidth : '25rem' ,
9673 margin : [ '0 auto' , 0 ] ,
9774 } ) }
75+ name = "email"
76+ id = "email"
77+ required
9878 />
99- < Button look = "secondary" size = "small" loading = { loading } type = { 'submit' } >
79+
80+ < div css = { { display : 'flex' , flexWrap : 'wrap' , gap : '0.25rem 0.75rem' } } >
81+ < div css = { { display : 'flex' , alignItems : 'center' , gap : '0.25rem' } } >
82+ < input
83+ type = "checkbox"
84+ name = "tags"
85+ id = "mailing-list-keystone"
86+ css = { { height : '1rem' , width : '1rem' } }
87+ value = "keystone_list"
88+ defaultChecked
89+ />
90+ < label css = { { fontSize : '0.9rem' } } htmlFor = "mailing-list-keystone" >
91+ Keystone news
92+ </ label >
93+ </ div >
94+ < div css = { { display : 'flex' , alignItems : 'center' , gap : '0.25rem' } } >
95+ < input
96+ type = "checkbox"
97+ name = "tags"
98+ id = "mailing-list-thinkmill"
99+ css = { { height : '1rem' , width : '1rem' } }
100+ value = "thinkmill_list"
101+ />
102+ < label css = { { fontSize : '0.9rem' } } htmlFor = "mailing-list-thinkmill" >
103+ Thinkmill news (
104+ < a
105+ href = "https://www.thinkmill.com.au/newsletter/tailwind-for-designers-multi-brand-design-systems-and-a-search-tool-for-public-domain-content"
106+ target = "_blank"
107+ aria-label = "Thinkmill (Opens in new tab)"
108+ >
109+ example
110+ </ a >
111+ )
112+ </ label >
113+ </ div >
114+ </ div >
115+
116+ < Button look = "secondary" size = "small" loading = { isPending } type = "submit" >
100117 { error ? 'Try again' : 'Subscribe' }
101118 </ Button >
102119 </ Stack >
103- { error ? < p css = { { margin : '0.5rem, 0' , color : 'red' } } > { error } </ p > : null }
120+ { error ? (
121+ < p css = { { marginTop : '0.5rem' , color : 'red' , fontSize : '0.85rem' } } > { error } </ p >
122+ ) : null }
104123 </ form >
105124 </ Fragment >
106125 ) : (
107- < p > ❤️ Thank you for subscribing! </ p >
126+ < p > ❤️ Thank you! Please check your email to confirm your subscription. </ p >
108127 )
109128}
0 commit comments