Created
July 15, 2024 21:33
-
-
Save gn-bcampbell/2e6ca985aa6c53fa11f6ca5dd5160abe to your computer and use it in GitHub Desktop.
Using NextJS, Zod, TypeScript, ShadCN and EmailJS to create a contact form
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
"use client"; | |
import { zodResolver } from "@hookform/resolvers/zod"; | |
import { useForm } from "react-hook-form"; | |
import { z } from "zod"; | |
import emailjs from "@emailjs/browser"; | |
import React, { useRef } from "react"; | |
import { env } from "~/env"; | |
import { Button } from "~/components/ui/button"; | |
import { | |
Form, | |
FormControl, | |
FormField, | |
FormItem, | |
FormLabel, | |
FormMessage, | |
} from "~/components/ui/form"; | |
import { Input } from "~/components/ui/input"; | |
import { useToast } from "~/components/ui/use-toast"; | |
import { Textarea } from "~/components/ui/textarea"; | |
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; | |
import { faPaperPlane } from "@fortawesome/free-solid-svg-icons"; //optional | |
const FormSchema = z.object({ | |
username: z.string().min(2, { | |
message: "Username must be at least 2 characters.", | |
}), | |
email: z.string().email("Invalid email address.").min(2, { | |
message: "Email must be at least 2 characters.", | |
}), | |
message: z.string().min(10, { | |
message: "Message should be at least 10 characters.", | |
}), | |
}); | |
export const Contact = () => { | |
// pass into form to support EmailJS requirements | |
const formRef = useRef<HTMLFormElement | null>(null); | |
const { toast } = useToast(); | |
const form = useForm<z.infer<typeof FormSchema>>({ | |
resolver: zodResolver(FormSchema), | |
defaultValues: { | |
username: "", | |
email: "", | |
message: "", | |
}, | |
}); | |
const onSubmit = (data: z.infer<typeof FormSchema>) => { | |
console.log("clicked"); | |
console.log(data); | |
if (formRef.current) { | |
emailjs | |
.sendForm( | |
env.NEXT_PUBLIC_EMAILJS_SERVICE_ID, | |
env.NEXT_PUBLIC_EMAILJS_TEMPLATE_ID, | |
formRef.current, | |
{ | |
publicKey: env.NEXT_PUBLIC_EMAILJS_PUBLIC_KEY, | |
}, | |
) | |
.then( | |
() => { | |
// eslint-disable-next-line @typescript-eslint/no-unsafe-call | |
toast({ | |
title: "Email sent.", | |
description: `Thanks ${data.username}, I'll be in touch.`, | |
}); | |
form.reset(); //clear the fields after submission | |
}, | |
(error) => { | |
// eslint-disable-next-line @typescript-eslint/no-unsafe-call | |
toast({ | |
variant: "destructive", | |
title: "Email failed to send.", | |
description: `If this continues, please try using the link at the bottom of the page.`, | |
}); | |
// console.warn("FAILED...", JSON.stringify(error)); | |
}, | |
); | |
} | |
}; | |
return ( | |
<> | |
<Form {...form}> | |
<form | |
ref={formRef} | |
onSubmit={form.handleSubmit(onSubmit)} | |
className="w-2/3 space-y-6" | |
> | |
<FormField | |
name="username" | |
render={({ field }) => ( | |
<FormItem> | |
<FormLabel className="text-lg">Name</FormLabel> | |
<FormControl> | |
<Input | |
className="border-primary bg-white" | |
placeholder="Your Name" | |
{...field} | |
/> | |
</FormControl> | |
<FormMessage className="text-xs text-red-600" /> | |
</FormItem> | |
)} | |
/> | |
<FormField | |
control={form.control} | |
name="email" | |
render={({ field }) => ( | |
<FormItem> | |
<FormLabel className="text-lg">Email</FormLabel> | |
<FormControl> | |
<Input | |
className="border-primary bg-white" | |
placeholder="Email Address" | |
{...field} | |
/> | |
</FormControl> | |
<FormMessage className="text-xs text-red-600" /> | |
</FormItem> | |
)} | |
/> | |
<FormField | |
control={form.control} | |
name="message" | |
render={({ field }) => ( | |
<FormItem> | |
<FormLabel className="text-lg">Message</FormLabel> | |
<FormControl> | |
<Textarea | |
className="border-primary bg-white" | |
placeholder="Type your message here." | |
id="message" | |
{...field} | |
/> | |
</FormControl> | |
<FormMessage className="text-xs text-red-600" /> | |
</FormItem> | |
)} | |
/> | |
<Button | |
type="submit" | |
className="text-md text-white hover:bg-secondary" | |
> | |
Send{" "} | |
<FontAwesomeIcon | |
icon={faPaperPlane} | |
size="lg" | |
className="ml-2 p-2" | |
/> | |
</Button> | |
</form> | |
</Form> | |
</> | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment