feat: implement micro-learning generation service and UI components for interactive topic-based learning
All checks were successful
On Push to Main / test (push) Successful in 32s
On Push to Main / publish (push) Successful in 59s
On Push to Main / deploy-dev (push) Successful in 1m33s

This commit is contained in:
RaymondVerhoef
2026-05-25 22:17:26 +02:00
parent f16438c1bc
commit a653812cd8
10 changed files with 227 additions and 263 deletions

View File

@@ -67,15 +67,15 @@ const Dashboard = () => {
console.warn('[Dashboard] Could not load curriculum data:', e.message);
}
setDashData({
topic,
learnDone,
testResult,
top3,
myRank,
myPoints,
activity,
yearProgress,
setDashData({
topic,
learnDone,
testResult,
top3,
myRank,
myPoints,
activity,
yearProgress,
hasCurriculum: curriculumExists,
theme: topic?.theme || '',
});
@@ -178,7 +178,7 @@ const Dashboard = () => {
<div className="flex justify-between items-start mb-4">
<div>
<h3 className="text-xl">Testing</h3>
<p className="text-fg-muted text-sm mt-1">Weekly knowledge test</p>
<p className="text-fg-muted text-sm mt-1">Weekly test 5 questions</p>
</div>
{testResult ? <Tag variant="success">Score: {testResult.percentage}%</Tag> : <Tag variant="default">To Do</Tag>}
</div>
@@ -207,9 +207,8 @@ const Dashboard = () => {
) : (
activity.slice(0, 5).map((act, i) => (
<div key={i} className="p-4 flex items-center gap-4 hover:bg-bg-warm transition-colors">
<div className={`w-10 h-10 rounded-[var(--r-org)] flex items-center justify-center font-bold ${
act.type === 'test' ? 'bg-accent-soft text-purple-700' : 'bg-sage text-teal-900'
}`}>
<div className={`w-10 h-10 rounded-[var(--r-org)] flex items-center justify-center font-bold ${act.type === 'test' ? 'bg-accent-soft text-purple-700' : 'bg-sage text-teal-900'
}`}>
{act.type === 'test' ? 'T' : 'L'}
</div>
<div>

View File

@@ -182,7 +182,7 @@ const Testen = () => {
<h1 className="text-3xl md:text-4xl font-bold text-teal mb-4">Weekly Test</h1>
<p className="text-fg-muted text-lg mb-2">Week {weekNumber}</p>
<p className="text-fg-muted mb-8 max-w-md mx-auto">
Test your knowledge with AI-generated questions. You have 5 minutes to complete the test. Good luck!
Test your knowledge with 5 AI-generated questions. You have 5 minutes to complete the test. Good luck!
</p>
{error && (
@@ -196,9 +196,9 @@ const Testen = () => {
<div className="space-y-3">
<div className="flex items-center justify-center gap-6 text-sm text-fg-muted">
<span className="flex items-center gap-1.5"><CheckSquare size={14} /> Up to 5 questions</span>
<span className="flex items-center gap-1.5"><CheckSquare size={14} /> 5 questions</span>
<span className="flex items-center gap-1.5"><Clock size={14} /> 5 minutes</span>
<span className="flex items-center gap-1.5"><Trophy size={14} /> 2 pts each</span>
<span className="flex items-center gap-1.5"><Trophy size={14} /> 20 pts max</span>
</div>
<Button onClick={startQuiz} className="text-lg px-8 py-3">
Start Test <ArrowRight size={20} className="ml-2" />
@@ -215,7 +215,7 @@ const Testen = () => {
<div className="p-4 md:p-8 max-w-2xl mx-auto text-center py-20">
<Loader size={48} className="mx-auto text-teal animate-spin mb-4" />
<p className="font-medium text-lg">AI is generating your test...</p>
<p className="text-sm text-fg-muted mt-2">Preparing questions based on your learning topics.</p>
<p className="text-sm text-fg-muted mt-2">Preparing 5 questions based on your learning topics.</p>
</div>
);
}
@@ -233,9 +233,8 @@ const Testen = () => {
animate={{ scale: 1, opacity: 1 }}
className="text-center mb-10"
>
<div className={`inline-flex items-center justify-center w-28 h-28 rounded-full mb-6 ${
isPerfect ? 'bg-teal text-white' : isGood ? 'bg-teal/10 text-teal' : 'bg-orange-100 text-orange-600'
}`}>
<div className={`inline-flex items-center justify-center w-28 h-28 rounded-full mb-6 ${isPerfect ? 'bg-teal text-white' : isGood ? 'bg-teal/10 text-teal' : 'bg-orange-100 text-orange-600'
}`}>
<span className="text-4xl font-bold">{result.percentage}%</span>
</div>
<h1 className="text-3xl font-bold mb-2">
@@ -281,9 +280,8 @@ const Testen = () => {
{result.breakdown.map((item, i) => (
<Card key={i} className={`border ${item.correct ? 'border-teal/30' : 'border-red-200'}`}>
<div className="flex items-start gap-3 mb-3">
<div className={`flex-shrink-0 w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold ${
item.correct ? 'bg-teal/10 text-teal' : 'bg-red-50 text-red-500'
}`}>
<div className={`flex-shrink-0 w-7 h-7 rounded-full flex items-center justify-center text-sm font-bold ${item.correct ? 'bg-teal/10 text-teal' : 'bg-red-50 text-red-500'
}`}>
{i + 1}
</div>
<div className="flex-1">
@@ -299,13 +297,12 @@ const Testen = () => {
return (
<div
key={oi}
className={`px-3 py-2 rounded-[var(--r-sm)] text-sm border ${
isCorrect
className={`px-3 py-2 rounded-[var(--r-sm)] text-sm border ${isCorrect
? 'border-teal bg-teal/5 text-teal font-medium'
: wasSelected
? 'border-red-300 bg-red-50 text-red-700'
: 'border-bg-warm text-fg-muted'
}`}
? 'border-red-300 bg-red-50 text-red-700'
: 'border-bg-warm text-fg-muted'
}`}
>
{isCorrect && <CheckCircle size={14} className="inline mr-1 -mt-0.5" />}
{wasSelected && !isCorrect && <XCircle size={14} className="inline mr-1 -mt-0.5" />}