Load contact form JS as external script
This commit is contained in:
parent
481c6a1627
commit
4c0bdbdbac
2 changed files with 263 additions and 203 deletions
55
public/contact-form.js
Normal file
55
public/contact-form.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
(() => {
|
||||
const form = document.querySelector("[data-contact-form]");
|
||||
const message = document.querySelector("[data-form-message]");
|
||||
const submitButton = document.querySelector("[data-form-submit]");
|
||||
|
||||
if (!form || !message || !submitButton) return;
|
||||
|
||||
form.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
if (submitButton.disabled) return;
|
||||
|
||||
submitButton.disabled = true;
|
||||
submitButton.textContent = "Sending...";
|
||||
message.textContent = "";
|
||||
|
||||
try {
|
||||
const response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
body: new FormData(form),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
let errorMessage = "Request failed";
|
||||
const errorData = await response.json().catch(() => null);
|
||||
if (errorData?.error) {
|
||||
errorMessage = errorData.details
|
||||
? `${errorData.error} (${errorData.details})`
|
||||
: errorData.error;
|
||||
} else {
|
||||
const errorText = await response.text().catch(() => "");
|
||||
if (errorText.trim()) {
|
||||
errorMessage = `${response.status} ${response.statusText}: ${errorText}`;
|
||||
} else {
|
||||
errorMessage = `${response.status} ${response.statusText}`;
|
||||
}
|
||||
}
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
message.textContent = "Thanks! Your message has been sent.";
|
||||
form.reset();
|
||||
if (window.turnstile && typeof window.turnstile.reset === "function") {
|
||||
window.turnstile.reset();
|
||||
}
|
||||
} catch (error) {
|
||||
message.textContent =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Sorry, something went wrong. Please try again.";
|
||||
} finally {
|
||||
submitButton.disabled = false;
|
||||
submitButton.textContent = "Send message";
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
@ -19,10 +19,13 @@ const turnstileSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY ?? "";
|
|||
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
|
||||
async
|
||||
defer
|
||||
></script>
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
<Fragment slot="head">
|
||||
<script src="/contact-form.js" defer></script>
|
||||
</Fragment>
|
||||
<div class="flex flex-col min-h-screen items-center bg-[#e2e2e2]">
|
||||
<main class="w-full">
|
||||
<section class="w-full max-w-[1200px] mx-auto px-0 sm:px-8 mt-0">
|
||||
|
|
@ -31,19 +34,35 @@ const turnstileSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY ?? "";
|
|||
style="background-image: url(/222957077_6028824210491349_4146132303877993139_n-1920w.webp);"
|
||||
>
|
||||
<div class="absolute inset-0 bg-black/45"></div>
|
||||
<SiteHeader navigationItems={navigationItems} theme="dark" className="px-6 sm:px-4" />
|
||||
<div class="relative px-6 sm:px-8 pb-32 pt-6 sm:pb-24 sm:pt-8">
|
||||
<div class="max-w-none sm:max-w-[760px] rounded-[7px] bg-black/45 px-5 py-5 sm:px-6 sm:py-6 backdrop-blur-sm">
|
||||
<p class="[font-family:'Public_Sans',Helvetica] font-semibold text-xs sm:text-sm uppercase tracking-[0.2em] text-white/90">
|
||||
<SiteHeader
|
||||
navigationItems={navigationItems}
|
||||
theme="dark"
|
||||
className="px-6 sm:px-4"
|
||||
/>
|
||||
<div
|
||||
class="relative px-6 sm:px-8 pb-32 pt-6 sm:pb-24 sm:pt-8"
|
||||
>
|
||||
<div
|
||||
class="max-w-none sm:max-w-[760px] rounded-[7px] bg-black/45 px-5 py-5 sm:px-6 sm:py-6 backdrop-blur-sm"
|
||||
>
|
||||
<p
|
||||
class="[font-family:'Public_Sans',Helvetica] font-semibold text-xs sm:text-sm uppercase tracking-[0.2em] text-white/90"
|
||||
>
|
||||
Get in touch
|
||||
</p>
|
||||
<div class="mt-3 h-[2px] w-10 bg-white/70"></div>
|
||||
<h1 class="mt-4 [font-family:'Merriweather',Helvetica] font-bold text-white text-[34px] sm:text-[44px] leading-[1.15]">
|
||||
<h1
|
||||
class="mt-4 [font-family:'Merriweather',Helvetica] font-bold text-white text-[34px] sm:text-[44px] leading-[1.15]"
|
||||
>
|
||||
Contact Highland Group RDA
|
||||
</h1>
|
||||
<p class="mt-4 [font-family:'Public_Sans',Helvetica] font-semibold text-white text-base sm:text-lg leading-[1.6] max-w-[720px]">
|
||||
We would love to hear from you about sessions, volunteering, or ways to support the group. Reach out
|
||||
and we will get back to you as soon as we can.
|
||||
<p
|
||||
class="mt-4 [font-family:'Public_Sans',Helvetica] font-semibold text-white text-base sm:text-lg leading-[1.6] max-w-[720px]"
|
||||
>
|
||||
We would love to hear from you about sessions,
|
||||
volunteering, or ways to support the group.
|
||||
Reach out and we will get back to you as soon as
|
||||
we can.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -53,22 +72,37 @@ const turnstileSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY ?? "";
|
|||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<img class="w-full h-full object-contain" alt="Donate via JustGiving" src="/Button.webp" />
|
||||
<img
|
||||
class="w-full h-full object-contain"
|
||||
alt="Donate via JustGiving"
|
||||
src="/Button.webp"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="w-full max-w-[1200px] mx-auto px-0 sm:px-8 mt-0 pb-0">
|
||||
<section
|
||||
class="w-full max-w-[1200px] mx-auto px-0 sm:px-8 mt-0 pb-0"
|
||||
>
|
||||
<div class="bg-[#d6d6d6] px-6 sm:px-8 py-6 sm:py-8">
|
||||
<div class="grid grid-cols-1 gap-8 sm:grid-cols-[1.1fr_0.9fr]">
|
||||
<div
|
||||
class="grid grid-cols-1 gap-8 sm:grid-cols-[1.1fr_0.9fr]"
|
||||
>
|
||||
<div>
|
||||
<h2 class="[font-family:'Merriweather',Helvetica] font-bold text-black text-2xl sm:text-3xl">
|
||||
<h2
|
||||
class="[font-family:'Merriweather',Helvetica] font-bold text-black text-2xl sm:text-3xl"
|
||||
>
|
||||
Contact details
|
||||
</h2>
|
||||
<p class="mt-4 [font-family:'Public_Sans',Helvetica] font-semibold text-black text-base sm:text-lg leading-[1.6]">
|
||||
Highland Group RDA, Sandycroft, Reelig, Kirkhill, IV5 7PP
|
||||
<p
|
||||
class="mt-4 [font-family:'Public_Sans',Helvetica] font-semibold text-black text-base sm:text-lg leading-[1.6]"
|
||||
>
|
||||
Highland Group RDA, Sandycroft, Reelig,
|
||||
Kirkhill, IV5 7PP
|
||||
</p>
|
||||
<p class="mt-3 [font-family:'Public_Sans',Helvetica] font-semibold text-black text-base sm:text-lg leading-[1.6]">
|
||||
<p
|
||||
class="mt-3 [font-family:'Public_Sans',Helvetica] font-semibold text-black text-base sm:text-lg leading-[1.6]"
|
||||
>
|
||||
Tel: +447500 203226
|
||||
<br />
|
||||
Email: info@highlandgrouprda.org.uk
|
||||
|
|
@ -84,19 +118,31 @@ const turnstileSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY ?? "";
|
|||
</div>
|
||||
|
||||
<div class="bg-white/70 px-6 sm:px-8 py-6 sm:py-8">
|
||||
<h2 class="[font-family:'Merriweather',Helvetica] font-bold text-black text-2xl sm:text-3xl">
|
||||
<h2
|
||||
class="[font-family:'Merriweather',Helvetica] font-bold text-black text-2xl sm:text-3xl"
|
||||
>
|
||||
Send a message
|
||||
</h2>
|
||||
<form class="mt-4 space-y-4" action="/api/contact" method="post" data-contact-form>
|
||||
<form
|
||||
class="mt-4 space-y-4"
|
||||
action="/api/contact"
|
||||
method="post"
|
||||
data-contact-form
|
||||
>
|
||||
{
|
||||
!turnstileSiteKey && (
|
||||
<p class="rounded-md border border-amber-300 bg-amber-50 px-3 py-2 text-sm font-semibold text-amber-900">
|
||||
Turnstile is not configured. Set PUBLIC_TURNSTILE_SITE_KEY and redeploy to enable the form.
|
||||
Turnstile is not configured. Set
|
||||
PUBLIC_TURNSTILE_SITE_KEY and
|
||||
redeploy to enable the form.
|
||||
</p>
|
||||
)
|
||||
}
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-black">Name</label>
|
||||
<label
|
||||
class="block text-sm font-semibold text-black"
|
||||
>Name</label
|
||||
>
|
||||
<input
|
||||
class="mt-2 w-full rounded-md border border-black/20 bg-white px-3 py-2 text-black"
|
||||
type="text"
|
||||
|
|
@ -106,7 +152,10 @@ const turnstileSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY ?? "";
|
|||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-black">Email</label>
|
||||
<label
|
||||
class="block text-sm font-semibold text-black"
|
||||
>Email</label
|
||||
>
|
||||
<input
|
||||
class="mt-2 w-full rounded-md border border-black/20 bg-white px-3 py-2 text-black"
|
||||
type="email"
|
||||
|
|
@ -116,16 +165,26 @@ const turnstileSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY ?? "";
|
|||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-semibold text-black">Message</label>
|
||||
<label
|
||||
class="block text-sm font-semibold text-black"
|
||||
>Message</label
|
||||
>
|
||||
<textarea
|
||||
class="mt-2 w-full rounded-md border border-black/20 bg-white px-3 py-2 text-black"
|
||||
name="message"
|
||||
rows="4"
|
||||
required
|
||||
></textarea>
|
||||
required></textarea>
|
||||
</div>
|
||||
<div class="cf-turnstile" data-sitekey={turnstileSiteKey}></div>
|
||||
<p class="text-sm font-semibold text-black" data-form-message></p>
|
||||
<div
|
||||
class="cf-turnstile"
|
||||
data-sitekey={turnstileSiteKey}
|
||||
>
|
||||
</div>
|
||||
<p
|
||||
class="text-sm font-semibold text-black"
|
||||
data-form-message
|
||||
>
|
||||
</p>
|
||||
<button
|
||||
class="inline-flex items-center rounded-full border border-black/20 px-5 py-2 text-sm font-semibold uppercase tracking-wide text-black"
|
||||
type="submit"
|
||||
|
|
@ -138,10 +197,14 @@ const turnstileSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY ?? "";
|
|||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="w-full max-w-[1200px] mx-auto px-0 sm:px-8 mt-0 pb-0">
|
||||
<section
|
||||
class="w-full max-w-[1200px] mx-auto px-0 sm:px-8 mt-0 pb-0"
|
||||
>
|
||||
<div class="bg-[#d6d6d6] px-6 sm:px-8 py-6 sm:py-8">
|
||||
<div class="h-px w-full bg-black/20 mb-6"></div>
|
||||
<div class="overflow-hidden rounded-[7px] border border-black/10">
|
||||
<div
|
||||
class="overflow-hidden rounded-[7px] border border-black/10"
|
||||
>
|
||||
<iframe
|
||||
title="Highland Group RDA location"
|
||||
src="https://www.google.com/maps?q=IV5%207PP&z=11&output=embed"
|
||||
|
|
@ -155,62 +218,4 @@ const turnstileSiteKey = import.meta.env.PUBLIC_TURNSTILE_SITE_KEY ?? "";
|
|||
<SiteFooter fullBleedOnMobile />
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script type="module">
|
||||
const turnstileSiteKey = {JSON.stringify(turnstileSiteKey)};
|
||||
|
||||
const form = document.querySelector("[data-contact-form]");
|
||||
const message = document.querySelector("[data-form-message]");
|
||||
const submitButton = document.querySelector("[data-form-submit]");
|
||||
|
||||
if (form && message && submitButton) {
|
||||
form.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
if (submitButton.disabled) return;
|
||||
|
||||
submitButton.disabled = true;
|
||||
submitButton.textContent = "Sending...";
|
||||
message.textContent = "";
|
||||
|
||||
try {
|
||||
const response = await fetch(form.action, {
|
||||
method: "POST",
|
||||
body: new FormData(form),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
let errorMessage = "Request failed";
|
||||
const errorData = await response.json().catch(() => null);
|
||||
if (errorData?.error) {
|
||||
errorMessage = errorData.details
|
||||
? `${errorData.error} (${errorData.details})`
|
||||
: errorData.error;
|
||||
} else {
|
||||
const errorText = await response.text().catch(() => "");
|
||||
if (errorText.trim()) {
|
||||
errorMessage = `${response.status} ${response.statusText}: ${errorText}`;
|
||||
} else {
|
||||
errorMessage = `${response.status} ${response.statusText}`;
|
||||
}
|
||||
}
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
message.textContent = "Thanks! Your message has been sent.";
|
||||
form.reset();
|
||||
if (window.turnstile && typeof window.turnstile.reset === "function") {
|
||||
window.turnstile.reset();
|
||||
}
|
||||
} catch (error) {
|
||||
message.textContent =
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "Sorry, something went wrong. Please try again.";
|
||||
} finally {
|
||||
submitButton.disabled = false;
|
||||
submitButton.textContent = "Send message";
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</Base>
|
||||
|
|
|
|||
Loading…
Reference in a new issue