feat: implement micro-learning generation service and UI components for interactive topic-based learning
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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" />}
|
||||
|
||||
Reference in New Issue
Block a user