160 lines
5.3 KiB
JavaScript
160 lines
5.3 KiB
JavaScript
import { register } from '@/services/mock/registry'
|
|
import { endpoints } from '@/services/api/endpoints'
|
|
import { adminCourses } from '@/services/mock/fixtures/admin-courses'
|
|
import { adminSessions } from '@/services/mock/fixtures/admin-sessions'
|
|
import { adminExams, examParticipants } from '@/services/mock/fixtures/admin-exams'
|
|
import {
|
|
filterDateRange,
|
|
filterItems,
|
|
findOrThrow,
|
|
isoNow,
|
|
makeId,
|
|
paginate,
|
|
removeById,
|
|
updateById,
|
|
} from '@/services/mock/helpers'
|
|
|
|
const resolveCourseFromSession = (session) => {
|
|
const courseId = session?.course?.id ?? session?.courseId
|
|
if (courseId == null) return null
|
|
return adminCourses.find((c) => c.id === Number(courseId)) || null
|
|
}
|
|
|
|
const sessionSnapshot = (session) => (session ? { id: session.id, title: session.title } : null)
|
|
|
|
const courseSnapshot = (course) => (course ? { id: course.id, title: course.title } : null)
|
|
|
|
register('GET', endpoints.getExamsList, ({ query }) => {
|
|
let list = filterItems(adminExams, query, {
|
|
title: 'includes',
|
|
courseId: (item, v) => String(item.course?.id) === String(v),
|
|
sessionId: (item, v) => String(item.sessionId) === String(v),
|
|
})
|
|
list = filterDateRange(list, query)
|
|
const { data: items, meta } = paginate(list, query)
|
|
return {
|
|
success: true,
|
|
message: 'OK',
|
|
data: items,
|
|
meta,
|
|
}
|
|
})
|
|
|
|
register('GET', endpoints.showExam, ({ params }) => ({
|
|
success: true,
|
|
message: 'OK',
|
|
data: findOrThrow(adminExams, params.id),
|
|
}))
|
|
|
|
register('POST', endpoints.addNewExam, ({ data }) => {
|
|
const session = adminSessions.find((s) => s.id === Number(data.sessionId))
|
|
const course = resolveCourseFromSession(session)
|
|
const item = {
|
|
id: makeId(),
|
|
sessionId: session?.id ?? Number(data.sessionId) ?? null,
|
|
title: data.title || '',
|
|
description: data.description || '',
|
|
passScore: Number(data.passingScore ?? data.passScore) || 0,
|
|
isActive: data.isActive ?? true,
|
|
questions: [],
|
|
// UI-only fallbacks for ExamItem / ExamDetailsModal.
|
|
session: sessionSnapshot(session),
|
|
sessionTitle: session?.title || '',
|
|
course: courseSnapshot(course),
|
|
courseTitle: course?.title || '',
|
|
questionsCount: 0,
|
|
createdAt: isoNow(),
|
|
}
|
|
adminExams.unshift(item)
|
|
return {
|
|
success: true,
|
|
message: 'Exam created.',
|
|
data: item,
|
|
}
|
|
})
|
|
|
|
register('PATCH', endpoints.updateExam, ({ params, data }) => {
|
|
const patch = {}
|
|
if (data.title !== undefined) patch.title = data.title
|
|
if (data.description !== undefined) patch.description = data.description
|
|
if (data.passingScore !== undefined) patch.passScore = Number(data.passingScore) || 0
|
|
if (data.passScore !== undefined) patch.passScore = Number(data.passScore) || 0
|
|
if (data.isActive !== undefined) patch.isActive = !!data.isActive
|
|
if (data.sessionId !== undefined) {
|
|
const session = adminSessions.find((s) => s.id === Number(data.sessionId))
|
|
const course = resolveCourseFromSession(session)
|
|
patch.sessionId = session?.id ?? Number(data.sessionId) ?? null
|
|
patch.session = sessionSnapshot(session)
|
|
patch.sessionTitle = session?.title ?? ''
|
|
patch.course = courseSnapshot(course)
|
|
patch.courseTitle = course?.title ?? ''
|
|
}
|
|
return {
|
|
success: true,
|
|
message: 'Exam updated.',
|
|
data: updateById(adminExams, params.id, patch),
|
|
}
|
|
})
|
|
|
|
register('DELETE', endpoints.deleteExam, ({ params }) => {
|
|
removeById(adminExams, params.id)
|
|
return { success: true, message: 'Exam deleted.', data: null }
|
|
})
|
|
|
|
// POST /exams/:examId/questions — atomic question + options create.
|
|
register('POST', endpoints.addExamQuestion, ({ params, data }) => {
|
|
const exam = findOrThrow(adminExams, params.examId)
|
|
const questionId = makeId()
|
|
const options = Array.isArray(data.options) ? data.options : []
|
|
const question = {
|
|
id: questionId,
|
|
questionText: data.questionText || '',
|
|
position: data.position ?? (exam.questions?.length ?? 0) + 1,
|
|
options: options.map((opt, idx) => ({
|
|
id: questionId * 100 + idx + 1,
|
|
optionText: opt.optionText || '',
|
|
isCorrect: !!opt.isCorrect,
|
|
})),
|
|
}
|
|
exam.questions = [...(exam.questions || []), question]
|
|
exam.questionsCount = exam.questions.length
|
|
return {
|
|
success: true,
|
|
message: 'Question added.',
|
|
data: question,
|
|
}
|
|
})
|
|
|
|
// POST /questions/:questionId/options — single option append.
|
|
register('POST', endpoints.addQuestionOption, ({ params, data }) => {
|
|
for (const exam of adminExams) {
|
|
const question = (exam.questions || []).find((q) => String(q.id) === String(params.questionId))
|
|
if (question) {
|
|
const option = {
|
|
id: makeId(),
|
|
optionText: data.optionText || '',
|
|
isCorrect: !!data.isCorrect,
|
|
}
|
|
question.options = [...(question.options || []), option]
|
|
return {
|
|
success: true,
|
|
message: 'Option added.',
|
|
data: option,
|
|
}
|
|
}
|
|
}
|
|
return { success: false, message: 'Question not found.', data: null }
|
|
})
|
|
|
|
// FE-mock-only.
|
|
register('GET', endpoints.getExamParticipants, ({ params, query }) => {
|
|
const list = examParticipants.get(Number(params.examId)) || []
|
|
return paginate(list, query)
|
|
})
|
|
|
|
register('GET', endpoints.showExamParticipant, ({ params }) => {
|
|
const list = examParticipants.get(Number(params.examId)) || []
|
|
const found = list.find((p) => String(p.id) === String(params.participantId))
|
|
return { data: found || null }
|
|
})
|