1
1
<script setup lang="ts">
2
2
import { ref , onMounted } from " vue" ;
3
3
4
- // Track form submission state and response message
5
4
const responseMessage = ref <string >();
6
5
const isSubmitting = ref <boolean >(false );
6
+ const formVisible = ref <boolean >(true );
7
7
8
8
const TURNSTILE_SITE_KEY = import .meta .env .PUBLIC_TURNSTILE_SITE_KEY || ' {TURNSTILE_SITE_KEY}' ;
9
9
10
- // Data for form inputs with two-way binding
11
10
const formData = ref ({
12
11
name: ' ' ,
13
12
email: ' ' ,
@@ -18,16 +17,13 @@ const formData = ref({
18
17
turnstileToken: ' '
19
18
});
20
19
21
- // Cloudflare Turnstile
22
20
onMounted (() => {
23
- // Dynamically load the Turnstile widget
24
21
const script = document .createElement (" script" );
25
22
script .src = " https://challenges.cloudflare.com/turnstile/v0/api.js" ;
26
23
script .async = true ;
27
24
script .defer = true ;
28
25
document .head .appendChild (script );
29
-
30
- // Initialize Turnstile once the script is loaded
26
+
31
27
script .onload = () => {
32
28
if (window .turnstile ) {
33
29
window .turnstile .render (" #turnstile-container" , {
@@ -40,13 +36,11 @@ onMounted(() => {
40
36
},
41
37
});
42
38
};
43
-
44
39
};
45
40
});
46
41
47
- // Phone number formatting logic
48
42
function formatPhoneNumber(value : string ): string {
49
- const cleaned = value .replace (/ \D / g , ' ' ); // Remove non-digit characters
43
+ const cleaned = value .replace (/ \D / g , ' ' );
50
44
const match = cleaned .match (/ (\d {0,3} )(\d {0,3} )(\d {0,4} )/ );
51
45
if (! match ) return ' ' ;
52
46
return ! match [2 ] ? match [1 ] : ` ${match [1 ]}-${match [2 ]}${match [3 ] ? ' -' + match [3 ] : ' ' } ` ;
@@ -57,14 +51,12 @@ function handlePhoneInput(event: Event) {
57
51
formData .value .phone = formatPhoneNumber (input .value );
58
52
};
59
53
60
- // Set character limits
61
54
const nameMaxLength = 100 ;
62
55
const emailMaxLength = 150 ;
63
56
const titleMaxLength = 50 ;
64
57
const companyMaxLength = 100 ;
65
58
const messageMaxLength = 500 ;
66
59
67
- // Handle form submission
68
60
async function submit(e : Event ) {
69
61
e .preventDefault ();
70
62
@@ -78,7 +70,7 @@ async function submit(e: Event) {
78
70
};
79
71
80
72
isSubmitting .value = true ;
81
- responseMessage .value = ' ' ; // Clear previous response message
73
+ responseMessage .value = ' ' ;
82
74
83
75
const dataToSend = new FormData ();
84
76
dataToSend .append (' name' , formData .value .name );
@@ -89,10 +81,6 @@ async function submit(e: Event) {
89
81
dataToSend .append (' message' , formData .value .message );
90
82
dataToSend .append (' turnstileToken' , formData .value .turnstileToken );
91
83
92
- // TODO: Rework this.
93
- // POST works and message is sent but response is ignored.
94
- // Make use of the server response!
95
-
96
84
try {
97
85
const response = await fetch (" /api/contact" , {
98
86
method: " POST" ,
@@ -103,7 +91,8 @@ async function submit(e: Event) {
103
91
104
92
if (response .ok ) {
105
93
responseMessage .value = " Message sent successfully!" ;
106
- resetForm ();
94
+ // Instead of resetting the form, hide it.
95
+ formVisible .value = false ;
107
96
} else {
108
97
responseMessage .value = ` Error: ${data .message || " Something went wrong" } ` ;
109
98
}
@@ -113,27 +102,13 @@ async function submit(e: Event) {
113
102
isSubmitting .value = false ;
114
103
};
115
104
};
116
-
117
- // Reset form data
118
- function resetForm() {
119
- formData .value = {
120
- name: ' ' ,
121
- phone: ' ' ,
122
- email: ' ' ,
123
- title: ' ' ,
124
- company: ' ' ,
125
- message: ' ' ,
126
- turnstileToken: ' '
127
- };
128
- responseMessage .value = ' ' ;
129
- };
130
105
</script >
131
106
132
-
133
107
<template >
134
108
<div class =" flex flex-col max-w-xl mx-auto rounded-lg backdrop-blur border border-[var(--highlight-blue-200)] dark:border-[var(--highlight-blue-400)] bg-[var(--neutral-100)] dark:bg-[var(--highlight-blue-900)] shadow p-4 sm:p-6 lg:p-8 w-full" >
135
- <form @submit =" submit" >
136
-
109
+
110
+ <!-- Show the form if formVisible is true -->
111
+ <form v-if =" formVisible" @submit =" submit" >
137
112
<div class =" mb-[15px]" >
138
113
<label for =" name" >Name <span class =" text-red-600" >*</span ></label >
139
114
<input
@@ -170,9 +145,9 @@ function resetForm() {
170
145
class =" flex items-center cursor-pointer text-[var(--neutral-400)] dark:text-[var(--neutral-100)]"
171
146
title =" Callbacks for US numbers only!"
172
147
>
173
- <svg xmlns =" http://www.w3.org/2000/svg" width =" 1em" height =" 1em" viewBox =" 0 0 24 24" >
174
- <path fill =" #6388c5" d =" M11 9h2V7h-2m1 13c-4.41 0-8-3.59-8-8s3.59-8 8-8s8 3.59 8 8s-3.59 8-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m-1 15h2v-6h-2z" />
175
- </svg >
148
+ <svg xmlns =" http://www.w3.org/2000/svg" width =" 1em" height =" 1em" viewBox =" 0 0 24 24" >
149
+ <path fill =" #6388c5" d =" M11 9h2V7h-2m1 13c-4.41 0-8-3.59-8-8s3.59-8 8-8s8 3.59 8 8s-3.59 8-8 8m0-18A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10A10 10 0 0 0 12 2m-1 15h2v-6h-2z" />
150
+ </svg >
176
151
</span >
177
152
</div >
178
153
<div class =" mb-[15px]" >
@@ -254,5 +229,18 @@ function resetForm() {
254
229
255
230
<p v-if =" responseMessage" class =" response-message" >{{ responseMessage }}</p >
256
231
</form >
232
+
233
+ <!-- Show a success message if formVisible is false -->
234
+ <div v-else class =" success-message" >
235
+ <div class =" flex justify-center items-center" >
236
+ <svg xmlns =" http://www.w3.org/2000/svg" width =" 64" height =" 64" viewBox =" 0 0 24 24" >
237
+ <path fill =" hsl(136, 48%, 46%)" d =" M20 12a8 8 0 0 1-8 8a8 8 0 0 1-8-8a8 8 0 0 1 8-8c.76 0 1.5.11 2.2.31l1.57-1.57A9.8 9.8 0 0 0 12 2A10 10 0 0 0 2 12a10 10 0 0 0 10 10a10 10 0 0 0 10-10M7.91 10.08L6.5 11.5L11 16L21 6l-1.41-1.42L11 13.17z" />
238
+ </svg >
239
+ </div >
240
+ <h2 class =" flex justify-center items-center mb-4" >Message Sent!</h2 >
241
+ <p class =" flex justify-center text-center mb-2" >Thank you for contacting us!</p >
242
+ <p class =" flex justify-center text-center" >We will get back to you within 1-2 business days.</p >
243
+ <p v-if =" responseMessage" >{{ responseMessage }}</p >
244
+ </div >
257
245
</div >
258
246
</template >
0 commit comments