Skip to content

Conversation

@GowthamDhanaraju
Copy link
Contributor

@GowthamDhanaraju GowthamDhanaraju commented Jun 15, 2025

Summary by CodeRabbit

  • New Features

    • Introduced comprehensive student and teacher results dashboards, including overview pages, detailed test analytics, and interactive charts for performance visualization.
    • Added components for displaying recent tests, course summaries, performance trends, and question-level statistics.
    • Enhanced navigation with updated links for student and teacher results in the sidebar.
  • Bug Fixes

    • Resolved import errors related to recent test results by adding a stub implementation.
  • Style

    • Improved code formatting and JSX structure for better readability and consistency.
    • Enhanced accessibility for answer selection in true/false questions.
  • Chores

    • Added new charting libraries to support advanced data visualizations.
    • Refactored and centralized exports for easier import and maintenance of results-related components and types.

- Added icons to question and explanation titles in Match Following, MCQ, and True/False question components for better visual representation.
- Updated the MCQ question component to allow clickable options for selecting correct answers, enhancing user experience.
- Improved the Tiptap editor to accept a height prop for better customization.
- Refactored select components for cleaner code and improved styling.
- Created a new test page for editing questions with sample data to facilitate testing.
…anagement

- Created types for student overall results, recent test results, course results, test summaries, detailed test results, question results, and results filters.
- Implemented ResultsAPI class with methods to fetch student overview, course results, test summaries, detailed test results, and recent results.
- Added mock data for development and testing purposes for both student and teacher results.
feat: implement StudentResultsTable component for detailed student results

feat: define types for teacher-specific results in types.ts

refactor: remove deprecated TestSummaries component and related types

refactor: delete unused types from results/types.ts

fix: update results-api to use new types and mock data structure

feat: create utility functions for consistent score color display

chore: add stub for useRecentTestResults to resolve import errors
Copilot AI review requested due to automatic review settings June 15, 2025 23:20
@coderabbitai
Copy link

coderabbitai bot commented Jun 15, 2025

Walkthrough

This update introduces a comprehensive student and teacher results system. It adds new React components for displaying student and teacher test results, summary dashboards, analytics, and detailed views. Supporting TypeScript types, utility functions, and mock API implementations are included. Navigation and dependencies are updated to integrate these features and improve accessibility.

Changes

File(s) Change Summary
package.json Added charting libraries: chart.js, react-chartjs-2, and recharts as dependencies.
src/app/(evalify)/(academics)/result/page.tsx Deleted static "Result Page" component.
src/app/(test)/results-data/page.tsx, src/app/(test)/results/page.tsx Added redirect components to forward legacy routes to /student-results.
src/app/(test)/student-results/page.tsx Added main student results page with overview, course, and test detail views, state management, data fetching, and navigation.
src/app/(test)/student-results/test/[testId]/page.tsx Added detailed test result page for students, with data fetching and error handling.
src/app/(test)/teacher-results/page.tsx Added teacher dashboard for results analytics, multi-level navigation, and data visualization.
src/components/navigation/side-navbar/side-navbar.tsx Updated "Results" nav link and added "Teacher Results" link with icon.
src/components/question_creation/question-editor.tsx, question-settings.tsx, question-types/fillup-question.tsx Code formatting and prop ordering improvements; no logic changes.
src/components/question_creation/question-types/true-false-question.tsx Improved accessibility and keyboard interaction for answer selection.
src/components/results/common/detailed-test-result.tsx Added detailed test result view component for displaying test breakdowns.
src/components/results/common/index.ts, types.ts Added and exported shared types and components for results.
src/components/results/index.ts Centralized exports for all results-related components and types.
src/components/results/student/course-card.tsx, course-results-grid.tsx, performance-trends.tsx, recent-tests-card.tsx, student-overview.tsx, test-summaries.tsx, types.ts, index.ts Added student-focused components for course summaries, trends, recent tests, overviews, test summaries, and supporting types/exports.
src/components/results/teacher/course-summary-card.tsx, course-tests-table.tsx, courses-grid.tsx, performance-distribution-chart.tsx, question-stats-table.tsx, recent-tests-card.tsx, student-results-table.tsx, types.ts, index.ts Added teacher-focused components for course/test analytics, performance charts, question stats, recent tests, student results, and supporting types/exports.
src/lib/results-api.ts Added API utilities and mock implementations for fetching student and teacher results data.
src/lib/utils/score-colors.ts Added utility functions for consistent score-based color styling.
src/repo/student-results/student-results-api.ts Added stub hook for recent test results to resolve import errors.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant StudentResultsPage
    participant ResultsAPI/MockResultsAPI
    participant Router

    User->>StudentResultsPage: Visit /student-results
    StudentResultsPage->>ResultsAPI/MockResultsAPI: Fetch overview & course results
    ResultsAPI/MockResultsAPI-->>StudentResultsPage: Return data
    StudentResultsPage->>User: Render overview and course summaries

    User->>StudentResultsPage: Click course or test
    StudentResultsPage->>Router: Update URL/search params
    StudentResultsPage->>ResultsAPI/MockResultsAPI: Fetch test summaries or details
    ResultsAPI/MockResultsAPI-->>StudentResultsPage: Return test data
    StudentResultsPage->>User: Render test summaries or details
Loading
sequenceDiagram
    participant User
    participant TeacherResultsPage
    participant MockTeacherResultsAPI
    participant Router

    User->>TeacherResultsPage: Visit /teacher-results
    TeacherResultsPage->>MockTeacherResultsAPI: Fetch courses & recent tests
    MockTeacherResultsAPI-->>TeacherResultsPage: Return overview data
    TeacherResultsPage->>User: Render dashboard

    User->>TeacherResultsPage: Navigate to course/test/student
    TeacherResultsPage->>Router: Update URL/query params
    TeacherResultsPage->>MockTeacherResultsAPI: Fetch relevant data (tests, stats, student results)
    MockTeacherResultsAPI-->>TeacherResultsPage: Return requested data
    TeacherResultsPage->>User: Render analytics, charts, or details
Loading

Suggested reviewers

  • Aksaykanthan

Poem

In the garden of code where results now bloom,
Charts and summaries chase away the gloom.
Teachers and students, both find delight,
In dashboards and details, shining bright.
With colors and trends, the data’s in view—
This rabbit hops on, to celebrate you!
🐇📊✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

npm error Exit handler never called!
npm error This is an error with npm itself. Please report this error at:
npm error https://github.com/npm/cli/issues
npm error A complete log of this run can be found in: /.npm/_logs/2025-06-15T23_22_37_736Z-debug-0.log

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements the new results page for both teacher and student views while updating several UI components and navigation routes. Key changes include the addition of new student results components (StudentOverviewCard, RecentTestsCard, PerformanceTrends, CourseResultsGrid, and CourseCard), updates to question creation components for improved accessibility and formatting, and revised navigation URLs along with new dependencies in package.json.

