1
+ // Configuration
2
+ const CONFIG = { displayTime : 500000 , loadingTime : 1500 , maxRetries : 3 } ;
3
+ const state = { retryCount : 0 } ;
4
+
5
+ // Form submission handler
6
+ document . getElementById ( 'contactForm' ) . addEventListener ( 'submit' , async function ( e ) {
7
+ e . preventDefault ( ) ;
8
+ try {
9
+ const formData = validateFormData ( {
10
+ name : document . getElementById ( 'name' ) . value . trim ( ) ,
11
+ email : document . getElementById ( 'email' ) . value . trim ( ) ,
12
+ message : document . getElementById ( 'message' ) . value . trim ( )
13
+ } ) ;
14
+ const recaptchaResponse = await getRecaptchaResponse ( ) ;
15
+ await processFormSubmission ( formData , recaptchaResponse ) ;
16
+ } catch ( error ) {
17
+ handleError ( error ) ;
18
+ }
19
+ } ) ;
20
+
21
+ // Core functions
22
+ function validateFormData ( data ) {
23
+ const errors = [ ] ;
24
+ if ( ! data . name ) errors . push ( 'Name is required!' ) ;
25
+ if ( ! data . email ) errors . push ( 'Email is required!' ) ;
26
+ if ( ! data . message ) errors . push ( 'Message is required!' ) ;
27
+ if ( data . email && ! / ^ [ ^ \s @ ] + @ [ ^ \s @ ] + \. [ ^ \s @ ] + $ / . test ( data . email ) ) errors . push ( 'Invalid email!' ) ;
28
+ if ( errors . length ) throw new Error ( errors . join ( ', ' ) ) ;
29
+ return data ;
30
+ }
31
+
32
+ async function getRecaptchaResponse ( ) {
33
+ const response = grecaptcha . getResponse ( ) ;
34
+ if ( ! response ) throw new Error ( 'Please complete the reCAPTCHA verification' ) ;
35
+ return response ;
36
+ }
37
+
38
+ async function processFormSubmission ( formData , recaptchaResponse ) {
39
+ showMessage ( 'Verifying reCAPTCHA and submitting form...' , 'info' ) ;
40
+ try {
41
+ await new Promise ( resolve => setTimeout ( resolve , CONFIG . loadingTime ) ) ;
42
+ const info = await extractRecaptchaInfo ( recaptchaResponse ) ;
43
+ displaySuccessMessage ( info ) ;
44
+ resetForm ( ) ;
45
+ } catch ( error ) {
46
+ throw new Error ( `Form submission failed: ${ error . message } ` ) ;
47
+ }
48
+ }
49
+
50
+ async function extractRecaptchaInfo ( response ) {
51
+ const timestamp = new Date ( ) ;
52
+ return {
53
+ timestamp : timestamp . toLocaleTimeString ( ) ,
54
+ date : timestamp . toLocaleDateString ( ) ,
55
+ browserInfo : getBrowserInfo ( ) ,
56
+ deviceInfo : getDeviceInfo ( )
57
+ } ;
58
+ }
59
+
60
+ // Helper functions
61
+ function getBrowserInfo ( ) {
62
+ const ua = navigator . userAgent ;
63
+ const browser = {
64
+ chrome : / C h r o m e \/ ( [ 0 - 9 . ] + ) / ,
65
+ firefox : / F i r e f o x \/ ( [ 0 - 9 . ] + ) / ,
66
+ safari : / V e r s i o n \/ ( [ 0 - 9 . ] + ) .* S a f a r i / ,
67
+ edge : / E d g \/ ( [ 0 - 9 . ] + ) / ,
68
+ ie : / M S I E ( [ 0 - 9 . ] + ) /
69
+ } ;
70
+
71
+ for ( const [ name , regex ] of Object . entries ( browser ) ) {
72
+ const match = ua . match ( regex ) ;
73
+ if ( match ) return { name : name . charAt ( 0 ) . toUpperCase ( ) + name . slice ( 1 ) , version : match [ 1 ] } ;
74
+ }
75
+ return { name : 'Unknown' , version : 'Unknown' } ;
76
+ }
77
+
78
+ function getDeviceInfo ( ) {
79
+ return {
80
+ screenSize : `${ window . innerWidth } x${ window . innerHeight } ` ,
81
+ platform : navigator . platform ,
82
+ language : navigator . language
83
+ } ;
84
+ }
85
+
86
+ function displaySuccessMessage ( info ) {
87
+ const successMessage = `
88
+ <div class="recaptcha-details">
89
+ <h3>reCAPTCHA Verification Details</h3>
90
+ <div class="info-grid">
91
+ <div class="info-card">
92
+ <div class="info-icon">🌐</div>
93
+ <div class="info-content">
94
+ <h4>Browser Information</h4>
95
+ <p>${ info . browserInfo . name } ${ info . browserInfo . version } </p>
96
+ <p>Platform: ${ info . deviceInfo . platform } </p>
97
+ <p>Language: ${ info . deviceInfo . language } </p>
98
+ </div>
99
+ </div>
100
+ <div class="info-card">
101
+ <div class="info-icon">📱</div>
102
+ <div class="info-content">
103
+ <h4>Device Details</h4>
104
+ <p>Screen: ${ info . deviceInfo . screenSize } </p>
105
+ <p>Time: ${ info . timestamp } </p>
106
+ <p>Date: ${ info . date } </p>
107
+ </div>
108
+ </div>
109
+ </div>
110
+ </div>
111
+ ` ;
112
+ showMessage ( successMessage , 'success' ) ;
113
+ }
114
+
115
+ function resetForm ( ) {
116
+ document . getElementById ( 'contactForm' ) . reset ( ) ;
117
+ grecaptcha . reset ( ) ;
118
+ state . retryCount = 0 ;
119
+ }
120
+
121
+ function handleError ( error ) {
122
+ console . error ( 'Error:' , error ) ;
123
+ if ( state . retryCount < CONFIG . maxRetries ) {
124
+ state . retryCount ++ ;
125
+ showMessage ( `Error: ${ error . message } . Retrying... (${ state . retryCount } /${ CONFIG . maxRetries } )` , 'error' ) ;
126
+ setTimeout ( ( ) => grecaptcha . reset ( ) , 1000 ) ;
127
+ } else {
128
+ showMessage ( `Error: ${ error . message } . Please try again later.` , 'error' ) ;
129
+ state . retryCount = 0 ;
130
+ }
131
+ }
132
+
133
+ function showMessage ( message , type ) {
134
+ const messageContainer = document . getElementById ( 'messageContainer' ) ;
135
+ messageContainer . innerHTML = message ;
136
+ messageContainer . className = type + ' visible' ;
137
+
138
+ if ( type === 'info' ) {
139
+ messageContainer . classList . add ( 'loading' ) ;
140
+ }
141
+
142
+ if ( type !== 'info' ) {
143
+ setTimeout ( ( ) => {
144
+ messageContainer . innerHTML = '' ;
145
+ messageContainer . className = '' ;
146
+ } , CONFIG . displayTime ) ;
147
+ }
148
+ }
149
+
150
+ // reCAPTCHA expiration handler
151
+ window . onload = function ( ) {
152
+ window . recaptchaExpired = ( ) => showMessage ( 'reCAPTCHA has expired. Please verify again!' , 'error' ) ;
153
+ } ;
0 commit comments