Skip to content

Commit 2eeb706

Browse files
authored
Merge pull request #7 from mbianchidev/copilot/manage-evaluation-and-answers
Add evaluation validation and response management to practice mode
2 parents fe2a710 + b13559c commit 2eeb706

File tree

1 file changed

+124
-17
lines changed

1 file changed

+124
-17
lines changed

app/practice/page.tsx

Lines changed: 124 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import { useState, useEffect, useRef } from 'react';
44
import Link from 'next/link';
55
import { allQuestions } from '@/lib/questionsData';
6-
import { saveResponse, deleteResponse } from '@/lib/responseStorage';
7-
import { saveEvaluation } from '@/lib/evaluationStorage';
6+
import { saveResponse, deleteResponse, clearAllResponses } from '@/lib/responseStorage';
7+
import { saveEvaluation, getAllEvaluations, SelfEvaluation } from '@/lib/evaluationStorage';
88

99
interface Question {
1010
id: string;
@@ -26,14 +26,25 @@ export default function PracticePage() {
2626
const [questionsInRound, setQuestionsInRound] = useState(0);
2727
const [extraTime, setExtraTime] = useState(0);
2828
const [showEvaluation, setShowEvaluation] = useState(false);
29-
const [evaluation, setEvaluation] = useState({
30-
confidence: 3,
31-
effectiveness: 3,
32-
knowledge: 3,
29+
const [evaluation, setEvaluation] = useState<{
30+
confidence: number | null;
31+
effectiveness: number | null;
32+
knowledge: number | null;
33+
}>({
34+
confidence: null,
35+
effectiveness: null,
36+
knowledge: null,
3337
});
38+
const [previousEvaluations, setPreviousEvaluations] = useState<SelfEvaluation[]>([]);
39+
const [showPreviousEvaluations, setShowPreviousEvaluations] = useState(false);
3440

3541
const skipQuestionRef = useRef<(() => void) | null>(null);
3642

43+
// Load previous evaluations on mount
44+
useEffect(() => {
45+
setPreviousEvaluations(getAllEvaluations());
46+
}, []);
47+
3748
useEffect(() => {
3849
let interval: NodeJS.Timeout | null = null;
3950

@@ -148,7 +159,21 @@ export default function PracticePage() {
148159
};
149160

150161
const handleSubmitEvaluation = () => {
151-
saveEvaluation(evaluation);
162+
// Validate that all evaluations are filled
163+
if (evaluation.confidence === null || evaluation.effectiveness === null || evaluation.knowledge === null) {
164+
alert('Please rate all three categories before submitting.');
165+
return;
166+
}
167+
168+
saveEvaluation({
169+
confidence: evaluation.confidence,
170+
effectiveness: evaluation.effectiveness,
171+
knowledge: evaluation.knowledge,
172+
});
173+
174+
// Reload evaluations to show the new one
175+
setPreviousEvaluations(getAllEvaluations());
176+
152177
// Reset for new round
153178
setShowEvaluation(false);
154179
setQuestionsInRound(0);
@@ -157,6 +182,11 @@ export default function PracticePage() {
157182
setCurrentQuestion(null);
158183
setTimer(TIMER_DURATION);
159184
setIsActive(false);
185+
setEvaluation({
186+
confidence: null,
187+
effectiveness: null,
188+
knowledge: null,
189+
});
160190
};
161191

162192
const handleStartNewRound = () => {
@@ -166,6 +196,14 @@ export default function PracticePage() {
166196
getRandomQuestion();
167197
};
168198

199+
const handleClearAllResponses = () => {
200+
if (window.confirm('Are you sure you want to delete all your recorded answers? This action cannot be undone.')) {
201+
clearAllResponses();
202+
setResponse('');
203+
alert('All responses have been cleared.');
204+
}
205+
};
206+
169207
return (
170208
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">
171209
<div className="container mx-auto px-4 py-8 max-w-4xl">
@@ -194,7 +232,7 @@ export default function PracticePage() {
194232
<div className="space-y-6">
195233
<div>
196234
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
197-
Confidence (1-5)
235+
Confidence (1-5) {evaluation.confidence === null && <span className="text-red-600 dark:text-red-400">*</span>}
198236
</label>
199237
<div className="flex gap-2 justify-center">
200238
{[1, 2, 3, 4, 5].map((val) => (
@@ -215,7 +253,7 @@ export default function PracticePage() {
215253

216254
<div>
217255
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
218-
Effectiveness (1-5)
256+
Effectiveness (1-5) {evaluation.effectiveness === null && <span className="text-red-600 dark:text-red-400">*</span>}
219257
</label>
220258
<div className="flex gap-2 justify-center">
221259
{[1, 2, 3, 4, 5].map((val) => (
@@ -236,7 +274,7 @@ export default function PracticePage() {
236274

237275
<div>
238276
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
239-
Knowledge (1-5)
277+
Knowledge (1-5) {evaluation.knowledge === null && <span className="text-red-600 dark:text-red-400">*</span>}
240278
</label>
241279
<div className="flex gap-2 justify-center">
242280
{[1, 2, 3, 4, 5].map((val) => (
@@ -262,6 +300,11 @@ export default function PracticePage() {
262300
>
263301
Submit Evaluation & Start New Round
264302
</button>
303+
{(evaluation.confidence === null || evaluation.effectiveness === null || evaluation.knowledge === null) && (
304+
<p className="text-sm text-red-600 dark:text-red-400 text-center">
305+
* Please rate all three categories before submitting
306+
</p>
307+
)}
265308
</div>
266309
) : !currentQuestion ? (
267310
<div className="text-center space-y-8">
@@ -271,13 +314,77 @@ export default function PracticePage() {
271314
<p className="text-md text-slate-500 dark:text-slate-400">
272315
Finish questions early? Your extra time rolls over to the next question!
273316
</p>
274-
<button
275-
onClick={handleStartNewRound}
276-
disabled={questions.length === 0}
277-
className="px-8 py-4 bg-green-600 hover:bg-green-700 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 text-lg disabled:opacity-50 disabled:cursor-not-allowed"
278-
>
279-
Start Practicing
280-
</button>
317+
318+
<div className="flex flex-col sm:flex-row gap-4 justify-center items-center">
319+
<button
320+
onClick={handleStartNewRound}
321+
disabled={questions.length === 0}
322+
className="px-8 py-4 bg-green-600 hover:bg-green-700 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 text-lg disabled:opacity-50 disabled:cursor-not-allowed"
323+
>
324+
Start Practicing
325+
</button>
326+
327+
<button
328+
onClick={handleClearAllResponses}
329+
className="px-6 py-3 bg-red-600 hover:bg-red-700 text-white font-semibold rounded-xl shadow-lg hover:shadow-xl transition-all duration-300"
330+
>
331+
Clear All Responses
332+
</button>
333+
</div>
334+
335+
{previousEvaluations.length > 0 && (
336+
<div className="mt-8">
337+
<button
338+
onClick={() => setShowPreviousEvaluations(!showPreviousEvaluations)}
339+
className="text-blue-600 dark:text-blue-400 hover:underline font-medium"
340+
>
341+
{showPreviousEvaluations ? '▼ Hide' : '▶'} Previous Evaluations ({previousEvaluations.length})
342+
</button>
343+
344+
{showPreviousEvaluations && (
345+
<div className="mt-4 space-y-4 max-w-3xl mx-auto">
346+
{previousEvaluations.slice().reverse().map((evalItem) => (
347+
<div
348+
key={evalItem.timestamp}
349+
className="bg-white dark:bg-slate-800 rounded-lg shadow-md p-6 text-left"
350+
>
351+
<div className="flex justify-between items-center mb-4">
352+
<h3 className="text-lg font-semibold text-slate-900 dark:text-slate-100">
353+
Round {evalItem.roundNumber}
354+
</h3>
355+
<span className="text-sm text-slate-500 dark:text-slate-400">
356+
{new Date(evalItem.timestamp).toLocaleDateString()} {new Date(evalItem.timestamp).toLocaleTimeString()}
357+
</span>
358+
</div>
359+
<div className="grid grid-cols-3 gap-4">
360+
<div>
361+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-1">Confidence</p>
362+
<div className="flex items-center">
363+
<span className="text-2xl font-bold text-blue-600 dark:text-blue-400">{evalItem.confidence}</span>
364+
<span className="text-sm text-slate-500 dark:text-slate-500 ml-1">/5</span>
365+
</div>
366+
</div>
367+
<div>
368+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-1">Effectiveness</p>
369+
<div className="flex items-center">
370+
<span className="text-2xl font-bold text-green-600 dark:text-green-400">{evalItem.effectiveness}</span>
371+
<span className="text-sm text-slate-500 dark:text-slate-500 ml-1">/5</span>
372+
</div>
373+
</div>
374+
<div>
375+
<p className="text-sm text-slate-600 dark:text-slate-400 mb-1">Knowledge</p>
376+
<div className="flex items-center">
377+
<span className="text-2xl font-bold text-purple-600 dark:text-purple-400">{evalItem.knowledge}</span>
378+
<span className="text-sm text-slate-500 dark:text-slate-500 ml-1">/5</span>
379+
</div>
380+
</div>
381+
</div>
382+
</div>
383+
))}
384+
</div>
385+
)}
386+
</div>
387+
)}
281388
</div>
282389
) : (
283390
<div className="space-y-6">

0 commit comments

Comments
 (0)