Reviewed Changes

Copilot reviewed 39 out of 39 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/components/results/student/student-overview.tsx Introduces a simple student overview card with placeholder content.
src/components/results/student/recent-tests-card.tsx Adds a component for displaying recent tests with loading and error states.
src/components/results/student/performance-trends.tsx Implements performance trends calculations and rendering with trend icons and history graph.
src/components/results/student/index.ts Re-exports student-specific components.
src/components/results/student/course-results-grid.tsx Creates a grid layout for displaying course results.
src/components/results/student/course-card.tsx Provides a card UI for individual course data with recent test summaries.
src/components/results/index.ts Re-exports both teacher and student results components and types.
src/components/results/common/types.ts Defines common types shared by results components.
src/components/results/common/index.ts Re-exports common components and types.
src/components/question_creation/question-types/true-false-question.tsx Enhances accessibility by adding ARIA roles and keyboard support for true/false options.
src/components/question_creation/question-types/fillup-question.tsx Applies formatting improvements and minor refactoring in blank insertion and error handling.
src/components/question_creation/question-settings.tsx Consolidates markup for related topics with minor formatting adjustments.
src/components/question_creation/question-editor.tsx Removes duplicate props for evaluation settings in the fillup question editor.
src/components/navigation/side-navbar/side-navbar.tsx Updates navigation URLs and adds a new menu item for teacher results.
src/app/(test)/student-results/test/[testId]/page.tsx Introduces the student test result page using a mock API for fetching detailed test results.
src/app/(test)/student-results/page.tsx Implements the main student results page with views for overview, course details, and test summaries.
src/app/(test)/results/page.tsx Redirects legacy results route to the new student results page.
src/app/(test)/results-data/page.tsx Redirects legacy results-data route to the new student results page.
src/app/(evalify)/(academics)/result/page.tsx Removes the old result page as it is no longer required.
package.json Adds new dependencies (chart.js, react-chartjs-2, recharts) to support enhanced charts.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 16

🔭 Outside diff range comments (1)
src/components/question_creation/question-settings.tsx (1)

136-159: ⚠️ Potential issue

Accidental nested <div> & spacing artefacts

<div> <div className="flex …"> nests an empty <div> and introduces lots of hard-coded spaces. Probably meant to keep a single wrapper:

-                <div>                  <div className="flex items-center gap-2 text-sm font-semibold mb-2">
+                <div className="flex items-center gap-2 text-sm font-semibold mb-2">

Also, )} </div> (line 159) has stray spaces that survive prettier. Run the file through the formatter to clean this up.

♻️ Duplicate comments (2)
src/components/question_creation/question-types/true-false-question.tsx (1)

89-94: Same improvement applies to “False” option

Add role, aria-checked, and maybe arrow-key handling to mirror typical radio behaviour.

src/app/(test)/results-data/page.tsx (1)

3-10: Same observation as /results redirect – deduplicate

See earlier comment on consolidating redirect boilerplate. Apply the same helper here to stay DRY.

🧹 Nitpick comments (36)
package.json (1)

50-74: Charting libs added – verify bundle impact & peer-deps

Adding chart.js, react-chartjs-2, and recharts is fine functionally, but they collectively add >250 kB gzipped to the client bundle.

  1. Ensure this PR really needs both charting stacks – react-chartjs-2 already wraps Chart.js, while recharts is an alternative library.
  2. chart.js@4 requires that you tree-shake unused controllers and may need import "chart.js/auto" somewhere—double-check that the wrapper components handle this.
  3. Chart.js lists canvas@^2 as an optional peer for SSR; if you do any server rendering, add it to devDependencies to avoid runtime warnings.

If these packages are only used in the new results pages, consider dynamic import() so dashboards are code-split away from the main app.

src/components/question_creation/question-types/fillup-question.tsx (5)

163-164: Inline comment after } can break Prettier formatting

Placing the comment on the same line as the closing brace (} // Check if editor…) tends to violate the repo’s prettier rules and causes diff churn. Prefer a new line:

-    } // Check if editor is destroyed or not ready
+    }
+    // Check if editor is destroyed or not ready

200-201: Same-line comment – move to its own line

Ditto for }); // Show user-friendly error message. Move the comment above the statement for consistency.


346-347: {" "} JSX whitespace markers are unnecessary

</CardHeader>{" "} renders an extra text node that has no visual benefit and slightly bloats the DOM. Safe to drop the {" "}.


600-601: Trailing {" "} after conditional JSX

Same as above – delete the superfluous whitespace expression.


662-663: Unneeded whitespace node

Remove the {" "} after </CardHeader> to keep markup clean.

src/lib/utils/score-colors.ts (2)

9-16: Docstring doesn’t match range & negative scores not handled

Comment says “Green 100-80, Yellow 79-50…” but implementation splits 90-99 into emerald and 80-89 into green. Update docs or unify colours.

Also, what about percentage < 0 or > 100? Consider Math.max(0, Math.min(percentage, 100)) to clamp unexpected inputs.


39-46: Return type could be narrowed

Returning string forfeits type-safety; consider:

export type TailwindColor =
  | "bg-emerald-600"
  | "bg-green-500"
  | ... // etc.

export function getProgressColor(p: number): TailwindColor {  }

This way consumers can’t pass the wrong class accidentally.

src/components/results/common/types.ts (1)

46-61: Extract shared string unions into reusable type aliases

"completed" | "in-progress" | "not-started" and the difficulty union are repeated across multiple interfaces. Duplicating these literals increases the chance of drifting definitions.

export type TestStatus = "completed" | "in-progress" | "not-started";
export type Difficulty = "easy" | "medium" | "hard";

Then reference TestStatus / Difficulty everywhere.
This keeps the domain vocabulary DRY and centralised.

src/components/navigation/side-navbar/side-navbar.tsx (1)

75-79: Visibility of “Teacher Results” menu item

The new entry is placed under the Administration section, which is already wrapped by AuthGuard for ADMIN and MANAGER.
If lecturers (non-admin teaching staff) also need access, this guard will hide the menu item for them; consider whether UserType.STAFF should be included.

src/components/results/student/student-overview.tsx (2)

5-8: Unused props type alias – simplify the component signature

StudentOverviewCard does not consume children or any other props, yet a StudentOverviewCardProps alias based on React.PropsWithChildren is declared and passed to React.FC.
Drop the alias (or actually accept children) to avoid dead-code noise and slightly smaller bundles.

