my-website-v2/frontend/routes/contact/index.tsx
Wyatt J. Miller 4104a76f3e built out contact form, added env variable
might make button island so that i can change the button's text
2024-12-04 23:36:49 -05:00

187 lines
5.3 KiB
TypeScript

import { Handlers, PageProps } from "$fresh/server.ts";
import { Head } from "$fresh/runtime.ts";
interface FormState {
name?: string;
email?: string;
message?: string;
errors?: {
name?: string;
email?: string;
message?: string;
};
submitted?: boolean;
failed?: boolean;
}
export const handler: Handlers = {
GET(_, ctx) {
return ctx.render({});
},
async POST(req, ctx) {
const formData = await req.formData();
const state: FormState = {
name: formData.get("name")?.toString(),
email: formData.get("email")?.toString(),
message: formData.get("message")?.toString(),
};
// Validation logic
const errors: FormState["errors"] = {};
if (!state.name || state.name.trim() === "") {
errors.name = "Name is required";
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!state.email) {
errors.email = "Email is required";
} else if (!emailRegex.test(state.email)) {
errors.email = "Invalid email format";
}
if (!state.message || state.message.trim() === "") {
errors.message = "Message is required";
}
// If there are errors, return the form with error messages
if (Object.keys(errors).length > 0) {
return ctx.render({
...state,
errors,
});
}
const res = await fetch(`${Deno.env.get("EMAIL_FORM")}`, {
method: "POST",
body: formData,
});
console.log(res);
if (!res.ok || res.status !== 200) {
return ctx.render({
...state,
failed: true,
});
}
return ctx.render({
...state,
submitted: true,
});
},
};
export default function Contact({ data }: PageProps<FormState>) {
return (
<div class="bg-[#313244] min-h-screen">
<div class="px-4 py-8 mx-auto p-6 flex flex-col bg-[#313244] min-h-screen w-full md:max-w-md">
<Head>
<title>Contact</title>
</Head>
<h1 class="text-3xl text-white font-bold uppercase text-center">
Contact
</h1>
{data?.submitted && (
<div
class="bg-[#a6e3a1] text-[#313244] px-4 py-3 rounded relative"
role="alert"
>
Your message has been sent successfully!
</div>
)}
{data?.failed && (
<div
class="bg-[#f38ba8] text-[#313245] px-4 py-3 rounded relative"
role="alert"
>
There has been a error in sending your message. Please try again
later.
</div>
)}
<form method="POST" class="space-y-4">
<div>
<label
htmlFor="name"
class="block text-[#cdd6f4] text-sm font-bold mb-2"
>
Name
</label>
<input
type="text"
id="name"
name="name"
required
placeholder="Your Name"
value={data?.name || ""}
class={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500
${data?.errors?.name ? "border-[#f38ba8]" : "border-[#313244]"}`}
/>
{data?.errors?.name && (
<p class="text-[#f38ba8] text-xs italic mt-1">
{data.errors.name}
</p>
)}
</div>
<div>
<label
htmlFor="email"
class="block text-[#cdd6f4] text-sm font-bold mb-2"
>
Email
</label>
<input
type="email"
id="email"
name="email"
required
placeholder="your@email.com"
value={data?.email || ""}
class={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500
${data?.errors?.email ? "border-[#f38ba8]" : "border-[#313244]"}`}
/>
{data?.errors?.email && (
<p class="text-red-500 text-xs italic mt-1">
{data.errors.email}
</p>
)}
</div>
<div>
<label
htmlFor="message"
class="block text-[#cdd6f4] text-sm font-bold mb-2"
>
Message
</label>
<textarea
id="message"
name="message"
required
placeholder="Write your message here..."
rows={4}
class={`w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500
${data?.errors?.message ? "border-red-500" : "border-gray-300"}`}
>
{data?.message || ""}
</textarea>
{data?.errors?.message && (
<p class="text-[#f38ba8] text-xs italic mt-1">
{data.errors.message}
</p>
)}
</div>
<input type="hidden" name="_gotcha" style="display:none !important" />
<div>
<button
type="submit"
class="w-full bg-[#89b4fa] text-[#313244] py-2 px-4 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
>
Send Message
</button>
</div>
</form>
</div>
</div>
);
}