267 lines
7.4 KiB
TypeScript
267 lines
7.4 KiB
TypeScript
export const dynamic = "force-dynamic";
|
|
import { useTranslations } from "next-intl";
|
|
import { getTranslations } from "next-intl/server";
|
|
import Link from "next/link";
|
|
import { db } from "@/lib/db";
|
|
import { CourseCard } from "@/components/CourseCard";
|
|
import { auth } from "@/auth";
|
|
|
|
export default async function HomePage({
|
|
params,
|
|
}: {
|
|
params: Promise<{ locale: string }>;
|
|
}) {
|
|
const { locale } = await params;
|
|
const t = await getTranslations({ locale, namespace: "home" });
|
|
const nav = await getTranslations({ locale, namespace: "nav" });
|
|
const courseT = await getTranslations({ locale, namespace: "course" });
|
|
const session = await auth();
|
|
|
|
const courses = await db.course.findMany({
|
|
where: { published: true },
|
|
orderBy: { order: "asc" },
|
|
take: 6,
|
|
include: { _count: { select: { modules: true } } },
|
|
});
|
|
|
|
// Get enrolled course IDs for current user
|
|
const enrolledIds = new Set<string>();
|
|
if (session?.user) {
|
|
const userId = (session.user as any).id;
|
|
const enrollments = await db.enrollment.findMany({
|
|
where: { userId },
|
|
select: { courseId: true },
|
|
});
|
|
enrollments.forEach((e) => enrolledIds.add(e.courseId));
|
|
}
|
|
|
|
const categories = ["GOVERNANCE", "CYBER", "OWLCUB", "OTHER"];
|
|
|
|
return (
|
|
<div>
|
|
{/* Hero Section */}
|
|
<section
|
|
style={{
|
|
background:
|
|
"linear-gradient(135deg, #0f1117 0%, #1a1f2e 50%, #0f1117 100%)",
|
|
padding: "80px 24px",
|
|
textAlign: "center",
|
|
position: "relative",
|
|
overflow: "hidden",
|
|
}}
|
|
>
|
|
{/* Background decoration */}
|
|
<div
|
|
style={{
|
|
position: "absolute",
|
|
top: "50%",
|
|
left: "50%",
|
|
transform: "translate(-50%, -50%)",
|
|
width: 600,
|
|
height: 600,
|
|
background: "radial-gradient(circle, rgba(29,78,216,0.12) 0%, transparent 70%)",
|
|
pointerEvents: "none",
|
|
}}
|
|
/>
|
|
<div style={{ position: "relative", maxWidth: 700, margin: "0 auto" }}>
|
|
<div
|
|
style={{
|
|
display: "inline-flex",
|
|
alignItems: "center",
|
|
gap: 8,
|
|
background: "rgba(29,78,216,0.15)",
|
|
border: "1px solid rgba(29,78,216,0.3)",
|
|
borderRadius: 999,
|
|
padding: "6px 16px",
|
|
marginBottom: 24,
|
|
fontSize: 13,
|
|
color: "#60a5fa",
|
|
fontWeight: 600,
|
|
}}
|
|
>
|
|
🦉 OwlCub Academy
|
|
</div>
|
|
<h1
|
|
style={{
|
|
fontSize: "clamp(32px, 5vw, 52px)",
|
|
fontWeight: 800,
|
|
color: "#f1f5f9",
|
|
lineHeight: 1.2,
|
|
marginBottom: 20,
|
|
}}
|
|
>
|
|
{t("hero_title")}
|
|
</h1>
|
|
<p
|
|
style={{
|
|
fontSize: 18,
|
|
color: "#94a3b8",
|
|
marginBottom: 36,
|
|
lineHeight: 1.6,
|
|
}}
|
|
>
|
|
{t("hero_sub")}
|
|
</p>
|
|
<Link
|
|
href={`/${locale}/courses`}
|
|
style={{
|
|
display: "inline-flex",
|
|
alignItems: "center",
|
|
gap: 8,
|
|
background: "#1d4ed8",
|
|
color: "#fff",
|
|
padding: "14px 28px",
|
|
borderRadius: 10,
|
|
fontWeight: 700,
|
|
fontSize: 16,
|
|
transition: "all 0.15s",
|
|
textDecoration: "none",
|
|
}}
|
|
>
|
|
{t("cta")} →
|
|
</Link>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Category pills */}
|
|
<section
|
|
style={{
|
|
maxWidth: 1200,
|
|
margin: "0 auto",
|
|
padding: "40px 24px 0",
|
|
}}
|
|
>
|
|
<div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
|
|
{categories.map((cat) => {
|
|
const catLabel = t(`categories.${cat}`);
|
|
return (
|
|
<Link
|
|
key={cat}
|
|
href={`/${locale}/courses?category=${cat}`}
|
|
style={{
|
|
background: "rgba(255,255,255,0.05)",
|
|
border: "1px solid rgba(255,255,255,0.1)",
|
|
borderRadius: 8,
|
|
padding: "8px 18px",
|
|
fontSize: 13,
|
|
fontWeight: 600,
|
|
color: "#94a3b8",
|
|
transition: "all 0.15s",
|
|
textDecoration: "none",
|
|
}}
|
|
>
|
|
{catLabel}
|
|
</Link>
|
|
);
|
|
})}
|
|
</div>
|
|
</section>
|
|
|
|
{/* Course grid */}
|
|
<section
|
|
style={{
|
|
maxWidth: 1200,
|
|
margin: "0 auto",
|
|
padding: "32px 24px 64px",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "space-between",
|
|
alignItems: "center",
|
|
marginBottom: 24,
|
|
}}
|
|
>
|
|
<h2 style={{ fontSize: 22, fontWeight: 700, color: "#f1f5f9" }}>
|
|
Formations populaires
|
|
</h2>
|
|
<Link
|
|
href={`/${locale}/courses`}
|
|
style={{ fontSize: 13, color: "#60a5fa", fontWeight: 600 }}
|
|
>
|
|
Voir tout →
|
|
</Link>
|
|
</div>
|
|
|
|
{courses.length === 0 ? (
|
|
<div
|
|
style={{
|
|
textAlign: "center",
|
|
padding: "60px 24px",
|
|
color: "#94a3b8",
|
|
}}
|
|
>
|
|
<div style={{ fontSize: 48, marginBottom: 16 }}>📚</div>
|
|
<p>Aucune formation disponible pour le moment.</p>
|
|
</div>
|
|
) : (
|
|
<div
|
|
style={{
|
|
display: "grid",
|
|
gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))",
|
|
gap: 20,
|
|
}}
|
|
>
|
|
{courses.map((course) => (
|
|
<CourseCard
|
|
key={course.id}
|
|
locale={locale}
|
|
course={course}
|
|
isEnrolled={enrolledIds.has(course.id)}
|
|
t={{
|
|
enroll: courseT("enroll"),
|
|
enrolled: courseT("enrolled"),
|
|
continue: courseT("continue"),
|
|
start: courseT("start"),
|
|
}}
|
|
/>
|
|
))}
|
|
</div>
|
|
)}
|
|
</section>
|
|
|
|
{/* Stats section */}
|
|
<section
|
|
style={{
|
|
background: "#1a1f2e",
|
|
borderTop: "1px solid rgba(255,255,255,0.08)",
|
|
borderBottom: "1px solid rgba(255,255,255,0.08)",
|
|
padding: "48px 24px",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
maxWidth: 800,
|
|
margin: "0 auto",
|
|
display: "grid",
|
|
gridTemplateColumns: "repeat(3, 1fr)",
|
|
gap: 32,
|
|
textAlign: "center",
|
|
}}
|
|
>
|
|
{[
|
|
{ label: "Formations", value: "20+" },
|
|
{ label: "Apprenants", value: "500+" },
|
|
{ label: "Certificats délivrés", value: "1 000+" },
|
|
].map((stat) => (
|
|
<div key={stat.label}>
|
|
<div
|
|
style={{
|
|
fontSize: 36,
|
|
fontWeight: 800,
|
|
color: "#1d4ed8",
|
|
marginBottom: 4,
|
|
}}
|
|
>
|
|
{stat.value}
|
|
</div>
|
|
<div style={{ fontSize: 14, color: "#94a3b8" }}>{stat.label}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
</div>
|
|
);
|
|
}
|