Add src/app/enroll/page.tsx
This commit is contained in:
296
src/app/enroll/page.tsx
Normal file
296
src/app/enroll/page.tsx
Normal file
@@ -0,0 +1,296 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
|
||||
import ReactLenis from "lenis/react";
|
||||
import NavbarLayoutFloatingInline from '@/components/navbar/NavbarLayoutFloatingInline';
|
||||
import FooterLogoReveal from '@/components/sections/footer/FooterLogoReveal';
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Mail, CheckCircle } from "lucide-react";
|
||||
|
||||
|
||||
export default function EnrollmentPage() {
|
||||
const router = useRouter();
|
||||
const [formData, setFormData] = useState({
|
||||
fullName: "", age: "", parentGuardianName: "", phoneNumber: "", emailAddress: "", programClassSelection: "", message: ""});
|
||||
const [errors, setErrors] = useState({});
|
||||
const [submissionStatus, setSubmissionStatus] = useState<"idle" | "loading" | "success" | "error">("idle");
|
||||
const [successMessage, setSuccessMessage] = useState("");
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
const programs = [
|
||||
"Early Childhood Learning", "Primary Education Support", "Secondary Education Coaching", "Adult Learning Programs", "Discipline & Character Development", "Holiday and Vacation Classes"];
|
||||
|
||||
const validate = () => {
|
||||
let newErrors = {};
|
||||
if (!formData.fullName) newErrors.fullName = "Student Full Name is required";
|
||||
if (!formData.age || isNaN(Number(formData.age)) || Number(formData.age) <= 0) newErrors.age = "Age is required and must be a positive number";
|
||||
if (!formData.parentGuardianName) newErrors.parentGuardianName = "Parent/Guardian Name is required";
|
||||
if (!formData.phoneNumber) newErrors.phoneNumber = "Phone Number is required";
|
||||
if (!formData.emailAddress) {
|
||||
newErrors.emailAddress = "Email Address is required";
|
||||
} else if (!/\S+@\S+\.\S+/.test(formData.emailAddress)) {
|
||||
newErrors.emailAddress = "Email Address is invalid";
|
||||
}
|
||||
if (!formData.programClassSelection) newErrors.programClassSelection = "Program/Class Selection is required";
|
||||
|
||||
setErrors(newErrors);
|
||||
return Object.keys(newErrors).length === 0;
|
||||
};
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData((prev) => ({ ...prev, [name]: value }));
|
||||
};
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setSubmissionStatus("loading");
|
||||
setSuccessMessage("");
|
||||
setErrorMessage("");
|
||||
|
||||
if (!validate()) {
|
||||
setSubmissionStatus("error");
|
||||
setErrorMessage("Please correct the errors in the form.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Simulate API call to Firebase/Supabase backend
|
||||
// In a real application, replace this with actual API endpoint and data submission.
|
||||
// The backend would handle secure submission, admin email, and database storage.
|
||||
const response = await fetch('/api/enrollments', { // Assuming an API route like /api/enrollments
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(formData),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setSubmissionStatus("success");
|
||||
setSuccessMessage("Enrollment submitted successfully! We will contact you shortly.");
|
||||
// Optionally clear form
|
||||
setFormData({
|
||||
fullName: "", age: "", parentGuardianName: "", phoneNumber: "", emailAddress: "", programClassSelection: "", message: ""});
|
||||
} else {
|
||||
const errorData = await response.json();
|
||||
throw new Error(errorData.message || "Failed to submit enrollment.");
|
||||
}
|
||||
} catch (err) {
|
||||
setSubmissionStatus("error");
|
||||
setErrorMessage(err.message || "An unexpected error occurred during submission.");
|
||||
console.error("Enrollment submission error:", err);
|
||||
}
|
||||
};
|
||||
|
||||
const navItems = [
|
||||
{ name: "Home", id: "/#home" },
|
||||
{ name: "About", id: "/#about" },
|
||||
{ name: "Programs", id: "/#programs" },
|
||||
{ name: "Why Choose Us", id: "/#why-choose-us" },
|
||||
{ name: "Testimonials", id: "/#testimonials" },
|
||||
{ name: "Gallery", id: "/#gallery" },
|
||||
{ name: "Enroll Now", id: "/enroll" }
|
||||
];
|
||||
|
||||
return (
|
||||
<ThemeProvider
|
||||
defaultButtonVariant="text-stagger"
|
||||
defaultTextAnimation="reveal-blur"
|
||||
borderRadius="rounded"
|
||||
contentWidth="mediumLarge"
|
||||
sizing="largeSmallSizeLargeTitles"
|
||||
background="none"
|
||||
cardStyle="gradient-mesh"
|
||||
primaryButtonStyle="shadow"
|
||||
secondaryButtonStyle="layered"
|
||||
headingFontWeight="semibold"
|
||||
>
|
||||
<ReactLenis root>
|
||||
<div id="nav" data-section="nav">
|
||||
<NavbarLayoutFloatingInline
|
||||
navItems={navItems}
|
||||
brandName="Victorious Education Services"
|
||||
button={{
|
||||
text: "Enroll Now", href: "/enroll"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="relative isolate overflow-hidden bg-background px-6 py-24 sm:py-32 lg:px-8">
|
||||
<div className="mx-auto max-w-2xl text-center">
|
||||
<h2 className="text-4xl font-bold tracking-tight text-foreground sm:text-6xl">Enroll Now</h2>
|
||||
<p className="mt-6 text-lg leading-8 text-foreground/70">
|
||||
Fill out the form below to enroll your child or yourself in our programs. We'll get back to you shortly!
|
||||
</p>
|
||||
</div>
|
||||
<div className="mx-auto max-w-xl p-8 mt-10 card-style">
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div>
|
||||
<label htmlFor="fullName" className="block text-sm font-medium leading-6 text-foreground">
|
||||
Student Full Name <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="mt-2">
|
||||
<input
|
||||
type="text"
|
||||
name="fullName"
|
||||
id="fullName"
|
||||
value={formData.fullName}
|
||||
onChange={handleChange}
|
||||
className={`block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-foreground/20 focus:ring-2 focus:ring-inset focus:ring-primary-cta sm:text-sm sm:leading-6 bg-card ${errors.fullName ? 'border-red-500' : ''}`}
|
||||
required
|
||||
/>
|
||||
{errors.fullName && <p className="mt-1 text-xs text-red-500">{errors.fullName}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="age" className="block text-sm font-medium leading-6 text-foreground">
|
||||
Age <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="mt-2">
|
||||
<input
|
||||
type="number"
|
||||
name="age"
|
||||
id="age"
|
||||
value={formData.age}
|
||||
onChange={handleChange}
|
||||
className={`block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-foreground/20 focus:ring-2 focus:ring-inset focus:ring-primary-cta sm:text-sm sm:leading-6 bg-card ${errors.age ? 'border-red-500' : ''}`}
|
||||
required
|
||||
/>
|
||||
{errors.age && <p className="mt-1 text-xs text-red-500">{errors.age}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="parentGuardianName" className="block text-sm font-medium leading-6 text-foreground">
|
||||
Parent/Guardian Name <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="mt-2">
|
||||
<input
|
||||
type="text"
|
||||
name="parentGuardianName"
|
||||
id="parentGuardianName"
|
||||
value={formData.parentGuardianName}
|
||||
onChange={handleChange}
|
||||
className={`block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-foreground/20 focus:ring-2 focus:ring-inset focus:ring-primary-cta sm:text-sm sm:leading-6 bg-card ${errors.parentGuardianName ? 'border-red-500' : ''}`}
|
||||
required
|
||||
/>
|
||||
{errors.parentGuardianName && <p className="mt-1 text-xs text-red-500">{errors.parentGuardianName}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="phoneNumber" className="block text-sm font-medium leading-6 text-foreground">
|
||||
Phone Number <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="mt-2">
|
||||
<input
|
||||
type="tel"
|
||||
name="phoneNumber"
|
||||
id="phoneNumber"
|
||||
value={formData.phoneNumber}
|
||||
onChange={handleChange}
|
||||
className={`block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-foreground/20 focus:ring-2 focus:ring-inset focus:ring-primary-cta sm:text-sm sm:leading-6 bg-card ${errors.phoneNumber ? 'border-red-500' : ''}`}
|
||||
required
|
||||
/>
|
||||
{errors.phoneNumber && <p className="mt-1 text-xs text-red-500">{errors.phoneNumber}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="emailAddress" className="block text-sm font-medium leading-6 text-foreground">
|
||||
Email Address <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="mt-2">
|
||||
<input
|
||||
type="email"
|
||||
name="emailAddress"
|
||||
id="emailAddress"
|
||||
value={formData.emailAddress}
|
||||
onChange={handleChange}
|
||||
className={`block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-foreground/20 focus:ring-2 focus:ring-inset focus:ring-primary-cta sm:text-sm sm:leading-6 bg-card ${errors.emailAddress ? 'border-red-500' : ''}`}
|
||||
required
|
||||
/>
|
||||
{errors.emailAddress && <p className="mt-1 text-xs text-red-500">{errors.emailAddress}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="programClassSelection" className="block text-sm font-medium leading-6 text-foreground">
|
||||
Program/Class Selection <span className="text-red-500">*</span>
|
||||
</label>
|
||||
<div className="mt-2">
|
||||
<select
|
||||
id="programClassSelection"
|
||||
name="programClassSelection"
|
||||
value={formData.programClassSelection}
|
||||
onChange={handleChange}
|
||||
className={`block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-foreground/20 focus:ring-2 focus:ring-inset focus:ring-primary-cta sm:text-sm sm:leading-6 bg-card ${errors.programClassSelection ? 'border-red-500' : ''}`}
|
||||
required
|
||||
>
|
||||
<option value="">Select a Program</option>
|
||||
{programs.map((program) => (
|
||||
<option key={program} value={program}>
|
||||
{program}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
{errors.programClassSelection && <p className="mt-1 text-xs text-red-500">{errors.programClassSelection}</p>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label htmlFor="message" className="block text-sm font-medium leading-6 text-foreground">
|
||||
Message (Optional)
|
||||
</label>
|
||||
<div className="mt-2">
|
||||
<textarea
|
||||
id="message"
|
||||
name="message"
|
||||
rows={4}
|
||||
value={formData.message}
|
||||
onChange={handleChange}
|
||||
className="block w-full rounded-md border-0 py-1.5 text-foreground shadow-sm ring-1 ring-inset ring-foreground/20 focus:ring-2 focus:ring-inset focus:ring-primary-cta sm:text-sm sm:leading-6 bg-card"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6">
|
||||
<button
|
||||
type="submit"
|
||||
className="primary-button-style group relative flex w-full justify-center"
|
||||
disabled={submissionStatus === "loading"}
|
||||
>
|
||||
{submissionStatus === "loading" ? "Submitting..." : "Submit Enrollment"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{submissionStatus === "success" && (
|
||||
<div className="mt-4 p-4 rounded-md bg-green-50 text-green-700 flex items-center">
|
||||
<CheckCircle className="h-5 w-5 mr-2" /> {successMessage}
|
||||
</div>
|
||||
)}
|
||||
{submissionStatus === "error" && (
|
||||
<div className="mt-4 p-4 rounded-md bg-red-50 text-red-700 flex items-center">
|
||||
<Mail className="h-5 w-5 mr-2" /> {errorMessage}
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="footer" data-section="footer">
|
||||
<FooterLogoReveal
|
||||
logoText="Victorious Education Services"
|
||||
leftLink={{
|
||||
text: "Privacy Policy", href: "#"}}
|
||||
rightLink={{
|
||||
text: "Terms of Service", href: "#"}}
|
||||
/>
|
||||
</div>
|
||||
</ReactLenis>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user