diff --git a/src/components/ContactForm.astro b/src/components/ContactForm.astro index 07aa22a..99b2701 100644 --- a/src/components/ContactForm.astro +++ b/src/components/ContactForm.astro @@ -2,8 +2,6 @@ const turnsiteSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY; --- - -
- +
-
@@ -38,21 +34,17 @@ const turnsiteSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY; Message -
- 500 characters remaining -
+ id="message" + name="message" + rows="4" + required + class="mt-1 w-full rounded-lg border border-black/25 dark:border-white/25 bg-transparent p-2 text-black dark:text-white focus:ring-2 focus:ring-black/25 dark:focus:ring-white/25 blend" + >
- + + \ No newline at end of file diff --git a/src/components/contactutils.ts b/src/components/contactutils.ts index 7e7d452..d962e46 100644 --- a/src/components/contactutils.ts +++ b/src/components/contactutils.ts @@ -1,176 +1,65 @@ -interface TurnstileWindow extends Window { - turnstile: { - render: (container: string | HTMLElement, options: any) => string; - reset: (widgetId?: string) => void; - getResponse: (widgetId?: string) => string | null; - }; -} - -const domainMessages: Record = { - 'husky.nz': 'Woof! Always great to hear from a fellow Husky! 🐕', - 'inde.nz': 'Why Hello there! Always awesome to see someone from Inde! 🚀', - 'rollestoncollege.nz': 'Hello what are you doing here? Testing out my form I see 🤔', -}; - -const specificEmailMessages: Record = { - 'peter@husky.nz': 'Hey, this is your own contact form silly! 😄', - 'mike.blair@inde.nz': 'Hi Mike! Nice to see you checking out my site! 👋', - 'royden@inde.nz': 'Hey Royden! Thanks for checking out my site! 👋', - 'preston.gallwas@inde.nz': 'Hey Preston! Thanks for checking out my site! 👋', -}; - -const nameMessages: Record = { - 'peter': 'Hey, that\'s my name too! 😄', - 'mike': 'Mike! Is that really you? 🤔', - 'royden': 'The legend himself! 🚀', - 'preston': 'Preston in the house! 💻', - 'bob': 'Bob the builder, can we fix it? Yes we can! 🏗️', - 'alice': 'Following any white rabbits lately? 🐰', -}; - -function resetEmailMessage(emailMessage: HTMLDivElement): void { - emailMessage.textContent = ''; - emailMessage.classList.add('hidden'); - emailMessage.classList.remove('text-blue-500', 'dark:text-blue-400'); -} - -function updateCharacterCount(textarea: HTMLTextAreaElement, charCount: HTMLElement): void { - const MAX_LENGTH = 500; - const WARNING_THRESHOLD = 200; - const CRITICAL_THRESHOLD = 50; - const remaining = MAX_LENGTH - textarea.value.length; - - // Update counter text and message - if (remaining <= 0) { - charCount.innerHTML = ` -
- You have run out of characters, please try and keep it short and sweet!!!! -
- `; - } else { - charCount.innerHTML = `${remaining} characters remaining`; - } - - charCount.classList.remove( - 'text-gray-500', 'dark:text-gray-400', - 'text-yellow-500', 'dark:text-yellow-400', - 'text-red-500', 'dark:text-red-400' - ); - - if (remaining < 0) { - charCount.classList.add('text-red-500', 'dark:text-red-400'); - } else if (remaining <= CRITICAL_THRESHOLD) { - charCount.classList.add('text-red-500', 'dark:text-red-400'); - } else if (remaining <= WARNING_THRESHOLD) { - charCount.classList.add('text-yellow-500', 'dark:text-yellow-400'); - } else { - charCount.classList.add('text-gray-500', 'dark:text-gray-400'); - } -} - -export function initializeContactForm(turnsiteSiteKey: string): void { - const form = document.getElementById('contactForm') as HTMLFormElement; - const nameInput = document.getElementById('name') as HTMLInputElement; - const emailMessage = document.getElementById('emailMessage') as HTMLDivElement; - const statusDiv = document.getElementById('statusDiv') as HTMLDivElement; - const statusText = document.getElementById('statusText') as HTMLParagraphElement; - let turnstileWidget: string; - - // Initialize Turnstile only when it's available - if (window.turnstile) { - turnstileWidget = window.turnstile.render('#turnstile-widget', { - sitekey: turnsiteSiteKey, - theme: 'auto', - }); - } - - // Reset form on page load/refresh - window.addEventListener('load', () => { - form.reset(); - resetEmailMessage(emailMessage); - updateCharacterCount(textarea, charCount); - statusDiv.classList.add('hidden'); +import { Resend } from 'resend'; +import type { APIRoute } from 'astro'; + +const resend = new Resend(import.meta.env.RESEND_API_KEY); + +async function verifyTurnstileToken(token: string) { + const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + secret: import.meta.env.TURNSTILE_SECRET_KEY, + response: token, + }), }); - // Initialize character counter - textarea.addEventListener('input', () => updateCharacterCount(textarea, charCount)); - updateCharacterCount(textarea, charCount); - - // Email validation and custom messages - emailInput.addEventListener('input', () => { - const email = emailInput.value.toLowerCase(); - resetEmailMessage(emailMessage); - - if (specificEmailMessages[email]) { - emailMessage.textContent = specificEmailMessages[email]; - emailMessage.classList.remove('hidden'); - emailMessage.classList.add('text-blue-500', 'dark:text-blue-400'); - return; - } - - const domain = email.split('@')[1]; - if (domain && domainMessages[domain]) { - emailMessage.textContent = domainMessages[domain]; - emailMessage.classList.remove('hidden'); - emailMessage.classList.add('text-blue-500', 'dark:text-blue-400'); - } - }); + const data = await response.json(); + return data.success; +} - // Name validation and custom messages - nameInput.addEventListener('input', () => { - const name = nameInput.value.toLowerCase(); - if (nameMessages[name]) { - emailMessage.textContent = nameMessages[name]; - emailMessage.classList.remove('hidden'); - emailMessage.classList.add('text-blue-500', 'dark:text-blue-400'); - } else { - resetEmailMessage(emailMessage); +export const POST: APIRoute = async ({ request }) => { + try { + const formData = await request.json(); + const { name, email, message, turnstileToken } = formData; + + // Verify turnstile token + const isValid = await verifyTurnstileToken(turnstileToken); + if (!isValid) { + return new Response( + JSON.stringify({ error: 'Invalid captcha' }), + { status: 400 } + ); } - }); - // Form submission - form.addEventListener('submit', async (e) => { - e.preventDefault(); - const formData = new FormData(form); - const turnstileToken = (window as unknown as TurnstileWindow).turnstile.getResponse(turnstileWidget); - - if (!turnstileToken) { - statusDiv.classList.remove('hidden'); - statusText.textContent = 'Please complete the captcha'; - statusText.classList.add('text-red-500'); - return; - } + const { data, error } = await resend.emails.send({ + from: import.meta.env.CONTACT_SEND_EMAIL, + to: import.meta.env.CONTACT_EMAIL, + subject: `New Contact Form Submission from ${name}`, + html: ` +

New Contact Form Submission

+

Name: ${name}

+

Email: ${email}

+

Message:

+

${message}

+ ` + }); - try { - const response = await fetch('/api/send-email', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - name: formData.get('name'), - email: formData.get('email'), - message: formData.get('message'), - turnstileToken - }), + if (error) { + return new Response(JSON.stringify({ error: error.message }), { + status: 400, }); - - const result = await response.json(); - - if (response.ok) { - statusDiv.classList.remove('hidden'); - statusText.textContent = 'Message sent successfully!'; - statusText.classList.add('text-green-500'); - form.reset(); - (window as unknown as TurnstileWindow).turnstile.reset(turnstileWidget); - } else { - throw new Error(result.message || 'Failed to send message'); - } - } catch (error) { - statusDiv.classList.remove('hidden'); - statusText.textContent = error instanceof Error ? error.message : 'An error occurred'; - statusText.classList.remove('text-green-500'); - statusText.classList.add('text-red-500'); } - }); -} \ No newline at end of file + + return new Response( + JSON.stringify({ message: 'Email sent successfully' }), + { status: 200 } + ); + } catch (e) { + return new Response( + JSON.stringify({ error: 'Failed to send email' }), + { status: 500 } + ); + } +}; \ No newline at end of file diff --git a/src/pages/api/send-email.ts b/src/pages/api/send-email.ts index e6d88d0..c28723e 100644 --- a/src/pages/api/send-email.ts +++ b/src/pages/api/send-email.ts @@ -36,7 +36,7 @@ export const POST: APIRoute = async ({ request }) => { const { data, error } = await resend.emails.send({ from: import.meta.env.CONTACT_SEND_EMAIL, to: import.meta.env.CONTACT_EMAIL, - subject: `New Contact Form Submission from ${name} there email is ${email}`, + subject: `A new message from ${name} on the main site contact form`, html: `

New Contact Form Submission

Name: ${name}

@@ -53,7 +53,7 @@ export const POST: APIRoute = async ({ request }) => { } return new Response( - JSON.stringify({ message: 'Email sent successfully, thank you I will get back to you shortly' }), + JSON.stringify({ message: 'Email sent successfully' }), { status: 200 } ); } catch (e) {