Skip to content

Commit b1daa9c

Browse files
refactor & style: about
1 parent 338cb3d commit b1daa9c

5 files changed

Lines changed: 280 additions & 954 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"use client";
2+
3+
import { ContactFormData, FormErrors } from "~/constants/contact";
4+
import { Captcha } from "~/components/ui/captcha";
5+
6+
const inputClass = "w-full px-3 py-2 border-2 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 border-gray-300 dark:border-gray-600";
7+
const labelClass = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
8+
const errClass = "text-red-500 text-xs mt-1";
9+
10+
type Props = {
11+
formData: ContactFormData;
12+
errors: FormErrors;
13+
isSubmitting: boolean;
14+
captchaValid: boolean;
15+
captchaKey?: number;
16+
onInputChange: (e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => void;
17+
onSubmit: (e: React.FormEvent) => void;
18+
onCaptchaChange: (payload: { isValid: boolean; text: string; answer: string }) => void;
19+
};
20+
21+
export default function AboutContactForm({ formData, errors, isSubmitting, captchaValid, captchaKey, onInputChange, onSubmit, onCaptchaChange }: Props) {
22+
const nameOk = (formData["your-name"] || "").trim().length > 0;
23+
const emailVal = (formData["your-email"] || "").trim();
24+
const emailOk = emailVal.length > 0 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailVal);
25+
const canSubmit = captchaValid && nameOk && emailOk;
26+
27+
return (
28+
<div className="rounded-xl shadow-lg border border-gray-200 dark:border-gray-700 overflow-hidden bg-[#ffffff] dark:bg-gray-800">
29+
<form onSubmit={onSubmit} className="p-6 space-y-4">
30+
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
31+
<div>
32+
<label className={labelClass}>Full Name *</label>
33+
<input type="text" name="your-name" placeholder="Enter your full name" value={formData["your-name"]} onChange={onInputChange} required disabled={isSubmitting}
34+
className={`${inputClass} ${errors["your-name"] ? "border-red-500" : ""}`} />
35+
{errors["your-name"] && <p className={errClass}>{errors["your-name"]}</p>}
36+
</div>
37+
<div>
38+
<label className={labelClass}>Phone Number</label>
39+
<input type="tel" name="your-number" placeholder="+84 123 456 789" value={formData["your-number"]} onChange={onInputChange} disabled={isSubmitting} className={inputClass} />
40+
</div>
41+
<div className="md:col-span-2">
42+
<label className={labelClass}>Email Address *</label>
43+
<input type="email" name="your-email" placeholder="your.email@example.com" value={formData["your-email"]} onChange={onInputChange} required disabled={isSubmitting} className={inputClass} />
44+
</div>
45+
<input type="hidden" name="event-location" value={formData["event-location"]} />
46+
</div>
47+
{errors.contact && <p className={errClass}>{errors.contact}</p>}
48+
<div>
49+
<label className={labelClass}>Message</label>
50+
<textarea name="message" placeholder="Tell us about your inquiry..." value={formData.message} onChange={onInputChange} rows={3} disabled={isSubmitting} className={`${inputClass} resize-none`} />
51+
</div>
52+
<div className={isSubmitting ? "opacity-60 pointer-events-none" : ""}>
53+
<Captcha key={captchaKey} onCaptchaChange={onCaptchaChange} />
54+
</div>
55+
<button type="submit" disabled={isSubmitting || !canSubmit} className="inline-flex items-center justify-center w-full rounded-lg text-lg bg-blue-600 dark:bg-white px-6 py-3 font-semibold text-white dark:text-blue-900 shadow-lg focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50">
56+
{isSubmitting ? <span className="flex items-center gap-2"><span className="w-4 h-4 border-2 border-white dark:border-blue-900 border-t-transparent rounded-full animate-spin" />Sending...</span> : "Send Message"}
57+
</button>
58+
</form>
59+
</div>
60+
);
61+
}

0 commit comments

Comments
 (0)