From e606400fcf849318aa44878d6d99d4651d8a3eee Mon Sep 17 00:00:00 2001 From: Deepak Pandey Date: Sun, 14 Sep 2025 21:07:26 +0530 Subject: [PATCH 1/2] feat: Add Core Team application form with authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✨ Features: - New Core Team application form at /join/core-team - Complete admin dashboard for managing applications - Authentication required for all application forms - User ID tracking for all applications πŸ”§ Technical Changes: - Added core_team_applications table with user_id field - Updated all existing forms to require authentication - Added user_id columns to all application tables - Created admin API routes and dashboard pages - Integrated with existing auth system 🎨 UI/UX: - Beautiful Core Team landing page with benefits - Consistent theming across all forms - Responsive design for all screen sizes - Loading states and error handling πŸ“Š Admin Features: - View, filter, and manage all applications - Export functionality to CSV - Status management (approve/reject) - Complete application details view - Statistics dashboard πŸ” Security: - All forms now require user authentication - User ID tracking for better data management - Proper error handling and validation βœ… Build Status: Clean build with no warnings βœ… Database: All tables updated with user_id fields βœ… Testing: All functionality verified --- app/admin/forms/core-team/page.tsx | 545 ++++++++++++++++++++++++ app/admin/layout.tsx | 6 + app/api/admin-core-team/route.ts | 97 +++++ app/join/core-team/page.tsx | 293 +++++++++++++ app/join/page.tsx | 15 + components/forms/collaboration-form.tsx | 67 +++ components/forms/core-team-form.tsx | 524 +++++++++++++++++++++++ components/forms/judges-form.tsx | 46 ++ components/forms/mentor-form.tsx | 68 +++ components/forms/sponsorship-form.tsx | 45 ++ components/forms/volunteer-form.tsx | 67 +++ scripts/add-user-id-columns.js | 81 ++++ scripts/setup-core-team-table.js | 59 +++ scripts/update-tables-add-user-id.js | 60 +++ 14 files changed, 1973 insertions(+) create mode 100644 app/admin/forms/core-team/page.tsx create mode 100644 app/api/admin-core-team/route.ts create mode 100644 app/join/core-team/page.tsx create mode 100644 components/forms/core-team-form.tsx create mode 100644 scripts/add-user-id-columns.js create mode 100644 scripts/setup-core-team-table.js create mode 100644 scripts/update-tables-add-user-id.js diff --git a/app/admin/forms/core-team/page.tsx b/app/admin/forms/core-team/page.tsx new file mode 100644 index 00000000..a7c1ca41 --- /dev/null +++ b/app/admin/forms/core-team/page.tsx @@ -0,0 +1,545 @@ +"use client"; + +import { useState, useEffect, useMemo } from "react"; +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; +import { apiFetch } from "@/lib/api-fetch"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Crown, Search, MoreHorizontal, Eye, Download } from "lucide-react"; +import { toast } from "sonner"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; + +const STATUS_COLORS: Record = { + pending: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200", + approved: "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200", + rejected: "bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200", +}; + +interface CoreTeamApplication { + id: number; + first_name: string; + last_name: string; + email: string; + phone?: string; + location: string; + occupation: string; + company?: string; + experience: string; + skills: string; + portfolio?: string; + preferred_role: string; + availability: string; + commitment: string; + motivation: string; + vision: string; + previous_experience?: string; + social_media?: string; + references_info?: string; + additional_info?: string; + status: string; + user_id?: string; + created_at: string; + updated_at: string; +} + +export default function AdminCoreTeamPage() { + const [applications, setApplications] = useState([]); + const [searchTerm, setSearchTerm] = useState(""); + const [statusFilter, setStatusFilter] = useState("all"); + const [roleFilter, setRoleFilter] = useState("all"); + const [loading, setLoading] = useState(true); + const [selectedApplication, setSelectedApplication] = useState(null); + const [isViewDialogOpen, setIsViewDialogOpen] = useState(false); + const [savingStatus, setSavingStatus] = useState>({}); + + // Fetch applications + useEffect(() => { + const fetchApplications = async () => { + try { + setLoading(true); + const response = await apiFetch("/api/admin-core-team"); + if (response.ok) { + const data = await response.json(); + setApplications(data.applications || []); + } else { + toast.error("Failed to fetch applications"); + } + } catch (error) { + console.error("Error fetching applications:", error); + toast.error("Error fetching applications"); + } finally { + setLoading(false); + } + }; + + fetchApplications(); + }, []); + + // Filter applications + const filteredApplications = useMemo(() => { + return applications.filter((app) => { + const matchesSearch = + app.first_name.toLowerCase().includes(searchTerm.toLowerCase()) || + app.last_name.toLowerCase().includes(searchTerm.toLowerCase()) || + app.email.toLowerCase().includes(searchTerm.toLowerCase()) || + app.occupation.toLowerCase().includes(searchTerm.toLowerCase()) || + app.preferred_role.toLowerCase().includes(searchTerm.toLowerCase()); + + const matchesStatus = statusFilter === "all" || app.status === statusFilter; + const matchesRole = roleFilter === "all" || app.preferred_role === roleFilter; + + return matchesSearch && matchesStatus && matchesRole; + }); + }, [applications, searchTerm, statusFilter, roleFilter]); + + // Statistics + const stats = { + total: applications.length, + pending: applications.filter(app => app.status === "pending").length, + approved: applications.filter(app => app.status === "approved").length, + rejected: applications.filter(app => app.status === "rejected").length, + }; + + // Get unique roles for filter + const uniqueRoles = useMemo(() => { + const roles = applications.map(app => app.preferred_role); + return Array.from(new Set(roles)).sort(); + }, [applications]); + + // Handle status update + const handleStatusUpdate = async (id: number, newStatus: string) => { + try { + setSavingStatus(prev => ({ ...prev, [id]: true })); + + const response = await apiFetch("/api/admin-core-team", { + method: "PATCH", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ id, status: newStatus }), + }); + + if (response.ok) { + setApplications(prev => + prev.map(app => + app.id === id ? { ...app, status: newStatus } : app + ) + ); + toast.success("Status updated successfully"); + } else { + toast.error("Failed to update status"); + } + } catch (error) { + console.error("Error updating status:", error); + toast.error("Error updating status"); + } finally { + setSavingStatus(prev => ({ ...prev, [id]: false })); + } + }; + + // Handle view application + const handleViewApplication = (application: CoreTeamApplication) => { + setSelectedApplication(application); + setIsViewDialogOpen(true); + }; + + // Export to CSV + const handleExportCSV = () => { + const csvContent = [ + ["Name", "Email", "Phone", "Location", "Occupation", "Company", "Preferred Role", "Status", "Applied Date"], + ...filteredApplications.map(app => [ + `${app.first_name} ${app.last_name}`, + app.email, + app.phone || "", + app.location, + app.occupation, + app.company || "", + app.preferred_role, + app.status, + new Date(app.created_at).toLocaleDateString() + ]) + ].map(row => row.map(cell => `"${cell}"`).join(",")).join("\n"); + + const blob = new Blob([csvContent], { type: "text/csv" }); + const url = window.URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = `core-team-applications-${new Date().toISOString().split('T')[0]}.csv`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + + toast.success("Applications exported successfully"); + }; + + if (loading) { + return ( +
+
+
+

Loading applications...

+
+
+ ); + } + + return ( +
+ {/* Header */} +
+
+

Core Team Applications

+

+ Manage and review core team applications +

+
+ +
+ + {/* Statistics */} +
+ + + Total Applications + + + +
{stats.total}
+
+
+ + + Pending +
+ + +
{stats.pending}
+
+ + + + Approved +
+ + +
{stats.approved}
+
+ + + + Rejected +
+ + +
{stats.rejected}
+
+ +
+ + {/* Filters */} + + + Filters + + +
+
+ +
+ + setSearchTerm(e.target.value)} + className="pl-10" + /> +
+
+
+ + +
+
+ + +
+
+
+
+ + {/* Applications Table */} + + + Applications ({filteredApplications.length}) + + Review and manage core team applications + + + +
+ + + + Name + Email + Occupation + Preferred Role + Status + Applied + Actions + + + + {filteredApplications.map((application) => ( + + + {application.first_name} {application.last_name} + + {application.email} + {application.occupation} + + + {application.preferred_role} + + + + + {application.status} + + + + {new Date(application.created_at).toLocaleDateString()} + + + + + + + + Actions + handleViewApplication(application)}> + + View Details + + handleStatusUpdate(application.id, "approved")} + disabled={savingStatus[application.id]} + > + Approve + + handleStatusUpdate(application.id, "rejected")} + disabled={savingStatus[application.id]} + > + Reject + + + + + + ))} + +
+
+
+
+ + {/* View Application Dialog */} + + + + Core Team Application Details + + Review the complete application details + + + + {selectedApplication && ( +
+ {/* Personal Information */} +
+
+ +

{selectedApplication.first_name} {selectedApplication.last_name}

+
+
+ +

{selectedApplication.email}

+
+
+ +

{selectedApplication.phone || "Not provided"}

+
+
+ +

{selectedApplication.location}

+
+
+ +

{selectedApplication.occupation}

+
+
+ +

{selectedApplication.company || "Not provided"}

+
+
+ + {/* Application Details */} +
+
+ + + {selectedApplication.preferred_role} + +
+
+ +

{selectedApplication.experience}

+
+
+ +

{selectedApplication.skills}

+
+
+ +

{selectedApplication.availability}

+
+
+ +

{selectedApplication.commitment}

+
+
+ +

{selectedApplication.motivation}

+
+
+ +

{selectedApplication.vision}

+
+ {selectedApplication.portfolio && ( +
+ +

{selectedApplication.portfolio}

+
+ )} + {selectedApplication.previous_experience && ( +
+ +

{selectedApplication.previous_experience}

+
+ )} + {selectedApplication.social_media && ( +
+ +

{selectedApplication.social_media}

+
+ )} + {selectedApplication.references_info && ( +
+ +

{selectedApplication.references_info}

+
+ )} + {selectedApplication.additional_info && ( +
+ +

{selectedApplication.additional_info}

+
+ )} +
+ + {/* Status and Dates */} +
+
+ + + {selectedApplication.status} + +
+
+ +

{new Date(selectedApplication.created_at).toLocaleDateString()}

+
+
+ +

{new Date(selectedApplication.updated_at).toLocaleDateString()}

+
+
+
+ )} + + + + {selectedApplication && ( + <> + + + + )} + +
+
+
+ ); +} diff --git a/app/admin/layout.tsx b/app/admin/layout.tsx index 09a3c35c..f0069334 100644 --- a/app/admin/layout.tsx +++ b/app/admin/layout.tsx @@ -22,6 +22,7 @@ import { HandHeart, ClipboardCheck, Award, + Crown, } from "lucide-react" import { useAuth } from "@/lib/hooks/useAuth" @@ -119,6 +120,11 @@ const sidebarItems: SidebarGroupType[] = [ url: "/admin/forms/volunteer", icon: HandHeart, }, + { + title: "Core Team", + url: "/admin/forms/core-team", + icon: Crown, + }, ], }, { diff --git a/app/api/admin-core-team/route.ts b/app/api/admin-core-team/route.ts new file mode 100644 index 00000000..f4f1ff5d --- /dev/null +++ b/app/api/admin-core-team/route.ts @@ -0,0 +1,97 @@ +import { NextResponse } from 'next/server'; +import { createClient } from '@supabase/supabase-js'; + +function getSupabaseClient() { + return createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.SUPABASE_SERVICE_ROLE_KEY! + ); +} + +export async function GET() { + try { + const supabase = getSupabaseClient(); + + const { data, error } = await supabase + .from('core_team_applications') + .select('*') + .order('created_at', { ascending: false }); + + if (error) { + console.error('Error fetching core team applications:', error); + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ applications: data }); + } catch (error) { + console.error('Unexpected error:', error); + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); + } +} + +export async function POST(req: Request) { + try { + const body = await req.json(); + const { id, status, notes } = body; + + if (!id || !status) { + return NextResponse.json({ error: 'Missing required fields' }, { status: 400 }); + } + + const supabase = getSupabaseClient(); + + const { data, error } = await supabase + .from('core_team_applications') + .update({ + status, + updated_at: new Date().toISOString(), + ...(notes && { notes }) + }) + .eq('id', id) + .select() + .single(); + + if (error) { + console.error('Error updating core team application:', error); + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ application: data }); + } catch (error) { + console.error('Unexpected error:', error); + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); + } +} + +export async function PATCH(req: Request) { + try { + const body = await req.json(); + const { id, ...updates } = body; + + if (!id) { + return NextResponse.json({ error: 'Missing application ID' }, { status: 400 }); + } + + const supabase = getSupabaseClient(); + + const { data, error } = await supabase + .from('core_team_applications') + .update({ + ...updates, + updated_at: new Date().toISOString() + }) + .eq('id', id) + .select() + .single(); + + if (error) { + console.error('Error updating core team application:', error); + return NextResponse.json({ error: error.message }, { status: 500 }); + } + + return NextResponse.json({ application: data }); + } catch (error) { + console.error('Unexpected error:', error); + return NextResponse.json({ error: 'Internal server error' }, { status: 500 }); + } +} diff --git a/app/join/core-team/page.tsx b/app/join/core-team/page.tsx new file mode 100644 index 00000000..24f05d12 --- /dev/null +++ b/app/join/core-team/page.tsx @@ -0,0 +1,293 @@ +"use client"; + +import Footer from "@/components/footer"; +import Header from "@/components/header"; +import { CoreTeamForm } from "@/components/forms/core-team-form"; +import { cn } from "@/lib/utils"; +import { motion } from "framer-motion"; +import { Sparkles, Crown, Users, Zap, Award } from "lucide-react"; + +export default function CoreTeamPage() { + const benefits = [ + { + icon: Crown, + title: "Leadership Role", + description: "Take on leadership responsibilities and help shape the future direction of Codeunia.", + color: "text-amber-500", + }, + { + icon: Users, + title: "Team Collaboration", + description: "Work closely with other core team members and build lasting professional relationships.", + color: "text-blue-500", + }, + { + icon: Zap, + title: "Creative Freedom", + description: "Bring your innovative ideas to life and have a direct impact on our community initiatives.", + color: "text-purple-500", + }, + { + icon: Award, + title: "Recognition & Growth", + description: "Get recognized for your contributions and develop valuable skills in your chosen field.", + color: "text-green-500", + }, + ]; + + const roles = [ + { + title: "Media Team", + description: "Content creation, social media management, video production, and brand development.", + icon: "πŸŽ₯", + }, + { + title: "Content Team", + description: "Blog writing, technical documentation, educational content, and community resources.", + icon: "πŸ“", + }, + { + title: "Technical Team", + description: "Platform development, technical infrastructure, and developer tooling.", + icon: "βš™οΈ", + }, + { + title: "Community Team", + description: "Community management, event coordination, and member engagement.", + icon: "🀝", + }, + { + title: "Strategy Team", + description: "Strategic planning, partnerships, and long-term vision development.", + icon: "🎯", + }, + ]; + + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.1, + delayChildren: 0.3, + }, + }, + }; + + const itemVariants = { + hidden: { opacity: 0, y: 20 }, + visible: { + opacity: 1, + y: 0, + transition: { duration: 0.5 }, + }, + }; + + return ( +
+
+ + {/* hero section */} +
+
+
+
+
+
+
+
+ + +
+ +
+ +
+
+ + Join Our{" "} + + Core Team + + + + Be part of the driving force behind Codeunia. Help us build the future of developer education and community. + +
+
+
+ + {/* roles section */} +
+
+ +

+ Available Core Team Roles +

+

+ Choose the role that best matches your skills and interests. +

+
+ + + {roles.map((role, index) => ( + +
+
{role.icon}
+

+ {role.title} +

+

+ {role.description} +

+
+
+ ))} +
+
+
+ + {/* benefits section */} +
+
+ +

+ Why Join Our Core Team? +

+

+ Discover the unique benefits of being part of Codeunia's core team. +

+
+ + + {benefits.map((benefit, index) => ( + +
+
+ +
+
+

{benefit.title}

+

{benefit.description}

+
+
+
+ ))} +
+
+
+ + {/* form section */} +
+
+
+ +

+ Ready to Lead with Us? +

+

+ Fill out the application below to join our core team. We'll review your application and get back to you within 72 hours. +

+
+ + +
+
+
+ +
+
+ ); +} diff --git a/app/join/page.tsx b/app/join/page.tsx index 3005b0ad..514a0803 100644 --- a/app/join/page.tsx +++ b/app/join/page.tsx @@ -17,6 +17,7 @@ import { Users, Award, HandHeart, + Crown, } from "lucide-react"; import Link from "next/link"; @@ -62,6 +63,14 @@ export default function JoinPage() { href: "/join/volunteer", color: "text-pink-500", }, + { + icon: Crown, + title: "Codeunia Core Team Application", + description: "Join our core team including media, content, and leadership roles to help shape Codeunia's future.", + gradient: "from-amber-500 to-yellow-500", + href: "/join/core-team", + color: "text-amber-500", + }, ]; const stats = [ @@ -89,6 +98,12 @@ export default function JoinPage() { icon: HandHeart, color: "text-orange-500", }, + { + number: "15+", + label: "Core Team", + icon: Crown, + color: "text-amber-500", + }, ]; const containerVariants = { diff --git a/components/forms/collaboration-form.tsx b/components/forms/collaboration-form.tsx index 9deaf69d..26b34750 100644 --- a/components/forms/collaboration-form.tsx +++ b/components/forms/collaboration-form.tsx @@ -10,8 +10,11 @@ import { Textarea } from "@/components/ui/textarea"; import { Building2, FileText, Loader2 } from "lucide-react"; import { createBrowserClient } from "@supabase/ssr"; import { toast } from "sonner"; +import { useAuth } from "@/lib/hooks/useAuth"; export function CollaborationForm() { + const { user, loading: authLoading } = useAuth(); + const getSupabaseClient = () => { return createBrowserClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, @@ -44,6 +47,11 @@ export function CollaborationForm() { return; } + if (!user) { + toast.error('Please sign in to submit your application.'); + return; + } + if (formData.website && !formData.website.startsWith("http")) { toast.error("Please enter a valid website URL starting with http:// or https://"); return; @@ -57,6 +65,7 @@ export function CollaborationForm() { .from('collaboration_applications') .insert([ { + user_id: user.id, organization_name: formData.organizationName, website: formData.website, contact_person: formData.contactPerson, @@ -87,6 +96,64 @@ export function CollaborationForm() { } }; + // Show loading state while checking authentication + if (authLoading) { + return ( + + + +
+
+

Loading...

+
+
+
+
+ ); + } + + // Show sign-in prompt if not authenticated + if (!user) { + return ( + + + +
+ +
+ Authentication Required +

+ Please sign in to submit your collaboration application +

+
+ +
+

+ You need to be signed in to submit an application. This helps us track your submissions and provide better support. +

+ +
+
+
+
+ ); + } + return ( { + return createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + ); + }; + + const [isSubmitting, setIsSubmitting] = useState(false); + const [formData, setFormData] = useState({ + // Personal Information + firstName: "", + lastName: "", + email: "", + phone: "", + location: "", + + // Professional Information + occupation: "", + company: "", + experience: "", + skills: "", + portfolio: "", + + // Core Team Application + preferredRole: "", + availability: "", + commitment: "", + motivation: "", + vision: "", + previousExperience: "", + + // Additional Information + socialMedia: "", + referencesInfo: "", + additionalInfo: "", + }); + + const coreTeamRoles = [ + { value: "media-team", label: "Media Team", icon: Camera, description: "Content creation, social media, video production" }, + { value: "content-team", label: "Content Team", icon: PenTool, description: "Blog writing, documentation, educational content" }, + { value: "technical-team", label: "Technical Team", icon: Code2, description: "Platform development, technical infrastructure" }, + { value: "community-team", label: "Community Team", icon: Users, description: "Community management, event coordination" }, + { value: "strategy-team", label: "Strategy Team", icon: Target, description: "Strategic planning, partnerships, vision" }, + ]; + + const commitmentLevels = [ + { value: "5-10-hours", label: "5-10 hours per week" }, + { value: "10-15-hours", label: "10-15 hours per week" }, + { value: "15-20-hours", label: "15-20 hours per week" }, + { value: "20-plus-hours", label: "20+ hours per week" }, + ]; + + const handleInputChange = (field: string, value: string) => { + setFormData(prev => ({ + ...prev, + [field]: value + })); + }; + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!user) { + toast.error('Please sign in to submit your application.'); + return; + } + + setIsSubmitting(true); + + try { + const supabase = getSupabaseClient(); + + const { error } = await supabase + .from('core_team_applications') + .insert([{ + user_id: user.id, + first_name: formData.firstName, + last_name: formData.lastName, + email: formData.email, + phone: formData.phone, + location: formData.location, + occupation: formData.occupation, + company: formData.company, + experience: formData.experience, + skills: formData.skills, + portfolio: formData.portfolio, + preferred_role: formData.preferredRole, + availability: formData.availability, + commitment: formData.commitment, + motivation: formData.motivation, + vision: formData.vision, + previous_experience: formData.previousExperience, + social_media: formData.socialMedia, + references_info: formData.referencesInfo, + additional_info: formData.additionalInfo, + created_at: new Date().toISOString(), + }]); + + if (error) { + console.error('Error submitting application:', error); + toast.error('Failed to submit application. Please try again.'); + return; + } + + toast.success('Application submitted successfully! We\'ll get back to you within 72 hours.'); + + // Reset form + setFormData({ + firstName: "", + lastName: "", + email: "", + phone: "", + location: "", + occupation: "", + company: "", + experience: "", + skills: "", + portfolio: "", + preferredRole: "", + availability: "", + commitment: "", + motivation: "", + vision: "", + previousExperience: "", + socialMedia: "", + referencesInfo: "", + additionalInfo: "", + }); + + } catch (error) { + console.error('Error submitting application:', error); + toast.error('An unexpected error occurred. Please try again.'); + } finally { + setIsSubmitting(false); + } + }; + + // Show loading state while checking authentication + if (authLoading) { + return ( + + + +
+
+

Loading...

+
+
+
+
+ ); + } + + // Show sign-in prompt if not authenticated + if (!user) { + return ( + + + +
+ +
+ Authentication Required +

+ Please sign in to submit your core team application +

+
+ +
+

+ You need to be signed in to submit an application. This helps us track your submissions and provide better support. +

+ +
+
+
+
+ ); + } + + return ( + + + +
+ +
+ Core Team Application +

+ Help us build the future of developer education and community +

+
+ +
+ {/* Personal Information */} +
+
+ +

Personal Information

+
+ +
+
+ + handleInputChange('firstName', e.target.value)} + required + placeholder="Enter your first name" + /> +
+
+ + handleInputChange('lastName', e.target.value)} + required + placeholder="Enter your last name" + /> +
+
+ +
+
+ + handleInputChange('email', e.target.value)} + required + placeholder="Enter your email" + /> +
+
+ + handleInputChange('phone', e.target.value)} + placeholder="Enter your phone number" + /> +
+
+ +
+ + handleInputChange('location', e.target.value)} + required + placeholder="City, Country" + /> +
+
+ + {/* Professional Information */} +
+
+ +

Professional Information

+
+ +
+
+ + handleInputChange('occupation', e.target.value)} + required + placeholder="e.g., Software Developer, Designer" + /> +
+
+ + handleInputChange('company', e.target.value)} + placeholder="Current company or organization" + /> +
+
+ +
+ + +
+ +
+ +