Refactor: Update petition form

This commit is contained in:
gpt-engineer-app[bot]
2025-10-24 14:19:23 +00:00
parent 3540e3ed7f
commit 0270c2f2dc
2 changed files with 89 additions and 35 deletions

View File

@ -12,20 +12,33 @@ const petitionSchema = z.object({
comment: z.string().trim().max(1000, "Comment must be less than 1000 characters").optional(), comment: z.string().trim().max(1000, "Comment must be less than 1000 characters").optional(),
}); });
export const PetitionForm = () => { const anonymousSchema = z.object({
email: z.string().trim().email("Invalid email address").max(255, "Email must be less than 255 characters"),
});
interface PetitionFormProps {
compact?: boolean;
}
export const PetitionForm = ({ compact = false }: PetitionFormProps) => {
const [formData, setFormData] = useState({ const [formData, setFormData] = useState({
name: "", name: "",
email: "", email: "",
comment: "", comment: "",
}); });
const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false);
const [isAnonymous, setIsAnonymous] = useState(false);
const handleSubmit = async (e: React.FormEvent) => { const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault(); e.preventDefault();
// Validate input // Validate input based on mode
try { try {
petitionSchema.parse(formData); if (isAnonymous) {
anonymousSchema.parse({ email: formData.email });
} else {
petitionSchema.parse(formData);
}
} catch (error) { } catch (error) {
if (error instanceof z.ZodError) { if (error instanceof z.ZodError) {
toast.error(error.errors[0].message); toast.error(error.errors[0].message);
@ -39,15 +52,16 @@ export const PetitionForm = () => {
const { error } = await supabase const { error } = await supabase
.from('petition_signatures') .from('petition_signatures')
.insert([{ .insert([{
name: formData.name.trim(), name: isAnonymous ? 'Anonymous' : formData.name.trim(),
email: formData.email.trim(), email: formData.email.trim(),
comment: formData.comment.trim() || null, comment: isAnonymous ? null : (formData.comment.trim() || null),
}]); }]);
if (error) throw error; if (error) throw error;
toast.success("Thank you for signing! Your voice matters."); toast.success("Thank you for signing! Your voice matters.");
setFormData({ name: "", email: "", comment: "" }); setFormData({ name: "", email: "", comment: "" });
setIsAnonymous(false);
} catch (error) { } catch (error) {
console.error('Error signing petition:', error); console.error('Error signing petition:', error);
toast.error("Failed to submit signature. Please try again."); toast.error("Failed to submit signature. Please try again.");
@ -57,16 +71,42 @@ export const PetitionForm = () => {
}; };
return ( return (
<form onSubmit={handleSubmit} className="space-y-4 max-w-xl mx-auto"> <form onSubmit={handleSubmit} className={`space-y-4 ${compact ? 'max-w-md' : 'max-w-xl'} mx-auto`}>
<div> {!compact && (
<Input <div className="mb-4 flex items-center gap-2">
placeholder="Your Name" <Button
value={formData.name} type="button"
onChange={(e) => setFormData({ ...formData, name: e.target.value })} variant={isAnonymous ? "outline" : "default"}
required size="sm"
className="bg-background border-border" onClick={() => setIsAnonymous(false)}
/> className="flex-1"
</div> >
Full Signature
</Button>
<Button
type="button"
variant={isAnonymous ? "default" : "outline"}
size="sm"
onClick={() => setIsAnonymous(true)}
className="flex-1"
>
Anonymous Sign
</Button>
</div>
)}
{!isAnonymous && (
<div>
<Input
placeholder="Your Name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
required
className="bg-background border-border"
/>
</div>
)}
<div> <div>
<Input <Input
type="email" type="email"
@ -77,14 +117,24 @@ export const PetitionForm = () => {
className="bg-background border-border" className="bg-background border-border"
/> />
</div> </div>
<div>
<Textarea {!isAnonymous && !compact && (
placeholder="Why is Victoria Way Carpark important to you? (Optional)" <div>
value={formData.comment} <Textarea
onChange={(e) => setFormData({ ...formData, comment: e.target.value })} placeholder="Why is Victoria Way Carpark important to you? (Optional)"
className="bg-background border-border min-h-24" value={formData.comment}
/> onChange={(e) => setFormData({ ...formData, comment: e.target.value })}
</div> className="bg-background border-border min-h-24"
/>
</div>
)}
{isAnonymous && (
<p className="text-sm text-muted-foreground">
Your signature will be recorded as "Anonymous" with only your email for verification.
</p>
)}
<Button <Button
type="submit" type="submit"
size="lg" size="lg"

View File

@ -74,8 +74,8 @@ const Index = () => {
return ( return (
<div className="min-h-screen bg-background"> <div className="min-h-screen bg-background">
{/* Hero Section */} {/* Hero Section with Petition */}
<section className="relative h-[600px] flex items-center justify-center text-center overflow-hidden"> <section className="relative min-h-[700px] flex items-center justify-center text-center overflow-hidden py-16">
<div <div
className="absolute inset-0 bg-cover bg-center" className="absolute inset-0 bg-cover bg-center"
style={{ backgroundImage: `url(${carparkHero})` }} style={{ backgroundImage: `url(${carparkHero})` }}
@ -89,13 +89,17 @@ const Index = () => {
<p className="text-xl md:text-2xl text-primary-foreground/90 mb-8"> <p className="text-xl md:text-2xl text-primary-foreground/90 mb-8">
We support safety-first action, but this area of Woking needs adequate parking and communication from the council We support safety-first action, but this area of Woking needs adequate parking and communication from the council
</p> </p>
<Button
size="lg" <div className="bg-card/95 backdrop-blur-sm rounded-lg p-8 shadow-[var(--shadow-elevated)] mb-6">
onClick={scrollToPetition} <div className="mb-6">
className="bg-gradient-to-r from-accent to-accent/90 hover:from-accent/90 hover:to-accent/80 text-accent-foreground text-lg px-8 py-6 shadow-[var(--shadow-elevated)] font-semibold" <h2 className="text-3xl font-bold text-primary mb-2">Sign the Petition</h2>
> <p className="text-lg text-muted-foreground">
Sign the Petition Now {signatureCount > 0 && <span className="font-semibold text-accent">{signatureCount} people</span>}
</Button> {signatureCount > 0 ? ' have' : 'Be the first to'} signed so far
</p>
</div>
<PetitionForm compact />
</div>
</div> </div>
</section> </section>
@ -359,14 +363,14 @@ const Index = () => {
</div> </div>
</section> </section>
{/* Petition Form */} {/* Additional Petition Section */}
<section id="petition" className="py-16 px-6"> <section id="petition" className="py-16 px-6">
<div className="max-w-4xl mx-auto text-center"> <div className="max-w-4xl mx-auto text-center">
<h2 className="text-4xl font-bold text-primary mb-4"> <h2 className="text-4xl font-bold text-primary mb-4">
Add Your Voice Add Your Story
</h2> </h2>
<p className="text-xl text-muted-foreground mb-12"> <p className="text-xl text-muted-foreground mb-12">
Sign the petition asking Woking Council to provide regular updates and adequate parking solutions for this area of Woking Share why this matters to you and add your full testimony to the petition
</p> </p>
<PetitionForm /> <PetitionForm />
</div> </div>