-// Using React.FC without props since this component doesn't take any props
-type StudentOverviewCardProps = React.PropsWithChildren;
-
-export const StudentOverviewCard: React.FC<StudentOverviewCardProps> = () => {
+export const StudentOverviewCard: React.FC = () => {

9-11: Placeholder component carries no semantic meaning

Rendering an empty <div> whose only purpose is spacing provides no real information to assistive technologies and may be removed by devs thinking it is vestigial.
Consider either:

  1. Deleting the component until real content lands, or
  2. Leaving a TODO comment explaining what will be rendered here and why the empty element is temporarily required.
src/app/(test)/results/page.tsx (2)

3-10: Redirect component duplicates logic already present in /results-data – consider a central util

You now have two almost-identical redirect pages (results and results-data). If more legacy routes appear this will bloat quickly.
Extract a tiny helper or config map, e.g.:

// lib/redirect.ts
export const legacyRedirect = (to: string) => () => redirect(to);

and then

export default legacyRedirect("/student-results");

Keeps the intent clear and removes repetition.


8-10: Return type could be never for clarity

redirect() throws a NEXT_REDIRECT to end execution. Declaring the component return type as never makes this explicit and silences “missing return” ESLint rules:

-export default function ResultsPage() {
+export default function ResultsPage(): never {
   redirect("/student-results");
 }
src/components/results/student/index.ts (1)

6-6: Inline comment leaks implementation history

// Re-enabled export is commit-era information that will age badly. Drop it or move to the PR description.

-export * from "./recent-tests-card"; // Re-enabled export
+export * from "./recent-tests-card";
src/components/results/teacher/index.ts (1)

1-9: Teacher barrel mirrors student barrel – ensure naming symmetry

Good to see parity between student/teacher modules. Consider grouping common re-exports (e.g. recent-tests-card) in a shared barrel to avoid duplication and improve discoverability.

No blocking issues – just architectural advice.

src/components/results/student/types.ts (1)

16-26: Consider using stricter date typing for lastTestDate.

If the field is always an ISO-8601 string, make that explicit via a branded/opaque type or at least a type ISODateString = string; alias.
It avoids accidental non-date strings sneaking in once real API wiring replaces the mocks.

src/app/(test)/student-results/test/[testId]/page.tsx (1)

19-42: Optional: abort fetch on unmount & avoid stale state updates.

If the user navigates away before MockResultsAPI.getTestResult resolves, setState will run on an unmounted component.
Wrapping the request in an AbortController (or a simple let cancelled = false guard) prevents React 18 warnings and wasted work.

useEffect(() => {
-  const loadTestResult = async () => {
+  const controller = new AbortController();
+  const loadTestResult = async () => {-    const data = await MockResultsAPI.getTestResult(mockStudentId, testId);
-    setResult(data);
+    const data = await MockResultsAPI.getTestResult(mockStudentId, testId, {
+      signal: controller.signal,
+    });
+    if (!controller.signal.aborted) setResult(data);
     …
   };
   …
-}, [params.testId]);
+  return () => controller.abort();
+}, [params.testId]);
src/components/results/teacher/course-summary-card.tsx (1)

18-23: Add basic accessibility for the clickable card.

Card renders a div, so keyboard users cannot trigger the onClick.
Either wrap the content in a <button> / <a> or add role="button" tabIndex={0} with onKeyDown (Enter/Space) handlers.

-<Card
-  className="hover:shadow-md transition-shadow duration-200 cursor-pointer overflow-hidden"
-  onClick={() => onViewCourse(course.courseId)}
->
+<Card
+  role="button"
+  tabIndex={0}
+  onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && onViewCourse(course.courseId)}
+  className="hover:shadow-md transition-shadow duration-200 cursor-pointer overflow-hidden focus:outline-none focus:ring-2 focus:ring-primary"
+  onClick={() => onViewCourse(course.courseId)}
+>
src/components/results/teacher/course-tests-table.tsx (3)

78-82: Compute expensive filter/sort once with useMemo.

filteredAndSortedTests is rebuilt on every render even when tests or sort/search state haven’t changed, which is unnecessary work for large datasets. Wrap the calculation in useMemo with [tests, searchQuery, sortField, sortDirection] as deps.


60-63: Re-think default sort direction for numeric columns.

When switching to totalSubmissions or averageScore, the code falls into the “else” branch and defaults to "asc", so teachers will see the smallest values first. Typical UX shows largest first (i.e. "desc"). Consider special-casing these fields the same way createdAt is handled.


145-152: Add type="button" to header buttons.

Although unlikely inside a <form>, it’s safer to mark these header buttons explicitly to prevent accidental form submission side-effects:

-<Button
+<Button type="button"
src/app/(test)/student-results/page.tsx (1)

56-66: Reset error state before fetching test summaries.

If a previous fetch failed, error stays set even after a later successful request because it isn’t cleared here. Add setError(null) before the try.

 const loadTestSummaries = React.useCallback(async (courseId: string) => {
   const mockStudentId = "student-1";
-  setLoading(true);
+  setLoading(true);
+  setError(null);
src/components/results/student/course-card.tsx (1)

23-36: Rename local averageScore & memoise calculations.

The local variable shadows course.averageScore, which is confusing. Rename to computedAverageScore (or similar) and wrap both the average and recentTests derivations in useMemo to avoid recomputation on every render.

src/components/results/teacher/performance-distribution-chart.tsx (2)

146-149: Remove leftover console.log statements.

Debug output in production clutters the browser console and can leak data. Please drop these logs or guard them with process.env.NODE_ENV !== "production".

Also applies to: 180-181


140-141: Avoid relying on parseInt with a trailing “%”.

parseInt("20%") works but is brittle; an explicit map is clearer:

const groupSize = { "5%": 5, "10%": 10, "20%": 20 }[grouping];

This also prevents accidental acceptance of invalid strings.

Also applies to: 154-156

src/components/results/teacher/recent-tests-card.tsx (2)

10-21: Extract getScoreBadgeColor to a shared util.

The same colour-grading logic exists in multiple components. Centralising it (e.g. lib/utils/score-colors.ts) eliminates duplication and keeps colours consistent.


31-37: Memoise recent-test slicing.

recentTests is recalculated on every render. Wrap the filter/sort/slice chain in useMemo with [tests] as dependency for a minor performance win.

src/components/results/student/performance-trends.tsx (3)

26-45: Memoize derived data to prevent unnecessary re-computations

sortedTests, scores, and the aggregate stats are recalculated on every render, even when tests is unchanged. Wrapping these calculations in useMemo will reduce render cost and avoid re-sorting large histories on every toggle of the “Show More / Less” button.

-  // Sort tests by completion date
-  const sortedTests = [...tests].sort(
-    (a, b) =>
-      new Date(a.completedAt).getTime() - new Date(b.completedAt).getTime(),
-  );
-
-  const scores = sortedTests.map((test) => test.percentage);
-
-  // Calculate stats
-  const averageScore =
-    scores.length > 0
-      ? scores.reduce((sum, score) => sum + score, 0) / scores.length
-      : 0;
-  const highestScore = scores.length > 0 ? Math.max(...scores) : 0;
-  const latestScore = scores.length > 0 ? scores[scores.length - 1] : 0;
+  const { sortedTests, scores, averageScore, highestScore, latestScore } =
+    React.useMemo(() => {
+      const sortedTests = [...tests].sort(
+        (a, b) =>
+          new Date(a.completedAt).getTime() -
+          new Date(b.completedAt).getTime(),
+      );
+      const scores = sortedTests.map((t) => t.percentage);
+      const averageScore =
+        scores.length === 0
+          ? 0
+          : scores.reduce((s, v) => s + v, 0) / scores.length;
+      return {
+        sortedTests,
+        scores,
+        averageScore,
+        highestScore: scores.length ? Math.max(...scores) : 0,
+        latestScore: scores.at(-1) ?? 0,
+      };
+    }, [tests]);

64-78: Compute trend once to avoid triple execution

getTrend() is called inside getTrendIcon(), getTrendColor(), and directly in JSX, resulting in three identical passes over the data per render. Cache the value with useMemo and pass it around instead.


168-196: Add accessible label & dynamic scaling to the SVG

Screen-reader users get no context for the chart, and very long histories may overflow the fixed viewBox height. Consider:

<svg
-  className="h-full w-full"
-  viewBox={`0 0 ${scores.length - 1} 100`}
+  className="h-full w-full"
+  role="img"
+  aria-label="Line chart of score history"
+  preserveAspectRatio="none"
+  viewBox={`0 0 ${Math.max(scores.length - 1, 1)} 100`}
>

This gives an accessible description and stops the polyline from squashing when only one point exists.

src/components/results/teacher/courses-grid.tsx (1)

16-40: Long if chain for colour mapping could be simplified

A lookup map (e.g. Record<string,string>) or hashing the first char into a limited palette would reduce repetition and make future maintenance painless.

src/components/results/student/recent-tests-card.tsx (1)

40-48: Cache sorting & slicing of tests

sortedTests and recentTests are recomputed on every render even when tests is unchanged. Wrap them in useMemo keyed by tests and limit to avoid needless work.

src/components/results/student/test-summaries.tsx (1)

226-236: Display placeholder when date is unavailable

Inside the test list the date cell unconditionally renders toLocaleDateString(). Show “—” (or similar) when completedAt is falsy to avoid confusing “Invalid Date” output.

src/app/(test)/teacher-results/page.tsx (1)

56-57: Single loading flag causes UI flicker

loading is toggled by every fetch helper. If a slow previous call finishes after a fast next call, it can wrongly hide content. Consider per-section loading flags or a ref counter.

Also applies to: 86-103

src/lib/results-api.ts (1)

20-96: Static-only class – switch to plain functions or a namespace

The class holds only static methods; linter already flags this (noStaticOnlyClass). Converting to a simple exported object or individual functions avoids unnecessary class semantics.

🧰 Tools
🪛 Biome (1.9.4)

[error] 20-96: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between db42055 and f953196.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (36)
  • package.json (2 hunks)
  • src/app/(evalify)/(academics)/result/page.tsx (0 hunks)
  • src/app/(test)/results-data/page.tsx (1 hunks)
  • src/app/(test)/results/page.tsx (1 hunks)
  • src/app/(test)/student-results/page.tsx (1 hunks)
  • src/app/(test)/student-results/test/[testId]/page.tsx (1 hunks)
  • src/app/(test)/teacher-results/page.tsx (1 hunks)
  • src/components/navigation/side-navbar/side-navbar.tsx (2 hunks)
  • src/components/question_creation/question-editor.tsx (1 hunks)
  • src/components/question_creation/question-settings.tsx (2 hunks)
  • src/components/question_creation/question-types/fillup-question.tsx (4 hunks)
  • src/components/question_creation/question-types/true-false-question.tsx (3 hunks)
  • src/components/results/common/detailed-test-result.tsx (1 hunks)
  • src/components/results/common/index.ts (1 hunks)
  • src/components/results/common/types.ts (1 hunks)
  • src/components/results/index.ts (1 hunks)
  • src/components/results/student/course-card.tsx (1 hunks)
  • src/components/results/student/course-results-grid.tsx (1 hunks)
  • src/components/results/student/index.ts (1 hunks)
  • src/components/results/student/performance-trends.tsx (1 hunks)
  • src/components/results/student/recent-tests-card.tsx (1 hunks)
  • src/components/results/student/student-overview.tsx (1 hunks)
  • src/components/results/student/test-summaries.tsx (1 hunks)
  • src/components/results/student/types.ts (1 hunks)
  • src/components/results/teacher/course-summary-card.tsx (1 hunks)
  • src/components/results/teacher/course-tests-table.tsx (1 hunks)
  • src/components/results/teacher/courses-grid.tsx (1 hunks)
  • src/components/results/teacher/index.ts (1 hunks)
  • src/components/results/teacher/performance-distribution-chart.tsx (1 hunks)
  • src/components/results/teacher/question-stats-table.tsx (1 hunks)
  • src/components/results/teacher/recent-tests-card.tsx (1 hunks)
  • src/components/results/teacher/student-results-table.tsx (1 hunks)
  • src/components/results/teacher/types.ts (1 hunks)
  • src/lib/results-api.ts (1 hunks)
  • src/lib/utils/score-colors.ts (1 hunks)
  • src/repo/student-results/student-results-api.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/app/(evalify)/(academics)/result/page.tsx
🧰 Additional context used
🧬 Code Graph Analysis (11)
src/components/results/teacher/course-summary-card.tsx (2)
src/components/results/teacher/types.ts (1)
  • TeacherCourseOverview (3-14)
src/components/ui/card.tsx (4)
  • Card (85-85)
  • CardHeader (86-86)
  • CardTitle (88-88)
  • CardContent (91-91)
src/components/results/teacher/question-stats-table.tsx (7)
src/components/results/teacher/types.ts (2)
  • DetailedTestStatistics (56-74)
  • QuestionStat (76-86)
src/components/ui/card.tsx (4)
  • Card (85-85)
  • CardHeader (86-86)
  • CardTitle (88-88)
  • CardContent (91-91)
src/components/ui/input.tsx (1)
  • Input (21-21)
src/components/ui/table.tsx (6)
  • Table (108-108)
  • TableHeader (109-109)
  • TableRow (113-113)
  • TableHead (112-112)
  • TableBody (110-110)
  • TableCell (114-114)
src/components/ui/button.tsx (1)
  • Button (59-59)
src/components/ui/badge.tsx (1)
  • Badge (46-46)
src/components/ui/progress.tsx (1)
  • Progress (31-31)
src/components/results/student/test-summaries.tsx (7)
src/components/results/common/types.ts (1)
  • TestSummary (3-15)
src/components/results/index.ts (2)
  • TestSummary (4-4)
  • TestSummaries (38-38)
src/components/ui/button.tsx (1)
  • Button (59-59)
src/components/ui/badge.tsx (1)
  • Badge (46-46)
src/components/ui/card.tsx (4)
  • Card (85-85)
  • CardHeader (86-86)
  • CardTitle (88-88)
  • CardContent (91-91)
src/lib/utils/score-colors.ts (2)
  • getScoreTextColor (9-16)
  • getScoreBgColor (22-34)
src/components/ui/calendar.tsx (1)
  • Calendar (260-260)
src/components/results/teacher/recent-tests-card.tsx (5)
src/components/results/index.ts (3)
  • TestOverview (15-15)
  • RecentTestsCard (26-26)
  • RecentTestsCard (35-35)
src/components/results/teacher/types.ts (1)
  • TestOverview (16-29)
src/components/ui/card.tsx (4)
  • Card (85-85)
  • CardHeader (86-86)
  • CardTitle (88-88)
  • CardContent (91-91)
src/components/ui/badge.tsx (1)
  • Badge (46-46)
src/components/ui/calendar.tsx (1)
  • Calendar (260-260)
src/components/results/teacher/student-results-table.tsx (6)
src/components/results/teacher/types.ts (2)
  • DetailedTestStatistics (56-74)
  • StudentTestResult (39-54)
src/components/ui/card.tsx (4)
  • Card (85-85)
  • CardHeader (86-86)
  • CardTitle (88-88)
  • CardContent (91-91)
src/components/ui/input.tsx (1)
  • Input (21-21)
src/components/ui/table.tsx (6)
  • Table (108-108)
  • TableHeader (109-109)
  • TableRow (113-113)
  • TableHead (112-112)
  • TableBody (110-110)
  • TableCell (114-114)
src/components/ui/button.tsx (1)
  • Button (59-59)
src/components/ui/badge.tsx (1)
  • Badge (46-46)
src/components/results/teacher/types.ts (1)
src/components/results/index.ts (6)
  • TeacherCourseOverview (14-14)
  • TestOverview (15-15)
  • PerformanceDistribution (16-16)
  • StudentTestResult (17-17)
  • DetailedTestStatistics (19-19)
  • QuestionStat (18-18)
src/components/results/teacher/courses-grid.tsx (4)
src/components/ui/select.tsx (5)
  • Select (175-175)
  • SelectTrigger (183-183)
  • SelectValue (184-184)
  • SelectContent (176-176)
  • SelectItem (178-178)
src/components/results/index.ts (2)
  • TeacherCourseOverview (14-14)
  • CoursesGrid (22-22)
src/components/results/teacher/types.ts (1)
  • TeacherCourseOverview (3-14)
src/components/ui/card.tsx (4)
  • Card (85-85)
  • CardContent (91-91)
  • CardHeader (86-86)
  • CardTitle (88-88)
src/components/results/student/course-card.tsx (5)
src/components/results/student/types.ts (1)
  • CourseResult (16-26)
src/components/results/common/types.ts (1)
  • TestSummary (3-15)
src/components/ui/card.tsx (4)
  • Card (85-85)
  • CardHeader (86-86)
  • CardTitle (88-88)
  • CardContent (91-91)
src/components/ui/badge.tsx (1)
  • Badge (46-46)
src/lib/utils/score-colors.ts (2)
  • getScoreTextColor (9-16)
  • getScoreBgColor (22-34)
src/components/results/teacher/performance-distribution-chart.tsx (5)
src/components/ui/tooltip.tsx (1)
  • Tooltip (61-61)
src/components/results/teacher/types.ts (3)
  • DetailedTestStatistics (56-74)
  • StudentTestResult (39-54)
  • PerformanceDistribution (31-37)
src/hooks/use-toast.ts (1)
  • useToast (22-67)
src/components/ui/card.tsx (4)
  • Card (85-85)
  • CardHeader (86-86)
  • CardTitle (88-88)
  • CardContent (91-91)
src/components/ui/select.tsx (5)
  • Select (175-175)
  • SelectTrigger (183-183)
  • SelectValue (184-184)
  • SelectContent (176-176)
  • SelectItem (178-178)
src/app/(test)/student-results/page.tsx (5)
src/components/results/student/types.ts (2)
  • StudentOverallResult (5-14)
  • CourseResult (16-26)
src/components/results/common/types.ts (1)
  • TestSummary (3-15)
src/lib/results-api.ts (1)
  • MockResultsAPI (99-723)
src/components/results/student/course-results-grid.tsx (1)
  • CourseResultsGrid (14-41)
src/components/results/student/test-summaries.tsx (1)
  • TestSummaries (27-266)
src/lib/results-api.ts (3)
src/components/results/student/types.ts (2)
  • StudentOverallResult (5-14)
  • CourseResult (16-26)
src/components/results/common/types.ts (2)
  • TestSummary (3-15)
  • DetailedTestResult (46-61)
src/components/results/teacher/types.ts (6)
  • TeacherCourseOverview (3-14)
  • TestOverview (16-29)
  • DetailedTestStatistics (56-74)
  • PerformanceDistribution (31-37)
  • StudentTestResult (39-54)
  • QuestionStat (76-86)
🪛 Biome (1.9.4)
src/components/results/teacher/question-stats-table.tsx

[error] 157-157: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)


[error] 236-236: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Unsafe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

src/lib/results-api.ts

[error] 20-96: Avoid classes that contain only static members.

Prefer using simple functions instead of classes with only static members.

(lint/complexity/noStaticOnlyClass)

🔇 Additional comments (9)
src/components/question_creation/question-types/true-false-question.tsx (1)

59-63: Great: added radiogroup semantics

Adding role="radiogroup" + aria-label improves accessibility. 💯

src/components/results/common/types.ts (1)

57-60: questions should be declared as readonly

The DetailedTestResult.questions array is intended to be immutable after construction. Expose it as readonly QuestionResult[] to avoid unintentional in-place mutations from component code.

-  questions: QuestionResult[];
+  readonly questions: ReadonlyArray<QuestionResult>;
src/components/navigation/side-navbar/side-navbar.tsx (1)

63-66: Route rename: ensure legacy links are redirected

The URL was changed from /result to /student-results. Double-check that a redirect (or route alias) exists so existing bookmarks and intra-app deep links do not break.

src/components/results/common/index.ts (1)

1-3: LGTM – unified barrel export

A concise barrel file; improves import ergonomics.

src/components/question_creation/question-editor.tsx (1)

289-291: Prop order change is safe

Only the prop ordering was adjusted; no functional impact.
Good cleanup.

src/components/results/student/index.ts (1)

1-8: Barrel exports: watch for accidental circular deps & tree-shaking issues

Barrel files are convenient but can create hidden cycles when sibling barrels re-export each other (e.g. src/components/results/index.ts importing this file).
Double-check imports with madge --circular (or similar) before merging; otherwise you may hit runtime 404s in Next.js’s app router.

No action required if the graph is clean – just flagging the usual pitfall.

src/components/results/student/course-results-grid.tsx (1)

18-39: Component is lean and well-structured – nothing to flag.

Nice job keeping the render logic minimal, with an empty-state fallback.
CourseCard receives the callbacks without unnecessary prop juggling, and the responsive grid utility classes are on point.

src/components/results/teacher/types.ts (1)

1-86: Type definitions look solid

Interfaces cover the expected teacher-side analytics data and match usage elsewhere.

src/components/results/index.ts (1)

1-41: Barrel exports are tidy

Centralised re-exports reduce import noise and the aliasing avoids clashes – nice.

Comment on lines +72 to +77
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
onCorrectAnswerChange(true);
}
}}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Missing role="radio" & aria-checked on each option

