feat: education
Deploy banu-front / deploy (push) Failing after 6s

This commit is contained in:
sajjadtalkhabi
2026-06-11 21:09:12 +03:30
parent 020a47f735
commit 4011c2f83b
18 changed files with 558 additions and 35 deletions
+102 -5
View File
@@ -4,10 +4,11 @@
// options: [{ id, optionText, isCorrect }] }] }
// (Backend hides `is_correct` from non-admin reads; the admin mock shows it.)
const buildQuestion = (id, questionText, position, options, correctIndex) => ({
const buildQuestion = (id, questionText, position, options, correctIndex, score = 10) => ({
id,
questionText,
position,
score,
options: options.map((optionText, idx) => ({
id: id * 100 + idx + 1,
optionText,
@@ -49,7 +50,10 @@ export const adminExams = [
sessionId: 101,
title: 'آزمون پایان فصل اول اخلاق',
description: 'آزمون چهار گزینه‌ای از مفاهیم درس‌های ۱ تا ۳.',
passScore: 12,
score: 20,
minimumScore: 12,
durationMinutes: 30,
isRandom: false,
isActive: true,
questions: ethicsQuestions,
// ── UI-only fields for ExamItem / ExamDetailsModal (not in backend). ──
@@ -65,7 +69,10 @@ export const adminExams = [
sessionId: 102,
title: 'آزمون مفاهیم قرآنی - میان‌ترم',
description: 'آزمون میان‌ترم برای مرور آیات کلیدی.',
passScore: 14,
score: 20,
minimumScore: 14,
durationMinutes: 20,
isRandom: false,
isActive: true,
questions: quranQuestions,
course: { id: 2, title: 'مفاهیم قرآنی' },
@@ -86,8 +93,10 @@ export const examAttempts = new Map([
{
id: 14,
examId: 201,
score: 85,
score: 20,
isPassed: true,
correctCount: 2,
totalQuestions: 2,
startedAt: '2026-04-12T15:00:00+03:30',
submittedAt: '2026-04-12T15:30:00+03:30',
deadlineAt: '2026-04-12T15:30:00+03:30',
@@ -109,8 +118,10 @@ export const examAttempts = new Map([
{
id: 15,
examId: 201,
score: 42,
score: 10,
isPassed: false,
correctCount: 1,
totalQuestions: 2,
startedAt: '2026-04-13T09:00:00+03:30',
submittedAt: '2026-04-13T09:25:00+03:30',
deadlineAt: '2026-04-13T09:30:00+03:30',
@@ -133,6 +144,92 @@ export const examAttempts = new Map([
],
])
// Mirrors GET /exam-attempts/:id — full per-attempt review. Questions carry
// every option with isCorrect (answer key) + isSelected (what the user picked).
const reviewQuestions = (questions, selectedByQuestionId) =>
questions.map((q) => ({
id: q.id,
questionText: q.questionText,
position: q.position,
score: q.score,
selectedOptionId: selectedByQuestionId[q.id] ?? null,
options: q.options.map((o) => ({
id: o.id,
optionText: o.optionText,
isCorrect: o.isCorrect,
isSelected: selectedByQuestionId[q.id] === o.id,
})),
}))
const examContext = {
id: 201,
title: 'آزمون پایان فصل اول اخلاق',
description: null,
score: 20,
minimumScore: 12,
durationMinutes: 30,
session: {
id: 101,
title: 'مقدمه‌ای بر اخلاق اسلامی',
course: {
id: 1,
title: 'اصول اخلاق اسلامی',
term: { id: 1, title: 'ترم بهار ۱۴۰۵', score: 20, minimumScore: 12 },
},
},
}
export const examAttemptReviews = new Map([
[
14,
{
id: 14,
examId: 201,
userId: 100,
user: {
id: 100,
name: 'فاطمه رضایی',
phone: '+989121234567',
roles: ['student'],
avatarUrl: null,
},
score: 20,
isPassed: true,
correctCount: 2,
totalQuestions: 2,
startedAt: '2026-04-12T15:00:00+03:30',
submittedAt: '2026-04-12T15:30:00+03:30',
exam: examContext,
// both answers correct (q1 → option 102, q2 → option 201)
questions: reviewQuestions(ethicsQuestions, { 1: 102, 2: 201 }),
},
],
[
15,
{
id: 15,
examId: 201,
userId: 102,
user: {
id: 102,
name: 'مریم احمدی',
phone: '+989121111111',
roles: ['student'],
avatarUrl: null,
},
score: 10,
isPassed: false,
correctCount: 1,
totalQuestions: 2,
startedAt: '2026-04-13T09:00:00+03:30',
submittedAt: '2026-04-13T09:25:00+03:30',
exam: examContext,
// q1 correct (102), q2 wrong (203)
questions: reviewQuestions(ethicsQuestions, { 1: 102, 2: 203 }),
},
],
])
// Kept for the FE-mock-only single-participant detail endpoint (no backend yet).
export const examParticipants = new Map([
[
@@ -0,0 +1,40 @@
// Mirrors the backend Homework shape (camelized). is_priority=true means the
// homework is required to pass the term; effective_deadline falls back to the
// term end date when no explicit deadline is set.
const sessionContext = (id, title, courseTitle, termTitle) => ({
id,
title,
course: { id: id - 90, title: courseTitle, term: { id: 1, title: termTitle } },
})
export const studentHomeworks = [
{
id: 301,
sessionId: 101,
title: 'تکلیف جلسه اول اخلاق',
description:
'یک متن ۵۰۰ کلمه‌ای دربارهٔ مفهوم تقوا بنویسید و فایل صوتی توضیح آن را بارگذاری کنید.',
deadline: '2026-05-01T23:59:00+03:30',
effectiveDeadline: '2026-05-01T23:59:00+03:30',
isActive: true,
isPriority: true,
submittersCount: 8,
createdAt: '2026-04-01T10:00:00.000Z',
media: [],
session: sessionContext(101, 'مقدمه‌ای بر اخلاق اسلامی', 'اصول اخلاق اسلامی', 'ترم پاییز ۱۴۰۴'),
},
{
id: 302,
sessionId: 103,
title: 'تکلیف احکام نماز جماعت',
description: 'خلاصه‌ای از احکام نماز جماعت را به همراه یک نمونهٔ صوتی ارائه دهید.',
deadline: null,
effectiveDeadline: '2026-04-20T00:00:00.000Z',
isActive: true,
isPriority: false,
submittersCount: 3,
createdAt: '2026-04-05T10:00:00.000Z',
media: [],
session: sessionContext(103, 'احکام نماز جماعت', 'فقه عبادات', 'ترم زمستان ۱۴۰۴'),
},
]