1
+ 'use client' ;
2
+
3
+ import { useState } from 'react' ;
4
+ import { Box } from '@/components/ui/box' ;
5
+ import { ArrowRightIcon , MailIcon } from '@/components/ui/icon' ;
6
+ import { Heading } from '@/components/ui/heading' ;
7
+ import { Text } from '@/components/ui/text' ;
8
+ import { Input , InputIcon , InputField } from '@/components/ui/input' ;
9
+ import { Button , ButtonText , ButtonIcon } from '@/components/ui/button' ;
10
+ import {
11
+ Avatar ,
12
+ AvatarFallbackText ,
13
+ AvatarGroup ,
14
+ } from '@/components/ui/avatar' ;
15
+ import { Link } from '@/components/ui/link' ;
16
+ import { VStack } from '@/components/ui/vstack' ;
17
+ import {
18
+ Modal ,
19
+ ModalBackdrop ,
20
+ ModalContent ,
21
+ ModalCloseButton ,
22
+ ModalHeader ,
23
+ ModalBody ,
24
+ } from '@/components/ui/modal' ;
25
+ import { Icon , CloseIcon } from '@/components/ui/icon' ;
26
+ import axios from 'axios' ;
27
+ import Image from 'next/image' ;
28
+
29
+
30
+ const emailValidator =
31
+ / ^ ( ( [ ^ < > ( ) \[ \] \\ . , ; : \s @ " ] + ( \. [ ^ < > ( ) \[ \] \\ . , ; : \s @ " ] + ) * ) | ( " .+ " ) ) @ ( ( \[ [ 0 - 9 ] { 1 , 3 } \. [ 0 - 9 ] { 1 , 3 } \. [ 0 - 9 ] { 1 , 3 } \. [ 0 - 9 ] { 1 , 3 } ] ) | ( ( [ a - z A - Z \- 0 - 9 ] + \. ) + [ a - z A - Z ] { 2 , } ) ) $ / ;
32
+
33
+ interface NewsletterModalProps {
34
+ showModal : boolean ;
35
+ setShowModal : ( show : boolean ) => void ;
36
+
37
+ }
38
+
39
+ export default function NewsletterModal ( {
40
+ showModal,
41
+ setShowModal,
42
+
43
+ } : NewsletterModalProps ) {
44
+ const [ loading , setLoading ] = useState ( false ) ;
45
+ const [ , setError ] = useState ( false ) ;
46
+ const [ success , setSuccess ] = useState ( false ) ;
47
+ const [ email , setEmail ] = useState < string > ( '' ) ;
48
+ const [ errorMessage , setErrorMessage ] = useState ( '' ) ;
49
+
50
+ const makeRequestToServer = async ( ) => {
51
+ try {
52
+ setLoading ( true ) ;
53
+ setError ( false ) ;
54
+ setErrorMessage ( '' ) ;
55
+
56
+ const response = await axios . post ( '/api/listmonk' , {
57
+ email : email ,
58
+ name : ''
59
+ } ) ;
60
+
61
+ if ( response . status === 200 ) {
62
+ setSuccess ( true ) ;
63
+ setError ( false ) ;
64
+ setErrorMessage ( '' ) ;
65
+ setEmail ( '' ) ;
66
+ }
67
+ } catch ( error : any ) {
68
+ setError ( true ) ;
69
+ setSuccess ( false ) ;
70
+
71
+ if ( error . response ?. status === 409 ) {
72
+ setErrorMessage ( 'This email is already subscribed!' ) ;
73
+ } else if ( error . response ?. status === 400 ) {
74
+ setErrorMessage ( 'Please enter a valid email address!' ) ;
75
+ } else {
76
+ setErrorMessage ( error . response ?. data ?. message || 'Error subscribing to newsletter. Please try again!' ) ;
77
+ }
78
+
79
+ setEmail ( '' ) ;
80
+ } finally {
81
+ setLoading ( false ) ;
82
+ }
83
+ } ;
84
+
85
+ const subscribeToNewsLetter = ( e : any ) => {
86
+ e . preventDefault ( ) ;
87
+ if ( email === '' ) {
88
+ setErrorMessage ( 'Email address is required!' ) ;
89
+ setError ( true ) ;
90
+ } else if ( ! emailValidator . test ( email ) ) {
91
+ setErrorMessage ( 'Enter a valid email address!' ) ;
92
+ setError ( true ) ;
93
+ } else {
94
+ makeRequestToServer ( ) ;
95
+ }
96
+ } ;
97
+
98
+ const handleClose = ( ) => {
99
+ setShowModal ( false ) ;
100
+ // Reset form state when closing
101
+ setEmail ( '' ) ;
102
+ setSuccess ( false ) ;
103
+ setError ( false ) ;
104
+ setErrorMessage ( '' ) ;
105
+ } ;
106
+
107
+ return (
108
+ < Modal isOpen = { showModal } onClose = { handleClose } size = "lg" >
109
+ < ModalBackdrop />
110
+ < ModalContent className = "max-w-2xl" >
111
+ < ModalHeader >
112
+ < ModalCloseButton >
113
+ < Icon as = { CloseIcon } />
114
+ </ ModalCloseButton >
115
+ </ ModalHeader >
116
+ < ModalBody >
117
+ < Box className = "p-6" >
118
+ < VStack className = "gap-3" >
119
+ < Heading className = "text-3xl font-bold leading-9 mb-3 text-typography-900" >
120
+ Get exclusive updates!
121
+ </ Heading >
122
+ < Text className = "text-lg font-normal leading-[30px]" >
123
+ We can't do this alone, we would love feedback and the
124
+ fastest way for us to reach out to you is via emails. We
125
+ won't spam, I promise!
126
+ </ Text >
127
+ < Link
128
+ className = "text-lg font-bold underline underline-offset-4"
129
+ href = "https://gluestack.io/support"
130
+ isExternal
131
+ >
132
+ Learn more
133
+ </ Link >
134
+ </ VStack >
135
+
136
+ < Box className = "flex-col items-center md:flex-row md:items-start md:w-full mt-8" >
137
+ < Input
138
+ size = "sm"
139
+ isReadOnly = { success }
140
+ className = "flex-row px-3 py-2 flex-1 mb-4 w-full md:mb-0"
141
+ >
142
+ < InputIcon as = { MailIcon } />
143
+ < InputField
144
+ onKeyPress = { ( e : any ) => {
145
+ if ( e . key === 'Enter' ) {
146
+ subscribeToNewsLetter ( e ) ;
147
+ }
148
+ } }
149
+ onChangeText = { ( value : string ) => {
150
+ setEmail ( value ) ;
151
+ } }
152
+ value = { email }
153
+ aria-label = "email"
154
+ placeholder = "Enter your email"
155
+ />
156
+ </ Input >
157
+ { ! success && (
158
+ < Button
159
+ size = "sm"
160
+ isDisabled = { success || loading }
161
+ className = "w-full ml-0 md:w-auto md:ml-3"
162
+ onPress = { subscribeToNewsLetter }
163
+ >
164
+ { loading ? (
165
+ < ButtonText > Loading...</ ButtonText >
166
+ ) : (
167
+ < >
168
+ < ButtonText className = "font-medium leading-normal" >
169
+ Subscribe
170
+ </ ButtonText >
171
+ < ButtonIcon
172
+ className = "w-[18px] h-[18px]"
173
+ as = { ArrowRightIcon }
174
+ />
175
+ </ >
176
+ ) }
177
+ </ Button >
178
+ ) }
179
+ </ Box >
180
+
181
+ < Box className = "mt-4" >
182
+ { success && (
183
+ < Text className = "text-green-500 mt-1" >
184
+ Thank you for subscribing to our newsletter!
185
+ </ Text >
186
+ ) }
187
+ { errorMessage && (
188
+ < Text className = "text-red-500" > { errorMessage } </ Text >
189
+ ) }
190
+ </ Box >
191
+
192
+ </ Box >
193
+ </ ModalBody >
194
+ </ ModalContent >
195
+ </ Modal >
196
+ ) ;
197
+ }
0 commit comments