-
Notifications
You must be signed in to change notification settings - Fork 6
implement course-completion feature #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,70 @@ | ||||||||||||||||
| import exprees from "express"; | ||||||||||||||||
| const router = exprees.Router(); | ||||||||||||||||
| import { requireAuth } from "../middlewares/auth.js"; | ||||||||||||||||
| import { validate } from "../middlewares/validate.js"; | ||||||||||||||||
| import { | ||||||||||||||||
| getCourseParamsSchema, | ||||||||||||||||
| getCourseQuerySchema, | ||||||||||||||||
| } from "../schemas/courses.js"; | ||||||||||||||||
| import * as Service from "../services/courses.js"; | ||||||||||||||||
| import * as topicService from "../services/topics.js"; | ||||||||||||||||
|
|
||||||||||||||||
| router.get( | ||||||||||||||||
| "/:courseId", | ||||||||||||||||
| requireAuth, | ||||||||||||||||
| validate({ params: getCourseParamsSchema }), | ||||||||||||||||
| async (req, res) => { | ||||||||||||||||
| const course = await Service.getCourse(req.params.courseId); | ||||||||||||||||
|
|
||||||||||||||||
| const totalTopics = await Service.getToltalTopics(req.params.courseId); | ||||||||||||||||
|
|
||||||||||||||||
| const completedTopics = await Service.getCompletedTopics( | ||||||||||||||||
| req.user!.id, | ||||||||||||||||
| req.params.courseId, | ||||||||||||||||
| ); | ||||||||||||||||
| const persentage = (completedTopics.length / totalTopics.length) * 100; | ||||||||||||||||
|
||||||||||||||||
| const persentage = (completedTopics.length / totalTopics.length) * 100; | |
| const persentage = | |
| totalTopics.length === 0 | |
| ? 0 | |
| : (completedTopics.length / totalTopics.length) * 100; |
Copilot
AI
Aug 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable name has a typo. 'persentage' should be 'percentage'.
| persentage, | |
| const percentage = (completedTopics.length / totalTopics.length) * 100; | |
| res.status(200).json({ | |
| course, | |
| totalTopics, | |
| percentage, |
Copilot
AI
Aug 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable name has a typo. 'filterdTopics' should be 'filteredTopics'.
| filterdTopics = completedTopics; | |
| let filteredTopics; | |
| if (completed === "true") { | |
| filteredTopics = completedTopics; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import express from "express"; | ||
| const router = express.Router(); | ||
| import { tracksRouter } from "./tracks.js"; | ||
| import { coursesRouter } from "./courses.js"; | ||
| import { topicsRouter } from "./topics.js"; | ||
|
|
||
| router.get("/", (req, res) => { | ||
| res.status(200).json({ | ||
| message: "hello from api.", | ||
| }); | ||
| }); | ||
|
|
||
| router.use("/tracks", tracksRouter); | ||
| router.use("/courses", coursesRouter); | ||
| router.use("/topics", topicsRouter); | ||
|
|
||
| export default router; |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,40 @@ | ||||||||
| import exprees from "express"; | ||||||||
| const router = exprees.Router(); | ||||||||
|
||||||||
| const router = exprees.Router(); | |
| import express from "express"; | |
| const router = express.Router(); |
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,60 @@ | ||||||||
| import exprees from "express"; | ||||||||
| const router = exprees.Router(); | ||||||||
|
||||||||
| const router = exprees.Router(); | |
| import express from "express"; | |
| const router = express.Router(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import z from "zod"; | ||
|
|
||
| export const getCourseParamsSchema = z.object({ | ||
| courseId: z.string().min(1, "courseId is required"), | ||
| }); | ||
|
|
||
| export const getCourseQuerySchema = z.object({ | ||
| completed: z.string().optional(), | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import z from "zod"; | ||
|
|
||
| export const getTopicParamsSchema = z.object({ | ||
| topicId: z.string().min(1, "topicId is required"), | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import z from "zod"; | ||
|
|
||
| export const getTrackParamsSchema = z.object({ | ||
| trackId: z.string().min(1, "trackId is required"), | ||
| }); | ||
| export const getTrackQuerySchema = z.object({ | ||
| levelId: z.string().optional(), | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,61 @@ | ||||||
| import { prisma } from "../lib/prisma.js"; | ||||||
|
|
||||||
| export const getCourse = async (courseId: string) => { | ||||||
| return await prisma.course.findUnique({ | ||||||
| where: { | ||||||
| id: courseId, | ||||||
| }, | ||||||
| }); | ||||||
| }; | ||||||
|
|
||||||
| export const getToltalTopics = async (courseId: string) => { | ||||||
|
||||||
| export const getToltalTopics = async (courseId: string) => { | |
| export const getTotalTopics = async (courseId: string) => { |
Copilot
AI
Aug 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate function 'getToltalTopics' exists in both courses.ts and topics.ts services. Consider consolidating this logic to avoid code duplication.
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,54 @@ | ||||||
| import { prisma } from "../lib/prisma.js"; | ||||||
|
|
||||||
| export const getTopic = async (topicId: string) => { | ||||||
| return prisma.topic.findUnique({ | ||||||
| where: { | ||||||
| id: topicId, | ||||||
| }, | ||||||
| select: { | ||||||
| title: true, | ||||||
| durationInMinutes: true, | ||||||
| content: true, | ||||||
| }, | ||||||
| }); | ||||||
| }; | ||||||
|
|
||||||
| export const completeTopic = async (userId: string, topicId: string) => { | ||||||
| return await prisma.userCompletion.create({ | ||||||
| data: { | ||||||
| userId, | ||||||
| topicId, | ||||||
| }, | ||||||
| }); | ||||||
| }; | ||||||
| export const inCompleteTopic = async (userId: string, topicId: string) => { | ||||||
| prisma.userCompletion.delete({ | ||||||
|
||||||
| prisma.userCompletion.delete({ | |
| return await prisma.userCompletion.delete({ |
Copilot
AI
Aug 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function name has a typo. 'getToltalTopics' should be 'getTotalTopics'.
| export const getToltalTopics = async (courseId: string) => { | |
| export const getTotalTopics = async (courseId: string) => { |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import { prisma } from "../lib/prisma.js"; | ||
|
|
||
| export const getAllTracks = async () => { | ||
| const tracks = await prisma.track.findMany({ | ||
| select: { | ||
| id: true, | ||
| title: true, | ||
| }, | ||
| }); | ||
| return tracks; | ||
| }; | ||
|
|
||
| export const getTrack = async (trackId: string) => { | ||
| const track = await prisma.track.findUnique({ | ||
| where: { | ||
| id: trackId, | ||
| }, | ||
| select: { | ||
| id: true, | ||
| title: true, | ||
| description: true, | ||
| }, | ||
| }); | ||
| return track; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import statement has a typo. 'exprees' should be 'express'.