Skip to content

Commit 8c0d5ed

Browse files
authored
Pull Request: Finance Education Module Enhancements (#32)
* feat(database) - Enhanced database for Educational Section * feat(hooks): - Implement achievement & progress hooks for global addressing * Add types & gamification tiers & calculation priciples * feat(FinanceEducation): - Add Education Page with Gamification for sample data - Implement tabs to switch tabs (Learn, Practice, Achievement) feat(Fix): - Fix all critical issues : missing components & unimported files & mismatched routes * Add backend support for Education Component Implement api calls for Education Component * Implement the frontend part * Compatible changes to prisma schema * Error in passport.ts TODO: fix it * Implement schema changes & exception handling in Controller * Add & Check imports in App.ts( made proper routes) Fix : Auth Controller * Custom hooks for user-stats, user-progress, user-achievements * Define Typesafety in hooks/use-progress Add custom spinner to load Implement components in Education Hub * Modify components to fetch data from backend
1 parent 3d7edd6 commit 8c0d5ed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+3614
-221
lines changed

backend-node/prisma/schema.prisma

Lines changed: 149 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,36 @@ datasource db {
88
}
99

1010
model User {
11-
id String @id @default(auto()) @map("_id") @db.ObjectId
11+
id String @id @default(auto()) @map("_id") @db.ObjectId
1212
username String
13-
email String @unique
14-
password String?
15-
emailVerified DateTime?
16-
image String?
17-
accounts Account[]
18-
13+
email String @unique
14+
password String?
15+
emailVerified DateTime?
16+
image String?
17+
level Int @default(1)
18+
xp Int @default(5)
19+
currentRank String @default("Novice")
20+
accounts Account[]
21+
educationProgress EducationProgress[]
22+
achievements Achievement[]
23+
skillTrees UserSkillTree[]
24+
dailyStreak Int @default(0)
25+
lastActiveDate DateTime?
26+
1927
createdAt DateTime @default(now())
2028
updatedAt DateTime @updatedAt
2129
}
2230

31+
model UserSkillTree {
32+
id String @id @default(uuid()) @map("_id")
33+
user User @relation(fields: [userId], references: [id])
34+
userId String @db.ObjectId
35+
skillTreeId String
36+
progress Json // Stores completed nodes, etc.
37+
38+
@@unique([userId, skillTreeId])
39+
}
40+
2341
model Account {
2442
id String @id @default(auto()) @map("_id") @db.ObjectId
2543
userId String @db.ObjectId
@@ -32,29 +50,137 @@ model Account {
3250
scope String?
3351
id_token String? @db.String
3452
session_state String?
35-
53+
3654
createdAt DateTime @default(now())
3755
updatedAt DateTime @updatedAt
38-
56+
3957
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
40-
58+
4159
@@unique([provider, providerAccountId])
4260
}
43-
4461

4562
model EmailVerificationToken {
46-
id String @id @default(auto()) @map("_id") @db.ObjectId
47-
userId String @unique @db.ObjectId
48-
token String @unique
49-
expireAt DateTime
50-
createdAt DateTime @default(now())
63+
id String @id @default(auto()) @map("_id") @db.ObjectId
64+
userId String @unique @db.ObjectId
65+
token String @unique
66+
expireAt DateTime
67+
createdAt DateTime @default(now())
5168
}
5269

5370
model PasswordResetToken {
54-
id String @id @default(auto()) @map("_id") @db.ObjectId
55-
userId String @unique @db.ObjectId
56-
token String @unique
57-
expireAt DateTime
58-
isUsed Boolean @default(false)
59-
createdAt DateTime @default(now())
60-
}
71+
id String @id @default(auto()) @map("_id") @db.ObjectId
72+
userId String @unique @db.ObjectId
73+
token String @unique
74+
expireAt DateTime
75+
isUsed Boolean @default(false)
76+
createdAt DateTime @default(now())
77+
}
78+
79+
model EducationProgress {
80+
id String @id @default(uuid()) @map("_id")
81+
user User @relation(fields: [userId], references: [id])
82+
userId String @db.ObjectId
83+
lessonId String
84+
completed Boolean @default(false)
85+
xpEarned Int @default(0)
86+
completedAt DateTime?
87+
88+
@@unique([userId, lessonId])
89+
}
90+
91+
model Lesson {
92+
id String @id @default(uuid()) @map("_id")
93+
title String
94+
description String
95+
duration Int // in minutes
96+
xpReward Int
97+
category String
98+
icon String?
99+
learningPath LearningPath? @relation(fields: [learningPathId], references: [id])
100+
learningPathId String? @db.ObjectId
101+
quizzes Quiz[]
102+
flashcardDecks FlashcardDeck[]
103+
createdAt DateTime @default(now())
104+
updatedAt DateTime @updatedAt
105+
}
106+
107+
model Quiz {
108+
id String @id @default(uuid()) @map("_id")
109+
lesson Lesson? @relation(fields: [lessonId], references: [id])
110+
lessonId String? @db.ObjectId
111+
title String
112+
description String
113+
xpReward Int
114+
questions QuizQuestion[]
115+
createdAt DateTime @default(now())
116+
updatedAt DateTime @updatedAt
117+
}
118+
119+
model QuizQuestion {
120+
id String @id @default(uuid()) @map("_id")
121+
quiz Quiz @relation(fields: [quizId], references: [id])
122+
quizId String @db.ObjectId
123+
question String
124+
options String[]
125+
correctAnswer Int
126+
explanation String
127+
}
128+
129+
model FlashcardDeck {
130+
id String @id @default(uuid()) @map("_id")
131+
lesson Lesson? @relation(fields: [lessonId], references: [id])
132+
lessonId String? @db.ObjectId
133+
title String
134+
description String
135+
flashcards Flashcard[]
136+
createdAt DateTime @default(now())
137+
updatedAt DateTime @updatedAt
138+
}
139+
140+
model Flashcard {
141+
id String @id @default(uuid()) @map("_id")
142+
deck FlashcardDeck @relation(fields: [deckId], references: [id])
143+
deckId String @db.ObjectId
144+
front String
145+
back String
146+
}
147+
148+
model LearningPath {
149+
id String @id @default(uuid()) @map("_id")
150+
title String
151+
color String
152+
icon String?
153+
lessons Lesson[]
154+
createdAt DateTime @default(now())
155+
updatedAt DateTime @updatedAt
156+
}
157+
158+
model SkillChallenge {
159+
id String @id @default(uuid()) @map("_id")
160+
title String
161+
description String
162+
difficulty String
163+
xpReward Int
164+
createdAt DateTime @default(now())
165+
updatedAt DateTime @updatedAt
166+
}
167+
168+
model Reward {
169+
id String @id @default(uuid()) @map("_id")
170+
title String
171+
description String
172+
icon String?
173+
unlockAtXp Int
174+
}
175+
176+
model Achievement {
177+
id String @id @default(uuid()) @map("_id")
178+
user User @relation(fields: [userId], references: [id])
179+
userId String @db.ObjectId
180+
type String
181+
title String
182+
description String
183+
color String?
184+
requirement String?
185+
earnedAt DateTime @default(now())
186+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { prisma } from '../../prisma/client';
2+
import { Request, Response } from 'express';
3+
4+
// Get all flashcard decks
5+
export async function getFlashcardDecks(req: Request, res: Response) {
6+
try {
7+
const decks = await prisma.flashcardDeck.findMany({
8+
include: { flashcards: true },
9+
});
10+
res.status(200).json({ decks });
11+
} catch (error) {
12+
console.error('Error fetching flashcard decks:', error);
13+
res.status(500).json({ error: 'Failed to fetch flashcard decks' });
14+
}
15+
}
16+
17+
// Get flashcard deck by ID
18+
export async function getFlashcardDeckById(req: Request, res: Response) {
19+
try {
20+
const { id } = req.params;
21+
const deck = await prisma.flashcardDeck.findUnique({
22+
where: { id },
23+
include: { flashcards: true },
24+
});
25+
if (!deck)
26+
return res.status(404).json({ error: 'Flashcard deck not found' });
27+
res.status(200).json({ deck });
28+
} catch (error) {
29+
console.error('Error fetching flashcard deck:', error);
30+
res.status(500).json({ error: 'Failed to fetch flashcard deck' });
31+
}
32+
}
33+
34+
// Create flashcard deck
35+
export async function createFlashcardDeck(req: Request, res: Response) {
36+
try {
37+
const { lessonId, title, description, flashcards } = req.body;
38+
const deck = await prisma.flashcardDeck.create({
39+
data: {
40+
lessonId,
41+
title,
42+
description,
43+
flashcards: {
44+
create: flashcards,
45+
},
46+
},
47+
include: { flashcards: true },
48+
});
49+
res.status(201).json({ deck });
50+
} catch (error) {
51+
console.error('Error creating flashcard deck:', error);
52+
res.status(500).json({ error: 'Failed to create flashcard deck' });
53+
}
54+
}
55+
56+
// Update flashcard deck
57+
export async function updateFlashcardDeck(req: Request, res: Response) {
58+
try {
59+
const { id } = req.params;
60+
const deck = await prisma.flashcardDeck.update({
61+
where: { id },
62+
data: req.body,
63+
include: { flashcards: true },
64+
});
65+
res.status(200).json({ deck });
66+
} catch (error) {
67+
console.error('Error updating flashcard deck:', error);
68+
res.status(500).json({ error: 'Failed to update flashcard deck' });
69+
}
70+
}
71+
72+
// Delete flashcard deck
73+
export async function deleteFlashcardDeck(req: Request, res: Response) {
74+
try {
75+
const { id } = req.params;
76+
await prisma.flashcardDeck.delete({ where: { id } });
77+
res.status(204).end();
78+
} catch (error) {
79+
console.error('Error deleting flashcard deck:', error);
80+
res.status(500).json({ error: 'Failed to delete flashcard deck' });
81+
}
82+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { RequestHandler, Router } from 'express';
2+
import { getFlashcardDeckById,
3+
getFlashcardDecks,
4+
createFlashcardDeck,
5+
updateFlashcardDeck,
6+
deleteFlashcardDeck
7+
} from './flashcardController';
8+
9+
const router = Router();
10+
11+
router.get('/', getFlashcardDecks);
12+
router.get('/:id', getFlashcardDeckById as RequestHandler);
13+
router.post('/', createFlashcardDeck);
14+
router.patch('/:id', updateFlashcardDeck);
15+
router.delete('/:id', deleteFlashcardDeck);
16+
17+
export default router;

0 commit comments

Comments
 (0)