diff --git a/public/fallback-cuEL-wxAt8lRMBzo05Qaf.js b/public/fallback-8u_CZnDJoQGp2wQUAuYFH.js similarity index 100% rename from public/fallback-cuEL-wxAt8lRMBzo05Qaf.js rename to public/fallback-8u_CZnDJoQGp2wQUAuYFH.js diff --git a/src/pages/api/enrollment/enroll.ts b/src/pages/api/enrollment/enroll.ts index 4e08c0c9b..03ea8c95c 100644 --- a/src/pages/api/enrollment/enroll.ts +++ b/src/pages/api/enrollment/enroll.ts @@ -3,19 +3,51 @@ import { requireAuth, AuthenticatedRequest } from '@/lib/rbac'; import prisma from '@/lib/prisma'; /** - * POST /api/enrollment/enroll + * GET /api/enrollment/enroll + * Fetch user's enrollments * + * POST /api/enrollment/enroll * Enroll user in a course * Body: { courseId: string } */ export default requireAuth(async (req: AuthenticatedRequest, res: NextApiResponse) => { + const userId = req.user!.id; + + // GET - Fetch user's enrollments + if (req.method === 'GET') { + try { + const enrollments = await prisma.enrollment.findMany({ + where: { userId }, + include: { + course: { + select: { + id: true, + title: true, + description: true, + imageUrl: true, + difficulty: true, + category: true, + }, + }, + }, + orderBy: { + enrolledAt: 'desc', + }, + }); + + return res.status(200).json({ enrollments }); + } catch (error) { + console.error('Error fetching enrollments:', error); + return res.status(500).json({ error: 'Failed to fetch enrollments' }); + } + } + if (req.method !== 'POST') { return res.status(405).json({ error: 'Method not allowed' }); } try { const { courseId } = req.body; - const userId = req.user!.id; // Validation if (!courseId) { diff --git a/src/pages/courses/index.tsx b/src/pages/courses/index.tsx index 521ad3658..ce3b50a76 100644 --- a/src/pages/courses/index.tsx +++ b/src/pages/courses/index.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import Link from "next/link"; import Layout01 from "@layout/layout-01"; import type { GetServerSideProps, NextPage } from "next"; @@ -7,6 +7,13 @@ import { options } from "@/pages/api/auth/options"; import SEO from "@components/seo/page-seo"; import Breadcrumb from "@components/breadcrumb"; +type Enrollment = { + id: string; + courseId: string; + status: string; + progress: number; +}; + type PageProps = { user: { id: string; @@ -27,6 +34,49 @@ type PageWithLayout = NextPage & { }; const CoursesIndex: PageWithLayout = ({ user }) => { + const [enrollments, setEnrollments] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + fetchEnrollments(); + }, []); + + const fetchEnrollments = async () => { + try { + setLoading(true); + const response = await fetch("/api/enrollment/enroll"); + const data = await response.json(); + + if (response.ok) { + setEnrollments(data.enrollments); + } + } catch (error) { + console.error("Error fetching enrollments:", error); + } finally { + setLoading(false); + } + }; + + // Helper function to check if user is enrolled in a vertical + // Map vertical slugs to course titles for enrollment checking + const verticalCourseMap: Record = { + "software-engineering": ["Software Engineering", "Full-Stack Development", "Web Development"], + "data-engineering": ["Data Engineering", "Data Science"], + "ai-engineering": ["AI Engineering", "Machine Learning", "Artificial Intelligence"], + "devops": ["DevOps", "Cloud Engineering"], + "web-development": ["Web Development", "Frontend Development"], + }; + + const isEnrolledInVertical = (verticalSlug: string): boolean => { + const matchingTitles = verticalCourseMap[verticalSlug] || []; + return enrollments.some( + (enrollment) => + enrollment.status === "ACTIVE" && + matchingTitles.some((title) => + enrollment.courseId.toLowerCase().includes(title.toLowerCase()) + ) + ); + }; return ( <> @@ -100,13 +150,21 @@ const CoursesIndex: PageWithLayout = ({ user }) => { {/* Software Engineering Vertical */}
-
-
- +
+
+
+ +
+

+ Software Engineering +

-

- Software Engineering -

+ {!loading && isEnrolledInVertical("software-engineering") && ( + + + Enrolled + + )}

Master full-stack development, system design, and software @@ -143,7 +201,11 @@ const CoursesIndex: PageWithLayout = ({ user }) => { href="/courses/software-engineering" className="tw-group tw-flex tw-w-full tw-items-center tw-justify-center tw-rounded-lg tw-bg-primary tw-px-6 tw-py-4 tw-font-semibold tw-text-white tw-transition-all tw-duration-200 hover:tw-bg-primary/90 hover:tw-shadow-lg" > - View Vertical + + {!loading && isEnrolledInVertical("software-engineering") + ? "Continue Learning" + : "View Vertical"} +

@@ -152,13 +214,21 @@ const CoursesIndex: PageWithLayout = ({ user }) => { {/* Data Engineering Vertical */}
-
-
- +
+
+
+ +
+

+ Data Engineering +

-

- Data Engineering -

+ {!loading && isEnrolledInVertical("data-engineering") && ( + + + Enrolled + + )}

Build data pipelines, work with big data technologies, and create @@ -195,7 +265,11 @@ const CoursesIndex: PageWithLayout = ({ user }) => { href="/courses/data-engineering" className="tw-group tw-flex tw-w-full tw-items-center tw-justify-center tw-rounded-lg tw-bg-secondary tw-px-6 tw-py-4 tw-font-semibold tw-text-white tw-transition-all tw-duration-200 hover:tw-bg-secondary/90 hover:tw-shadow-lg" > - View Vertical + + {!loading && isEnrolledInVertical("data-engineering") + ? "Continue Learning" + : "View Vertical"} +

@@ -204,13 +278,21 @@ const CoursesIndex: PageWithLayout = ({ user }) => { {/* AI Engineering Vertical */}
-
-
- +
+
+
+ +
+

+ AI Engineering +

-

- AI Engineering -

+ {!loading && isEnrolledInVertical("ai-engineering") && ( + + + Enrolled + + )}

Develop AI/ML models, work with neural networks, and build @@ -247,7 +329,11 @@ const CoursesIndex: PageWithLayout = ({ user }) => { href="/courses/ai-engineering" className="tw-group tw-flex tw-w-full tw-items-center tw-justify-center tw-rounded-lg tw-bg-success tw-px-6 tw-py-4 tw-font-semibold tw-text-white tw-transition-all tw-duration-200 hover:tw-bg-success/90 hover:tw-shadow-lg" > - View Vertical + + {!loading && isEnrolledInVertical("ai-engineering") + ? "Continue Learning" + : "View Vertical"} +

diff --git a/src/pages/courses/software-engineering.tsx b/src/pages/courses/software-engineering.tsx index 7e0242645..cbc4c04b5 100644 --- a/src/pages/courses/software-engineering.tsx +++ b/src/pages/courses/software-engineering.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import Link from "next/link"; import Layout01 from "@layout/layout-01"; import type { GetServerSideProps, NextPage } from "next"; @@ -7,6 +7,13 @@ import { options } from "@/pages/api/auth/options"; import SEO from "@components/seo/page-seo"; import Breadcrumb from "@components/breadcrumb"; +type Enrollment = { + id: string; + courseId: string; + status: string; + progress: number; +}; + type PageProps = { user: { id: string; @@ -102,6 +109,47 @@ const modules = [ const SoftwareEngineeringCourse: PageWithLayout = ({ user: _user }) => { const [selectedModule, setSelectedModule] = useState(null); + const [enrollments, setEnrollments] = useState([]); + const [loading, setLoading] = useState(true); + const [enrollmentError, setEnrollmentError] = useState(null); + + useEffect(() => { + fetchEnrollments(); + }, []); + + const fetchEnrollments = async () => { + try { + setLoading(true); + const response = await fetch("/api/enrollment/enroll"); + const data = await response.json(); + + if (response.ok) { + setEnrollments(data.enrollments); + } + } catch (error) { + console.error("Error fetching enrollments:", error); + } finally { + setLoading(false); + } + }; + + // Check if enrolled in Software Engineering vertical + const isEnrolled = (): boolean => { + const matchingTitles = ["Software Engineering", "Full-Stack Development", "Web Development"]; + return enrollments.some( + (enrollment) => + enrollment.status === "ACTIVE" && + matchingTitles.some((title) => + enrollment.courseId.toLowerCase().includes(title.toLowerCase()) + ) + ); + }; + + const handleEnroll = async () => { + // For now, this is a placeholder since we don't have a courseId + // In a real implementation, you'd need to map the vertical to an actual course + setEnrollmentError("Enrollment is not yet configured for this vertical. Please contact an administrator."); + }; return ( <> @@ -134,6 +182,36 @@ const SoftwareEngineeringCourse: PageWithLayout = ({ user: _user }) => {

+ {/* Enrollment Status/CTA */} + {!loading && ( +
+ {isEnrolled() ? ( +
+ + + You're enrolled in this vertical + +
+ ) : ( +
+ + {enrollmentError && ( +

+ {enrollmentError} +

+ )} +
+ )} +
+ )} + {/* Course Stats */}