-
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.
Merge pull request #25 from firehawk89/add-contact-section
Add Contact Section
- Loading branch information
Showing
19 changed files
with
458 additions
and
13 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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 |
---|---|---|
|
@@ -3,4 +3,6 @@ Bochkovskyi | |
clsx | ||
Nextdotjs | ||
Tailwindcss | ||
Skauna | ||
Skauna | ||
hookform | ||
sonner |
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 |
---|---|---|
@@ -0,0 +1,37 @@ | ||
'use server' | ||
|
||
import { ContactFormInputs, ContactFormSchema } from '@/utils' | ||
import emailjs, { EmailJSResponseStatus } from '@emailjs/nodejs' | ||
|
||
export const sendEmail = async (data: ContactFormInputs) => { | ||
const dataParseResult = ContactFormSchema.safeParse(data) | ||
|
||
if (dataParseResult.success) { | ||
const parsedData = dataParseResult.data | ||
|
||
try { | ||
const response = await emailjs.send( | ||
process.env.EMAILJS_SERVICE_ID!, | ||
process.env.EMAILJS_TEMPLATE_ID!, | ||
parsedData, | ||
{ | ||
privateKey: process.env.EMAILJS_PRIVATE_KEY!, | ||
publicKey: process.env.EMAILJS_PUBLIC_KEY!, | ||
} | ||
) | ||
|
||
return { message: response.text, success: true } | ||
} catch (error) { | ||
if (error instanceof EmailJSResponseStatus) { | ||
return { message: error.text, success: false } | ||
} | ||
} | ||
} | ||
|
||
if (!dataParseResult.success) { | ||
return { | ||
message: JSON.stringify(dataParseResult.error.format()), | ||
success: false, | ||
} | ||
} | ||
} |
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 |
---|---|---|
@@ -0,0 +1,105 @@ | ||
'use client' | ||
|
||
import { sendEmail } from '@/app/actions' | ||
import Button from '@/components/ui/button' | ||
import FormItem from '@/components/ui/form-item' | ||
import Input from '@/components/ui/input' | ||
import Label from '@/components/ui/label' | ||
import Textarea from '@/components/ui/textarea' | ||
import { ContactFormInputs, ContactFormSchema, cn } from '@/utils' | ||
import { zodResolver } from '@hookform/resolvers/zod' | ||
import { FC, FormHTMLAttributes, useState } from 'react' | ||
import { SubmitHandler, useForm } from 'react-hook-form' | ||
import { toast } from 'sonner' | ||
|
||
interface ContactFormProps extends FormHTMLAttributes<HTMLFormElement> {} | ||
|
||
const ContactForm: FC<ContactFormProps> = ({ className, ...props }) => { | ||
const [isSubmitting, setIsSubmitting] = useState<boolean>(false) | ||
const { | ||
formState: { errors }, | ||
handleSubmit, | ||
register, | ||
reset, | ||
} = useForm<ContactFormInputs>({ | ||
resolver: zodResolver(ContactFormSchema), | ||
}) | ||
|
||
const onSubmit: SubmitHandler<ContactFormInputs> = async (data) => { | ||
setIsSubmitting(true) | ||
|
||
const loadingToast = toast.loading('Sending a message...') | ||
const result = await sendEmail(data) | ||
|
||
if (result?.success) { | ||
setIsSubmitting(false) | ||
|
||
toast.dismiss(loadingToast) | ||
toast.success('Your message has been sent!', { | ||
closeButton: true, | ||
}) | ||
|
||
reset() | ||
return | ||
} | ||
|
||
setIsSubmitting(false) | ||
toast.dismiss(loadingToast) | ||
toast.error('Oops! Something went wrong!', { | ||
closeButton: true, | ||
}) | ||
} | ||
|
||
return ( | ||
<form | ||
className={cn( | ||
'grid grid-cols-1 gap-y-6 sm:grid-cols-2 sm:gap-x-6 sm:gap-y-8 md:gap-x-10', | ||
className | ||
)} | ||
onSubmit={handleSubmit(onSubmit)} | ||
{...props} | ||
> | ||
<FormItem error={errors.name?.message}> | ||
<Label htmlFor="name">Enter your name</Label> | ||
<Input | ||
disabled={isSubmitting} | ||
id="name" | ||
name="name" | ||
placeholder="Name" | ||
register={register} | ||
required | ||
type="text" | ||
/> | ||
</FormItem> | ||
<FormItem error={errors.email?.message}> | ||
<Label htmlFor="email">Enter your email</Label> | ||
<Input | ||
disabled={isSubmitting} | ||
id="email" | ||
name="email" | ||
placeholder="Email" | ||
register={register} | ||
required | ||
type="email" | ||
/> | ||
</FormItem> | ||
<FormItem className="sm:col-span-2" error={errors.message?.message}> | ||
<Label htmlFor="message">Enter your message</Label> | ||
<Textarea | ||
disabled={isSubmitting} | ||
id="message" | ||
name="message" | ||
placeholder="Message" | ||
register={register} | ||
required | ||
rows={4} | ||
/> | ||
</FormItem> | ||
<Button className="w-full sm:w-fit" disabled={isSubmitting} type="submit"> | ||
Submit | ||
</Button> | ||
</form> | ||
) | ||
} | ||
|
||
export default ContactForm |
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 |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import ContactForm from '@/components/sections/contact/contact-form' | ||
import Content from '@/components/ui/content' | ||
import Heading from '@/components/ui/heading' | ||
import { cn } from '@/utils' | ||
import { FC, HTMLAttributes } from 'react' | ||
|
||
interface ContactProps extends HTMLAttributes<HTMLDivElement> {} | ||
|
||
const Contact: FC<ContactProps> = ({ className, ...props }) => { | ||
return ( | ||
<section className={cn('bg-light dark:bg-black', className)} {...props}> | ||
<Content className="max-w-4xl"> | ||
<Heading size="h2" variant="underline"> | ||
Get In Touch | ||
</Heading> | ||
<p className="mt-6 md:text-xl"> | ||
Drop me a message using the form below or reach out via my email{' '} | ||
<a | ||
className="font-semibold transition-colors hover:text-accent" | ||
href="mailto:[email protected]" | ||
> | ||
[email protected] | ||
</a> | ||
. | ||
</p> | ||
<ContactForm className="mt-6" /> | ||
</Content> | ||
</section> | ||
) | ||
} | ||
|
||
export default Contact |
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
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
Oops, something went wrong.