114 lines
4.2 KiB
TypeScript
114 lines
4.2 KiB
TypeScript
import { RefObject, useRef, useState } from 'react';
|
|
import { useForm, SubmitHandler, FieldValues } from 'react-hook-form';
|
|
import ReCAPTCHA from 'react-google-recaptcha';
|
|
|
|
export interface ContactFormData extends FieldValues {
|
|
firstName: string,
|
|
lastName: string,
|
|
email: string,
|
|
subject: string,
|
|
summary: string,
|
|
honeypot_xyz: string
|
|
};
|
|
|
|
const ContactForm = () => {
|
|
const {
|
|
register,
|
|
resetField,
|
|
handleSubmit,
|
|
setValue,
|
|
formState: { errors },
|
|
} = useForm();
|
|
|
|
const [submitted, setSubmitted] = useState(false);
|
|
|
|
const handleFormSubmission: SubmitHandler<FieldValues> = async (data: FieldValues) => {
|
|
const submissionData = data as ContactFormData;
|
|
console.log(submissionData)
|
|
|
|
if (submissionData.honeypot_xyz !== "") {
|
|
// Form submission is spam
|
|
return;
|
|
}
|
|
const res = await fetch('/api/contact', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Accept': 'application/json, text/plain, */*',
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(submissionData)
|
|
});
|
|
|
|
console.log('Response received')
|
|
if (res.status === 200) {
|
|
console.log('Response succeeded!')
|
|
setSubmitted(true)
|
|
resetField('captchaToken')
|
|
}
|
|
};
|
|
|
|
const handleFormError: SubmitHandler<FieldValues> = (error) => {
|
|
console.log(error)
|
|
};
|
|
|
|
const onCaptchaChange = (token: string | null) => {
|
|
// Set the captcha token when the user completes the reCAPTCHA
|
|
if (token) {
|
|
setValue('captchaToken', token);
|
|
}
|
|
};
|
|
return (
|
|
<div className='w-full flex flex-row justify-center'>
|
|
<form className=" w-1/2" onSubmit={handleSubmit(handleFormSubmission, handleFormError)}>
|
|
<div className="flex flex-col justify-center h-full">
|
|
<div className=' flex flex-col justify-between space-y-4 w-full'>
|
|
<div className='flex flex-row justify-between space-x-2'>
|
|
<div className='w-1/2'>
|
|
<input placeholder='First Name' className='w-full' {...register('firstName', { required: true })} />
|
|
{errors.firstName && <p>First name is required.</p>}
|
|
</div>
|
|
<div className='w-1/2'>
|
|
<input placeholder='Last Name' className='w-full' {...register('lastName', { required: true })} />
|
|
{errors.lastName && <p>Last name is required.</p>}
|
|
</div>
|
|
</div>
|
|
<div className='flex flex-col space-y-4 w-full'>
|
|
<div>
|
|
<input placeholder='Email' type="email" className='w-full' {...register('email', { required: true })} />
|
|
{errors.email && <p>Email is required.</p>}
|
|
</div>
|
|
<div>
|
|
<select placeholder='Subject...' className='w-full' {...register('subject', { required: true })}>
|
|
<option>Subject...</option>
|
|
<option>Inquiry</option>
|
|
<option>Consultations</option>
|
|
<option>Want To Hire For Potential Job/Contract</option>
|
|
</select>
|
|
{errors.subject && <p>Subject is required.</p>}
|
|
</div>
|
|
<div className="flex flex-col w-full">
|
|
<input type='hidden' value="" {...register('honeypot_xyz', { required: true })}/>
|
|
</div>
|
|
|
|
<div className="flex flex-col w-full">
|
|
<textarea placeholder='Summary...' className="flex grow h-52" {...register('summary')} />
|
|
{errors.summary && <p>Please enter a message for your Project Inquiry.</p>}
|
|
</div>
|
|
<div className="pb-20px">
|
|
<ReCAPTCHA
|
|
size="normal"
|
|
sitekey={process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY ? process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY : 'ENTER_API_KEY'}
|
|
{...register('captchaToken', { required: true })}
|
|
onChange={onCaptchaChange}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<input className="bg-blue-600 text-white rounded-sm cursor-pointer" type="submit" />
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ContactForm; |