-
Notifications
You must be signed in to change notification settings - Fork 6
Results page for teacher and students #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Results page for teacher and students #43
Conversation
- 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
WalkthroughThis 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
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
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
Suggested reviewers
Poem
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
npm error Exit handler never called! ✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 16
🔭 Outside diff range comments (1)
src/components/question_creation/question-settings.tsx (1)
136-159:⚠️ Potential issueAccidental 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” optionAdd
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/resultsredirect – deduplicateSee 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-depsAdding
chart.js,react-chartjs-2, andrechartsis fine functionally, but they collectively add >250 kB gzipped to the client bundle.
- Ensure this PR really needs both charting stacks –
react-chartjs-2already wraps Chart.js, whilerechartsis an alternative library.chart.js@4requires that you tree-shake unused controllers and may needimport "chart.js/auto"somewhere—double-check that the wrapper components handle this.- Chart.js lists
canvas@^2as an optional peer for SSR; if you do any server rendering, add it todevDependenciesto 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 formattingPlacing 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 lineDitto 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 JSXSame as above – delete the superfluous whitespace expression.
662-663: Unneeded whitespace nodeRemove the
{" "}after</CardHeader>to keep markup clean.src/lib/utils/score-colors.ts (2)
9-16: Docstring doesn’t match range & negative scores not handledComment 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 < 0or> 100? ConsiderMath.max(0, Math.min(percentage, 100))to clamp unexpected inputs.
39-46: Return type could be narrowedReturning
stringforfeits 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/Difficultyeverywhere.
This keeps the domain vocabulary DRY and centralised.src/components/navigation/side-navbar/side-navbar.tsx (1)
75-79: Visibility of “Teacher Results” menu itemThe new entry is placed under the Administration section, which is already wrapped by
AuthGuardforADMINandMANAGER.
If lecturers (non-admin teaching staff) also need access, this guard will hide the menu item for them; consider whetherUserType.STAFFshould be included.src/components/results/student/student-overview.tsx (2)
5-8: Unused props type alias – simplify the component signature
StudentOverviewCarddoes not consumechildrenor any other props, yet aStudentOverviewCardPropsalias based onReact.PropsWithChildrenis declared and passed toReact.FC.
Drop the alias (or actually acceptchildren) 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 meaningRendering 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:
- Deleting the component until real content lands, or
- 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 utilYou now have two almost-identical redirect pages (
resultsandresults-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 beneverfor clarity
redirect()throws aNEXT_REDIRECTto end execution. Declaring the component return type asnevermakes 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 exportis 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 symmetryGood 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 forlastTestDate.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.getTestResultresolves,setStatewill run on an unmounted component.
Wrapping the request in anAbortController(or a simplelet cancelled = falseguard) 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.
Cardrenders adiv, so keyboard users cannot trigger theonClick.
Either wrap the content in a<button>/<a>or addrole="button" tabIndex={0}withonKeyDown(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 withuseMemo.
filteredAndSortedTestsis rebuilt on every render even whentestsor sort/search state haven’t changed, which is unnecessary work for large datasets. Wrap the calculation inuseMemowith[tests, searchQuery, sortField, sortDirection]as deps.
60-63: Re-think default sort direction for numeric columns.When switching to
totalSubmissionsoraverageScore, 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 waycreatedAtis handled.
145-152: Addtype="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,
errorstays set even after a later successful request because it isn’t cleared here. AddsetError(null)before thetry.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 localaverageScore& memoise calculations.The local variable shadows
course.averageScore, which is confusing. Rename tocomputedAverageScore(or similar) and wrap both the average andrecentTestsderivations inuseMemoto avoid recomputation on every render.src/components/results/teacher/performance-distribution-chart.tsx (2)
146-149: Remove leftoverconsole.logstatements.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 onparseIntwith 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: ExtractgetScoreBadgeColorto 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.
recentTestsis recalculated on every render. Wrap the filter/sort/slice chain inuseMemowith[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 whentestsis unchanged. Wrapping these calculations inuseMemowill 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 insidegetTrendIcon(),getTrendColor(), and directly in JSX, resulting in three identical passes over the data per render. Cache the value withuseMemoand pass it around instead.
168-196: Add accessible label & dynamic scaling to the SVGScreen-reader users get no context for the chart, and very long histories may overflow the fixed
viewBoxheight. 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: Longifchain for colour mapping could be simplifiedA 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
sortedTestsandrecentTestsare recomputed on every render even whentestsis unchanged. Wrap them inuseMemokeyed bytestsandlimitto avoid needless work.src/components/results/student/test-summaries.tsx (1)
226-236: Display placeholder when date is unavailableInside the test list the date cell unconditionally renders
toLocaleDateString(). Show “—” (or similar) whencompletedAtis falsy to avoid confusing “Invalid Date” output.src/app/(test)/teacher-results/page.tsx (1)
56-57: Singleloadingflag causes UI flicker
loadingis 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 namespaceThe class holds only static methods; linter already flags this (
noStaticOnlyClass). Converting to a simple exported object or individual functions avoids unnecessaryclasssemantics.🧰 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
⛔ Files ignored due to path filters (1)
package-lock.jsonis 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 semanticsAdding
role="radiogroup"+aria-labelimproves accessibility. 💯src/components/results/common/types.ts (1)
57-60:questionsshould be declared as readonlyThe
DetailedTestResult.questionsarray is intended to be immutable after construction. Expose it asreadonly 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 redirectedThe URL was changed from
/resultto/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 exportA concise barrel file; improves import ergonomics.
src/components/question_creation/question-editor.tsx (1)
289-291: Prop order change is safeOnly 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 issuesBarrel files are convenient but can create hidden cycles when sibling barrels re-export each other (e.g.
src/components/results/index.tsimporting this file).
Double-check imports withmadge --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.
CourseCardreceives 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 solidInterfaces cover the expected teacher-side analytics data and match usage elsewhere.
src/components/results/index.ts (1)
1-41: Barrel exports are tidyCentralised re-exports reduce import noise and the aliasing avoids clashes – nice.
| onKeyDown={(e) => { | ||
| if (e.key === "Enter" || e.key === " ") { | ||
| e.preventDefault(); | ||
| onCorrectAnswerChange(true); | ||
| } | ||
| }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ 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.
| 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"; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ 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 objectsIf 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.
| 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.
| export function useRecentTestResults() { | ||
| // Return empty data and loading false for now | ||
| return useMemo(() => ({ data: [], isLoading: false, isError: false }), []); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| export function QuestionStatsTable({}: QuestionStatsTableProps) { | ||
| const [searchQuery, setSearchQuery] = useState(""); | ||
| const [sortField, setSortField] = useState<SortField>("questionNumber"); | ||
| const [sortDirection, setSortDirection] = useState<SortDirection>("asc"); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| 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) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ 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.
| // 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", | ||
| }, | ||
| ]; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| setSelectedStudentId(studentId); | ||
| setCurrentView("student-detail"); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| // 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 | ||
| }; | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Summary by CodeRabbit
New Features
Bug Fixes
Style
Chores