For a complete a11y implementation, each choice needs:

role="radio"
aria-checked={correctAnswer === true}

Likewise for the “False” block. This allows assistive tech to announce state and arrow-key navigation.

Also consider e.key === " "e.key === " " is fine, but e.code === "Space" is more explicit.

🤖 Prompt for AI Agents
In src/components/question_creation/question-types/true-false-question.tsx
around lines 72 to 77, the onKeyDown handler for the true/false options lacks
proper accessibility attributes. Add role="radio" and aria-checked attributes to
each option element, setting aria-checked based on whether the option matches
the current correctAnswer state. Also, update the key check from e.key === " "
to e.code === "Space" for clearer intent and better accessibility support.

Comment on lines +22 to +34
export function getScoreBgColor(percentage: number): string {
if (percentage >= 90)
return "bg-emerald-100 text-emerald-800 border-emerald-300 dark:bg-emerald-950 dark:text-emerald-300";
if (percentage >= 80)
return "bg-green-100 text-green-800 border-green-300 dark:bg-green-950/80 dark:text-green-300";
if (percentage >= 70)
return "bg-lime-100 text-lime-800 border-lime-300 dark:bg-lime-950 dark:text-lime-300";
if (percentage >= 60)
return "bg-yellow-100 text-yellow-800 border-yellow-300 dark:bg-yellow-950 dark:text-yellow-300";
if (percentage >= 50)
return "bg-amber-100 text-amber-800 border-amber-300 dark:bg-amber-950 dark:text-amber-300";
return "bg-red-100 text-red-800 border-red-300 dark:bg-red-950 dark:text-red-300";
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consistent palette between functions

getScoreBgColor returns emerald for ≥90 and green for ≥80, whereas getProgressColor returns green for ≥90 and emerald for ≥80 (lines 40-42). That inversion will yield mismatched badge vs progress colours for the same score.

Align the ranges:

-  if (percentage >= 90) return "bg-green-600";
-  if (percentage >= 80) return "bg-emerald-500";
+  if (percentage >= 90) return "bg-emerald-600";
+  if (percentage >= 80) return "bg-green-500";

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/lib/utils/score-colors.ts between lines 22 and 34, the color ranges in
getScoreBgColor are inconsistent with those in getProgressColor, causing
mismatched badge and progress colors for the same score. Adjust the color
thresholds in getScoreBgColor to match getProgressColor by swapping the emerald
and green color assignments for the ≥90 and ≥80 ranges so both functions use
green for ≥90 and emerald for ≥80.

Comment on lines +24 to +38
timeTaken: number; // in minutes
completedAt: string;
status: "completed" | "in-progress" | "not-started";
}

