|
85 | 85 | </div> |
86 | 86 | </div> |
87 | 87 | </section> |
88 | | - |
89 | | -<script> |
90 | | - let turnstileLoaded = false; |
91 | | - let widgetId = null; |
92 | | - |
93 | | - const script = document.createElement("script"); |
94 | | - script.src = |
95 | | - "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit"; |
96 | | - script.async = true; |
97 | | - script.defer = true; |
98 | | - script.onload = () => { |
99 | | - turnstileLoaded = true; |
100 | | - renderTurnstile(); |
101 | | - }; |
102 | | - document.head.appendChild(script); |
103 | | - |
104 | | - function renderTurnstile() { |
105 | | - if (!turnstileLoaded || !window.turnstile) { |
106 | | - setTimeout(renderTurnstile, 100); |
107 | | - return; |
108 | | - } |
109 | | - |
110 | | - try { |
111 | | - const container = document.getElementById("turnstile-widget"); |
112 | | - if (container && !widgetId) { |
113 | | - widgetId = window.turnstile.render("#turnstile-widget", { |
114 | | - sitekey: "0x4AAAAAACJLRahSOte2nhUO", |
115 | | - theme: "dark", |
116 | | - size: "normal", |
117 | | - callback: function (token) { |
118 | | - console.log("Turnstile verified:", token); |
119 | | - }, |
120 | | - "error-callback": function () { |
121 | | - console.error("Turnstile error"); |
122 | | - showMessage( |
123 | | - "Verification failed. Please refresh the page.", |
124 | | - "error" |
125 | | - ); |
126 | | - }, |
127 | | - "expired-callback": function () { |
128 | | - console.log("Turnstile expired"); |
129 | | - }, |
130 | | - }); |
131 | | - } |
132 | | - } catch (error) { |
133 | | - console.error("Failed to render Turnstile:", error); |
134 | | - showMessage( |
135 | | - "Could not load verification. Please refresh the page.", |
136 | | - "error" |
137 | | - ); |
138 | | - } |
139 | | - } |
140 | | - |
141 | | - function initForm() { |
142 | | - const form = document.getElementById("contact-form") as HTMLFormElement; |
143 | | - const submitBtn = form?.querySelector( |
144 | | - 'button[type="submit"]' |
145 | | - ) as HTMLButtonElement; |
146 | | - |
147 | | - if (!form) return; |
148 | | - |
149 | | - form.addEventListener("submit", async (e) => { |
150 | | - e.preventDefault(); |
151 | | - |
152 | | - const token = window.turnstile?.getResponse(widgetId); |
153 | | - |
154 | | - if (!token) { |
155 | | - showMessage("Please complete the verification", "error"); |
156 | | - return; |
157 | | - } |
158 | | - |
159 | | - submitBtn.disabled = true; |
160 | | - submitBtn.textContent = "Sending..."; |
161 | | - |
162 | | - try { |
163 | | - const formData = new FormData(form); |
164 | | - const data = Object.fromEntries(formData); |
165 | | - |
166 | | - const response = await fetch("/api/contact", { |
167 | | - method: "POST", |
168 | | - headers: { "Content-Type": "application/json" }, |
169 | | - body: JSON.stringify({ ...data, token }), |
170 | | - }); |
171 | | - |
172 | | - if (response.ok) { |
173 | | - form.reset(); |
174 | | - if (window.turnstile && widgetId) { |
175 | | - window.turnstile.reset(widgetId); |
176 | | - } |
177 | | - showMessage("Message sent successfully!", "success"); |
178 | | - } else { |
179 | | - const errorData = await response.json().catch(() => ({})); |
180 | | - showMessage( |
181 | | - errorData.error || "Failed to send message. Please try again.", |
182 | | - "error" |
183 | | - ); |
184 | | - } |
185 | | - } catch (error) { |
186 | | - console.error("Form submission error:", error); |
187 | | - showMessage("An error occurred. Please try again.", "error"); |
188 | | - } finally { |
189 | | - submitBtn.disabled = false; |
190 | | - submitBtn.textContent = "Send message"; |
191 | | - } |
192 | | - }); |
193 | | - } |
194 | | - |
195 | | - function showMessage(text: string, type: string) { |
196 | | - const messageEl = document.getElementById("form-message"); |
197 | | - if (messageEl) { |
198 | | - messageEl.textContent = text; |
199 | | - messageEl.className = `text-sm ${ |
200 | | - type === "success" ? "text-green-500" : "text-red-500" |
201 | | - }`; |
202 | | - messageEl.classList.remove("hidden"); |
203 | | - setTimeout(() => messageEl.classList.add("hidden"), 5000); |
204 | | - } |
205 | | - } |
206 | | - |
207 | | - if (document.readyState === "loading") { |
208 | | - document.addEventListener("DOMContentLoaded", () => { |
209 | | - initForm(); |
210 | | - renderTurnstile(); |
211 | | - }); |
212 | | - } else { |
213 | | - initForm(); |
214 | | - renderTurnstile(); |
215 | | - } |
216 | | -</script> |
0 commit comments