diff --git a/app/api/courses/[courseId]/past-questions/route.ts b/app/api/courses/[courseId]/past-questions/route.ts index 5e7703a..3d59c30 100644 --- a/app/api/courses/[courseId]/past-questions/route.ts +++ b/app/api/courses/[courseId]/past-questions/route.ts @@ -5,7 +5,10 @@ import { authOptions } from "@/lib/auth"; import prisma from "@/lib/prisma"; import { validateUser } from "@/services/userCourse"; -export async function GET(request: NextRequest, context: { params: Promise<{ courseId: string }> }) { +export async function GET( + request: NextRequest, + context: { params: Promise<{ courseId: string }> }, +) { try { const session = await getServerSession(authOptions); if (!session?.user) { @@ -24,7 +27,7 @@ export async function GET(request: NextRequest, context: { params: Promise<{ cou } if (!(await validateUser(session.user.id, courseId, Role.LECTURER))) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + return NextResponse.json({ error: "Questions not Found" }, { status: 404 }); } const pastQuestions = await prisma.question.findMany({ diff --git a/app/api/export/[courseId]/route.ts b/app/api/export/[courseId]/route.ts index 0602c36..36cc4b0 100644 --- a/app/api/export/[courseId]/route.ts +++ b/app/api/export/[courseId]/route.ts @@ -5,7 +5,8 @@ import { getServerSession } from "next-auth"; import { authOptions } from "@/lib/auth"; import { csvAdvancedFieldNames, csvBasicFieldNames } from "@/lib/constants"; import prisma from "@/lib/prisma"; -import { ExportCSVType } from "@/types/ExportCSVType"; +import { ExportCSVType } from "@/models/ExportCSVType"; +import { validateUser } from "@/services/userCourse"; export async function GET(req: NextRequest, context: { params: Promise<{ courseId: string }> }) { const session = await getServerSession(authOptions); @@ -15,22 +16,12 @@ export async function GET(req: NextRequest, context: { params: Promise<{ courseI const { courseId } = await context.params; - if (!courseId || Number.isNaN(+courseId)) { - return NextResponse.json({ error: "Course Id is required" }, { status: 403 }); - } - - const courseLecturers = await prisma.userCourse.findMany({ - where: { - courseId: +courseId, - role: Role.LECTURER, - }, - select: { - userId: true, - }, - }); - - if (!courseLecturers.find((lecturer) => lecturer.userId === session.user.id)) { - return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + if ( + !courseId || + Number.isNaN(+courseId) || + !(await validateUser(session.user.id, +courseId, Role.LECTURER)) + ) { + return NextResponse.json({ error: "Not Found" }, { status: 404 }); } const url = new URL(req.url); diff --git a/app/api/fetchCourseSessionQuestion/route.ts b/app/api/fetchCourseSessionQuestion/route.ts index 98f18a6..9ce2f28 100644 --- a/app/api/fetchCourseSessionQuestion/route.ts +++ b/app/api/fetchCourseSessionQuestion/route.ts @@ -3,6 +3,7 @@ import { NextRequest, NextResponse } from "next/server"; import { getServerSession } from "next-auth/next"; import { authOptions } from "@/lib/auth"; import prisma from "@/lib/prisma"; +import { validateUser } from "@/services/userCourse"; export async function GET(request: NextRequest) { try { @@ -48,7 +49,7 @@ export async function GET(request: NextRequest) { }, }); - if (!courseSession) { + if (!courseSession || !(await validateUser(session.user.id, courseSession.courseId))) { return NextResponse.json({ error: "Course session not found" }, { status: 404 }); } diff --git a/app/api/fetchQuestionById/route.ts b/app/api/fetchQuestionById/route.ts index b9f4af8..c475469 100644 --- a/app/api/fetchQuestionById/route.ts +++ b/app/api/fetchQuestionById/route.ts @@ -3,6 +3,7 @@ import { NextRequest, NextResponse } from "next/server"; import { getServerSession } from "next-auth/next"; import { authOptions } from "@/lib/auth"; import prisma from "@/lib/prisma"; +import { validateUser } from "@/services/userCourse"; // Make sure we're using the correct export format for Next.js App Router export async function GET(request: NextRequest) { @@ -24,6 +25,23 @@ export async function GET(request: NextRequest) { ); } + const course = await prisma.question.findFirst({ + where: { + id: +questionId, + }, + select: { + session: { + select: { + courseId: true, + }, + }, + }, + }); + + if (!course || !(await validateUser(session.user.id, course.session.courseId))) { + return NextResponse.json({ error: "Question not found" }, { status: 404 }); + } + // Fetch the question with its options const question = await prisma.question.findUnique({ where: { diff --git a/app/api/getResponseCounts/route.ts b/app/api/getResponseCounts/route.ts index c7bd8e0..6a5e5a4 100644 --- a/app/api/getResponseCounts/route.ts +++ b/app/api/getResponseCounts/route.ts @@ -1,7 +1,9 @@ +import { Role } from "@prisma/client"; import { NextRequest, NextResponse } from "next/server"; import { getServerSession } from "next-auth/next"; import { authOptions } from "@/lib/auth"; import prisma from "@/lib/prisma"; +import { validateUser } from "@/services/userCourse"; export async function GET(request: NextRequest) { try { @@ -20,6 +22,27 @@ export async function GET(request: NextRequest) { ); } + const courseId = await prisma.course.findFirst({ + where: { + sessions: { + some: { + questions: { + some: { + id: +questionId, + }, + }, + }, + }, + }, + select: { + id: true, + }, + }); + + if (!courseId || !(await validateUser(session.user.id, courseId.id, Role.LECTURER))) { + return NextResponse.json({ error: "Responses not found" }, { status: 404 }); + } + const groups = await prisma.response.groupBy({ by: ["optionId"], where: { questionId: Number(questionId) }, diff --git a/app/api/session/[sessionId]/activeQuestion/route.ts b/app/api/session/[sessionId]/activeQuestion/route.ts index 10d59f2..f239dfc 100644 --- a/app/api/session/[sessionId]/activeQuestion/route.ts +++ b/app/api/session/[sessionId]/activeQuestion/route.ts @@ -1,17 +1,42 @@ +import { Role } from "@prisma/client"; import { NextResponse } from "next/server"; -import { ActiveQuestionPayload } from "../../../../../models/CourseSession"; +import { getServerSession } from "next-auth"; +import { authOptions } from "@/lib/auth"; import prisma from "@/lib/prisma"; +import { ActiveQuestionPayload } from "@/models/CourseSession"; +import { validateUser } from "@/services/userCourse"; export async function PATCH( request: Request, { params }: { params: Promise<{ sessionId: string }> }, ) { try { - const resolvedParams = await params; + const session = await getServerSession(authOptions); + if (!session?.user) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const { sessionId } = await params; + + const courseSession = await prisma.courseSession.findFirst({ + where: { + id: +sessionId, + }, + select: { + courseId: true, + }, + }); + + if ( + !courseSession?.courseId || + !(await validateUser(session.user.id, courseSession.courseId, Role.LECTURER)) + ) { + return NextResponse.json({ error: "Responses not found" }, { status: 404 }); + } + const { activeQuestionId } = (await request.json()) as ActiveQuestionPayload; - const sessionId = parseInt(resolvedParams.sessionId, 10); const updatedSession = await prisma.courseSession.update({ - where: { id: sessionId }, + where: { id: +sessionId }, data: { activeQuestionId }, }); return NextResponse.json(updatedSession); diff --git a/app/api/session/[sessionId]/wildcard/route.ts b/app/api/session/[sessionId]/wildcard/route.ts index b8c7d37..cadbebf 100644 --- a/app/api/session/[sessionId]/wildcard/route.ts +++ b/app/api/session/[sessionId]/wildcard/route.ts @@ -1,16 +1,41 @@ +import { Role } from "@prisma/client"; import { NextResponse } from "next/server"; +import { getServerSession } from "next-auth"; +import { authOptions } from "@/lib/auth"; +import prisma from "@/lib/prisma"; import { WildcardPayload } from "@/models/CourseSession"; import { createWildcardQuestion } from "@/services/session"; +import { validateUser } from "@/services/userCourse"; export async function POST( request: Request, { params }: { params: Promise<{ sessionId: string }> }, ) { try { - const resolvedParams = await params; + const session = await getServerSession(authOptions); + if (!session?.user) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + const { sessionId } = await params; + + const courseSession = await prisma.courseSession.findFirst({ + where: { + id: +sessionId, + }, + select: { + courseId: true, + }, + }); + + if ( + !courseSession?.courseId || + !(await validateUser(session.user.id, courseSession.courseId, Role.LECTURER)) + ) { + return NextResponse.json({ error: "Responses not found" }, { status: 404 }); + } const { position, questionType } = (await request.json()) as WildcardPayload; - const sessionId = parseInt(resolvedParams.sessionId, 10); - const wildcardQuestion = await createWildcardQuestion(sessionId, position, questionType); + const wildcardQuestion = await createWildcardQuestion(+sessionId, position, questionType); return NextResponse.json(wildcardQuestion); } catch (error) { console.error(error); diff --git a/app/api/updateCourse/[id]/route.ts b/app/api/updateCourse/[id]/route.ts index 36cecc4..67f14b3 100644 --- a/app/api/updateCourse/[id]/route.ts +++ b/app/api/updateCourse/[id]/route.ts @@ -1,8 +1,10 @@ +import { Role } from "@prisma/client"; import { NextResponse } from "next/server"; import { getServerSession } from "next-auth/next"; import { z } from "zod"; import { authOptions } from "@/lib/auth"; import prisma from "@/lib/prisma"; +import { validateUser } from "@/services/userCourse"; const updateSchema = z.object({ title: z.string().min(2), @@ -34,17 +36,8 @@ export async function PUT(request: Request) { const courseId = getCourseId(request); // Verify user has permission - const userCourse = await prisma.userCourse.findUnique({ - where: { - userId_courseId: { - userId: session.user.id, - courseId, - }, - }, - }); - - if (!userCourse || userCourse.role !== "LECTURER") { - return NextResponse.json({ error: "Forbidden" }, { status: 403 }); + if (!courseId || !(await validateUser(session.user.id, courseId, Role.LECTURER))) { + return NextResponse.json({ error: "Course not found" }, { status: 404 }); } // Validate request body diff --git a/app/dashboard/course/[courseId]/(lecturerPages)/admin/page.tsx b/app/dashboard/course/[courseId]/(lecturerPages)/admin/page.tsx new file mode 100644 index 0000000..e697bbf --- /dev/null +++ b/app/dashboard/course/[courseId]/(lecturerPages)/admin/page.tsx @@ -0,0 +1,7 @@ +import { AddInstructorForm } from "@/components/AddInstuctorForm"; + +const CourseAdminPage = () => { + return ; +}; + +export default CourseAdminPage; diff --git a/app/dashboard/course/[courseId]/(courseInfo)/analytics/page.tsx b/app/dashboard/course/[courseId]/(lecturerPages)/analytics/page.tsx similarity index 97% rename from app/dashboard/course/[courseId]/(courseInfo)/analytics/page.tsx rename to app/dashboard/course/[courseId]/(lecturerPages)/analytics/page.tsx index acb223d..00a2a8b 100644 --- a/app/dashboard/course/[courseId]/(courseInfo)/analytics/page.tsx +++ b/app/dashboard/course/[courseId]/(lecturerPages)/analytics/page.tsx @@ -8,7 +8,7 @@ import PerformanceData from "@/components/ui/PerformanceData"; import StudentTable from "@/components/ui/StudentTable"; import { toast } from "@/hooks/use-toast"; import { analyticsPages } from "@/lib/constants"; -import { ExportCSVType } from "@/types/ExportCSVType"; +import { ExportCSVType } from "@/models/ExportCSVType"; export default function Page() { const params = useParams(); diff --git a/app/dashboard/course/[courseId]/(courseInfo)/layout.tsx b/app/dashboard/course/[courseId]/(lecturerPages)/layout.tsx similarity index 90% rename from app/dashboard/course/[courseId]/(courseInfo)/layout.tsx rename to app/dashboard/course/[courseId]/(lecturerPages)/layout.tsx index 8ffdf91..07b86fb 100644 --- a/app/dashboard/course/[courseId]/(courseInfo)/layout.tsx +++ b/app/dashboard/course/[courseId]/(lecturerPages)/layout.tsx @@ -67,11 +67,7 @@ export default function CourseInfoLayout({ - - -
- {fullText} -
-
- - - )} + + + + + {payload.value} + + + + + + + ); } diff --git a/components/ui/AttendanceLineChart.tsx b/components/ui/AttendanceLineChart.tsx index 9e1d02b..ea2d78c 100644 --- a/components/ui/AttendanceLineChart.tsx +++ b/components/ui/AttendanceLineChart.tsx @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState } from "react"; import { ChartContainer } from "@/components/ui/chart"; import { CartesianGrid, Line, LineChart, ResponsiveContainer, XAxis, YAxis } from "recharts"; import dayjs from "dayjs"; -import { attendanceChartConfig } from "@/lib/constants"; +import { attendanceChartConfig } from "@/lib/charts"; import { calculateWeekAttendance } from "@/lib/utils"; import { useToast } from "@/hooks/use-toast"; import LoaderComponent from "./loader"; diff --git a/components/ui/DonutChart.tsx b/components/ui/DonutChart.tsx index c20ed0d..7cfccdd 100644 --- a/components/ui/DonutChart.tsx +++ b/components/ui/DonutChart.tsx @@ -1,3 +1,5 @@ +"use client"; + import React from "react"; import { ChartConfig, diff --git a/components/ui/PastQuestions.tsx b/components/ui/PastQuestions.tsx index 0d1dffd..776148a 100644 --- a/components/ui/PastQuestions.tsx +++ b/components/ui/PastQuestions.tsx @@ -8,21 +8,7 @@ import { } from "@/components/ui/select"; import { Question, QuestionType } from "@prisma/client"; import Link from "next/link"; - -const questionTypeStyles = { - [QuestionType.MCQ]: { - bgColor: "#FFFED3", - textColor: "#58560B", - borderColor: "#58570B", - label: "Multiple Choice", - }, - [QuestionType.MSQ]: { - bgColor: "#EBCFFF", - textColor: "#602E84", - borderColor: "#602E84", - label: "Select-All", - }, -}; +import { questionTypeColors, questionTypeMap } from "@/lib/constants"; interface PastQuestion extends Question { session: { startTime: Date }; @@ -158,14 +144,12 @@ function PastQuestions({ courseId }: Props) { - {questionTypeStyles[question.type].label} + {questionTypeMap[question.type]}

{question.text} diff --git a/components/ui/PerformanceData.tsx b/components/ui/PerformanceData.tsx index 504aafb..a66a591 100644 --- a/components/ui/PerformanceData.tsx +++ b/components/ui/PerformanceData.tsx @@ -1,13 +1,7 @@ import React, { useCallback, useEffect, useState } from "react"; import DonutChart from "@/components/ui/DonutChart"; -import { - dataKey, - description, - nameKey, - performanceChartConfig, - questionTypeColors, - questionTypeMap, -} from "@/lib/constants"; +import { performanceChartConfig } from "@/lib/charts"; +import { questionTypeColors, questionTypeMap } from "@/lib/constants"; import { useToast } from "@/hooks/use-toast"; import { getLimitedPastQuestions, getResponses } from "@/services/question"; import { getIncorrectAndCorrectResponseCounts, getQuestionsWithAverageScore } from "@/lib/utils"; @@ -88,9 +82,9 @@ export default function PerformanceData({ courseId }: Props) { - - 0 ? "#E6F6EC" : "#E5E7EB"} - strokeWidth={thickness} - className="transition-colors duration-300" - /> - - - - - - -

- Class Average: - {Math.round(value)}% -
- - ); -} diff --git a/components/ui/tooltip.tsx b/components/ui/tooltip.tsx index d07e1ce..34ecf9c 100644 --- a/components/ui/tooltip.tsx +++ b/components/ui/tooltip.tsx @@ -20,7 +20,7 @@ const TooltipContent = React.forwardRef< ref={ref} sideOffset={sideOffset} className={cn( - "z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", + "z-50 overflow-hidden animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2", className, )} {...props} @@ -31,7 +31,7 @@ TooltipContent.displayName = TooltipPrimitive.Content.displayName; const StringTooltipContainer = ({ text }: { text: string }) => { return ( -
+
{text}
); diff --git a/hooks/use-poll-socket.ts b/hooks/use-poll-socket.ts index e0b15bf..39617e3 100644 --- a/hooks/use-poll-socket.ts +++ b/hooks/use-poll-socket.ts @@ -61,7 +61,7 @@ export function usePollSocket({ wsRef.current.close(); } }; - }, [courseSessionId, userId, onConnect, onDisconnect, onMessage]); + }, [courseSessionId, userId]); return wsRef; } diff --git a/lib/charts.ts b/lib/charts.ts new file mode 100644 index 0000000..090563e --- /dev/null +++ b/lib/charts.ts @@ -0,0 +1,32 @@ +import { ChartConfig } from "@/components/ui/chart"; + +export const performanceChartConfig = { + count: { + label: "Count", + }, + correct: { + label: "Correct", + color: "green", + }, + incorrect: { + label: "Incorrect", + color: "gray", + }, +} satisfies ChartConfig; + +export const attendanceChartConfig = { + attendance: { + label: "Attendance", + color: "black", + }, +} satisfies ChartConfig; + +export const studentAnalyticsScoreChartConfig = { + Correct: { label: "Correct", color: "#BFF2A7" }, + Incorrect: { label: "Incorrect", color: "#FFFFFF" }, +} satisfies ChartConfig; + +export const studentAnalyticsAttendanceChartConfig = { + Correct: { label: "Attended", color: "#A7F2C2" }, + Incorrect: { label: "Missed", color: "#FFFFFF" }, +} satisfies ChartConfig; diff --git a/lib/constants.ts b/lib/constants.ts index 0d9870f..b3b08bf 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1,9 +1,6 @@ -import { $Enums } from "@prisma/client"; -import { ChartConfig } from "@/components/ui/chart"; - export const questionTypes = ["Multiple Choice", "Select All"] as const; -export const colorOptions = ["#ED9D9D", "#F3AB7E", "#EEF583", "#94ED79", "#8E87F2"]; +export const colorOptions = ["#ED9D9D", "#F3AB7E", "#EEF583", "#94ED79", "#8E87F2"]; export const daysOptions = ["M", "T", "W", "Th", "F"] as const; export const dayLabels: Record<(typeof daysOptions)[number], string> = { @@ -24,97 +21,11 @@ export const questionTypeColors = { MCQ: { bg: "#EBCFFF", fg: "#602E84" }, }; -// donut chart config -export const dataKey = "count"; -export const nameKey = "result"; -export const description = "Class Average"; -export const performanceChartConfig = { - count: { - label: "Count", - }, - correct: { - label: "Correct", - color: "green", - }, - incorrect: { - label: "Incorrect", - color: "gray", - }, -} satisfies ChartConfig; - -export const attendanceChartConfig = { - attendance: { - label: "Attendance", - color: "black", - }, -} satisfies ChartConfig; - -export const studentAnalyticsScoreChartConfig = { - Correct: { label: "Correct", color: "#BFF2A7" }, - Incorrect: { label: "Incorrect", color: "#FFFFFF" }, -} satisfies ChartConfig; - -export const studentAnalyticsAttendanceChartConfig = { - Correct: { label: "Attended", color: "#A7F2C2" }, - Incorrect: { label: "Missed", color: "#FFFFFF" }, -} satisfies ChartConfig; - export const analyticsPages = ["Performance", "Attendance Rate"]; -export const coursePages = ["Questionnaire", "Analytics"]; +export const coursePages = ["Questionnaire", "Analytics", "Admin"] as const; export const DEFAULT_SHOW_RESULTS = false; -export type QuestionWithResponesAndOptions = { - options: { - isCorrect: boolean; - text: string; - id: number; - questionId: number; - }[]; - responses: { - userId: string; - questionId: number; - optionId: number; - answeredAt: Date; - }[]; -} & { - text: string; - id: number; - type: $Enums.QuestionType; - sessionId: number; - position: number; -}; - -export type Response = { - options: { - isCorrect: boolean; - id: number; - text: string; - questionId: number; - }[]; - responses: { - optionId: number; - questionId: number; - userId: string; - answeredAt: Date; - }[]; -}; - -export type Student = { - id: string; - responses: { - question: { - sessionId: number; - options: { - isCorrect: boolean; - }[]; - }; - }[]; - email: string | null; - firstName: string; - lastName: string | null; -}; - export const csvBasicFieldNames = ["email", "num_questions_answered", "date_of_session"]; export const csvAdvancedFieldNames = [ "email", diff --git a/lib/utils.ts b/lib/utils.ts index 7bdbc64..0e664b8 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -2,7 +2,11 @@ import { clsx } from "clsx"; import type { ClassValue } from "clsx"; import dayjs from "dayjs"; import { twMerge } from "tailwind-merge"; -import { QuestionWithResponesAndOptions, Response, Student } from "./constants"; +import { + QuestionWithResponesAndOptions, + ResponseWithOptions, + StudentWithResponses, +} from "@/models/Analytics"; import { getAttendanceCount, getStudentCount } from "@/services/userCourse"; /** * A utility function that merges tailwind classes with conditional classes combining functionalities of twMerge and clsx. @@ -27,8 +31,8 @@ export function greetUser(name: string): string { /** * A utility function that replaces date objects time to 00:00:00 and returns ISO String. * - * @param date - The name to greet. - * @returns A greeting message. + * @param date - Date object to convert. + * @returns Formattted Date object. */ export function formatDateToISO(date: Date) { return new Date(date.setHours(0, 0, 0, 0)).toISOString(); @@ -74,7 +78,7 @@ export function getQuestionsWithAverageScore(questions: QuestionWithResponesAndO return questionsWithScores; } -export function getIncorrectAndCorrectResponseCounts(responses: Response[]) { +export function getIncorrectAndCorrectResponseCounts(responses: ResponseWithOptions[]) { let correctResponses = 0; let incorrectReponses = 0; @@ -97,7 +101,7 @@ export function getIncorrectAndCorrectResponseCounts(responses: Response[]) { return { incorrect: incorrectReponses, correct: correctResponses }; } -export function getStudentsWithScores(students: Student[], sessionIds: number[]) { +export function getStudentsWithScores(students: StudentWithResponses[], sessionIds: number[]) { const studentData = students.map((student) => { // get total number of sessions const totalSessions = sessionIds.length; diff --git a/models/Analytics.ts b/models/Analytics.ts new file mode 100644 index 0000000..abc5483 --- /dev/null +++ b/models/Analytics.ts @@ -0,0 +1,23 @@ +import { Option, Question, Response as ResponseSchema } from "@prisma/client"; + +export type QuestionWithResponesAndOptions = ResponseWithOptions & Question; + +export type ResponseWithOptions = { + options: Option[]; + responses: ResponseSchema[]; +}; + +export type StudentWithResponses = { + id: string; + responses: { + question: { + sessionId: number; + options: { + isCorrect: boolean; + }[]; + }; + }[]; + email: string | null; + firstName: string; + lastName: string | null; +}; diff --git a/types/ExportCSVType.ts b/models/ExportCSVType.ts similarity index 100% rename from types/ExportCSVType.ts rename to models/ExportCSVType.ts diff --git a/models/User.ts b/models/User.ts deleted file mode 100644 index 04d7091..0000000 --- a/models/User.ts +++ /dev/null @@ -1,9 +0,0 @@ -// Example - -export type User = { - id: number; - name: string; - email: string; - createdAt: string; - updatedAt: string; -}; diff --git a/services/analytics.ts b/services/analytics.ts index 6e89f5a..98a12b8 100644 --- a/services/analytics.ts +++ b/services/analytics.ts @@ -94,11 +94,10 @@ export async function getQuestionsAndResponsesForDate( courseId: number, studentId: string, isoDate: string, - ) { - const start = new Date(isoDate) - const end = new Date(start) - end.setUTCHours(23, 59, 59, 999) + const start = new Date(isoDate); + const end = new Date(start); + end.setUTCHours(23, 59, 59, 999); try { const sessions = await prisma.courseSession.findMany({ where: { diff --git a/services/userCourse.ts b/services/userCourse.ts index 1df2936..ccc784f 100644 --- a/services/userCourse.ts +++ b/services/userCourse.ts @@ -39,16 +39,17 @@ export async function getUserCourses(userId: string) { }, }); - // const courses = await Promise.all( - // userCourses.map(async (course) => await getCourseWithId(course.courseId)), - // ); return courses.map(({ course, role }) => ({ ...course, role, })); } -export async function validateUser(userId: string, courseId: number, role: Role): Promise { +export async function validateUser( + userId: string, + courseId: number, + role?: Role, +): Promise { const userCourse = await prisma.userCourse.findFirst({ where: { userId,