export interface QuestionResult {
questionId: string;
questionText: string;
questionType: "mcq" | "fillup" | "true-false" | "descriptive" | "coding";
marks: number;
studentAnswer: string | string[] | boolean | Record<string, unknown>;
correctAnswer: string | string[] | boolean | Record<string, unknown>;
isCorrect: boolean;
timeTaken: number;
explanation?: string;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent date / time representations

completedAt is typed as string, whereas dateRange.start / end in the ResultsFilters interface are Date instances. Mixing raw strings and Date objects will quickly lead to runtime coercion bugs and unnecessary parsing in consumers.

-  completedAt: string;
+  completedAt: Date;               // keep all timestamps as Date objects

If serialisation to ISO-8601 is required at the API boundary, convert at that boundary rather than storing as string in the model.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
timeTaken: number; // in minutes
completedAt: string;
status: "completed" | "in-progress" | "not-started";
}
export interface QuestionResult {
questionId: string;
questionText: string;
questionType: "mcq" | "fillup" | "true-false" | "descriptive" | "coding";
marks: number;
studentAnswer: string | string[] | boolean | Record<string, unknown>;
correctAnswer: string | string[] | boolean | Record<string, unknown>;
isCorrect: boolean;
timeTaken: number;
explanation?: string;
timeTaken: number; // in minutes
- completedAt: string;
+ completedAt: Date; // keep all timestamps as Date objects
status: "completed" | "in-progress" | "not-started";
}
export interface QuestionResult {
questionId: string;
questionText: string;
questionType: "mcq" | "fillup" | "true-false" | "descriptive" | "coding";
marks: number;
studentAnswer: string | string[] | boolean | Record<string, unknown>;
correctAnswer: string | string[] | boolean | Record<string, unknown>;
isCorrect: boolean;
timeTaken: number;
explanation?: string;
}
🤖 Prompt for AI Agents
In src/components/results/common/types.ts between lines 24 and 38, the
completedAt field is typed as a string while other date fields like
dateRange.start and end use Date objects, causing inconsistency and potential
runtime errors. Change the type of completedAt from string to Date to maintain
consistent date/time representations across the model. If ISO-8601 string
serialization is needed, perform that conversion only at the API boundary, not
within the model definition.

