Refactor: Update petition form
This commit is contained in:
@ -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"
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user