135 lines
6.6 KiB
TypeScript
135 lines
6.6 KiB
TypeScript
"use client";
|
||
|
||
import Link from "next/link";
|
||
import { useEffect, useState } from "react";
|
||
|
||
export default function UpcomingWebinars() {
|
||
const [data, setData] = useState<any>(null);
|
||
const [categories, setCategories] = useState<string[]>([]);
|
||
const [active, setActive] = useState<string>("All");
|
||
|
||
useEffect(() => {
|
||
fetch("/api/public/app-setup")
|
||
.then((r) => r.json())
|
||
.then((d) => setCategories(["All", ...(d?.setup?.categories || [])]))
|
||
.catch(() => setCategories(["All"]));
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
fetch("/api/webinars")
|
||
.then((r) => r.json())
|
||
.then(setData)
|
||
.catch(() => setData({ ok: false, message: "Something went wrong. Please contact the website owner." }));
|
||
}, []);
|
||
|
||
const webinars = data?.ok ? data.webinars : [];
|
||
const filtered = active === "All" ? webinars : webinars.filter((w: any) => w.category === active);
|
||
|
||
return (
|
||
<section className="py-28 bg-gradient-to-br from-gray-50 via-white to-blue-50 dark:from-slate-900 dark:via-darkbg dark:to-slate-900">
|
||
<div className="max-w-7xl mx-auto px-6">
|
||
<div className="space-y-8">
|
||
{/* Header */}
|
||
<div className="text-center space-y-3">
|
||
<h2 className="text-5xl font-black text-gray-900 dark:text-white">
|
||
📚 Upcoming <span className="text-primary">Webinars</span>
|
||
</h2>
|
||
<p className="text-lg text-gray-600 dark:text-gray-300 font-medium">Register now to secure your spot in our expert-led sessions</p>
|
||
</div>
|
||
|
||
{/* Category Filter */}
|
||
<div className="flex flex-wrap gap-3 justify-center">
|
||
{categories.map((c) => (
|
||
<button
|
||
key={c}
|
||
onClick={() => setActive(c)}
|
||
className={`px-6 py-2.5 rounded-full text-sm font-bold transition-all duration-300 border-2 ${
|
||
active === c
|
||
? "bg-primary text-white border-transparent shadow-glow hover:shadow-lg"
|
||
: "border-gray-300 dark:border-slate-600 text-gray-700 dark:text-gray-300 hover:border-primary hover:text-primary dark:hover:text-primary"
|
||
}`}
|
||
>
|
||
{c}
|
||
</button>
|
||
))}
|
||
</div>
|
||
|
||
{/* Webinars Table */}
|
||
<div className="overflow-hidden rounded-2xl shadow-soft border border-gray-200 dark:border-slate-700">
|
||
<div className="overflow-x-auto">
|
||
<div className="bg-gray-50 dark:bg-slate-800 grid grid-cols-5 gap-4 px-6 py-4 text-xs font-bold text-gray-700 dark:text-gray-300 uppercase tracking-wider">
|
||
<div className="col-span-2">📝 Webinar</div>
|
||
<div>📅 Date & Time</div>
|
||
<div>👨🏫 Instructor</div>
|
||
<div className="text-right">💰 Price</div>
|
||
</div>
|
||
|
||
<div className="divide-y divide-gray-200 dark:divide-slate-700 bg-white dark:bg-slate-800/50">
|
||
{!data ? (
|
||
<div className="px-6 py-8 text-center">
|
||
<div className="inline-flex items-center gap-2 text-gray-600 dark:text-gray-400 font-medium">
|
||
<div className="w-4 h-4 border-2 border-primary border-r-transparent rounded-full animate-spin"></div>
|
||
Loading webinars...
|
||
</div>
|
||
</div>
|
||
) : !data.ok ? (
|
||
<div className="px-6 py-8 text-center text-danger font-semibold">{data.message}</div>
|
||
) : filtered.length === 0 ? (
|
||
<div className="px-6 py-8 text-center text-gray-600 dark:text-gray-400 font-medium">No webinars found in this category</div>
|
||
) : (
|
||
filtered.map((w: any) => (
|
||
<div key={w.id} className="grid grid-cols-5 gap-4 px-6 py-4 items-center hover:bg-gray-50 dark:hover:bg-slate-700/30 transition-colors duration-200 group">
|
||
{/* Webinar Title & Tags */}
|
||
<div className="col-span-2 space-y-2">
|
||
<div className="font-bold text-gray-900 dark:text-white group-hover:text-primary transition-colors">{w.title}</div>
|
||
<div className="flex gap-2 flex-wrap">
|
||
<span className={`px-3 py-1 rounded-full text-xs font-bold ${
|
||
w.priceCents <= 0
|
||
? "bg-success/15 text-success dark:text-emerald-400"
|
||
: "bg-secondary/15 text-secondary dark:text-pink-400"
|
||
}`}>
|
||
{w.priceCents <= 0 ? "✨ FREE" : "⭐ PREMIUM"}
|
||
</span>
|
||
<span className="px-3 py-1 rounded-full text-xs font-bold bg-primary/15 text-primary dark:text-indigo-400">
|
||
{w.category}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Date & Time */}
|
||
<div className="text-sm font-semibold text-gray-600 dark:text-gray-400">
|
||
{new Date(w.startAt).toLocaleDateString()} <br />
|
||
<span className="text-xs opacity-80">{new Date(w.startAt).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>
|
||
</div>
|
||
|
||
{/* Instructor */}
|
||
<div className="text-sm font-semibold text-gray-600 dark:text-gray-400">{w.speaker}</div>
|
||
|
||
{/* Price & Button */}
|
||
<div className="flex items-center justify-end gap-4">
|
||
<div className={`text-lg font-black ${w.priceCents <= 0 ? "text-success" : "text-primary"}`}>
|
||
{w.priceCents <= 0 ? "FREE" : `$${(w.priceCents / 100).toFixed(0)}`}
|
||
</div>
|
||
<Link href={`/webinars/${w.id}`} className="btn-primary !px-5 !py-2.5 text-sm font-bold whitespace-nowrap">
|
||
{w.priceCents <= 0 ? "🎓 Register" : "💳 Purchase"}
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
))
|
||
)}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* View All Link */}
|
||
<div className="text-center">
|
||
<Link href="/webinars" className="inline-flex items-center gap-2 text-lg font-bold text-primary hover:text-secondary transition-colors duration-300 hover-lift">
|
||
🔗 View All Webinars <span className="group-hover:translate-x-1 transition-transform">→</span>
|
||
</Link>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|