1
1
'use client' ;
2
2
3
- import { useRef , useState } from 'react' ;
3
+ import { useState } from 'react' ;
4
4
import { CallToAction , cn , Heading , Input } from '@theguild/components' ;
5
5
6
6
export function NewsletterFormCard ( props : React . HTMLAttributes < HTMLElement > ) {
7
7
type Idle = undefined ;
8
- type Pending = { status : 'pending' ; message ?: never } ;
8
+ type Pending = {
9
+ status : 'pending' ;
10
+ /**
11
+ * potentially revious error message to reduce layout shift
12
+ */
13
+ message : string | undefined ;
14
+ } ;
9
15
type Success = { status : 'success' ; message : string } ;
10
16
type Error = { status : 'error' ; message : string } ;
11
17
type State = Idle | Pending | Success | Error ;
12
18
const [ state , setState ] = useState < State > ( ) ;
13
19
14
- // we don't want to blink a message on retries when request is pending
15
- const lastErrorMessage = useRef < string > ( ) ;
16
- lastErrorMessage . current = state ?. message || lastErrorMessage . current ;
17
-
18
20
return (
19
21
< article
20
22
{ ...props }
@@ -47,7 +49,10 @@ export function NewsletterFormCard(props: React.HTMLAttributes<HTMLElement>) {
47
49
return ;
48
50
}
49
51
50
- setState ( { status : 'pending' } ) ;
52
+ setState ( s => ( {
53
+ status : 'pending' ,
54
+ message : s ?. status === 'error' ? 'Retrying...' : undefined ,
55
+ } ) ) ;
51
56
52
57
try {
53
58
const response = await fetch ( 'https://utils.the-guild.dev/api/newsletter-subscribe' , {
@@ -57,8 +62,7 @@ export function NewsletterFormCard(props: React.HTMLAttributes<HTMLElement>) {
57
62
58
63
const json = await response . json ( ) ;
59
64
if ( json . status === 'success' ) {
60
- lastErrorMessage . current = undefined ;
61
- setState ( { status : 'success' , message : json . message } ) ;
65
+ setState ( { status : 'success' , message : 'Please check your email to confirm.' } ) ;
62
66
} else {
63
67
setState ( { status : 'error' , message : json . message } ) ;
64
68
}
@@ -78,12 +82,21 @@ export function NewsletterFormCard(props: React.HTMLAttributes<HTMLElement>) {
78
82
setState ( { status : 'error' , message : 'Something went wrong. Please let us know.' } ) ;
79
83
}
80
84
} }
85
+ onReset = { ( ) => {
86
+ setState ( undefined ) ;
87
+ } }
81
88
>
82
89
< Input
83
90
name = "email"
84
91
placeholder = "E-mail"
85
- severity = { lastErrorMessage . current ? 'critical' : undefined }
86
- message = { lastErrorMessage . current }
92
+ severity = {
93
+ state ?. status === 'error'
94
+ ? 'critical'
95
+ : state ?. status === 'success'
96
+ ? 'positive'
97
+ : undefined
98
+ }
99
+ message = { state ?. message }
87
100
/>
88
101
{ ! state || state . status === 'error' ? (
89
102
< CallToAction type = "submit" variant = "secondary-inverted" className = "mt-2 !w-full" >
@@ -103,13 +116,6 @@ export function NewsletterFormCard(props: React.HTMLAttributes<HTMLElement>) {
103
116
type = "reset"
104
117
variant = "secondary-inverted"
105
118
className = "group/button mt-2 !w-full before:absolute"
106
- onClick = { ( ) => {
107
- // the default behavior of <button type="reset"> doesn't work here
108
- // because it gets unmounted too fast
109
- setTimeout ( ( ) => {
110
- setState ( undefined ) ;
111
- } , 0 ) ;
112
- } }
113
119
>
114
120
< span className = "group-hover/button:hidden group-focus/button:hidden" > Subscribed</ span >
115
121
< span aria-hidden className = "hidden group-hover/button:block group-focus/button:block" >
0 commit comments