owlcub-academy/src/app/[locale]/paths/page.tsx

160 lines
6.6 KiB
TypeScript

import { auth } from "@/auth";
import { db } from "@/lib/db";
import { setRequestLocale } from "next-intl/server";
import Link from "next/link";
import { EnrollPathButton } from "./EnrollPathButton";
export const dynamic = "force-dynamic";
function getLocaleText(obj: any, locale: string, field: string) {
if (locale === "en") return obj[`${field}En`] || obj[`${field}Fr`];
if (locale === "es") return obj[`${field}Es`] || obj[`${field}Fr`];
return obj[`${field}Fr`];
}
const levelColors: Record<string, string> = {
BEGINNER: "#4ade80",
INTERMEDIATE: "#fbbf24",
ADVANCED: "#f87171",
};
export default async function PathsPage({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
setRequestLocale(locale);
const session = await auth();
const userId = (session?.user as any)?.id as string | undefined;
const paths = await db.learningPath.findMany({
where: { published: true },
orderBy: { order: "asc" },
include: {
courses: {
include: {
course: {
include: { modules: { include: { lessons: { select: { id: true } } } } },
},
},
orderBy: { order: "asc" },
},
_count: { select: { enrollments: true } },
},
});
// Check which paths the user is enrolled in
const enrolledPathIds = userId
? new Set(
(await db.learningPathEnrollment.findMany({ where: { userId }, select: { learningPathId: true } })).map(
(e) => e.learningPathId
)
)
: new Set<string>();
return (
<div style={{ maxWidth: 1100, margin: "0 auto", padding: "40px 24px" }}>
<div style={{ marginBottom: 40 }}>
<h1 style={{ fontSize: 28, fontWeight: 800, color: "#f1f5f9", marginBottom: 8 }}>
Parcours de formation
</h1>
<p style={{ color: "#94a3b8", fontSize: 15 }}>
Des programmes complets pour maîtriser la GRC et l'application OwlCub.
</p>
</div>
{paths.length === 0 ? (
<div style={{ textAlign: "center", padding: "60px 24px", background: "#1a1f2e", borderRadius: 12, border: "1px solid rgba(255,255,255,0.08)" }}>
<p style={{ color: "#64748b", fontSize: 16 }}>Aucun parcours disponible pour l'instant.</p>
</div>
) : (
<div style={{ display: "flex", flexDirection: "column", gap: 24 }}>
{paths.map((path) => {
const title = getLocaleText(path, locale, "title");
const desc = getLocaleText(path, locale, "desc");
const totalLessons = path.courses.reduce((sum, lpc) => sum + lpc.course.modules.reduce((s, m) => s + m.lessons.length, 0), 0);
const isEnrolled = enrolledPathIds.has(path.id);
return (
<div
key={path.id}
className="card"
style={{
display: "grid",
gridTemplateColumns: "1fr auto",
gap: 24,
background: "linear-gradient(135deg, #1a1f2e, #1e2a4a)",
border: "1px solid rgba(29,78,216,0.25)",
}}
>
<div>
<div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 10 }}>
<h2 style={{ fontSize: 20, fontWeight: 700, color: "#f1f5f9" }}>{title}</h2>
{isEnrolled && (
<span style={{ fontSize: 11, fontWeight: 600, background: "rgba(34,197,94,0.15)", color: "#4ade80", border: "1px solid rgba(34,197,94,0.3)", borderRadius: 4, padding: "2px 8px" }}>
Inscrit
</span>
)}
</div>
<p style={{ color: "#94a3b8", fontSize: 14, marginBottom: 16, lineHeight: 1.6 }}>{desc}</p>
{/* Course list */}
<div style={{ display: "flex", flexDirection: "column", gap: 6, marginBottom: 16 }}>
{path.courses.map((lpc, i) => {
const courseTitle = getLocaleText(lpc.course, locale, "title");
const lessonCount = lpc.course.modules.reduce((s, m) => s + m.lessons.length, 0);
return (
<div key={lpc.id} style={{ display: "flex", alignItems: "center", gap: 10 }}>
<span style={{ width: 22, height: 22, background: "rgba(29,78,216,0.3)", color: "#60a5fa", borderRadius: 4, display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, fontWeight: 700, flexShrink: 0 }}>
{i + 1}
</span>
<span style={{ fontSize: 13, color: "#cbd5e1" }}>{courseTitle}</span>
<span style={{ fontSize: 11, color: "#475569" }}>· {lessonCount} leçon{lessonCount !== 1 ? "s" : ""}</span>
<span style={{ fontSize: 11, fontWeight: 600, color: levelColors[lpc.course.level] ?? "#94a3b8" }}>
{lpc.course.level}
</span>
</div>
);
})}
</div>
<div style={{ display: "flex", gap: 16, fontSize: 13, color: "#64748b" }}>
<span>📚 {path.courses.length} formation{path.courses.length !== 1 ? "s" : ""}</span>
<span>🎬 {totalLessons} leçons</span>
<span>👥 {path._count.enrollments} inscrits</span>
</div>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 10, alignItems: "flex-end", justifyContent: "center", minWidth: 160 }}>
{isEnrolled ? (
<Link
href={`/${locale}/courses/${path.courses[0]?.course.slug ?? ""}/learn`}
className="btn btn-primary"
style={{ width: "100%", justifyContent: "center", fontSize: 14 }}
>
Continuer
</Link>
) : (
<EnrollPathButton
pathId={path.id}
locale={locale}
isLoggedIn={!!session}
/>
)}
<Link
href={`/${locale}/paths/${path.slug}`}
style={{ fontSize: 13, color: "#60a5fa", textAlign: "center", width: "100%" }}
>
Voir le détail
</Link>
</div>
</div>
);
})}
</div>
)}
</div>
);
}