Merge version_2_1783007875303 into main #2
@@ -1,218 +1,39 @@
|
||||
import AboutText from '@/components/sections/about/AboutText';
|
||||
import ContactCta from '@/components/sections/contact/ContactCta';
|
||||
import FaqTwoColumn from '@/components/sections/faq/FaqTwoColumn';
|
||||
import FeaturesBorderGlow from '@/components/sections/features/FeaturesBorderGlow';
|
||||
import FeaturesRevealCardsBento from '@/components/sections/features/FeaturesRevealCardsBento';
|
||||
import HeroBillboard from '@/components/sections/hero/HeroBillboard';
|
||||
import MetricsMediaCards from '@/components/sections/metrics/MetricsMediaCards';
|
||||
import { BookOpen, Globe2, MessageCircle, Mic, PenTool, Users, Video } from "lucide-react";
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
// AUTO-GENERATED shell by per-section-migrate.
|
||||
// Section bodies live in the sibling sections/ folder (one file per section).
|
||||
// Edit those section files directly. Non-block content (wrappers,
|
||||
// non-inlinable sections) is preserved inline; extracted section blocks
|
||||
// become component refs.
|
||||
|
||||
export default function HomePage() {
|
||||
import React from 'react';
|
||||
import HeroSection from './HomePage/sections/Hero';
|
||||
import AboutSection from './HomePage/sections/About';
|
||||
import FeaturesSection from './HomePage/sections/Features';
|
||||
import DemoSection from './HomePage/sections/Demo';
|
||||
import ScheduleSection from './HomePage/sections/Schedule';
|
||||
|
||||
|
||||
import PlacementSection from './HomePage/sections/Placement';
|
||||
import RegisterSection from './HomePage/sections/Register';
|
||||
import LoginSection from './HomePage/sections/Login';
|
||||
import ContactSection from './HomePage/sections/Contact';export default function HomePage(): React.JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<div id="hero" data-section="hero">
|
||||
<SectionErrorBoundary name="hero">
|
||||
<HeroBillboard
|
||||
tag="Elevate Your Potential"
|
||||
title="Master English with Confidence"
|
||||
description="Join live English classes that improve your speaking confidence, pronunciation, grammar, spelling, vocabulary, and overall fluency."
|
||||
primaryButton={{
|
||||
text: "Register Now",
|
||||
href: "#register",
|
||||
}}
|
||||
secondaryButton={{
|
||||
text: "Book Free Demo",
|
||||
href: "#demo",
|
||||
}}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/luxury-modern-living-room-with-elegant-design-generated-by-ai_188544-21319.jpg"
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<>
|
||||
<HeroSection />
|
||||
|
||||
<div id="about" data-section="about">
|
||||
<SectionErrorBoundary name="about">
|
||||
<AboutText
|
||||
title="Speak Hub Global helps students become confident English speakers through structured live sessions, practical worksheets, pronunciation training, recorded lessons, and personal guidance."
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<AboutSection />
|
||||
|
||||
<div id="features" data-section="features">
|
||||
<SectionErrorBoundary name="features">
|
||||
<FeaturesBorderGlow
|
||||
tag="Our Curriculum"
|
||||
title="Comprehensive Features"
|
||||
description="Tailored training for every level."
|
||||
features={[
|
||||
{
|
||||
icon: Users,
|
||||
title: "Live Interactive Sessions",
|
||||
description: "Structured sessions for real-time engagement.",
|
||||
},
|
||||
{
|
||||
icon: BookOpen,
|
||||
title: "Daily Practice Worksheets",
|
||||
description: "Reinforce learning with curated worksheets.",
|
||||
},
|
||||
{
|
||||
icon: MessageCircle,
|
||||
title: "One-to-One Doubt Solving",
|
||||
description: "Personal guidance from our experts.",
|
||||
},
|
||||
{
|
||||
icon: Mic,
|
||||
title: "Pronunciation Drill Challenges",
|
||||
description: "Master accent and clarity.",
|
||||
},
|
||||
{
|
||||
icon: PenTool,
|
||||
title: "Grammar & Spelling Improvement",
|
||||
description: "Solidify your linguistic foundations.",
|
||||
},
|
||||
{
|
||||
icon: Globe2,
|
||||
title: "Speaking Fluency Training",
|
||||
description: "Speak confidently in any environment.",
|
||||
},
|
||||
{
|
||||
icon: Video,
|
||||
title: "Recorded Lessons",
|
||||
description: "Access lessons anytime for revision.",
|
||||
},
|
||||
]}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<FeaturesSection />
|
||||
<PlacementSection />
|
||||
|
||||
<div id="placement" data-section="placement">
|
||||
<SectionErrorBoundary name="placement">
|
||||
<FeaturesRevealCardsBento
|
||||
tag="Evaluation"
|
||||
title="English Placement Test"
|
||||
description="Discover your current English level and get a customized recommendation."
|
||||
items={[
|
||||
{
|
||||
title: "A1 Beginner",
|
||||
description: "Understand basic words and phrases.",
|
||||
href: "#contact",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/cheerful-girl-stylish-shirt-headphones-communicates-with-friend-by-video-link_197531-4884.jpg",
|
||||
},
|
||||
{
|
||||
title: "B1 Intermediate",
|
||||
description: "Handle travel, interviews, and business.",
|
||||
href: "#contact",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/sudoku-game-page-arrangement_23-2149072728.jpg",
|
||||
},
|
||||
{
|
||||
title: "C1 Advanced",
|
||||
description: "Communicate professionally and express ideas.",
|
||||
href: "#contact",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/teleworker-doing-remote-teleconference-meeting-with-colleagues-close-up_482257-119749.jpg",
|
||||
},
|
||||
{
|
||||
title: "Beginner Course",
|
||||
description: "Build foundations confidently.",
|
||||
href: "#contact",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/shocked-caucasian-female-call-center-operator-headphones-sitting-desk-with-office-tools-with-hand-close-her-mouth-looking-up_141793-121646.jpg",
|
||||
},
|
||||
{
|
||||
title: "Business Course",
|
||||
description: "Master meetings and presentations.",
|
||||
href: "#contact",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/literacy-abc-icon-alphabet-concept_53876-121086.jpg",
|
||||
},
|
||||
{
|
||||
title: "Advanced Course",
|
||||
description: "Complex ideas made simple.",
|
||||
href: "#contact",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/mix-raced-team-colleagues-discussing-ideas-project_74855-2985.jpg",
|
||||
},
|
||||
{
|
||||
title: "Fluency Module",
|
||||
description: "Speak with international clarity.",
|
||||
href: "#contact",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/rear-view-young-college-student-paying-attention-listening-her-online-teacher-laptop-home_662251-2487.jpg",
|
||||
},
|
||||
]}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
|
||||
<div id="demo" data-section="demo">
|
||||
<SectionErrorBoundary name="demo">
|
||||
<MetricsMediaCards
|
||||
tag="Start Free"
|
||||
title="20-Minute Demo Class"
|
||||
description="Experience our premium teaching methodology firsthand."
|
||||
metrics={[
|
||||
{
|
||||
value: "20m",
|
||||
title: "Free Live Demo",
|
||||
description: "Get to know our process.",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/modern-office-space-with-futuristic-decor-furniture_23-2151797633.jpg",
|
||||
},
|
||||
]}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<DemoSection />
|
||||
|
||||
<div id="schedule" data-section="schedule">
|
||||
<SectionErrorBoundary name="schedule">
|
||||
<FaqTwoColumn
|
||||
tag="Time Table"
|
||||
title="Class Schedules"
|
||||
description="Convenient weekend sessions for professionals."
|
||||
items={[
|
||||
{
|
||||
question: "Saturday Session",
|
||||
answer: "9:00 PM – 11:00 PM",
|
||||
},
|
||||
{
|
||||
question: "Sunday Session",
|
||||
answer: "4:00 PM – 6:00 PM",
|
||||
},
|
||||
]}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
<ScheduleSection />
|
||||
<LoginSection />
|
||||
<ContactSection />
|
||||
<RegisterSection />
|
||||
|
||||
<div id="login" data-section="login">
|
||||
<SectionErrorBoundary name="login">
|
||||
<AboutText
|
||||
title="Student Portal - Login required for enrolled members."
|
||||
primaryButton={{
|
||||
text: "Login",
|
||||
href: "#",
|
||||
}}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
|
||||
<div id="register" data-section="register">
|
||||
<SectionErrorBoundary name="register">
|
||||
<ContactCta
|
||||
tag="Registration"
|
||||
text="Register for Inquiry to begin your English journey."
|
||||
primaryButton={{
|
||||
text: "Submit Inquiry",
|
||||
href: "#",
|
||||
}}
|
||||
secondaryButton={{
|
||||
text: "WhatsApp Community",
|
||||
href: "https://chat.whatsapp.com/Dn87aph09qiJQ56TSktJfC",
|
||||
}}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
19
src/pages/HomePage/sections/About.tsx
Normal file
19
src/pages/HomePage/sections/About.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "about" section.
|
||||
|
||||
import React from 'react';
|
||||
import AboutText from '@/components/sections/about/AboutText';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function AboutSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="about" data-section="about">
|
||||
<SectionErrorBoundary name="about">
|
||||
<AboutText
|
||||
title="Speak Hub Global helps students become confident English speakers through structured live sessions, practical worksheets, pronunciation training, recorded lessons, and personal guidance."
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
65
src/pages/HomePage/sections/Contact.tsx
Normal file
65
src/pages/HomePage/sections/Contact.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React from 'react';
|
||||
import Card from '@/components/ui/Card';
|
||||
import TextAnimation from '@/components/ui/TextAnimation';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
import Tag from '@/components/ui/Tag';
|
||||
import { MessageCircle, Instagram, User } from 'lucide-react';
|
||||
|
||||
export default function ContactSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="contact" data-webild-section="contact" className="py-24 bg-background">
|
||||
<SectionErrorBoundary name="contact">
|
||||
<div className="w-content-width mx-auto flex flex-col items-center">
|
||||
<Tag text="Get in Touch" className="mb-6" />
|
||||
<TextAnimation
|
||||
text="Contact Us"
|
||||
variant="slide-up"
|
||||
tag="h2"
|
||||
gradientText={false}
|
||||
className="text-4xl md:text-5xl font-bold text-foreground mb-12 text-center"
|
||||
/>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 w-full max-w-5xl">
|
||||
<Card className="p-8 flex flex-col items-center text-center hover:border-primary-cta transition-colors">
|
||||
<div className="w-16 h-16 bg-background-accent rounded-full flex items-center justify-center mb-6">
|
||||
<User className="w-8 h-8 text-primary-cta" />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-foreground mb-2">Instructor</h3>
|
||||
<p className="text-accent text-lg">Sophie Rose</p>
|
||||
</Card>
|
||||
|
||||
<a
|
||||
href="https://chat.whatsapp.com/Dn87aph09qiJQ56TSktJfC"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block"
|
||||
>
|
||||
<Card className="p-8 flex flex-col items-center text-center hover:border-primary-cta transition-colors h-full">
|
||||
<div className="w-16 h-16 bg-background-accent rounded-full flex items-center justify-center mb-6">
|
||||
<MessageCircle className="w-8 h-8 text-primary-cta" />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-foreground mb-2">WhatsApp Community</h3>
|
||||
<p className="text-accent text-sm">Join our active learning community</p>
|
||||
</Card>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://www.instagram.com/speakhub_global1?igsh=MW1rOGl3cW42NXRkMA=="
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="block"
|
||||
>
|
||||
<Card className="p-8 flex flex-col items-center text-center hover:border-primary-cta transition-colors h-full">
|
||||
<div className="w-16 h-16 bg-background-accent rounded-full flex items-center justify-center mb-6">
|
||||
<Instagram className="w-8 h-8 text-primary-cta" />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-foreground mb-2">Instagram</h3>
|
||||
<p className="text-accent text-sm">Follow us for daily tips</p>
|
||||
</Card>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
29
src/pages/HomePage/sections/Demo.tsx
Normal file
29
src/pages/HomePage/sections/Demo.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "demo" section.
|
||||
|
||||
import React from 'react';
|
||||
import MetricsMediaCards from '@/components/sections/metrics/MetricsMediaCards';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function DemoSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="demo" data-section="demo">
|
||||
<SectionErrorBoundary name="demo">
|
||||
<MetricsMediaCards
|
||||
tag="Start Free"
|
||||
title="20-Minute Demo Class"
|
||||
description="Experience our premium teaching methodology firsthand."
|
||||
metrics={[
|
||||
{
|
||||
value: "20m",
|
||||
title: "Free Live Demo",
|
||||
description: "Get to know our process.",
|
||||
imageSrc: "http://img.b2bpic.net/free-photo/modern-office-space-with-futuristic-decor-furniture_23-2151797633.jpg",
|
||||
},
|
||||
]}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
59
src/pages/HomePage/sections/Features.tsx
Normal file
59
src/pages/HomePage/sections/Features.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "features" section.
|
||||
|
||||
import React from 'react';
|
||||
import FeaturesBorderGlow from '@/components/sections/features/FeaturesBorderGlow';
|
||||
import { BookOpen, Globe2, MessageCircle, Mic, PenTool, Users, Video } from "lucide-react";
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function FeaturesSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="features" data-section="features">
|
||||
<SectionErrorBoundary name="features">
|
||||
<FeaturesBorderGlow
|
||||
tag="Our Curriculum"
|
||||
title="Comprehensive Features"
|
||||
description="Tailored training for every level."
|
||||
features={[
|
||||
{
|
||||
icon: Users,
|
||||
title: "Live Interactive Sessions",
|
||||
description: "Structured sessions for real-time engagement.",
|
||||
},
|
||||
{
|
||||
icon: BookOpen,
|
||||
title: "Daily Practice Worksheets",
|
||||
description: "Reinforce learning with curated worksheets.",
|
||||
},
|
||||
{
|
||||
icon: MessageCircle,
|
||||
title: "One-to-One Doubt Solving",
|
||||
description: "Personal guidance from our experts.",
|
||||
},
|
||||
{
|
||||
icon: Mic,
|
||||
title: "Pronunciation Drill Challenges",
|
||||
description: "Master accent and clarity.",
|
||||
},
|
||||
{
|
||||
icon: PenTool,
|
||||
title: "Grammar & Spelling Improvement",
|
||||
description: "Solidify your linguistic foundations.",
|
||||
},
|
||||
{
|
||||
icon: Globe2,
|
||||
title: "Speaking Fluency Training",
|
||||
description: "Speak confidently in any environment.",
|
||||
},
|
||||
{
|
||||
icon: Video,
|
||||
title: "Recorded Lessons",
|
||||
description: "Access lessons anytime for revision.",
|
||||
},
|
||||
]}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
30
src/pages/HomePage/sections/Hero.tsx
Normal file
30
src/pages/HomePage/sections/Hero.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "hero" section.
|
||||
|
||||
import React from 'react';
|
||||
import HeroBillboard from '@/components/sections/hero/HeroBillboard';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function HeroSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="hero" data-section="hero">
|
||||
<SectionErrorBoundary name="hero">
|
||||
<HeroBillboard
|
||||
tag="Elevate Your Potential"
|
||||
title="Master English with Confidence"
|
||||
description="Join live English classes that improve your speaking confidence, pronunciation, grammar, spelling, vocabulary, and overall fluency."
|
||||
primaryButton={{
|
||||
text: "Register Now",
|
||||
href: "#register",
|
||||
}}
|
||||
secondaryButton={{
|
||||
text: "Book Free Demo",
|
||||
href: "#demo",
|
||||
}}
|
||||
imageSrc="http://img.b2bpic.net/free-photo/luxury-modern-living-room-with-elegant-design-generated-by-ai_188544-21319.jpg"
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
97
src/pages/HomePage/sections/Login.tsx
Normal file
97
src/pages/HomePage/sections/Login.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import React, { useState } from 'react';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Card from '@/components/ui/Card';
|
||||
import TextAnimation from '@/components/ui/TextAnimation';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
import Tag from '@/components/ui/Tag';
|
||||
import Input from '@/components/ui/Input';
|
||||
import Label from '@/components/ui/Label';
|
||||
|
||||
export default function LoginSection(): React.JSX.Element {
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
// In a real app, this would send to aminsophie98@gmail.com
|
||||
setSubmitted(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div id="login" data-webild-section="login" className="py-24 bg-background">
|
||||
<SectionErrorBoundary name="login">
|
||||
<div className="w-content-width mx-auto flex flex-col items-center">
|
||||
<Tag text="Student Portal" className="mb-6" />
|
||||
<TextAnimation
|
||||
text="Welcome Back"
|
||||
variant="slide-up"
|
||||
tag="h2"
|
||||
gradientText={false}
|
||||
className="text-4xl md:text-5xl font-bold text-foreground mb-4 text-center"
|
||||
/>
|
||||
<p className="text-lg text-accent text-center mb-12 max-w-2xl">
|
||||
Login to access your live sessions, daily practice worksheets, and recorded lessons.
|
||||
</p>
|
||||
|
||||
<Card className="w-full max-w-md p-8 md:p-12">
|
||||
{submitted ? (
|
||||
<div className="text-center py-8">
|
||||
<div className="w-16 h-16 bg-primary-cta/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||
<svg className="w-8 h-8 text-primary-cta" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-xl font-bold text-foreground mb-2">Login Request Sent</h3>
|
||||
<p className="text-accent text-sm">
|
||||
Your login request has been sent to the administrator. You will be contacted shortly.
|
||||
</p>
|
||||
<Button
|
||||
text="Back to Login"
|
||||
onClick={() => setSubmitted(false)}
|
||||
variant="secondary"
|
||||
className="mt-6 w-full"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="loginEmail" className="text-foreground">Email</Label>
|
||||
<Input
|
||||
id="loginEmail"
|
||||
type="email"
|
||||
required
|
||||
placeholder="student@example.com"
|
||||
className="w-full bg-background-accent border-background-accent focus:border-primary-cta text-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between items-center">
|
||||
<Label htmlFor="password" className="text-foreground">Password</Label>
|
||||
<a href="#" className="text-xs text-primary-cta hover:underline">Forgot password?</a>
|
||||
</div>
|
||||
<Input
|
||||
id="password"
|
||||
type="password"
|
||||
required
|
||||
placeholder="••••••••"
|
||||
className="w-full bg-background-accent border-background-accent focus:border-primary-cta text-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
text="Login"
|
||||
variant="primary"
|
||||
className="w-full pt-2"
|
||||
/>
|
||||
|
||||
<p className="text-center text-sm text-accent mt-4">
|
||||
Not enrolled yet? <a href="#register" className="text-primary-cta hover:underline">Register for Inquiry</a>
|
||||
</p>
|
||||
</form>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
141
src/pages/HomePage/sections/Placement.tsx
Normal file
141
src/pages/HomePage/sections/Placement.tsx
Normal file
@@ -0,0 +1,141 @@
|
||||
import React, { useState } from 'react';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Card from '@/components/ui/Card';
|
||||
import TextAnimation from '@/components/ui/TextAnimation';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
import Tag from '@/components/ui/Tag';
|
||||
|
||||
const questions = [
|
||||
{ q: "1. I ___ from Spain.", options: ["am", "is", "are"], answer: 0 },
|
||||
{ q: "2. She ___ to the store every day.", options: ["go", "goes", "going"], answer: 1 },
|
||||
{ q: "3. ___ you like coffee?", options: ["Do", "Does", "Are"], answer: 0 },
|
||||
{ q: "4. I have been living here ___ 5 years.", options: ["since", "for", "in"], answer: 1 },
|
||||
{ q: "5. If I ___ you, I would study harder.", options: ["was", "were", "am"], answer: 1 },
|
||||
{ q: "6. By this time next year, I ___ my degree.", options: ["will finish", "will have finished", "finish"], answer: 1 },
|
||||
{ q: "7. He is the man ___ stole my car.", options: ["who", "which", "whose"], answer: 0 },
|
||||
{ q: "8. I'm looking forward ___ you.", options: ["to see", "to seeing", "seeing"], answer: 1 },
|
||||
{ q: "9. She asked me where ___.", options: ["I lived", "did I live", "do I live"], answer: 0 },
|
||||
{ q: "10. Hardly ___ the house when it started to rain.", options: ["I had left", "had I left", "I left"], answer: 1 }
|
||||
];
|
||||
|
||||
export default function PlacementSection(): React.JSX.Element {
|
||||
const [currentQuestion, setCurrentQuestion] = useState(0);
|
||||
const [score, setScore] = useState(0);
|
||||
const [showResult, setShowResult] = useState(false);
|
||||
|
||||
const handleAnswer = (selectedIndex: number) => {
|
||||
if (selectedIndex === questions[currentQuestion].answer) {
|
||||
setScore(score + 1);
|
||||
}
|
||||
|
||||
if (currentQuestion < questions.length - 1) {
|
||||
setCurrentQuestion(currentQuestion + 1);
|
||||
} else {
|
||||
setShowResult(true);
|
||||
}
|
||||
};
|
||||
|
||||
const resetQuiz = () => {
|
||||
setCurrentQuestion(0);
|
||||
setScore(0);
|
||||
setShowResult(false);
|
||||
};
|
||||
|
||||
const getResult = () => {
|
||||
if (score <= 3) {
|
||||
return {
|
||||
level: "A1 Beginner",
|
||||
description: "Speak basic English confidently and build grammar foundations.",
|
||||
course: "Beginner Course"
|
||||
};
|
||||
} else if (score <= 7) {
|
||||
return {
|
||||
level: "B1 Intermediate",
|
||||
description: "Handle travel, interviews, daily conversations, and business meetings confidently.",
|
||||
course: "Intermediate Course"
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
level: "C1 Advanced",
|
||||
description: "Communicate professionally, give presentations, and express complex ideas fluently.",
|
||||
course: "Advanced Course"
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div id="placement" data-webild-section="placement" className="py-24 bg-background">
|
||||
<SectionErrorBoundary name="placement">
|
||||
<div className="w-content-width mx-auto flex flex-col items-center">
|
||||
<Tag text="Evaluation" className="mb-6" />
|
||||
<TextAnimation
|
||||
text="FREE Placement Test"
|
||||
variant="slide-up"
|
||||
tag="h2"
|
||||
gradientText={false}
|
||||
className="text-4xl md:text-5xl font-bold text-foreground mb-4 text-center"
|
||||
/>
|
||||
<p className="text-lg text-accent text-center mb-12 max-w-2xl">
|
||||
Take our quick 10-question test to discover your current English level and get a customized class recommendation.
|
||||
</p>
|
||||
|
||||
<Card className="w-full max-w-3xl p-8 md:p-12">
|
||||
{!showResult ? (
|
||||
<div className="flex flex-col">
|
||||
<div className="flex justify-between items-center mb-8">
|
||||
<span className="text-accent font-medium">Question {currentQuestion + 1} of 10</span>
|
||||
<div className="w-1/2 bg-background-accent h-2 rounded-full overflow-hidden">
|
||||
<div
|
||||
className="bg-primary-cta h-full transition-all duration-300"
|
||||
style={{ width: `${((currentQuestion + 1) / 10) * 100}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 className="text-2xl font-semibold text-foreground mb-8">
|
||||
{questions[currentQuestion].q}
|
||||
</h3>
|
||||
|
||||
<div className="flex flex-col gap-4">
|
||||
{questions[currentQuestion].options.map((option, idx) => (
|
||||
<button
|
||||
key={idx}
|
||||
onClick={() => handleAnswer(idx)}
|
||||
className="w-full text-left p-4 rounded-lg border border-background-accent hover:border-primary-cta hover:bg-background-accent transition-colors text-foreground text-lg"
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col items-center text-center py-8">
|
||||
<div className="w-24 h-24 rounded-full bg-background-accent flex items-center justify-center mb-6 border-4 border-primary-cta">
|
||||
<span className="text-3xl font-bold text-primary-cta">{score}/10</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-3xl font-bold text-foreground mb-2">
|
||||
Your Level: {getResult().level}
|
||||
</h3>
|
||||
|
||||
<p className="text-xl text-accent mb-8 max-w-lg">
|
||||
{getResult().description}
|
||||
</p>
|
||||
|
||||
<div className="bg-background-accent p-6 rounded-xl mb-8 w-full">
|
||||
<p className="text-sm text-accent mb-2 uppercase tracking-wider">Recommended Class</p>
|
||||
<p className="text-2xl font-semibold text-foreground">{getResult().course}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col sm:flex-row gap-4 w-full sm:w-auto">
|
||||
<Button text="Book Free Demo" href="#demo" variant="primary" className="w-full sm:w-auto" />
|
||||
<Button text="Retake Test" onClick={resetQuiz} variant="secondary" className="w-full sm:w-auto" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
110
src/pages/HomePage/sections/Register.tsx
Normal file
110
src/pages/HomePage/sections/Register.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
import React, { useState } from 'react';
|
||||
import Button from '@/components/ui/Button';
|
||||
import Card from '@/components/ui/Card';
|
||||
import TextAnimation from '@/components/ui/TextAnimation';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
import Tag from '@/components/ui/Tag';
|
||||
import Input from '@/components/ui/Input';
|
||||
import Label from '@/components/ui/Label';
|
||||
|
||||
export default function RegisterSection(): React.JSX.Element {
|
||||
const [submitted, setSubmitted] = useState(false);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
// In a real app, this would send to aminsophie98@gmail.com
|
||||
setSubmitted(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div id="register" data-webild-section="register" className="py-24 bg-background">
|
||||
<SectionErrorBoundary name="register">
|
||||
<div className="w-content-width mx-auto flex flex-col items-center">
|
||||
<Tag text="Registration" className="mb-6" />
|
||||
<TextAnimation
|
||||
text="Register for Inquiry"
|
||||
variant="slide-up"
|
||||
tag="h2"
|
||||
gradientText={false}
|
||||
className="text-4xl md:text-5xl font-bold text-foreground mb-4 text-center"
|
||||
/>
|
||||
<p className="text-lg text-accent text-center mb-12 max-w-2xl">
|
||||
Fill out the form below and we will contact you shortly to begin your English journey.
|
||||
</p>
|
||||
|
||||
<Card className="w-full max-w-2xl p-8 md:p-12">
|
||||
{submitted ? (
|
||||
<div className="text-center py-12">
|
||||
<div className="w-20 h-20 bg-primary-cta/20 rounded-full flex items-center justify-center mx-auto mb-6">
|
||||
<svg className="w-10 h-10 text-primary-cta" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
</div>
|
||||
<h3 className="text-2xl font-bold text-foreground mb-4">Thank you!</h3>
|
||||
<p className="text-lg text-accent">
|
||||
We received your inquiry and will contact you shortly.
|
||||
</p>
|
||||
<Button
|
||||
text="Submit Another Inquiry"
|
||||
onClick={() => setSubmitted(false)}
|
||||
variant="secondary"
|
||||
className="mt-8"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="fullName" className="text-foreground">Full Name</Label>
|
||||
<Input
|
||||
id="fullName"
|
||||
required
|
||||
placeholder="John Doe"
|
||||
className="w-full bg-background-accent border-background-accent focus:border-primary-cta text-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="phone" className="text-foreground">Phone Number</Label>
|
||||
<Input
|
||||
id="phone"
|
||||
type="tel"
|
||||
required
|
||||
placeholder="+1 (555) 000-0000"
|
||||
className="w-full bg-background-accent border-background-accent focus:border-primary-cta text-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="email" className="text-foreground">Email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
type="email"
|
||||
required
|
||||
placeholder="john@example.com"
|
||||
className="w-full bg-background-accent border-background-accent focus:border-primary-cta text-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="city" className="text-foreground">City / Location</Label>
|
||||
<Input
|
||||
id="city"
|
||||
required
|
||||
placeholder="New York, NY"
|
||||
className="w-full bg-background-accent border-background-accent focus:border-primary-cta text-foreground"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
text="Submit Inquiry"
|
||||
variant="primary"
|
||||
className="w-full pt-4"
|
||||
/>
|
||||
</form>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
31
src/pages/HomePage/sections/Schedule.tsx
Normal file
31
src/pages/HomePage/sections/Schedule.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
|
||||
// file as the canonical source for the "schedule" section.
|
||||
|
||||
import React from 'react';
|
||||
import FaqTwoColumn from '@/components/sections/faq/FaqTwoColumn';
|
||||
import SectionErrorBoundary from "@/components/ui/SectionErrorBoundary";
|
||||
|
||||
export default function ScheduleSection(): React.JSX.Element {
|
||||
return (
|
||||
<div id="schedule" data-section="schedule">
|
||||
<SectionErrorBoundary name="schedule">
|
||||
<FaqTwoColumn
|
||||
tag="Time Table"
|
||||
title="Class Schedules"
|
||||
description="Convenient weekend sessions for professionals."
|
||||
items={[
|
||||
{
|
||||
question: "Saturday Session",
|
||||
answer: "9:00 PM – 11:00 PM",
|
||||
},
|
||||
{
|
||||
question: "Sunday Session",
|
||||
answer: "4:00 PM – 6:00 PM",
|
||||
},
|
||||
]}
|
||||
textAnimation="slide-up"
|
||||
/>
|
||||
</SectionErrorBoundary>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user