Comment on lines +4 to +7
export function useRecentTestResults() {
// Return empty data and loading false for now
return useMemo(() => ({ data: [], isLoading: false, isError: false }), []);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Stub hook risks silent UI degradation

Returning an empty dataset with isLoading: false & isError: false can mask integration bugs — components will render “no data” rather than a spinner or error state.
Add a TODO comment and consider throwing in non-prod environments to surface the missing implementation.

 export function useRecentTestResults() {
-  // Return empty data and loading false for now
-  return useMemo(() => ({ data: [], isLoading: false, isError: false }), []);
+  // TODO: Implement real data fetching (e.g. SWR / TanStack Query)
+  if (process.env.NODE_ENV !== "production") {
+    // eslint-disable-next-line no-console
+    console.warn("useRecentTestResults is a stub – replace with real API call");
+  }
+  return useMemo(
+    () => ({ data: [], isLoading: true, isError: false }),
+    []
+  );
 }
🤖 Prompt for AI Agents
In src/repo/student-results/student-results-api.ts around lines 4 to 7, the stub
hook returns empty data with isLoading and isError set to false, which can
silently degrade the UI by showing no data instead of loading or error states.
Add a TODO comment indicating the hook needs proper implementation and modify
the code to throw an error in non-production environments to alert developers
about the missing implementation.

Comment on lines +157 to +161
export function QuestionStatsTable({}: QuestionStatsTableProps) {
const [searchQuery, setSearchQuery] = useState("");
const [sortField, setSortField] = useState<SortField>("questionNumber");
const [sortDirection, setSortDirection] = useState<SortDirection>("asc");

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Empty destructuring pattern breaks lint – remove or use the prop.

Biome flags export function QuestionStatsTable({}: …) as invalid.
Either drop the parameter or keep statistics for later use:

-export function QuestionStatsTable({}: QuestionStatsTableProps) {
+export function QuestionStatsTable({ statistics }: QuestionStatsTableProps) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function QuestionStatsTable({}: QuestionStatsTableProps) {
const [searchQuery, setSearchQuery] = useState("");
const [sortField, setSortField] = useState<SortField>("questionNumber");
const [sortDirection, setSortDirection] = useState<SortDirection>("asc");
export function QuestionStatsTable({ statistics }: QuestionStatsTableProps) {
const [searchQuery, setSearchQuery] = useState("");
const [sortField, setSortField] = useState<SortField>("questionNumber");
const [sortDirection, setSortDirection] = useState<SortDirection>("asc");
🧰 Tools
🪛 Biome (1.9.4)

[error] 157-157: Unexpected empty object pattern.

(lint/correctness/noEmptyPattern)

🤖 Prompt for AI Agents
In src/components/results/teacher/question-stats-table.tsx around lines 157 to
161, the function parameter uses an empty destructuring pattern which breaks
lint rules. Fix this by either removing the empty destructuring entirely if no
props are used or by including the expected prop (e.g., statistics) in the
destructuring if it will be used later.

Comment on lines +200 to +207
export function StudentResultsTable({
onViewStudentResult,
}: StudentResultsTableProps) {
const [searchQuery, setSearchQuery] = useState("");
const [sortField, setSortField] = useState<SortField>("score");
const [sortDirection, setSortDirection] = useState<SortDirection>("desc");

const handleSort = (field: SortField) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

statistics prop unused

statistics is accepted but never referenced. Use it (see above) or drop the prop to avoid dead code and type drift.

🤖 Prompt for AI Agents
In src/components/results/teacher/student-results-table.tsx around lines 200 to
207, the `statistics` prop is declared but never used in the component, leading
to dead code. Either remove the `statistics` prop from the component's props
definition and usage to clean up unused code, or integrate it properly within
the component logic where relevant data or display requires it.

Comment on lines +36 to +199
// Mock data for student results
const mockStudentResults: StudentTestResult[] = [
{
studentId: "1",
studentName: "Alice Johnson",
rollNumber: "CS2021001",
score: 85,
maxScore: 100,
percentage: 85,
timeTaken: 45,
completedAt: "2025-06-15T10:30:00Z",
status: "completed",
attemptCount: 1,
correctAnswers: 17,
wrongAnswers: 2,
unansweredQuestions: 1,
submittedAt: "2025-06-15T10:30:00Z",
},
{
studentId: "2",
studentName: "Bob Smith",
rollNumber: "CS2021002",
score: 92,
maxScore: 100,
percentage: 92,
timeTaken: 38,
completedAt: "2025-06-15T09:45:00Z",
status: "completed",
attemptCount: 1,
correctAnswers: 18,
wrongAnswers: 1,
unansweredQuestions: 1,
submittedAt: "2025-06-15T09:45:00Z",
},
{
studentId: "3",
studentName: "Carol Davis",
rollNumber: "CS2021003",
score: 78,
maxScore: 100,
percentage: 78,
timeTaken: 52,
completedAt: "2025-06-15T11:15:00Z",
status: "completed",
attemptCount: 2,
correctAnswers: 15,
wrongAnswers: 3,
unansweredQuestions: 2,
submittedAt: "2025-06-15T11:15:00Z",
},
{
studentId: "4",
studentName: "David Wilson",
rollNumber: "CS2021004",
score: 95,
maxScore: 100,
percentage: 95,
timeTaken: 42,
completedAt: "2025-06-15T10:00:00Z",
status: "completed",
attemptCount: 1,
correctAnswers: 19,
wrongAnswers: 1,
unansweredQuestions: 0,
submittedAt: "2025-06-15T10:00:00Z",
},
{
studentId: "5",
studentName: "Emma Brown",
rollNumber: "CS2021005",
score: 67,
maxScore: 100,
percentage: 67,
timeTaken: 58,
completedAt: "2025-06-15T12:00:00Z",
status: "completed",
attemptCount: 1,
correctAnswers: 13,
wrongAnswers: 5,
unansweredQuestions: 2,
submittedAt: "2025-06-15T12:00:00Z",
},
{
studentId: "6",
studentName: "Frank Miller",
rollNumber: "CS2021006",
score: 88,
maxScore: 100,
percentage: 88,
timeTaken: 40,
completedAt: "2025-06-15T09:30:00Z",
status: "completed",
attemptCount: 1,
correctAnswers: 17,
wrongAnswers: 2,
unansweredQuestions: 1,
submittedAt: "2025-06-15T09:30:00Z",
},
{
studentId: "7",
studentName: "Grace Lee",
rollNumber: "CS2021007",
score: 73,
maxScore: 100,
percentage: 73,
timeTaken: 48,
completedAt: "2025-06-15T11:45:00Z",
status: "completed",
attemptCount: 1,
correctAnswers: 14,
wrongAnswers: 4,
unansweredQuestions: 2,
submittedAt: "2025-06-15T11:45:00Z",
},
{
studentId: "8",
studentName: "Henry Chen",
rollNumber: "CS2021008",
score: 91,
maxScore: 100,
percentage: 91,
timeTaken: 35,
completedAt: "2025-06-15T08:45:00Z",
status: "completed",
attemptCount: 1,
correctAnswers: 18,
wrongAnswers: 1,
unansweredQuestions: 1,
submittedAt: "2025-06-15T08:45:00Z",
},
{
studentId: "9",
studentName: "Isabella Rodriguez",
rollNumber: "CS2021009",
score: 56,
maxScore: 100,
percentage: 56,
timeTaken: 60,
completedAt: "2025-06-15T13:30:00Z",
status: "completed",
attemptCount: 3,
correctAnswers: 11,
wrongAnswers: 7,
unansweredQuestions: 2,
submittedAt: "2025-06-15T13:30:00Z",
},
{
studentId: "10",
studentName: "Jack Thompson",
rollNumber: "CS2021010",
score: 82,
maxScore: 100,
percentage: 82,
timeTaken: 44,
completedAt: "2025-06-15T10:15:00Z",
status: "completed",
attemptCount: 1,
correctAnswers: 16,
wrongAnswers: 3,
unansweredQuestions: 1,
submittedAt: "2025-06-15T10:15:00Z",
},
];

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Component ships with hard-coded mock data

StudentResultsTable ignores the statistics prop and always renders mockStudentResults, so production pages will never show real data.

Recommended minimal fix:

-const mockStudentResults: StudentTestResult[] = [...]
+// Fallback only when real data isn't supplied
+const fallbackResults: StudentTestResult[] = [...]
 ...
-const filtered = mockStudentResults.filter(
+const source = statistics?.studentResults ?? fallbackResults;
+const filtered = source.filter(

Remove the mock array altogether once the API is wired.

🤖 Prompt for AI Agents
In src/components/results/teacher/student-results-table.tsx between lines 36 and
199, the component currently uses a hard-coded mockStudentResults array instead
of the statistics prop, causing it to ignore real data. To fix this, remove the
mockStudentResults array entirely and update the component to render data from
the statistics prop so that it displays actual student results when the API is
connected.

Comment on lines +118 to +123
export const DetailedTestResultView: React.FC<DetailedTestResultProps> = ({
onBack,
}) => {
// Use mock data for now
const result = mockDetailedTestResult; // No longer needed - imported at the top
const getQuestionIcon = (isCorrect: boolean, questionType: string) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Prop is ignored – component always shows mock data

result from props is shadowed by the local const result = mockDetailedTestResult;, so the view can never display real data. Replace with a defaulted parameter instead of overriding:

-export const DetailedTestResultView: React.FC<DetailedTestResultProps> = ({
-  onBack,
-}) => {
-  // Use mock data for now
-  const result = mockDetailedTestResult; // No longer needed - imported at the top
+export const DetailedTestResultView: React.FC<DetailedTestResultProps> = ({
+  result = mockDetailedTestResult,
+  onBack,
+}) => {

Remove the extra local declaration.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const DetailedTestResultView: React.FC<DetailedTestResultProps> = ({
onBack,
}) => {
// Use mock data for now
const result = mockDetailedTestResult; // No longer needed - imported at the top
const getQuestionIcon = (isCorrect: boolean, questionType: string) => {
export const DetailedTestResultView: React.FC<DetailedTestResultProps> = ({
result = mockDetailedTestResult,
onBack,
}) => {
const getQuestionIcon = (isCorrect: boolean, questionType: string) => {
// …
}
// …
}
🤖 Prompt for AI Agents
In src/components/results/common/detailed-test-result.tsx around lines 118 to
123, the prop 'result' is ignored because it is shadowed by a local constant
assigned to mock data. Remove the local declaration of 'result' and instead
accept 'result' as a prop with a default value of mockDetailedTestResult to
allow real data to be displayed while retaining mock data as fallback.

Comment on lines +167 to +169
setSelectedStudentId(studentId);
setCurrentView("student-detail");
};
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Student-detail view wired, but data never passed

handleViewStudentResult only switches currentView without fetching or supplying the selected student’s detailed result; DetailedTestResultView is rendered with no result prop. Users will therefore see the mock data from the child component.

At minimum, pass the student’s actual result:

const selectedStudent = testStatistics?.studentResults.find(
  s => s.studentId === selectedStudentId
);

{currentView === "student-detail" && selectedStudent && (
  <DetailedTestResultView result={selectedStudent} onBack={handleBack} />
)}

(or fetch fresh data via API).

Without this, the whole drill-down loses integrity.

Also applies to: 567-569

🤖 Prompt for AI Agents
In src/app/(test)/teacher-results/page.tsx around lines 167 to 169, the
handleViewStudentResult function only sets the current view without passing the
selected student's detailed result to DetailedTestResultView, causing it to
render mock data. Fix this by finding the selected student's result from
testStatistics.studentResults using the selectedStudentId and passing it as the
result prop to DetailedTestResultView when rendering the student-detail view.
Apply the same fix around lines 567 to 569.

Comment on lines +1098 to +1117
// Generate mock student results
const studentResults: StudentTestResult[] = Array.from(
{ length: 20 },
(_, i) => {
const score = Math.floor(Math.random() * 60) + 40; // Random score between 40 and 100
return {
studentId: `student-${i + 1}`,
studentName: `Student ${i + 1}`,
score: score,
maxScore: 100,
percentage: score,
timeTaken: Math.floor(Math.random() * 60) + 30, // Random time between 30 and 90 minutes
completedAt: new Date(
Date.now() - Math.floor(Math.random() * 7) * 24 * 60 * 60 * 1000,
).toISOString(),
status: "completed",
attemptCount: Math.floor(Math.random() * 2) + 1, // 1 or 2 attempts
};
},
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Mock data violates StudentTestResult interface

Objects lack mandatory fields (rollNumber, correctAnswers, wrongAnswers, unansweredQuestions, submittedAt). This breaks type safety and will not compile.

        return {
          studentId: `student-${i + 1}`,
          studentName: `Student ${i + 1}`,
+         rollNumber: `RN${(i + 1).toString().padStart(3, "0")}`,
          score: score,
          maxScore: 100,
          percentage: score,
          timeTaken: Math.floor(Math.random() * 60) + 30,
          completedAt: new Date(
            Date.now() - Math.floor(Math.random() * 7) * 86400000,
          ).toISOString(),
+         submittedAt: new Date().toISOString(),
          status: "completed",
          attemptCount: Math.floor(Math.random() * 2) + 1,
+         correctAnswers: Math.round(score / 5),
+         wrongAnswers: 20 - Math.round(score / 5),
+         unansweredQuestions: 0,
        };

Align all mock producers with the declared types to keep the dev build green.

🤖 Prompt for AI Agents
In src/lib/results-api.ts around lines 1098 to 1117, the mock student results
objects are missing required fields from the StudentTestResult interface such as
rollNumber, correctAnswers, wrongAnswers, unansweredQuestions, and submittedAt.
To fix this, add these missing fields to each mock object with appropriate mock
values that match their expected types, ensuring full compliance with the
interface and maintaining type safety.

@Aksaykanthan Aksaykanthan merged commit 24c1382 into evalify:development Jun 16, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants