Spaces:
Sleeping
Sleeping
| import React, { useState } from 'react'; | |
| import axios from 'axios'; | |
| const DEFAULT_ENDPOINT = 'https://formsubmit.co/ajax/jadeinfrapune@gmail.com'; | |
| export default function ContactForm() { | |
| const [status, setStatus] = useState({ state: 'idle', message: '' }); | |
| async function onSubmit(e) { | |
| e.preventDefault(); | |
| const form = new FormData(e.currentTarget); | |
| const payload = { | |
| name: String(form.get('name') || '').trim(), | |
| email: String(form.get('email') || '').trim(), | |
| phone: String(form.get('phone') || '').trim(), | |
| message: String(form.get('message') || '').trim() | |
| }; | |
| if (!payload.name || !payload.email || !payload.phone || !payload.message) { | |
| setStatus({ | |
| state: 'error', | |
| message: 'All fields are required. Please complete the form.' | |
| }); | |
| return; | |
| } | |
| const namePattern = /^[A-Za-z\s]{2,60}$/; | |
| if (!namePattern.test(payload.name)) { | |
| setStatus({ | |
| state: 'error', | |
| message: 'Please enter a valid name using alphabets only.' | |
| }); | |
| return; | |
| } | |
| const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; | |
| if (!emailPattern.test(payload.email)) { | |
| setStatus({ | |
| state: 'error', | |
| message: 'Please enter a valid email address.' | |
| }); | |
| return; | |
| } | |
| const phonePattern = /^[0-9]{10}$/; | |
| if (!phonePattern.test(payload.phone)) { | |
| setStatus({ | |
| state: 'error', | |
| message: 'Please enter a valid 10-digit phone number.' | |
| }); | |
| return; | |
| } | |
| setStatus({ state: 'loading', message: '' }); | |
| try { | |
| const endpoint = import.meta.env.VITE_CONTACT_ENDPOINT || DEFAULT_ENDPOINT; | |
| const structuredMessage = [ | |
| 'New enquiry received via jadeinfra.in contact form:', | |
| '', | |
| `Name : ${payload.name}`, | |
| `Email : ${payload.email}`, | |
| `Phone : ${payload.phone}`, | |
| '', | |
| 'Message:', | |
| payload.message | |
| ].join('\n'); | |
| await axios.post( | |
| endpoint, | |
| { | |
| name: payload.name, | |
| email: payload.email, | |
| phone: payload.phone, | |
| message: payload.message, | |
| _subject: 'New enquiry via jadeinfra.in contact form', | |
| _template: 'box', | |
| _replyto: payload.email, | |
| _captcha: 'false', | |
| content: structuredMessage | |
| }, | |
| { | |
| headers: { 'Content-Type': 'application/json' } | |
| } | |
| ); | |
| setStatus({ state: 'success', message: 'Thanks! We will get back to you shortly.' }); | |
| e.currentTarget.reset(); | |
| } catch (err) { | |
| setStatus({ | |
| state: 'error', | |
| message: | |
| 'Sorry, there was an issue sending your message. Please try again or email us directly.' | |
| }); | |
| } | |
| } | |
| return ( | |
| <form className="space-y-4" onSubmit={onSubmit} noValidate aria-labelledby="contact-heading"> | |
| <div className="grid grid-cols-1 gap-4 md:grid-cols-2"> | |
| <div> | |
| <label htmlFor="name" className="block text-sm font-medium text-slate-700">Name</label> | |
| <input | |
| id="name" | |
| name="name" | |
| required | |
| pattern="[A-Za-z\s]{2,60}" | |
| autoComplete="name" | |
| className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 | |
| focus:outline-none focus:ring-2 focus:ring-brand-600" | |
| /> | |
| </div> | |
| <div> | |
| <label htmlFor="email" className="block text-sm font-medium text-slate-700">Email</label> | |
| <input | |
| id="email" | |
| name="email" | |
| type="email" | |
| required | |
| pattern="^[^\s@]+@[^\s@]+\.[^\s@]+$" | |
| autoComplete="email" | |
| className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 | |
| focus:outline-none focus:ring-2 focus:ring-brand-600" | |
| /> | |
| </div> | |
| <div className="md:col-span-2"> | |
| <label htmlFor="phone" className="block text-sm font-medium text-slate-700">Phone</label> | |
| <input | |
| id="phone" | |
| name="phone" | |
| type="tel" | |
| required | |
| pattern="[0-9]{10}" | |
| inputMode="numeric" | |
| autoComplete="tel" | |
| className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 | |
| focus:outline-none focus:ring-2 focus:ring-brand-600" | |
| /> | |
| </div> | |
| <div className="md:col-span-2"> | |
| <label htmlFor="message" className="block text-sm font-medium text-slate-700">Message</label> | |
| <textarea | |
| id="message" | |
| name="message" | |
| required | |
| rows="5" | |
| className="mt-1 w-full rounded-md border border-slate-300 px-3 py-2 | |
| focus:outline-none focus:ring-2 focus:ring-brand-600" | |
| ></textarea> | |
| </div> | |
| </div> | |
| <div className="flex items-center gap-3"> | |
| <button type="submit" className="btn btn-primary" aria-live="polite"> | |
| Send Message | |
| </button> | |
| {status.state === 'loading' && ( | |
| <span role="status" className="text-sm text-slate-600">Sending…</span> | |
| )} | |
| {status.state === 'success' && ( | |
| <span className="text-sm text-green-700">{status.message}</span> | |
| )} | |
| {status.state === 'error' && ( | |
| <span className="text-sm text-red-700">{status.message}</span> | |
| )} | |
| </div> | |
| </form> | |
| ); | |
| } | |