From 0bf9a9e076ce7173d61ec3377af2fb8dd8df9204 Mon Sep 17 00:00:00 2001 From: Jerry Date: Mon, 23 Jun 2025 15:31:59 -0700 Subject: [PATCH 01/11] minor rearrange and lint --- .../[courseId]/past-questions/route.ts | 5 +- components/StudentAnalyticsDrawer.tsx | 2 +- lib/constants.ts | 52 ------------------- lib/utils.ts | 14 +++-- services/analytics.ts | 7 ++- types/Analytics.ts | 23 ++++++++ 6 files changed, 40 insertions(+), 63 deletions(-) create mode 100644 types/Analytics.ts diff --git a/app/api/courses/[courseId]/past-questions/route.ts b/app/api/courses/[courseId]/past-questions/route.ts index 5e7703a..6c76b53 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) { diff --git a/components/StudentAnalyticsDrawer.tsx b/components/StudentAnalyticsDrawer.tsx index 30ebcf4..efe67f8 100644 --- a/components/StudentAnalyticsDrawer.tsx +++ b/components/StudentAnalyticsDrawer.tsx @@ -1,6 +1,5 @@ "use client"; -import { formatDateToISO } from "@/lib/utils"; import { VisuallyHidden } from "@radix-ui/react-visually-hidden"; import { format } from "date-fns"; import { useEffect, useState } from "react"; @@ -13,6 +12,7 @@ import { studentAnalyticsAttendanceChartConfig, studentAnalyticsScoreChartConfig, } from "@/lib/constants"; +import { formatDateToISO } from "@/lib/utils"; import { getQuestionsAndResponsesForDate, getStudentAnalytics } from "@/services/analytics"; type Props = { diff --git a/lib/constants.ts b/lib/constants.ts index 0d9870f..ec4d489 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1,4 +1,3 @@ -import { $Enums } from "@prisma/client"; import { ChartConfig } from "@/components/ui/chart"; export const questionTypes = ["Multiple Choice", "Select All"] as const; @@ -64,57 +63,6 @@ export const coursePages = ["Questionnaire", "Analytics"]; 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..09c68fc 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -2,8 +2,12 @@ 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 { getAttendanceCount, getStudentCount } from "@/services/userCourse"; +import { + QuestionWithResponesAndOptions, + ResponseWithOptions, + StudentWithResponses, +} from "@/types/Analytics"; /** * 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/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/types/Analytics.ts b/types/Analytics.ts new file mode 100644 index 0000000..abc5483 --- /dev/null +++ b/types/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; +}; From ac9dced6f835dba415e833b9bfa1d34ba4b4b8a8 Mon Sep 17 00:00:00 2001 From: Jerry Date: Mon, 23 Jun 2025 16:33:08 -0700 Subject: [PATCH 02/11] rearrange file dirs --- .../course/[courseId]/admin/page.tsx | 7 +++++ .../{(courseInfo) => }/analytics/page.tsx | 0 .../[courseId]/{(courseInfo) => }/layout.tsx | 6 +--- .../[questionId]/responses/page.tsx | 30 ++++++++++++++----- .../{(courseInfo) => }/questionnaire/page.tsx | 1 - 5 files changed, 30 insertions(+), 14 deletions(-) create mode 100644 app/dashboard/course/[courseId]/admin/page.tsx rename app/dashboard/course/[courseId]/{(courseInfo) => }/analytics/page.tsx (100%) rename app/dashboard/course/[courseId]/{(courseInfo) => }/layout.tsx (90%) rename app/dashboard/course/[courseId]/{(courseInfo) => }/questionnaire/[questionId]/responses/page.tsx (92%) rename app/dashboard/course/[courseId]/{(courseInfo) => }/questionnaire/page.tsx (99%) diff --git a/app/dashboard/course/[courseId]/admin/page.tsx b/app/dashboard/course/[courseId]/admin/page.tsx new file mode 100644 index 0000000..e697bbf --- /dev/null +++ b/app/dashboard/course/[courseId]/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]/analytics/page.tsx similarity index 100% rename from app/dashboard/course/[courseId]/(courseInfo)/analytics/page.tsx rename to app/dashboard/course/[courseId]/analytics/page.tsx diff --git a/app/dashboard/course/[courseId]/(courseInfo)/layout.tsx b/app/dashboard/course/[courseId]/layout.tsx similarity index 90% rename from app/dashboard/course/[courseId]/(courseInfo)/layout.tsx rename to app/dashboard/course/[courseId]/layout.tsx index 8ffdf91..1dff40a 100644 --- a/app/dashboard/course/[courseId]/(courseInfo)/layout.tsx +++ b/app/dashboard/course/[courseId]/layout.tsx @@ -67,11 +67,7 @@ export default function CourseInfoLayout({ - - -
- {fullText} -
-
- - - )} + + + + + {payload.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}
); From 44b09a6feffdd9a3ea85b76d413190294799827c Mon Sep 17 00:00:00 2001 From: Jerry Date: Mon, 23 Jun 2025 18:54:57 -0700 Subject: [PATCH 11/11] lint fix --- components/YAxisTick.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/YAxisTick.tsx b/components/YAxisTick.tsx index a279a34..e31f63b 100644 --- a/components/YAxisTick.tsx +++ b/components/YAxisTick.tsx @@ -1,4 +1,4 @@ -import { TooltipContent, StringTooltipContainer, Tooltip, TooltipTrigger } from "./ui/tooltip"; +import { StringTooltipContainer, Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; interface EllipsisYAxisTickProps { x?: number; @@ -9,7 +9,6 @@ interface EllipsisYAxisTickProps { export function LetteredYAxisTick({ x = 0, y = 0, payload }: EllipsisYAxisTickProps) { if (!payload) return null; - return (