193 lines
12 KiB
TypeScript
193 lines
12 KiB
TypeScript
import { Link } from "react-router-dom";
|
|
import Header from "@/components/Header";
|
|
import Footer from "@/components/Footer";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Card, CardContent } from "@/components/ui/card";
|
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
|
|
import { Star, Check, Clock, BookOpen, Users, Play, Award } from "lucide-react";
|
|
import { useSaasMutation } from "@/hooks/use-tygarun";
|
|
import { toast } from "sonner";
|
|
|
|
const learningPoints = [
|
|
"Build responsive websites with HTML5, CSS3, and modern JavaScript", "Create dynamic single-page applications with React and hooks", "Design and build RESTful APIs with Node.js and Express",
|
|
"Work with SQL and NoSQL databases for full-stack apps", "Deploy applications to the cloud with CI/CD pipelines", "Implement authentication, testing, and security best practices",
|
|
];
|
|
|
|
const modules = [
|
|
{ title: "Web Fundamentals — HTML, CSS & JavaScript", lessons: 8, duration: "3h 20m" },
|
|
{ title: "Frontend Mastery with React", lessons: 10, duration: "4h 15m" },
|
|
{ title: "Backend Development with Node.js", lessons: 12, duration: "5h 30m" },
|
|
{ title: "Databases & Data Modeling", lessons: 9, duration: "3h 45m" },
|
|
{ title: "Deployment, Testing & DevOps", lessons: 11, duration: "4h 50m" },
|
|
];
|
|
|
|
const reviews = [
|
|
{ name: "Michael Torres", rating: 5, text: "The best web dev course I have taken. The projects are practical and the explanations are crystal clear. Landed a junior dev role within 3 months!" },
|
|
{ name: "Lisa Wang", rating: 5, text: "Dr. Chen breaks down complex topics into digestible pieces. The curriculum is perfectly structured from basics to advanced concepts." },
|
|
{ name: "Raj Patel", rating: 4, text: "Great course overall. Very thorough coverage of the full stack. The database section was particularly strong." },
|
|
];
|
|
|
|
const relatedCourses = [
|
|
{ title: "Advanced React Patterns", instructor: "Dr. Sarah Chen", price: "$79", gradient: "from-amber-500 to-orange-600" },
|
|
{ title: "TypeScript for Professionals", instructor: "James Rivera", price: "$69", gradient: "from-emerald-500 to-teal-600" },
|
|
{ title: "Node.js Microservices", instructor: "Alex Kim", price: "$89", gradient: "from-rose-500 to-pink-600" },
|
|
];
|
|
|
|
export default function CourseDetailPage() {
|
|
const { mutate: enroll, loading: enrolling } = useSaasMutation("billing", "/checkout");
|
|
const handleEnroll = async () => {
|
|
try {
|
|
const amount = Math.round(Number("$89".replace(/[^0-9.]/g, "")) * 100);
|
|
const res = await enroll({ course: "Full-Stack Web Development Bootcamp", amount });
|
|
if (res?.url && res.url.indexOf("#") !== 0) { window.location.href = res.url; return; }
|
|
toast.success("Enrollment started for Full-Stack Web Development Bootcamp.");
|
|
} catch { toast.error("Could not start enrollment. Please try again."); }
|
|
};
|
|
return (
|
|
<div className="min-h-screen bg-white dark:bg-slate-950">
|
|
<Header />
|
|
|
|
{/* ── Hero ── */}
|
|
<section className="relative pt-32 pb-16 overflow-hidden">
|
|
<div className="absolute inset-0 bg-gradient-to-br from-indigo-700 via-indigo-600 to-purple-700" />
|
|
<div className="relative mx-auto max-w-7xl px-6">
|
|
<div className="max-w-3xl">
|
|
<div className="flex gap-2 mb-4 animate-fade-up">
|
|
<Badge className="bg-white/20 text-white border-0">Web Development</Badge>
|
|
<Badge className="bg-amber-500/20 text-amber-200 border-0">Beginner</Badge>
|
|
</div>
|
|
<h1 className="text-3xl sm:text-4xl lg:text-5xl font-extrabold text-white leading-tight mb-4 animate-fade-up" style={{ animationDelay: "0.05s" }}>Full-Stack Web Development Bootcamp</h1>
|
|
<p className="text-indigo-100 mb-6 animate-fade-up" style={{ animationDelay: "0.1s" }}>Master HTML, CSS, JavaScript, React, Node.js, and databases in this comprehensive bootcamp designed for aspiring developers.</p>
|
|
<div className="flex flex-wrap items-center gap-6 mb-6 animate-fade-up" style={{ animationDelay: "0.15s" }}>
|
|
<div className="flex items-center gap-3">
|
|
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-indigo-400 to-purple-500 flex items-center justify-center text-white font-bold text-sm">SC</div>
|
|
<span className="text-white font-medium">Dr. Sarah Chen</span>
|
|
</div>
|
|
<div className="flex items-center gap-1">
|
|
<Star className="h-5 w-5 fill-amber-400 text-amber-400" />
|
|
<span className="text-white font-semibold">4.9</span>
|
|
<span className="text-indigo-200">(1,240 reviews)</span>
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-wrap items-center gap-4 animate-fade-up" style={{ animationDelay: "0.2s" }}>
|
|
<span className="text-3xl font-bold text-white">$89</span>
|
|
<Button onClick={handleEnroll} disabled={enrolling} className="bg-amber-500 hover:bg-amber-600 text-white rounded-full px-8 shadow-xl shadow-amber-500/20 active:scale-[0.97] transition-all">{enrolling ? "Processing…" : "Enroll Now"}</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* ── What You'll Learn ── */}
|
|
<section className="py-16">
|
|
<div className="mx-auto max-w-7xl px-6">
|
|
<h2 className="text-2xl sm:text-3xl font-bold mb-8 animate-fade-up">What You'll Learn</h2>
|
|
<div className="grid md:grid-cols-2 gap-4">
|
|
{learningPoints.map((point, i) => (
|
|
<div key={i} className="flex items-start gap-3 animate-fade-up" style={{ animationDelay: `${i * 0.06}s` }}>
|
|
<Check className="h-5 w-5 text-indigo-600 dark:text-indigo-400 mt-0.5 shrink-0" />
|
|
<span>{point}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* ── Curriculum ── */}
|
|
<section className="py-16 bg-slate-50 dark:bg-slate-900/50">
|
|
<div className="mx-auto max-w-7xl px-6">
|
|
<h2 className="text-2xl sm:text-3xl font-bold mb-8 animate-fade-up">Course Curriculum</h2>
|
|
<Accordion type="single" collapsible className="space-y-3 max-w-3xl animate-fade-up" style={{ animationDelay: "0.1s" }}>
|
|
{modules.map((m, i) => (
|
|
<AccordionItem key={i} value={`mod-${i}`} className="bg-white dark:bg-slate-900 rounded-xl border border-slate-200/60 dark:border-slate-800/60 px-6">
|
|
<AccordionTrigger className="hover:no-underline">
|
|
<div className="flex items-center gap-3 text-left">
|
|
<div className="w-8 h-8 rounded-lg bg-indigo-100 dark:bg-indigo-900/40 flex items-center justify-center text-sm font-bold text-indigo-600 dark:text-indigo-400">{i + 1}</div>
|
|
<div>
|
|
<div className="font-semibold">{m.title}</div>
|
|
<div className="text-xs text-muted-foreground">{m.lessons} lessons · {m.duration}</div>
|
|
</div>
|
|
</div>
|
|
</AccordionTrigger>
|
|
<AccordionContent className="text-muted-foreground pl-11">
|
|
Module content includes video lectures, quizzes, and hands-on exercises covering all core concepts.
|
|
</AccordionContent>
|
|
</AccordionItem>
|
|
))}
|
|
</Accordion>
|
|
</div>
|
|
</section>
|
|
|
|
{/* ── Instructor Bio ── */}
|
|
<section className="py-16">
|
|
<div className="mx-auto max-w-7xl px-6">
|
|
<h2 className="text-2xl sm:text-3xl font-bold mb-8 animate-fade-up">Your Instructor</h2>
|
|
<Card className="bg-white/70 dark:bg-slate-900/70 backdrop-blur border-slate-200/60 dark:border-slate-800/60 rounded-2xl p-8 max-w-3xl animate-fade-up" style={{ animationDelay: "0.1s" }}>
|
|
<div className="flex flex-col sm:flex-row gap-6">
|
|
<div className="w-24 h-24 rounded-2xl bg-gradient-to-br from-indigo-500 to-purple-600 flex items-center justify-center shrink-0">
|
|
<span className="text-3xl font-bold text-white">SC</span>
|
|
</div>
|
|
<div>
|
|
<h3 className="text-xl font-bold mb-1">Dr. Sarah Chen</h3>
|
|
<p className="text-muted-foreground mb-4">Dr. Sarah Chen is a senior software engineer and educator with 12 years of industry experience at top tech companies. She is passionate about making web development accessible to everyone.</p>
|
|
<div className="flex flex-wrap gap-6 text-sm">
|
|
<div className="flex items-center gap-2"><BookOpen className="h-4 w-4 text-indigo-500" /><span>12 Courses</span></div>
|
|
<div className="flex items-center gap-2"><Users className="h-4 w-4 text-indigo-500" /><span>3,200 Students</span></div>
|
|
<div className="flex items-center gap-2"><Star className="h-4 w-4 text-amber-500" /><span>4.9 Rating</span></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
</section>
|
|
|
|
{/* ── Student Reviews ── */}
|
|
<section className="py-16 bg-slate-50 dark:bg-slate-900/50">
|
|
<div className="mx-auto max-w-7xl px-6">
|
|
<h2 className="text-2xl sm:text-3xl font-bold mb-8 animate-fade-up">Student Reviews</h2>
|
|
<div className="grid md:grid-cols-3 gap-6">
|
|
{reviews.map((r, i) => (
|
|
<Card key={i} className="bg-white/70 dark:bg-slate-900/70 backdrop-blur border-slate-200/60 dark:border-slate-800/60 rounded-2xl p-6 animate-fade-up" style={{ animationDelay: `${i * 0.1}s` }}>
|
|
<div className="flex items-center gap-1 mb-3">
|
|
{Array.from({ length: r.rating }).map((_, j) => (
|
|
<Star key={j} className="h-4 w-4 fill-amber-400 text-amber-400" />
|
|
))}
|
|
</div>
|
|
<p className="text-muted-foreground mb-4 leading-relaxed">{r.text}</p>
|
|
<div className="font-semibold">{r.name}</div>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* ── Related Courses ── */}
|
|
<section className="py-16">
|
|
<div className="mx-auto max-w-7xl px-6">
|
|
<h2 className="text-2xl sm:text-3xl font-bold mb-8 animate-fade-up">Related Courses</h2>
|
|
<div className="grid md:grid-cols-3 gap-6">
|
|
{relatedCourses.map((c, i) => (
|
|
<Card key={i} className="group bg-white/70 dark:bg-slate-900/70 backdrop-blur border-slate-200/60 dark:border-slate-800/60 rounded-2xl overflow-hidden hover:-translate-y-1 hover:shadow-xl transition-all duration-300 animate-fade-up" style={{ animationDelay: `${i * 0.1}s` }}>
|
|
<div className={`h-32 bg-gradient-to-br ${c.gradient} flex items-center justify-center`}>
|
|
<BookOpen className="h-10 w-10 text-white/80" />
|
|
</div>
|
|
<CardContent className="p-5">
|
|
<h3 className="font-semibold mb-1">{c.title}</h3>
|
|
<p className="text-sm text-muted-foreground mb-3">{c.instructor}</p>
|
|
<div className="flex items-center justify-between">
|
|
<span className="text-lg font-bold text-indigo-600 dark:text-indigo-400">{c.price}</span>
|
|
<Button asChild variant="outline" size="sm" className="rounded-full">
|
|
<Link to="/course/1">View</Link>
|
|
</Button>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<Footer />
|
|
</div>
|
|
);
|
|
} |