diff --git a/backend/server.js b/backend/server.js
index 0675a0f..14d4100 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -344,12 +344,16 @@ app.post('/api/sessions/:id/submit', (req, res) => {
const examProgressMap = {};
for (const r of examProgressRows) examProgressMap[r.scenario_id] = r;
+ // Also pull time_spent_seconds from global progress (tracked per scenario during the exam)
+ const globalProgress = loadProgress();
+
const snapshot = bundleScenarios.map(s => ({
id: s.id, title: s.title, weight: s.weight,
category: s.category, type: s.type, difficulty: s.difficulty,
status: examProgressMap[s.id]?.status || 'not_started',
completed_at: examProgressMap[s.id]?.completed_at || null,
attempts: examProgressMap[s.id]?.attempts || 0,
+ time_spent_seconds: globalProgress[s.id]?.time_spent_seconds || 0,
}));
const startedAt = new Date(session.started_at + 'Z');
const durationSecs = Math.round((Date.now() - startedAt.getTime()) / 1000);
diff --git a/frontend/src/components/ExamHistory.jsx b/frontend/src/components/ExamHistory.jsx
index f192dfe..b0608a7 100644
--- a/frontend/src/components/ExamHistory.jsx
+++ b/frontend/src/components/ExamHistory.jsx
@@ -22,6 +22,14 @@ function formatDate(iso) {
})
}
+function formatRowTime(secs) {
+ if (!secs || secs === 0) return '—'
+ const m = Math.floor(secs / 60)
+ const s = secs % 60
+ if (m > 0) return `${m}m ${s > 0 ? s + 's' : ''}`.trim()
+ return `${s}s`
+}
+
function ScoreRing({ pct, passed, size = 72 }) {
const r = (size / 2) - 7
const circ = 2 * Math.PI * r
@@ -169,6 +177,15 @@ function AttemptDetail({ attempt }) {
{s.attempts > 0 && (
{s.attempts} attempt{s.attempts > 1 ? 's' : ''}
)}
+
+ {(s.time_spent_seconds > 0) && (
+
+ )}
+ {formatRowTime(s.time_spent_seconds)}
+
{s.status === 'completed' ? s.weight : 0}/{s.weight} pts
diff --git a/frontend/src/components/ExamHistory.module.css b/frontend/src/components/ExamHistory.module.css
index 8bc4af6..6bac197 100644
--- a/frontend/src/components/ExamHistory.module.css
+++ b/frontend/src/components/ExamHistory.module.css
@@ -430,6 +430,15 @@
border-radius: 3px;
flex-shrink: 0;
}
+.rowTime {
+ font-family: var(--mono);
+ font-size: 11px;
+ color: var(--text-3);
+ flex-shrink: 0;
+ min-width: 52px;
+ display: flex;
+ align-items: center;
+}
.rowPts {
font-family: var(--mono);
font-size: 11px;
diff --git a/frontend/src/components/ExamReport.jsx b/frontend/src/components/ExamReport.jsx
index 88980c2..2ffb30b 100644
--- a/frontend/src/components/ExamReport.jsx
+++ b/frontend/src/components/ExamReport.jsx
@@ -10,6 +10,14 @@ function formatDuration(secs) {
return `${s}s`
}
+function formatRowTime(secs) {
+ if (!secs || secs === 0) return '—'
+ const m = Math.floor(secs / 60)
+ const s = secs % 60
+ if (m > 0) return `${m}m ${s > 0 ? s + 's' : ''}`.trim()
+ return `${s}s`
+}
+
const DIFF_COLOR = { Easy: 'var(--green)', Medium: 'var(--amber)', Hard: 'var(--red)' }
export default function ExamReport({ report, bundle, onClose, onRetry }) {
@@ -86,6 +94,15 @@ export default function ExamReport({ report, bundle, onClose, onRetry }) {
{s.difficulty}
+
+ {s.time_spent_seconds > 0 && (
+
+ )}
+ {formatRowTime(s.time_spent_seconds)}
+
{s.status === 'completed' ? s.weight : 0}/{s.weight} pts
))}
diff --git a/frontend/src/components/ExamReport.module.css b/frontend/src/components/ExamReport.module.css
index 6826b9b..884c165 100644
--- a/frontend/src/components/ExamReport.module.css
+++ b/frontend/src/components/ExamReport.module.css
@@ -101,6 +101,15 @@
.rowIcon { font-size: 14px; flex-shrink: 0; }
.rowTitle { flex: 1; }
.rowDiff { font-size: 11px; font-weight: 600; flex-shrink: 0; }
+.rowTime {
+ font-family: var(--mono);
+ font-size: 11px;
+ color: var(--text-3);
+ flex-shrink: 0;
+ min-width: 52px;
+ display: flex;
+ align-items: center;
+}
.rowPts { font-family: var(--mono); font-size: 12px; color: var(--text-3); flex-shrink: 0; min-width: 60px; text-align: right; }
/* Actions */