-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix contact form with small regestion by removeing word count and spi…
…cle email messages
- Loading branch information
1 parent
dbfa5b1
commit 404bcdb
Showing
3 changed files
with
132 additions
and
196 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<string, string> = { | ||
'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<string, string> = { | ||
'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<string, string> = { | ||
'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 = ` | ||
<div class="text-l mt-1 text-red-500 dark:text-red-400"> | ||
You have run out of characters, please try and keep it short and sweet!!!! | ||
</div> | ||
`; | ||
} else { | ||
charCount.innerHTML = `<span>${remaining} characters remaining</span>`; | ||
} | ||
|
||
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: ` | ||
<h2>New Contact Form Submission</h2> | ||
<p><strong>Name:</strong> ${name}</p> | ||
<p><strong>Email:</strong> ${email}</p> | ||
<p><strong>Message:</strong></p> | ||
<p>${message}</p> | ||
` | ||
}); | ||
|
||
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'); | ||
} | ||
}); | ||
} | ||
|
||
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 } | ||
); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters