From e89a7e97414c449b2533f3382636c8578d284b44 Mon Sep 17 00:00:00 2001 From: jeromehardaway Date: Thu, 4 Dec 2025 15:28:46 -0500 Subject: [PATCH 1/9] feat: Complete LMS implementation with full e2e functionality This commit completes the Learning Management System with comprehensive features for students, instructors, and administrators. ## API Endpoints Added - Module Management (create, read, update, delete) - Lesson Management (create, read, update, delete) - Assignment Management (create, read, update, delete) ## Frontend Features - Student Dashboard: View enrollments and progress - Instructor Grading: Review and grade submissions - Admin Course Creation: UI for creating new courses - Real API Integration: Connected all pages to backend APIs ## Authentication & Security - Fixed hardcoded admin access to use proper RBAC - Role-based permissions throughout application - Dev login endpoint for local testing ## Documentation - LMS_GUIDE.md: Comprehensive user guide with all features - VERCEL_DEPLOYMENT.md: Step-by-step deployment instructions - README.md: Updated with LMS quick start ## Key Changes - /admin/courses.tsx: Connected to real API, proper RBAC - /admin/users.tsx: Fixed RBAC authentication - /admin/courses/create.tsx: New course creation UI - /dashboard.tsx: Real enrollment data with progress tracking - /instructor/grading.tsx: Complete grading interface - /courses/web-development.tsx: Real enrollment API - /assignments/submit/[assignmentId].tsx: Real submission API All features tested and working end-to-end. --- LMS_GUIDE.md | 400 ++++++++++++++++++ README.md | 41 ++ VERCEL_DEPLOYMENT.md | 254 +++++++++++ public/fallback-S8huqORtZv15wClwfMyrc.js | 1 + src/pages/admin/courses.tsx | 122 +++--- src/pages/admin/courses/create.tsx | 376 ++++++++++++++++ src/pages/admin/users.tsx | 8 +- src/pages/api/assignments/[assignmentId].ts | 180 ++++++++ src/pages/api/assignments/index.ts | 127 ++++++ src/pages/api/dev/init-user.ts | 57 +-- src/pages/api/lessons/[lessonId].ts | 188 ++++++++ src/pages/api/lessons/index.ts | 88 ++++ src/pages/api/modules/[moduleId].ts | 160 +++++++ src/pages/api/modules/index.ts | 66 +++ .../assignments/submit/[assignmentId].tsx | 68 ++- src/pages/courses/web-development.tsx | 79 +++- src/pages/dashboard.tsx | 201 ++++++--- src/pages/instructor/grading.tsx | 343 +++++++++++++++ 18 files changed, 2579 insertions(+), 180 deletions(-) create mode 100644 LMS_GUIDE.md create mode 100644 VERCEL_DEPLOYMENT.md create mode 100644 public/fallback-S8huqORtZv15wClwfMyrc.js create mode 100644 src/pages/admin/courses/create.tsx create mode 100644 src/pages/api/assignments/[assignmentId].ts create mode 100644 src/pages/api/assignments/index.ts create mode 100644 src/pages/api/lessons/[lessonId].ts create mode 100644 src/pages/api/lessons/index.ts create mode 100644 src/pages/api/modules/[moduleId].ts create mode 100644 src/pages/api/modules/index.ts create mode 100644 src/pages/instructor/grading.tsx diff --git a/LMS_GUIDE.md b/LMS_GUIDE.md new file mode 100644 index 000000000..ec720a93b --- /dev/null +++ b/LMS_GUIDE.md @@ -0,0 +1,400 @@ +# VetsWhoCode LMS - Complete Guide ๐ŸŽ“ + +## ๐Ÿš€ Quick Start (Local Development) + +### 1. Sign In +**URL:** `http://localhost:3000/login` + +**Two Options:** +- **Dev Login**: Click "Dev Login (Jerome Only)" - instant admin access (local only) +- **GitHub OAuth**: Click "Sign in with GitHub" - production-like authentication + +--- + +## ๐Ÿ“ Navigation Map + +### For Students ๐Ÿ‘จโ€๐ŸŽ“ + +| Page | URL | Description | +|------|-----|-------------| +| **Dashboard** | `/dashboard` | View your enrolled courses, progress stats, and next lessons | +| **All Courses** | `/courses` | Browse all available courses | +| **Web Dev Course** | `/courses/web-development` | View course details and enroll | +| **Course Detail** | `/courses/[courseId]` | View specific course modules and lessons | +| **Submit Assignment** | `/assignments/submit/[assignmentId]` | Submit your assignment with GitHub URL | + +### For Instructors ๐Ÿ‘จโ€๐Ÿซ + +| Page | URL | Description | +|------|-----|-------------| +| **Grading Dashboard** | `/instructor/grading` | Review and grade pending student submissions | + +### For Admins ๐Ÿ‘จโ€๐Ÿ’ผ + +| Page | URL | Description | +|------|-----|-------------| +| **Course Management** | `/admin/courses` | View, filter, and manage all courses | +| **Create Course** | `/admin/courses/create` | Create a new course with all details | +| **User Management** | `/admin/users` | View and manage all users | +| **Edit Course** | `/admin/courses/[courseId]` | Edit specific course details | + +--- + +## ๐ŸŽฏ User Roles & Permissions + +### STUDENT +- โœ… View published courses +- โœ… Enroll in courses +- โœ… Track progress +- โœ… Submit assignments +- โœ… View grades and feedback +- โœ… Access dashboard + +### INSTRUCTOR +- โœ… All student permissions +- โœ… Create and edit courses +- โœ… Create assignments +- โœ… Grade student submissions +- โœ… View pending submissions + +### MENTOR +- โœ… All student permissions +- โœ… Grade student submissions +- โœ… Provide feedback + +### ADMIN +- โœ… All permissions +- โœ… Delete courses +- โœ… Manage users +- โœ… Access all admin tools + +--- + +## ๐Ÿงช Test Accounts (Seeded Database) + +| Email | Role | Password | +|-------|------|----------| +| jerome@vetswhocode.io | ADMIN | (GitHub OAuth or Dev Login) | +| admin@vetswhocode.io | ADMIN | (GitHub OAuth) | +| instructor@vetswhocode.io | INSTRUCTOR | (GitHub OAuth) | +| student@vetswhocode.io | STUDENT | (GitHub OAuth) | + +--- + +## ๐Ÿ“š Sample Course Content + +### Web Development Fundamentals +**Status:** Published +**Difficulty:** BEGINNER +**Duration:** 120 hours +**Modules:** 5 + +#### Module 1: HTML Fundamentals +- Introduction to HTML +- Semantic HTML Elements +- Forms and Inputs +- HTML Best Practices + +#### Module 2: CSS Styling +- CSS Basics +- Flexbox Layout +- CSS Grid +- Responsive Design +- Advanced Selectors + +#### Module 3: JavaScript Fundamentals +- Variables and Data Types +- Functions and Scope +- DOM Manipulation +- Events and Event Handling +- ES6+ Features + +#### Module 4: React Basics +- Components and Props +- State Management +- React Hooks +- Event Handling +- Conditional Rendering + +#### Module 5: Node.js and APIs +- Node.js Fundamentals +- Express.js Basics +- RESTful APIs +- Database Integration +- Authentication + +**Assignments:** 4 total +- HTML Portfolio Project +- CSS Responsive Website +- JavaScript Interactive App +- React + Node.js Full Stack Project + +--- + +## ๐Ÿ”ง API Endpoints Reference + +### Course Management +- `GET /api/courses` - List all courses (with filters) +- `POST /api/courses` - Create new course (Admin/Instructor) +- `GET /api/courses/[courseId]` - Get course details +- `PUT /api/courses/[courseId]` - Update course (Admin/Instructor) +- `DELETE /api/courses/[courseId]` - Delete course (Admin only) + +### Module Management +- `POST /api/modules` - Create module (Admin/Instructor) +- `GET /api/modules/[moduleId]` - Get module details +- `PUT /api/modules/[moduleId]` - Update module (Admin/Instructor) +- `DELETE /api/modules/[moduleId]` - Delete module (Admin/Instructor) + +### Lesson Management +- `POST /api/lessons` - Create lesson (Admin/Instructor) +- `GET /api/lessons/[lessonId]` - Get lesson details +- `PUT /api/lessons/[lessonId]` - Update lesson (Admin/Instructor) +- `DELETE /api/lessons/[lessonId]` - Delete lesson (Admin/Instructor) + +### Assignment Management +- `GET /api/assignments?courseId=[id]` - Get assignments for course +- `POST /api/assignments` - Create assignment (Admin/Instructor) +- `GET /api/assignments/[assignmentId]` - Get assignment details +- `PUT /api/assignments/[assignmentId]` - Update assignment (Admin/Instructor) +- `DELETE /api/assignments/[assignmentId]` - Delete assignment (Admin/Instructor) + +### Enrollment +- `POST /api/enrollment/enroll` - Enroll in course +- `GET /api/enrollment` - Get user's enrollments +- `GET /api/enrollment/status?courseId=[id]` - Check enrollment status + +### Progress Tracking +- `GET /api/progress?enrollmentId=[id]` - Get progress for enrollment +- `POST /api/progress` - Update lesson progress + +### Submissions & Grading +- `POST /api/lms/submissions` - Submit assignment +- `GET /api/lms/submissions/pending` - Get pending submissions (Instructor/Mentor/Admin) +- `PUT /api/lms/submissions/[id]/grade` - Grade submission (Instructor/Mentor/Admin) + +### Certificates +- `POST /api/certificates/generate` - Generate certificate +- `GET /api/certificates/[certificateId]` - View certificate +- `GET /api/certificates/verify?certificateId=[id]` - Verify certificate + +--- + +## ๐ŸŽฌ Common Workflows + +### Student: Enroll in Course and Complete Lesson +1. Browse courses at `/courses` +2. Click on "Web Development" course +3. Click "Enroll Now" +4. Go to `/dashboard` to see your enrollment +5. Click "Continue Learning" +6. Complete lessons and mark progress + +### Student: Submit Assignment +1. Navigate to assignment page +2. Enter GitHub repository URL +3. (Optional) Add live demo URL +4. Add notes about your submission +5. Click "Submit Assignment" +6. Wait for instructor feedback + +### Instructor: Grade Submission +1. Go to `/instructor/grading` +2. Review student submission (GitHub URL, live demo, notes) +3. Enter score (out of total points) +4. Provide detailed feedback +5. Click "Submit Grade" + +### Admin: Create New Course +1. Go to `/admin/courses` +2. Click "New Course" +3. Fill in course details: + - Title + - Description + - Category + - Difficulty level + - Estimated hours + - Prerequisites + - Tags +4. Toggle "Publish" if ready +5. Click "Create Course" +6. Add modules and lessons using API or future UI + +--- + +## ๐Ÿ“Š Dashboard Features + +### Student Dashboard (`/dashboard`) + +**Quick Stats:** +- Total courses enrolled +- Courses completed +- Total lessons completed +- Average progress percentage + +**Current Courses Section:** +- Course title and description +- Progress bar with percentage +- "Continue Learning" button +- Enrollment date + +**Sidebar:** +- Upcoming assignments with due dates +- Recent activity timeline +- Quick links (Jobs, Profile, Courses, Support) + +--- + +## ๐Ÿ”’ Authentication & Authorization + +### Local Development +- Use "Dev Login" button at `/login` +- Bypasses GitHub OAuth +- Instantly logs in as Jerome (Admin) + +### Production (Vercel) +- Uses GitHub OAuth +- Requires valid GitHub account +- Role assigned from database based on email +- Jerome's GitHub account (`jeromehardaway`) gets admin access + +--- + +## ๐ŸŒ Deployment to Vercel + +### Required Environment Variables + +Add these to your Vercel project settings: + +```bash +# Database +DATABASE_URL=your_neon_postgresql_url +DIRECT_URL=your_neon_postgresql_url + +# NextAuth +NEXTAUTH_SECRET=generate_random_secret_key +NEXTAUTH_URL=https://your-domain.vercel.app + +# GitHub OAuth (Required for Production) +GITHUB_CLIENT_ID=your_github_oauth_client_id +GITHUB_CLIENT_SECRET=your_github_oauth_client_secret + +# Optional +GITHUB_ORG=Vets-Who-Code +``` + +### Setting Up GitHub OAuth + +1. **Create GitHub OAuth App:** + - Go to: https://github.com/settings/developers + - Click "New OAuth App" + - **Application name:** VetsWhoCode LMS + - **Homepage URL:** `https://your-domain.vercel.app` + - **Authorization callback URL:** `https://your-domain.vercel.app/api/auth/callback/github` + - Click "Register application" + +2. **Get Credentials:** + - Copy the **Client ID** + - Generate a new **Client Secret** + - Add both to Vercel environment variables + +3. **How Sign In Works on Vercel:** + - User goes to `/login` + - Clicks "Sign in with GitHub" + - Redirected to GitHub to authorize + - Returns to your app + - Session created with role from database + +### Assign Admin Role for Production + +After deploying, assign yourself admin role: + +```bash +# Connect to your production database +# Using Prisma Studio or direct SQL + +UPDATE "User" +SET role = 'ADMIN' +WHERE email = 'jerome@vetswhocode.io'; +``` + +Or use the Neon console SQL editor. + +--- + +## ๐Ÿ› Troubleshooting + +### "Access Denied" on Admin Pages +- Check your user role in database +- Ensure you're signed in with correct account +- Verify RBAC is working (check browser console for errors) + +### "Failed to fetch courses" +- Check database connection +- Verify Prisma client is generated +- Check API endpoint logs + +### "Cannot enroll in course" +- Ensure course is published (`isPublished: true`) +- Check if already enrolled +- Verify authentication + +### GitHub OAuth Not Working +- Verify callback URL matches exactly +- Check environment variables are set +- Ensure GitHub OAuth app is active + +--- + +## ๐Ÿ“ Database Schema Overview + +### Core Tables +- **User** - User accounts with roles +- **Course** - Course information +- **Module** - Course modules +- **Lesson** - Individual lessons +- **Assignment** - Course assignments +- **Enrollment** - User course enrollments +- **Progress** - Lesson completion tracking +- **Submission** - Assignment submissions +- **Certificate** - Course completion certificates +- **Cohort** - Student cohorts + +### Relationships +- Course โ†’ Modules โ†’ Lessons +- Course โ†’ Assignments +- User โ†’ Enrollments โ†’ Course +- User โ†’ Progress โ†’ Lesson +- User โ†’ Submissions โ†’ Assignment + +--- + +## ๐ŸŽ“ Next Steps + +### Immediate Tasks +1. Sign in and explore the dashboard +2. Test course enrollment flow +3. Submit a test assignment +4. Grade a submission as instructor +5. Create a new course as admin + +### Future Enhancements +- File upload for assignments +- Live video integration +- Discussion forums +- Email notifications +- Certificate PDF generation +- Advanced analytics +- Mobile responsive improvements + +--- + +## ๐Ÿ“ž Support + +For issues or questions: +- GitHub Issues: [Create an issue](https://github.com/Vets-Who-Code/vets-who-code-app/issues) +- Email: jerome@vetswhocode.io + +--- + +**Built with โค๏ธ for #VetsWhoCode** diff --git a/README.md b/README.md index 584acbb3c..61847dd70 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,47 @@ $ npm run dev Navigate to `http://localhost:3000/` to see the app in action. +## LMS (Learning Management System) ๐ŸŽ“ + +This app includes a complete Learning Management System for veterans to learn coding skills! + +### Quick Setup + +```sh +# Generate Prisma client and setup database +$ npm run dev:setup + +# Seed database with test data +$ npx prisma db seed + +# Start development server +$ npm run dev +``` + +### Sign In + +**Local Development:** + +- Go to `http://localhost:3000/login` +- Click **"Dev Login (Jerome Only)"** for instant access + +**Production (Vercel):** + +- Sign in with your GitHub account +- Admin access automatically granted to authorized users + +### ๐Ÿ“š Complete Guide + +For detailed information about the LMS features, API endpoints, and workflows, see **[LMS_GUIDE.md](LMS_GUIDE.md)** + +**Quick Links:** + +- Student Dashboard: `/dashboard` +- Browse Courses: `/courses` +- Admin Panel: `/admin/courses` +- Create Course: `/admin/courses/create` +- Instructor Grading: `/instructor/grading` + ## Development using Dev Container (Optional) ๐Ÿณ We support development containers for an easier setup experience. diff --git a/VERCEL_DEPLOYMENT.md b/VERCEL_DEPLOYMENT.md new file mode 100644 index 000000000..1c262f465 --- /dev/null +++ b/VERCEL_DEPLOYMENT.md @@ -0,0 +1,254 @@ +# Deploying LMS to Vercel ๐Ÿš€ + +## Prerequisites + +Before deploying, you need: +1. A Vercel account +2. GitHub OAuth App credentials +3. A Neon (or other PostgreSQL) database + +--- + +## Step 1: Create GitHub OAuth App + +### 1.1 Create the OAuth App + +1. Go to: https://github.com/settings/developers +2. Click **"New OAuth App"** +3. Fill in the details: + - **Application name:** VetsWhoCode LMS + - **Homepage URL:** `https://your-app-name.vercel.app` (or your custom domain) + - **Authorization callback URL:** `https://your-app-name.vercel.app/api/auth/callback/github` +4. Click **"Register application"** + +### 1.2 Get Your Credentials + +1. Copy the **Client ID** +2. Click **"Generate a new client secret"** +3. Copy the **Client Secret** (you won't be able to see it again!) +4. Save both values - you'll need them for Vercel + +--- + +## Step 2: Deploy to Vercel + +### 2.1 Connect Repository + +1. Go to [Vercel Dashboard](https://vercel.com/dashboard) +2. Click **"Add New Project"** +3. Import your GitHub repository +4. Click **"Import"** + +### 2.2 Configure Environment Variables + +Before deploying, add these environment variables in Vercel: + +**Required Variables:** + +```bash +# Database +DATABASE_URL=postgresql://user:password@host/database?sslmode=require +DIRECT_URL=postgresql://user:password@host/database?sslmode=require + +# NextAuth +NEXTAUTH_SECRET=your-random-secret-key-generate-with-openssl +NEXTAUTH_URL=https://your-app-name.vercel.app + +# GitHub OAuth (from Step 1) +GITHUB_CLIENT_ID=your_github_client_id_from_step_1 +GITHUB_CLIENT_SECRET=your_github_client_secret_from_step_1 + +# GitHub Organization (optional) +GITHUB_ORG=Vets-Who-Code +``` + +**How to generate NEXTAUTH_SECRET:** +```bash +openssl rand -base64 32 +``` + +### 2.3 Deploy + +1. Click **"Deploy"** +2. Wait for the build to complete +3. Your app is now live! ๐ŸŽ‰ + +--- + +## Step 3: Setup Database + +After deploying, you need to set up your production database: + +### 3.1 Push Schema to Production Database + +From your local machine: + +```bash +# Make sure DATABASE_URL points to production in your .env +npx prisma db push +``` + +Or use Vercel CLI: + +```bash +vercel env pull .env.production.local +npx prisma db push +``` + +### 3.2 Seed Production Database (Optional) + +```bash +npx prisma db seed +``` + +This creates test users and sample courses. + +--- + +## Step 4: Assign Admin Role + +After deployment, assign yourself admin access: + +### Option 1: Using Prisma Studio Locally + +```bash +# Connect to production database +DATABASE_URL="your-production-db-url" npx prisma studio +``` + +Then: +1. Navigate to the `User` table +2. Find `jerome@vetswhocode.io` +3. Change `role` to `ADMIN` + +### Option 2: Using Neon Console + +1. Go to your Neon dashboard +2. Open SQL Editor +3. Run this query: + +```sql +UPDATE "User" +SET role = 'ADMIN' +WHERE email = 'jerome@vetswhocode.io'; +``` + +### Option 3: Sign In First, Then Update + +1. Sign in to your deployed app with GitHub +2. This creates your user account +3. Then use Option 1 or 2 to update your role to ADMIN + +--- + +## Step 5: Test Sign In + +### How Sign In Works on Vercel + +1. Go to: `https://your-app-name.vercel.app/login` +2. Click **"Sign in with GitHub"** +3. Authorize the app +4. You'll be redirected back to your app +5. Your session is created with the role from the database + +**Important:** The "Dev Login" button **won't work** on Vercel - it's local development only! + +--- + +## Step 6: Verify Everything Works + +Test these pages after deploying: + +- [ ] `/login` - Sign in with GitHub +- [ ] `/dashboard` - See your dashboard +- [ ] `/admin/courses` - Access admin panel (requires ADMIN role) +- [ ] `/courses` - Browse courses +- [ ] `/instructor/grading` - Grade submissions (requires INSTRUCTOR/MENTOR/ADMIN role) + +--- + +## Common Issues & Solutions + +### Issue: "Access Denied" on Admin Pages + +**Solution:** +- Check your role in the database +- Make sure you're signed in with the correct GitHub account +- Verify the email in the database matches your GitHub email + +### Issue: GitHub OAuth Redirect Error + +**Solution:** +- Verify callback URL in GitHub OAuth app matches exactly: `https://your-domain.vercel.app/api/auth/callback/github` +- Check `NEXTAUTH_URL` environment variable in Vercel +- Ensure `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET` are correct + +### Issue: Database Connection Error + +**Solution:** +- Verify `DATABASE_URL` is correct +- Check if your database allows connections from Vercel IPs +- For Neon: ensure connection pooling is enabled + +### Issue: "Cannot read properties of undefined (reading 'role')" + +**Solution:** +- User might not exist in database yet +- Sign in once to create the user +- Then update the role to ADMIN + +--- + +## Environment Variables Checklist + +Before deploying, make sure you have all these set in Vercel: + +- [ ] `DATABASE_URL` +- [ ] `DIRECT_URL` +- [ ] `NEXTAUTH_SECRET` +- [ ] `NEXTAUTH_URL` +- [ ] `GITHUB_CLIENT_ID` +- [ ] `GITHUB_CLIENT_SECRET` +- [ ] `GITHUB_ORG` (optional) + +--- + +## Security Best Practices + +1. **Never commit secrets** to your repository +2. **Rotate secrets regularly** (especially `NEXTAUTH_SECRET`) +3. **Use different OAuth apps** for production and staging +4. **Restrict GitHub Organization** access if needed +5. **Monitor failed login attempts** in your logs + +--- + +## After Deployment + +1. **Update GitHub OAuth App** callback URL if your domain changes +2. **Regenerate Prisma Client** if you change the schema +3. **Run migrations** carefully in production +4. **Backup your database** regularly +5. **Monitor Vercel logs** for errors + +--- + +## Production URLs + +After deployment, share these with your team: + +- **Login:** `https://your-app-name.vercel.app/login` +- **Dashboard:** `https://your-app-name.vercel.app/dashboard` +- **Courses:** `https://your-app-name.vercel.app/courses` +- **Admin:** `https://your-app-name.vercel.app/admin/courses` + +--- + +## Need Help? + +- Check Vercel logs: `vercel logs` +- View deployment details in Vercel dashboard +- Check database logs in Neon console +- Review [LMS_GUIDE.md](LMS_GUIDE.md) for feature documentation + +**Built with โค๏ธ for #VetsWhoCode** diff --git a/public/fallback-S8huqORtZv15wClwfMyrc.js b/public/fallback-S8huqORtZv15wClwfMyrc.js new file mode 100644 index 000000000..541a72639 --- /dev/null +++ b/public/fallback-S8huqORtZv15wClwfMyrc.js @@ -0,0 +1 @@ +(()=>{"use strict";self.fallback=async e=>"document"===e.destination?caches.match("/_offline",{ignoreSearch:!0}):Response.error()})(); \ No newline at end of file diff --git a/src/pages/admin/courses.tsx b/src/pages/admin/courses.tsx index 533bd9a63..a773e4690 100644 --- a/src/pages/admin/courses.tsx +++ b/src/pages/admin/courses.tsx @@ -5,6 +5,7 @@ import Layout01 from "@layout/layout-01"; import type { GetStaticProps, NextPage } from "next"; import SEO from "@components/seo/page-seo"; import Breadcrumb from "@components/breadcrumb"; +import type { Role } from "@/lib/rbac"; type Course = { id: string; @@ -33,11 +34,10 @@ type PageWithLayout = NextPage & { Layout?: typeof Layout01; }; -const ADMIN_GITHUB_USERNAME = "jeromehardaway"; - const AdminCoursesPage: PageWithLayout = () => { const { data: session, status } = useSession(); const [courses, setCourses] = useState([]); + const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(""); const [statusFilter, setStatusFilter] = useState<"all" | "published" | "draft" | "archived">( "all" @@ -47,70 +47,51 @@ const AdminCoursesPage: PageWithLayout = () => { >("all"); useEffect(() => { - // TODO: Fetch real course data from API - // Mock data for demonstration - const mockCourses: Course[] = [ - { - id: "1", - title: "Introduction to Web Development", - description: "Learn the basics of HTML, CSS, and JavaScript", - instructor: "Jerome Hardaway", - duration: "8 weeks", - level: "Beginner", - enrollments: 47, - status: "published", - createdAt: "2025-07-01", - updatedAt: "2025-08-15", - modules: 4, - lessons: 24, - }, - { - id: "2", - title: "JavaScript Fundamentals", - description: "Deep dive into JavaScript programming concepts", - instructor: "Alex Thompson", - duration: "6 weeks", - level: "Intermediate", - enrollments: 32, - status: "published", - createdAt: "2025-07-15", - updatedAt: "2025-08-10", - modules: 3, - lessons: 18, - }, - { - id: "3", - title: "React Development Bootcamp", - description: "Build modern web applications with React", - instructor: "Sarah Chen", - duration: "12 weeks", - level: "Advanced", - enrollments: 23, - status: "draft", - createdAt: "2025-08-01", - updatedAt: "2025-08-28", - modules: 6, - lessons: 36, - }, - { - id: "4", - title: "Python for Veterans", - description: "Programming fundamentals with Python", - instructor: "Mike Rodriguez", - duration: "10 weeks", - level: "Beginner", - enrollments: 15, - status: "published", - createdAt: "2025-06-15", - updatedAt: "2025-08-20", - modules: 5, - lessons: 30, - }, - ]; - setCourses(mockCourses); - }, []); + const fetchCourses = async () => { + try { + setLoading(true); + // Fetch all courses (no limit for admin view) + const response = await fetch("/api/courses?limit=100"); + const data = await response.json(); + + if (response.ok && data.courses) { + // Map API data to Course type + const mappedCourses: Course[] = data.courses.map((course: any) => ({ + id: course.id, + title: course.title, + description: course.description, + instructor: "N/A", // TODO: Add instructor field to course schema + duration: course.estimatedHours + ? `${course.estimatedHours} hours` + : "N/A", + level: + course.difficulty === "BEGINNER" + ? "Beginner" + : course.difficulty === "INTERMEDIATE" + ? "Intermediate" + : "Advanced", + enrollments: course._count?.enrollments || 0, + status: course.isPublished ? "published" : "draft", + createdAt: new Date(course.createdAt).toISOString().split("T")[0], + updatedAt: new Date(course.updatedAt).toISOString().split("T")[0], + modules: course._count?.modules || 0, + lessons: course._count?.lessons || 0, + })); + setCourses(mappedCourses); + } + } catch (error) { + console.error("Error fetching courses:", error); + } finally { + setLoading(false); + } + }; - if (status === "loading") { + if (status !== "loading") { + fetchCourses(); + } + }, [status]); + + if (status === "loading" || loading) { return (
@@ -121,8 +102,9 @@ const AdminCoursesPage: PageWithLayout = () => { ); } - // Check admin access - if (!session || session.user?.email !== `${ADMIN_GITHUB_USERNAME}@users.noreply.github.com`) { + // Check admin access using RBAC + const userRole = (session?.user as any)?.role as Role | undefined; + if (!session || userRole !== 'ADMIN') { return (
@@ -201,13 +183,13 @@ const AdminCoursesPage: PageWithLayout = () => {

Create and manage learning content

- + & { + Layout?: typeof Layout01; +}; + +const CreateCoursePage: PageWithLayout = () => { + const router = useRouter(); + const { data: session, status } = useSession(); + const [submitting, setSubmitting] = useState(false); + const [error, setError] = useState(null); + + // Form state + const [title, setTitle] = useState(""); + const [description, setDescription] = useState(""); + const [category, setCategory] = useState(""); + const [difficulty, setDifficulty] = useState<"BEGINNER" | "INTERMEDIATE" | "ADVANCED">( + "BEGINNER" + ); + const [estimatedHours, setEstimatedHours] = useState(0); + const [prerequisites, setPrerequisites] = useState(""); + const [tags, setTags] = useState(""); + const [isPublished, setIsPublished] = useState(false); + const [imageUrl, setImageUrl] = useState(""); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setSubmitting(true); + setError(null); + + try { + const response = await fetch("/api/courses", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + title, + description, + category, + difficulty, + estimatedHours, + prerequisites: prerequisites.split("\n").filter((p) => p.trim()), + tags: tags.split(",").map((t) => t.trim()).filter((t) => t), + isPublished, + imageUrl: imageUrl || undefined, + }), + }); + + const data = await response.json(); + + if (response.ok) { + router.push(`/admin/courses/${data.course.id}`); + } else { + setError(data.error || "Failed to create course"); + } + } catch (err) { + console.error("Error creating course:", err); + setError("An unexpected error occurred"); + } finally { + setSubmitting(false); + } + }; + + if (status === "loading") { + return ( +
+
+
+

Loading...

+
+
+ ); + } + + const userRole = (session?.user as any)?.role as Role | undefined; + if (!session || !["ADMIN", "INSTRUCTOR"].includes(userRole || "")) { + return ( +
+
+

+ Access Denied +

+

+ This page is only accessible to admins and instructors. +

+ + โ† Back to Courses + +
+
+ ); + } + + return ( + <> + + + +
+
+
+

+ Create New Course +

+

+ Set up a new course for students to enroll in +

+
+ + + Back to Courses + +
+ + {error && ( +
+ + {error} +
+ )} + +
+
+
+ {/* Title */} +
+ + setTitle(e.target.value)} + placeholder="e.g., Full Stack Web Development" + className="tw-block tw-w-full tw-rounded-md tw-border tw-border-gray-300 tw-px-3 tw-py-2 focus:tw-border-primary focus:tw-outline-none focus:tw-ring-1 focus:tw-ring-primary" + /> +
+ + {/* Description */} +
+ +