feat: add collections management and study coach features
Test / backend (push) Failing after 13s
Test / frontend (push) Successful in 25s

- Implemented collection repository with CRUD operations for user collections.
- Created routes for managing collections, including listing, creating, updating, and deleting collections.
- Added sharing functionality for exams, allowing users to share and clone exams.
- Developed a study coach service that analyzes exam results and provides study tips based on weak areas.
- Introduced frontend components for managing collections, sharing exams, and displaying study coach insights.
- Enhanced user experience with loading states and error handling in shared components.
This commit is contained in:
LaurensBartelds committed 2026-05-02 16:55:08 +02:00
1 parent 7755e77039
commit 1ec1633dd9
26 files changed
+2557 -127

No files matched your search

+45
View File
@@ -0,0 +1,45 @@
import { Router } from 'express'
import { asyncHandler } from '../utils/asyncHandler.js'
import { AppError } from '../middleware/error.js'
import { requireAuth } from '../middleware/auth.js'
import * as examRepo from '../repositories/examRepo.js'
import type { Request } from 'express'
const router = Router()
// GET /api/share/:token — public, no auth required
router.get(
'/:token',
asyncHandler(async (req: Request, res) => {
const token = String(req.params.token)
const exam = examRepo.getExamByShareToken(token)
if (!exam) {
throw new AppError(404, 'Shared exam not found')
}
const parsed = JSON.parse(exam.exam_json)
res.json({
title: exam.title,
subtitle: exam.subtitle,
questionCount: JSON.parse(exam.exam_json).questions?.length ?? 0,
exam: parsed,
shareMode: exam.share_mode ?? 'clone',
})
})
)
// POST /api/share/:token/clone — requires auth
router.post(
'/:token/clone',
requireAuth,
asyncHandler(async (req: Request, res) => {
const token = String(req.params.token)
const source = examRepo.getExamByShareToken(token)
if (!source) {
throw new AppError(404, 'Shared exam not found')
}
const { id } = examRepo.cloneExam(req.user!.userId, source, token)
res.status(201).json({ id, title: source.title + ' (copy)' })
})
)
export default router