feat: add course catalog, enrollment, progress tracking, quizzes, and reviews
Backend changes: - Add Enrollment and LessonProgress models to track user progress - Add UserRole enum (USER, MODERATOR, ADMIN) - Add course verification and moderation fields - New CatalogModule: public course browsing, publishing, verification - New EnrollmentModule: enroll, progress tracking, quiz submission, reviews - Add quiz generation endpoint to LessonsController Frontend changes: - Redesign course viewer: proper course UI with lesson navigation, progress bar - Add beautiful typography styles for course content (prose-course) - Fix first-login bug with token exchange retry logic - New pages: /catalog (public courses), /catalog/[id] (course details), /learning (enrollments) - Add LessonQuiz component with scoring and results - Update sidebar navigation: add Catalog and My Learning links - Add publish/verify buttons in course editor - Integrate enrollment progress tracking with backend All courses now support: sequential progression, quiz tests, reviews, ratings, author verification badges, and full marketplace publishing workflow. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
84
apps/api/src/enrollment/enrollment.controller.ts
Normal file
84
apps/api/src/enrollment/enrollment.controller.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import {
|
||||
Controller,
|
||||
Post,
|
||||
Get,
|
||||
Param,
|
||||
Body,
|
||||
Query,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { EnrollmentService } from './enrollment.service';
|
||||
import { CurrentUser } from '../auth/decorators/current-user.decorator';
|
||||
import { User } from '@coursecraft/database';
|
||||
|
||||
@ApiTags('enrollment')
|
||||
@Controller('enrollment')
|
||||
@ApiBearerAuth()
|
||||
export class EnrollmentController {
|
||||
constructor(private enrollmentService: EnrollmentService) {}
|
||||
|
||||
@Post(':courseId/enroll')
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
@ApiOperation({ summary: 'Enroll in a course' })
|
||||
async enroll(@Param('courseId') courseId: string, @CurrentUser() user: User): Promise<any> {
|
||||
return this.enrollmentService.enroll(user.id, courseId);
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Get my enrolled courses' })
|
||||
async myEnrollments(@CurrentUser() user: User): Promise<any> {
|
||||
return this.enrollmentService.getUserEnrollments(user.id);
|
||||
}
|
||||
|
||||
@Get(':courseId/progress')
|
||||
@ApiOperation({ summary: 'Get my progress for a course' })
|
||||
async getProgress(@Param('courseId') courseId: string, @CurrentUser() user: User): Promise<any> {
|
||||
return this.enrollmentService.getProgress(user.id, courseId);
|
||||
}
|
||||
|
||||
@Post(':courseId/lessons/:lessonId/complete')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Mark a lesson as completed' })
|
||||
async completeLesson(
|
||||
@Param('courseId') courseId: string,
|
||||
@Param('lessonId') lessonId: string,
|
||||
@CurrentUser() user: User,
|
||||
): Promise<any> {
|
||||
return this.enrollmentService.completeLesson(user.id, courseId, lessonId);
|
||||
}
|
||||
|
||||
@Post(':courseId/lessons/:lessonId/quiz')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Submit quiz score' })
|
||||
async submitQuiz(
|
||||
@Param('courseId') courseId: string,
|
||||
@Param('lessonId') lessonId: string,
|
||||
@Body('score') score: number,
|
||||
@CurrentUser() user: User,
|
||||
): Promise<any> {
|
||||
return this.enrollmentService.saveQuizScore(user.id, courseId, lessonId, score);
|
||||
}
|
||||
|
||||
@Post(':courseId/review')
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
@ApiOperation({ summary: 'Leave a review' })
|
||||
async createReview(
|
||||
@Param('courseId') courseId: string,
|
||||
@Body() body: { rating: number; title?: string; content?: string },
|
||||
@CurrentUser() user: User,
|
||||
): Promise<any> {
|
||||
return this.enrollmentService.createReview(user.id, courseId, body.rating, body.title, body.content);
|
||||
}
|
||||
|
||||
@Get(':courseId/reviews')
|
||||
@ApiOperation({ summary: 'Get course reviews' })
|
||||
async getReviews(
|
||||
@Param('courseId') courseId: string,
|
||||
@Query('page') page?: number,
|
||||
@Query('limit') limit?: number,
|
||||
): Promise<any> {
|
||||
return this.enrollmentService.getCourseReviews(courseId, page, limit);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user