Skip to content

E2602 - Reimplement frontend of student task view#182

Open
bestinlalu wants to merge 2 commits into
expertiza:mainfrom
bestinlalu:main
Open

E2602 - Reimplement frontend of student task view#182
bestinlalu wants to merge 2 commits into
expertiza:mainfrom
bestinlalu:main

Conversation

@bestinlalu

@bestinlalu bestinlalu commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Convert ReviewTable.scss to CSS Modules (ViewTeamGrades.module.scss) and fix Bootstrap p-4 class name collision
  • Replace multi-step API waterfall with a single GET /grades/:id/view_our_scores call
  • Redesign score heatgrid to match FeedbackTable layout — sticky columns, horizontal scroll, no toggle
  • Add Scores / Feedback view toggle with a dynamic round dropdown selector
  • Add SectionHeader support — section headings render as full-width rows in both tables
  • Rename utils.ts → heatgridUtils.ts; delete unused Data/ folder
  • Add comments to all changed files in ViewTeamGrades/ and StudentTasks/
  • Rewrite StudentTasks.tsx as a full assignments dashboard grouped by course
  • Align StudentTasks table row colours with the scores heatgrid colour scheme

Changes

src/pages/ViewTeamGrades/ViewTeamGrades.module.scss (renamed from ReviewTable.module.scss)

  • Converted from a side-effect import to a proper CSS Module (import styles from "./ViewTeamGrades.module.scss").
  • Renamed .p-4 to .page-wrapper to prevent Bootstrap's p-4 utility class (which applies padding: 1.5rem !important) from being shadowed.
  • Wrapped colour classes (c0–c5, cf) and ShowReviews classes in :global {} so they keep their original names after hashing and can be used as plain strings by getColorClass().
  • Removed dead rules: .has-prompt, .item-prompt-header, .item-prompt-cell, tooltip rules.

src/css-modules.d.ts

  • Added declare module "*.module.scss" with a proper typed export.
  • Removed the blanket declare module ".scss" and declare module ".css" hacks that suppressed missing-file TypeScript errors.

src/pages/ViewTeamGrades/ReviewTable.tsx

  • Single API call: replaced a 6-step waterfall (view_our_scores → participants/user/:id → teams_participants/:id/list_participants → users/:id per member) with a single GET /grades/:id/view_our_scores. Team metadata (team_name, grade, comment, submission_links, members) is now embedded in the response by the backend.
  • Scores / Feedback toggle: added a viewMode state ('scores' | 'feedback') driving a button group. "Scores" renders the colour-coded heatgrid per round; "Feedback" renders FeedbackTable.
  • Score heatgrid layout: mirrors FeedbackTable exactly — borderCollapse: "separate", borderSpacing: 0, sticky # column (52 px) and Question column (340 px), horizontally scrollable reviewer columns (110 px each), width: "max-content" to prevent columns stretching when fewer reviewers are present.
  • Section headers: when a round array contains a { type: "header" } sentinel, a full-width is rendered with white background and #986633 bold text (matching the StudentTasks page heading colour), position: relative, zIndex: 4 so it sits above body sticky cells and is not overlaid by them.
  • Average peer review score chip: displayed as an inline pill below each round table.
  • Removed: showToggleQuestion checkbox, ShowAuthorFeedback, fetchTeamMetadata waterfall, getAuthToken/jwtDecode.

src/pages/ViewTeamGrades/ReviewTableRow.tsx

  • Full rewrite to match FeedbackTable row structure: sticky # cell (52 px), sticky Question cell (340 px), scrollable colour-coded reviewer cells (110 px).
  • Alternating row background (#fff / #f5f5f5) with explicit background on sticky cells to prevent scroll bleed-through (required by borderCollapse: "separate").
  • No truncation — full itemText and full textResponse are displayed.

src/pages/ViewTeamGrades/heatgridUtils.ts

  • Renamed from utils.ts
  • Added RoundRow = ReviewData | SectionHeaderData type alias and isHeader() type guard.
  • normalizeReviewDataArray: passes SectionHeaderData sentinels through unchanged.
  • convertBackendRoundArray: detects { type: "header" } objects and returns them as SectionHeaderData instead of attempting to build ReviewData from them.
  • calculateAverages: filters out header sentinels before computing numeric averages; re-inserts headers at their original positions in sortedData for asc/desc sort modes.

src/pages/ViewTeamGrades/FeedbackTable.tsx

  • Imports RoundRow and isHeader from heatgridUtils to handle mixed arrays of ReviewData and SectionHeaderData.
  • RoundFeedbackTable finds the first non-header row to determine reviewer count, rather than relying on roundData[0] which may be a header sentinel.
  • Section header sentinels rendered as full-width rows with the same white background / #986633 bold text treatment as the scores table.
  • width: "max-content" added to prevent feedback columns from stretching.
  • borderCollapse: "separate", borderSpacing: 0 for sticky column scroll bleed prevention.
  • Heading changed from h4 (Round 1 / Round 2) to h2 with "Review (Round: X of Y)" format matching the scores table.

src/pages/ViewTeamGrades/App.tsx

  • Added SectionHeaderData exported interface ({ type: "header"; txt: string }).

src/pages/ViewTeamGrades/Statistics.tsx

  • Filters out SectionHeaderData sentinels before accessing ReviewData-only fields (RowAvg).

src/pages/StudentTasks/StudentTasks.tsx

  • Rewrote from a topic sign-up sheet to a full assignments dashboard.
  • Single GET /student_tasks/list call; parseStudentTasks() normalises the raw API response into typed Task[].
  • Assignments grouped by course name with tasksGroupedByCourse.
  • extractAssignments() converts Task[] to Revision[] for the sidebar.

src/pages/StudentTasks/StudentTasksList.tsx

  • Sidebar showing tasks not yet started, revisions, and teammates grouped by course.
  • Teammates fetched via GET /student_tasks/team.

src/pages/StudentTasks/StudentTaskDetail.tsx

  • Per-assignment detail page with dual data sources (router state + API).
  • Due-dates timeline with step-based progress bar; date parsing handles both ISO and dd-mm-yyyy formats.
  • "Your feedbacks" link navigates to /view-team-grades?assignmentId=X.

src/pages/StudentTasks/StudentTasks.module.css

  • Table row colours aligned with the scores heatgrid: odd rows #fff, even rows #f5f5f5, header #f0f0f0.

src/pages/ViewTeamGrades/RoundSelector.tsx

  • Replaced static buttons with a dropdown, height 36 px to match the Scores/Feedback toggle.
  • Options generated dynamically.

Frontend View:

image image image image

Summary by CodeRabbit

Release Notes

  • New Features
    • Added a Student Task Detail page with submission/review timeline and deadline links.
    • Redesigned “My Assignments” into course-grouped task tables with improved “Show as Example?” behavior.
    • Added a Scores/Feedback toggle and a new FeedbackTable layout in View Team Grades.
  • Enhancements
    • Improved table filtering behavior, including global/column filter visibility and per-column header tooltips.
    • Refined View Team Grades heatmap styling, sticky headers, and question/response display.
  • Bug Fixes
    • Pagination and timeline progress now reflect filtered results more accurately.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@bestinlalu, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 50 minutes and 58 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5306b966-1054-4e9b-a53a-96694246137e

📥 Commits

Reviewing files that changed from the base of the PR and between 162d8a8 and f9e5049.

📒 Files selected for processing (10)
  • src/pages/StudentTasks/StudentTaskDetail.module.css
  • src/pages/StudentTasks/StudentTaskDetail.tsx
  • src/pages/StudentTasks/StudentTasks.module.css
  • src/pages/StudentTasks/StudentTasks.tsx
  • src/pages/StudentTasks/StudentTasksList.tsx
  • src/pages/ViewTeamGrades/FeedbackTable.tsx
  • src/pages/ViewTeamGrades/ReviewTable.tsx
  • src/pages/ViewTeamGrades/ReviewTableRow.tsx
  • src/pages/ViewTeamGrades/ViewTeamGrades.module.scss
  • src/pages/ViewTeamGrades/heatgridUtils.ts
📝 Walkthrough

Walkthrough

The PR adds a Student Tasks dashboard that replaces the topic-signup-sheet workflow with a /student_tasks/list-driven assignments view grouped by course, a new StudentTaskDetail page with a visual due-date timeline, and a StudentTasksList sidebar. In parallel, ViewTeamGrades is refactored to fetch from a single endpoint, adds a FeedbackTable component, and extends the heatgrid pipeline to support sentinel section-header rows.

Changes

Student Tasks Dashboard and Detail Page

Layer / File(s) Summary
Shared utilities, routing, Table, and CSS module types
src/utils/dataFormatter.ts, src/css-modules.d.ts, src/components/Table/Table.tsx, src/App.tsx
Adds capitalizeFirstWord/formatDate utilities, extends CSS module typings with .module.scss, updates TableProps (fluid, headingComments, removes onRowClick), fixes pagination count to use pre-filter row model, and registers the student_task_detail/:id protected route.
StudentTasksList sidebar
src/pages/StudentTasks/StudentTasksList.tsx, src/pages/StudentTasks/StudentTasksList.module.css
Adds the Revision type and StudentTasksList component. Fetches teammate groups from /student_tasks/team and renders three sidebar sections: not-started tasks, revision tasks with days-remaining, and course-grouped teammate counts.
StudentTasks dashboard rewrite
src/pages/StudentTasks/StudentTasks.tsx, src/pages/StudentTasks/StudentTasks.module.css
Replaces the topic-signup-sheet with a /student_tasks/list-driven dashboard. Introduces parseStudentTasks, extractAssignments, per-row toggleShowAsExample optimistic state, dynamic TanStack columns with badge/tooltip/detail links, and per-course Table rendering.
StudentTaskDetail page with timeline
src/pages/StudentTasks/StudentTaskDetail.tsx, src/pages/StudentTasks/StudentTaskDetail.module.css
New page that fetches from /student_tasks/show/:id, normalizes legacy date formats, classifies each due-date node as completed/current/pending, computes progressPercent, and renders a 3-row visual timeline with gradient track and deadline links.

ViewTeamGrades Heatgrid and FeedbackTable Refactor

Layer / File(s) Summary
SectionHeaderData type, RoundRow union, and heatgridUtils sentinel support
src/pages/ViewTeamGrades/App.tsx, src/pages/ViewTeamGrades/heatgridUtils.ts
Adds SectionHeaderData interface and optional name to ReviewData.reviews[]. Introduces RoundRow union, isHeader type-guard, and updates normalizeReviewDataArray, convertBackendRoundArray, calculateAverages, and sort logic to pass header sentinels through without affecting scored-item numbering or averages.
FeedbackTable new component
src/pages/ViewTeamGrades/FeedbackTable.tsx
Adds a horizontally scrollable feedback table with sticky #/Question columns. Renders sentinel header rows via isHeader with colspan, alternating row backgrounds, and per-reviewer cells for score+comment, text, selections, option, file, or placeholder. The FeedbackTable wrapper reads Redux auth state and filters rounds by roundSelected.
ReviewTableRow heatgrid rewrite and RoundSelector dropdown
src/pages/ViewTeamGrades/ReviewTableRow.tsx, src/pages/ViewTeamGrades/RoundSelector.tsx
Rewrites ReviewTableRow to sticky inline styles, removes showToggleQuestion, renders per-reviewer cells with getColorClass and onReviewClick, and replaces weight-circle with a maxScore badge. Converts RoundSelector from a button row to a styled native <select> with dynamic round options.
ReviewTable single-endpoint refactor with Scores/Feedback toggle
src/pages/ViewTeamGrades/ReviewTable.tsx
Rewrites data fetching to a single /grades/:id/view_our_scores request embedding team metadata, rounds, and average final score. Adds viewMode state, rewrites renderTable as a sticky heatgrid with sentinel handling and student reviewer anonymization, and adds a button-group toggle between scores heatgrid and FeedbackTable.
SCSS scoping, import fixes, test/fixture removal
src/pages/ViewTeamGrades/ViewTeamGrades.module.scss, src/pages/ViewTeamGrades/ShowReviews.tsx, src/pages/ViewTeamGrades/Statistics.tsx, src/pages/ReviewTableau/ScoreWidgets.tsx, src/pages/ViewTeamGrades/Data/*
Moves heatgrid color classes and review UI classes into :global SCSS blocks, renames .p-4 to .page-wrapper, adjusts tooltip z-index/positioning. Redirects getColorClass imports to heatgridUtils across consumers. Updates ShowReviews Review interface and Statistics sentinel filter. Removes dummy JSON data files.

Sequence Diagram(s)

sequenceDiagram
  participant Browser as Student Browser
  participant StudentTasks
  participant StudentTaskDetail
  participant axiosClient
  participant API as Backend API

  Browser->>StudentTasks: navigate /student_tasks
  StudentTasks->>axiosClient: GET /student_tasks/list
  axiosClient->>API: HTTP GET
  API-->>axiosClient: raw task list
  axiosClient-->>StudentTasks: response.data
  StudentTasks->>StudentTasks: parseStudentTasks() → Task[]
  StudentTasks->>StudentTasks: extractAssignments() → Revision[]
  StudentTasks-->>Browser: render per-course Table + StudentTasksList sidebar

  Browser->>StudentTaskDetail: click assignment link → /student_task_detail/:id
  StudentTaskDetail->>axiosClient: GET /student_tasks/show/:id
  axiosClient->>API: HTTP GET
  API-->>axiosClient: TaskData (due_dates, current_stage)
  axiosClient-->>StudentTaskDetail: response.data
  StudentTaskDetail->>StudentTaskDetail: normalize dates, getStageStatus, progressPercent
  StudentTaskDetail-->>Browser: render timeline + nav/footer links
Loading
sequenceDiagram
  participant Browser as Student Browser
  participant ReviewTable
  participant axiosClient
  participant API as /grades/:id/view_our_scores
  participant FeedbackTable
  participant renderTable as renderTable heatgrid

  Browser->>ReviewTable: navigate /view-team-grades
  ReviewTable->>axiosClient: GET /grades/:id/view_our_scores
  axiosClient->>API: HTTP GET
  API-->>axiosClient: rounds + team_members + averageFinalScore
  axiosClient-->>ReviewTable: response.data
  ReviewTable->>ReviewTable: convertBackendRoundArray → RoundRow[][]

  alt viewMode scores
    ReviewTable->>renderTable: render sticky heatgrid (sentinels + reviewer anonymization)
    renderTable-->>Browser: scores heatgrid
  else viewMode feedback
    ReviewTable->>FeedbackTable: pass roundsData + roundSelected
    FeedbackTable-->>Browser: feedback table
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 Hippity-hop, new pages appear,
A timeline blooms with each due date near,
The heatgrid now passes its headers right through,
Sentinel rows standing proud in the queue.
One endpoint to rule all the grades in one call—
This rabbit is pleased with the changes, y'all! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'E2602 - Reimplement frontend of student task view' directly corresponds to the main objective of reimplementing the StudentTasks and ViewTeamGrades components. The title is clear, concise, and accurately summarizes the primary change.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 18

🧹 Nitpick comments (1)
src/pages/ViewTeamGrades/ReviewTableRow.tsx (1)

73-99: 💤 Low value

Move cellContent declaration inside the map callback.

The cellContent variable is declared at line 76 outside the map() but only used within each iteration. Moving it inside the callback improves readability and prevents potential bugs if the code is modified later.

♻️ Suggested refactor
 const ReviewTableRow: React.FC<ReviewTableRowProps> = ({ row, rowIndex, onReviewClick }) => {
   const bg = rowIndex % 2 === 0 ? "`#fff`" : "`#f5f5f5`";

-  let cellContent;
-  // The score cells — build one per reviewer
   const reviewCells = row.reviews.map((review, idx) => {
     let bgClass = 'cf';
+    let cellContent;

     if (review.score !== undefined) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/ViewTeamGrades/ReviewTableRow.tsx` around lines 73 - 99, The
cellContent variable is declared outside the reviewCells map callback but is
only used and reassigned within each iteration. Move the let cellContent
declaration from line 76 (before the row.reviews.map call) to inside the map
callback function body, placing it at the start of the callback. This ensures
cellContent is properly scoped to each iteration and prevents potential bugs
from variable reuse across iterations.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Table/Table.tsx`:
- Line 213: The ToolTip component on line 213 is being rendered with an empty id
attribute, which causes duplicate ids and breaks tooltip/ARIA associations.
Generate a unique identifier for each header cell (based on the column key,
index, or header name) and pass this unique value to the ToolTip's id prop
instead of the empty string, ensuring each tooltip instance has a distinct id.
- Around line 183-187: Replace the `<span>` element containing the global filter
toggle with a semantic `<button>` element. The button should maintain the same
onClick handler (toggleGlobalFilter), style attribute with marginLeft, and the
conditional text render logic with the FaSearch icon. This will make the toggle
keyboard accessible while preserving the existing functionality.

In `@src/pages/ReviewTableau/ScoreWidgets.tsx`:
- Line 2: Import the ViewTeamGrades.module.scss stylesheet in ScoreWidgets.tsx
to ensure that the CSS classes used by the ScoreWidgets component (grade-circle,
underlined, circle-container, weight-circle, circle, tick, and color classes c0
through c5 and cf) are available at runtime when rendered on the ReviewTableau
path.

In `@src/pages/StudentTasks/StudentTaskDetail.tsx`:
- Around line 175-177: The Link component in StudentTaskDetail.tsx is currently
pointing to a placeholder route `/program/{id}` that is not registered in the
application's router configuration in App.tsx, causing users to hit NotFound
pages. Replace this placeholder route and any similar ones (also found in the
range 192-199) with the actual registered routes from App.tsx that should handle
program or assignment details. Ensure the route path and any id parameters are
correctly passed to match the actual route definitions in your router
configuration.
- Line 185: The route path in the `to` prop at line 185 contains a typo where it
uses the plural form `email_the_authors` instead of the singular form that
matches the registered route. Update the `to` prop value from
`/email_the_authors/` to `/email_the_author/` to match the actual registered
route name.
- Around line 102-106: The date normalization logic in the conditional block
that processes legacy date formats is appending 'Z' to the safeDateString
variable, which forces the timestamp to be treated as UTC time. This causes
deadline shifts if the backend is providing local wall-clock times rather than
UTC times. Remove the 'Z' from the end of the safeDateString assignment where
the date is being reconstructed from year, month, day, and timePart components
so that the timestamp is treated as local time instead of UTC.
- Around line 97-116: The due_dates array returned from the useMemo hook needs
to be sorted by date before being returned, as timeline node states and
progressPercent calculations depend on ordered deadlines. After the map function
that transforms the API data, add a sort step to order the due dates
chronologically based on the date field, ensuring the array is sorted by the ISO
date string in ascending order before returning it.

In `@src/pages/StudentTasks/StudentTasks.tsx`:
- Around line 115-116: The dueDate property mapping for task.stageDeadline is
truncating the full timestamp to only the date portion using split("T")[0],
which removes time and timezone information needed for accurate "days left"
calculations that cause off-by-one errors in the sidebar. Remove the
split("T")[0] truncation operation and pass the complete task.stageDeadline
value directly to the dueDate property, preserving the full timestamp for
correct countdown math.
- Line 216: The div element with className="assignments-page" on line 216 is
using a literal string instead of the CSS module reference. Change the className
from the literal string "assignments-page" to reference the imported styles
object using either styles['assignments-page'] or styles.assignments-page, to
match the pattern used for other elements in the same component like
styles['assignments-title'] and styles.pageLayout.
- Around line 91-92: The assignmentId field in the Task type is defined as a
required number but the code at line 91 assigns null as a fallback value (from
participant.parent_id ?? item.assignment_id ?? null), creating a type mismatch.
Update the Task type definition to allow assignmentId to be number | null
instead of just number to properly reflect that this field can legitimately be
null, ensuring type safety is maintained throughout the codebase including where
this value is passed to route state at line 145.

In `@src/pages/StudentTasks/StudentTasksList.module.css`:
- Around line 95-104: In the .badge CSS class, remove the duplicate and invalid
padding declaration on line 103 (padding: 1). The valid padding rule is already
defined earlier on line 95 as padding: 0.25em 0.4em, which uses proper CSS
units. The unitless padding: 1 value is invalid and causes duplication, so
simply delete that entire line to resolve the stylelint warning.

In `@src/pages/ViewTeamGrades/FeedbackTable.tsx`:
- Around line 258-263: The selector equality function in the FeedbackTable
component only compares the isAuthenticated field, but the component also
depends on auth.user.role to determine isStudent for masking reviewer identity.
Update the equality comparison function to also check if the role has changed by
comparing prev.user.role with next.user.role, ensuring the selector properly
memoizes when either authentication status or user role changes, preventing
stale role-based anonymization logic.
- Around line 271-274: The filtering logic in FeedbackTable.tsx only handles
hardcoded conditions for roundSelected values 1 and 2, causing any higher round
selections to bypass filtering entirely. Generalize the filtering by replacing
the two specific if conditions with a single general condition that checks
whether roundSelected (when not equal to -1 for "all") matches the current
roundIndex, ensuring that only the selected round is displayed regardless of
which round number is selected.

In `@src/pages/ViewTeamGrades/ReviewTable.tsx`:
- Around line 94-97: The useEffect hook is missing assignmentId in its
dependency array despite using it in the fetchBackend call. When assignmentId
changes during navigation, the effect won't re-run because the dependency array
is empty. Add assignmentId to the dependency array of the useEffect hook so that
the effect re-runs whenever assignmentId changes and fetches the correct data.

In `@src/pages/ViewTeamGrades/Statistics.tsx`:
- Around line 3-4: The styles import from ViewTeamGrades.module.scss is not
being utilized in the Statistics component. Either remove the unused styles
import statement, or if the tbl_heat class name (used in the table around line
40) should reference the styles module, update the class reference from the
plain string "tbl_heat" to styles.tbl_heat to properly use the imported SCSS
module.

In `@src/pages/ViewTeamGrades/ViewTeamGrades.module.scss`:
- Around line 89-90: Resolve the stylelint errors in ViewTeamGrades.module.scss
by addressing two issues: first, fix the `:global` pseudo-class syntax error
around line 89-90 (and line 184 and 329-330 as noted) by either wrapping the
selector properly as `:global(.className)` or adding a stylelint disable comment
if intentional; second, locate and replace the deprecated `word-wrap` property
with `overflow-wrap` throughout the file to resolve the deprecation warning.
Verify that all three locations mentioned in the comment have been corrected and
that stylelint no longer reports blocking errors.

In `@src/utils/dataFormatter.ts`:
- Around line 7-8: The capitalizeFirstWord function does not guard against null
or undefined input values, which will cause a runtime error when charAt() is
called on a nullish parameter. Add a guard clause at the beginning of the
capitalizeFirstWord function to check if the str parameter is null or undefined,
and return a safe default value (such as an empty string) in those cases before
proceeding with the charAt(0) and slice operations.
- Around line 17-27: The formatDate function returns "Invalid Date" string from
toLocaleString when given an invalid date, which is truthy and prevents
downstream fallback logic (like || "No deadline") from executing. Add a
validation check after creating the Date object to verify if the date is valid
using isNaN(date.getTime()). If the date is invalid, return an empty string
instead of calling toLocaleString, so that downstream null-coalescing or OR
operators can properly trigger their fallback values.

---

Nitpick comments:
In `@src/pages/ViewTeamGrades/ReviewTableRow.tsx`:
- Around line 73-99: The cellContent variable is declared outside the
reviewCells map callback but is only used and reassigned within each iteration.
Move the let cellContent declaration from line 76 (before the row.reviews.map
call) to inside the map callback function body, placing it at the start of the
callback. This ensures cellContent is properly scoped to each iteration and
prevents potential bugs from variable reuse across iterations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6e3c9340-5aeb-4f4f-95b5-b4c529a4f045

📥 Commits

Reviewing files that changed from the base of the PR and between 474e9f7 and 9b4f62b.

📒 Files selected for processing (28)
  • src/App.tsx
  • src/components/Table/Table.tsx
  • src/css-modules.d.ts
  • src/pages/ReviewTableau/ScoreWidgets.tsx
  • src/pages/StudentTasks/StudentTaskDetail.module.css
  • src/pages/StudentTasks/StudentTaskDetail.tsx
  • src/pages/StudentTasks/StudentTasks.module.css
  • src/pages/StudentTasks/StudentTasks.tsx
  • src/pages/StudentTasks/StudentTasksList.module.css
  • src/pages/StudentTasks/StudentTasksList.tsx
  • src/pages/ViewTeamGrades/App.tsx
  • src/pages/ViewTeamGrades/Data/authorFeedback.json
  • src/pages/ViewTeamGrades/Data/dummyData.json
  • src/pages/ViewTeamGrades/Data/heatMapData.json
  • src/pages/ViewTeamGrades/Data/teammateData.json
  • src/pages/ViewTeamGrades/FeedbackTable.tsx
  • src/pages/ViewTeamGrades/ReviewTable.tsx
  • src/pages/ViewTeamGrades/ReviewTableRow.tsx
  • src/pages/ViewTeamGrades/RoundSelector.tsx
  • src/pages/ViewTeamGrades/ShowReviews.tsx
  • src/pages/ViewTeamGrades/Statistics.tsx
  • src/pages/ViewTeamGrades/ViewTeamGrades.module.scss
  • src/pages/ViewTeamGrades/__tests__/ReviewTable.test.tsx
  • src/pages/ViewTeamGrades/__tests__/ReviewTableRow.test.tsx
  • src/pages/ViewTeamGrades/__tests__/ShowReviews.test.tsx
  • src/pages/ViewTeamGrades/__tests__/utils.test.ts
  • src/pages/ViewTeamGrades/heatgridUtils.ts
  • src/utils/dataFormatter.ts
💤 Files with no reviewable changes (8)
  • src/pages/ViewTeamGrades/Data/teammateData.json
  • src/pages/ViewTeamGrades/tests/ReviewTable.test.tsx
  • src/pages/ViewTeamGrades/tests/ReviewTableRow.test.tsx
  • src/pages/ViewTeamGrades/Data/dummyData.json
  • src/pages/ViewTeamGrades/tests/utils.test.ts
  • src/pages/ViewTeamGrades/tests/ShowReviews.test.tsx
  • src/pages/ViewTeamGrades/Data/heatMapData.json
  • src/pages/ViewTeamGrades/Data/authorFeedback.json

Comment on lines +183 to +187
<span style={{ marginLeft: "5px" }} onClick={toggleGlobalFilter}>
<FaSearch style={{ cursor: "pointer" }} />
{isGlobalFilterVisible ? " Hide" : " Show"}
</span>*/}
</Row>
</Container>
)}
<Container>
<Row style={{ flex: 1 }}>
</span>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a semantic button for the global-search toggle.

The clickable <span> is not keyboard accessible, so keyboard-only users cannot toggle global search.

Proposed fix
-          {!disableGlobalFilter && (
-            <span style={{ marginLeft: "5px" }} onClick={toggleGlobalFilter}>
-              <FaSearch style={{ cursor: "pointer" }} />
-              {isGlobalFilterVisible ? " Hide" : " Show"}
-            </span>
-          )}
+          {!disableGlobalFilter && (
+            <button
+              type="button"
+              className="btn btn-link p-0 ms-1"
+              onClick={toggleGlobalFilter}
+              aria-expanded={isGlobalFilterVisible}
+              aria-label={`${isGlobalFilterVisible ? "Hide" : "Show"} global search`}
+            >
+              <FaSearch aria-hidden="true" />
+              {isGlobalFilterVisible ? " Hide" : " Show"}
+            </button>
+          )}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Table/Table.tsx` around lines 183 - 187, Replace the `<span>`
element containing the global filter toggle with a semantic `<button>` element.
The button should maintain the same onClick handler (toggleGlobalFilter), style
attribute with marginLeft, and the conditional text render logic with the
FaSearch icon. This will make the toggle keyboard accessible while preserving
the existing functionality.

}}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{comment && <ToolTip id="" info={comment} />}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Pass a unique tooltip id per header cell.

Using id="" for every tooltip duplicates ids and can break tooltip/ARIA associations.

Proposed fix
-                                {comment && <ToolTip id="" info={comment} />}
+                                {comment && <ToolTip id={header.id} info={comment} />}
📝 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
{comment && <ToolTip id="" info={comment} />}
{comment && <ToolTip id={header.id} info={comment} />}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Table/Table.tsx` at line 213, The ToolTip component on line
213 is being rendered with an empty id attribute, which causes duplicate ids and
breaks tooltip/ARIA associations. Generate a unique identifier for each header
cell (based on the column key, index, or header name) and pass this unique value
to the ToolTip's id prop instead of the empty string, ensuring each tooltip
instance has a distinct id.

@@ -1,7 +1,6 @@
import React from 'react';
import { getColorClass } from '../ViewTeamGrades/utils';
import { getColorClass } from '../ViewTeamGrades/heatgridUtils';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locate class definitions =="
rg -n --type=scss -C2 '\.(grade-circle|underlined|circle-container|weight-circle|circle|tick|c0|c1|c2|c3|c4|c5|cf)\b'

echo
echo "== Locate SCSS imports on ReviewTableau path =="
rg -n --type=tsx -C3 'import .*\.s?css' src/pages/ReviewTableau

echo
echo "== Locate module/global style imports that could provide these classes =="
rg -n --type=tsx -C3 'ViewTeamGrades.*(module\.scss|grades\.scss)' src

echo
echo "== Confirm ScoreWidgets class usage =="
rg -n --type=tsx -C2 'grade-circle|underlined|circle-container|weight-circle|tick|getColorClass' src/pages/ReviewTableau/ScoreWidgets.tsx

Repository: expertiza/reimplementation-front-end

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Find SCSS files in the repo =="
fd -e scss | head -20

echo
echo "== Find CSS files in the repo =="
fd -e css | head -20

echo
echo "== Check what's exported from heatgridUtils =="
cat -n src/pages/ViewTeamGrades/heatgridUtils.ts 2>/dev/null | head -50

echo
echo "== Check imports and class usage in ScoreWidgets =="
cat -n src/pages/ReviewTableau/ScoreWidgets.tsx

Repository: expertiza/reimplementation-front-end

Length of output: 6306


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Search for getColorClass definition in heatgridUtils =="
rg -n 'getColorClass' src/pages/ViewTeamGrades/heatgridUtils.ts

echo
echo "== Check full heatgridUtils file =="
wc -l src/pages/ViewTeamGrades/heatgridUtils.ts
tail -100 src/pages/ViewTeamGrades/heatgridUtils.ts

echo
echo "== Search for getColorClass anywhere in the codebase =="
rg -n 'getColorClass' src

echo
echo "== Search for grade-circle class definition =="
rg -n 'grade-circle' src --type=scss
rg -n 'grade-circle' src --type=css

echo
echo "== Check ViewTeamGrades.module.scss =="
cat -n src/pages/ViewTeamGrades/ViewTeamGrades.module.scss

echo
echo "== Check ReviewTableau.scss =="
cat -n src/pages/ReviewTableau/ReviewTableau.scss

echo
echo "== Check if ReviewTableau imports the SCSS =="
rg -n 'import' src/pages/ReviewTableau/ReviewTableau.tsx | head -20

Repository: expertiza/reimplementation-front-end

Length of output: 5437


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Full ViewTeamGrades.module.scss =="
cat -n src/pages/ViewTeamGrades/ViewTeamGrades.module.scss

echo
echo "== Full ReviewTableau.scss =="
cat -n src/pages/ReviewTableau/ReviewTableau.scss

echo
echo "== Search for color classes c1-c5, cf =="
rg -n '\bc[0-5]\b|cf' src/pages/ViewTeamGrades/ViewTeamGrades.module.scss

echo
echo "== Search for grade-circle, underlined, weight-circle, circle, tick =="
rg -n 'grade-circle|underlined|weight-circle|^.*circle|^.*tick' src/pages/ViewTeamGrades/ViewTeamGrades.module.scss

echo
echo "== Check ReviewTableau.tsx imports =="
cat -n src/pages/ReviewTableau/ReviewTableau.tsx | head -50

Repository: expertiza/reimplementation-front-end

Length of output: 20932


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Verify if ReviewTableau.tsx imports ViewTeamGrades styles =="
rg -n 'ViewTeamGrades' src/pages/ReviewTableau/ReviewTableau.tsx

echo
echo "== Check if there's a global stylesheet import that loads ViewTeamGrades styles =="
rg -n 'ViewTeamGrades.module.scss|import.*scss' src/pages/ReviewTableau

echo
echo "== Check main App or index files for global style imports =="
rg -n 'ViewTeamGrades.module.scss' src

echo
echo "== Check if custom.scss (global stylesheet) imports ViewTeamGrades styles =="
cat -n src/custom.scss | head -50

echo
echo "== Check App.tsx for stylesheet imports =="
fd -n 'App.tsx' -x cat -n {} | head -30

Repository: expertiza/reimplementation-front-end

Length of output: 144


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Full custom.scss content =="
cat -n src/custom.scss

echo
echo "== Find and check index files =="
fd -n 'index.tsx\|index.ts' src | head -5 | xargs -I {} sh -c 'echo "=== {} ===" && head -30 {}'

echo
echo "== Check main App.tsx or entry point =="
rg -n 'import.*module.scss|import.*custom.scss|import.*ViewTeamGrades' src/index.tsx src/App.tsx 2>/dev/null || echo "No matches found"

echo
echo "== List all SCSS/CSS imports at repository entry point =="
grep -n 'import.*\.\(scss\|css\)' src/index.tsx src/App.tsx 2>/dev/null || echo "No direct stylesheet imports"

echo
echo "== Confirm which files import ReviewTableau.scss =="
rg -n 'ReviewTableau.scss' src

Repository: expertiza/reimplementation-front-end

Length of output: 5186


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check index.tsx/index.ts entry points =="
find src -maxdepth 1 -name 'index.*' -exec cat -n {} \;

echo
echo "== Check App.tsx for stylesheet imports =="
find src -maxdepth 1 -name 'App.tsx' -exec cat -n {} \;

echo
echo "== Verify ReviewTableau.scss is actually imported in ReviewTableau.tsx =="
grep -n 'ReviewTableau.scss' src/pages/ReviewTableau/ReviewTableau.tsx

echo
echo "== Check if ViewTeamGrades.module.scss is globally imported anywhere =="
rg 'ViewTeamGrades.module.scss' src

echo
echo "== Confirm module.scss scoping - check if styles in ReviewTableau.tsx use :global =="
rg -A5 -B5 'grade-circle|underlined|circle-container|weight-circle|tick|c[0-5]' src/pages/ReviewTableau/ReviewTableau.scss

Repository: expertiza/reimplementation-front-end

Length of output: 23781


Add ViewTeamGrades.module.scss import to ReviewTableau.tsx or ScoreWidgets.tsx.

ScoreWidgets renders CSS classes (grade-circle, underlined, circle-container, weight-circle, circle, tick, and color classes c0c5, cf) that are defined in src/pages/ViewTeamGrades/ViewTeamGrades.module.scss. However, this stylesheet is not imported on the ReviewTableau path, so these styles won't be available at runtime. Either import the stylesheet in ReviewTableau.tsx or move the style definitions to a shared location.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/ReviewTableau/ScoreWidgets.tsx` at line 2, Import the
ViewTeamGrades.module.scss stylesheet in ScoreWidgets.tsx to ensure that the CSS
classes used by the ScoreWidgets component (grade-circle, underlined,
circle-container, weight-circle, circle, tick, and color classes c0 through c5
and cf) are available at runtime when rendered on the ReviewTableau path.

Comment on lines +97 to +116
const due_dates: DueDates[] = useMemo(() => {
return (apiData?.due_dates || []).map((due: any) => {
let safeDateString = due.date;

// Only reformat dd-mm-yyyy strings; skip ISO dates (which already start YYYY-)
if (due.date && due.date.includes('-') && !/^\d{4}-/.test(due.date)) {
const [datePart, timePart] = due.date.split(' ');
const [day, month, year] = datePart.split('-');
safeDateString = `${year}-${month}-${day}T${timePart}Z`;
}

return {
id: due.id ?? null,
type: due.type,
name: due.name || "Unknown Stage",
date: safeDateString || new Date().toISOString(),
round: due.round ?? null
};
});
}, [apiData?.due_dates]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Sort due_dates before computing stage status and progress.

Timeline node states and progressPercent depend on ordered deadlines, but this array is currently used in raw API order.

Proposed fix
 const due_dates: DueDates[] = useMemo(() => {
-  return (apiData?.due_dates || []).map((due: any) => {
+  const normalized = (apiData?.due_dates || []).map((due: any) => {
       let safeDateString = due.date;
       ...
       return {
         id: due.id ?? null,
         type: due.type,
         name: due.name || "Unknown Stage",
         date: safeDateString || new Date().toISOString(),
         round: due.round ?? null
       };
     });
+  return normalized.sort(
+    (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
+  );
 }, [apiData?.due_dates]);
📝 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
const due_dates: DueDates[] = useMemo(() => {
return (apiData?.due_dates || []).map((due: any) => {
let safeDateString = due.date;
// Only reformat dd-mm-yyyy strings; skip ISO dates (which already start YYYY-)
if (due.date && due.date.includes('-') && !/^\d{4}-/.test(due.date)) {
const [datePart, timePart] = due.date.split(' ');
const [day, month, year] = datePart.split('-');
safeDateString = `${year}-${month}-${day}T${timePart}Z`;
}
return {
id: due.id ?? null,
type: due.type,
name: due.name || "Unknown Stage",
date: safeDateString || new Date().toISOString(),
round: due.round ?? null
};
});
}, [apiData?.due_dates]);
const due_dates: DueDates[] = useMemo(() => {
const normalized = (apiData?.due_dates || []).map((due: any) => {
let safeDateString = due.date;
// Only reformat dd-mm-yyyy strings; skip ISO dates (which already start YYYY-)
if (due.date && due.date.includes('-') && !/^\d{4}-/.test(due.date)) {
const [datePart, timePart] = due.date.split(' ');
const [day, month, year] = datePart.split('-');
safeDateString = `${year}-${month}-${day}T${timePart}Z`;
}
return {
id: due.id ?? null,
type: due.type,
name: due.name || "Unknown Stage",
date: safeDateString || new Date().toISOString(),
round: due.round ?? null
};
});
return normalized.sort(
(a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
);
}, [apiData?.due_dates]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/StudentTasks/StudentTaskDetail.tsx` around lines 97 - 116, The
due_dates array returned from the useMemo hook needs to be sorted by date before
being returned, as timeline node states and progressPercent calculations depend
on ordered deadlines. After the map function that transforms the API data, add a
sort step to order the due dates chronologically based on the date field,
ensuring the array is sorted by the ISO date string in ascending order before
returning it.

Comment on lines +102 to +106
if (due.date && due.date.includes('-') && !/^\d{4}-/.test(due.date)) {
const [datePart, timePart] = due.date.split(' ');
const [day, month, year] = datePart.split('-');
safeDateString = `${year}-${month}-${day}T${timePart}Z`;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Legacy date normalization is forcing UTC and can shift deadlines.

Appending Z treats legacy timestamps as UTC; if backend strings are local wall-clock times, displayed time moves by timezone offset.

Proposed fix
-        safeDateString = `${year}-${month}-${day}T${timePart}Z`;
+        safeDateString = `${year}-${month}-${day}T${timePart || "00:00:00"}`;
📝 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
if (due.date && due.date.includes('-') && !/^\d{4}-/.test(due.date)) {
const [datePart, timePart] = due.date.split(' ');
const [day, month, year] = datePart.split('-');
safeDateString = `${year}-${month}-${day}T${timePart}Z`;
}
if (due.date && due.date.includes('-') && !/^\d{4}-/.test(due.date)) {
const [datePart, timePart] = due.date.split(' ');
const [day, month, year] = datePart.split('-');
safeDateString = `${year}-${month}-${day}T${timePart || "00:00:00"}`;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/StudentTasks/StudentTaskDetail.tsx` around lines 102 - 106, The
date normalization logic in the conditional block that processes legacy date
formats is appending 'Z' to the safeDateString variable, which forces the
timestamp to be treated as UTC time. This causes deadline shifts if the backend
is providing local wall-clock times rather than UTC times. Remove the 'Z' from
the end of the safeDateString assignment where the date is being reconstructed
from year, month, day, and timePart components so that the timestamp is treated
as local time instead of UTC.

Comment on lines 94 to 97
useEffect(() => {
fetchBackend(assignmentId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Missing assignmentId in useEffect dependencies.

If the URL's assignmentId query parameter changes (e.g., navigation without full remount), the effect won't re-run and stale data will be displayed. Either add assignmentId to dependencies or document that the component expects a full remount on route changes.

🔧 Suggested fix
   useEffect(() => {
     fetchBackend(assignmentId);
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, []);
+  }, [assignmentId]);
📝 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
useEffect(() => {
fetchBackend(assignmentId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
fetchBackend(assignmentId);
}, [assignmentId]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/ViewTeamGrades/ReviewTable.tsx` around lines 94 - 97, The useEffect
hook is missing assignmentId in its dependency array despite using it in the
fetchBackend call. When assignmentId changes during navigation, the effect won't
re-run because the dependency array is empty. Add assignmentId to the dependency
array of the useEffect hook so that the effect re-runs whenever assignmentId
changes and fetches the correct data.

Comment on lines +3 to +4
import { calculateAverages, normalizeReviewDataArray } from "./heatgridUtils";
import styles from "./ViewTeamGrades.module.scss"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Unused styles import.

The styles object imported from ViewTeamGrades.module.scss is never used in this component. The table at line 40 uses a plain "tbl_heat" class name.

🧹 Suggested fix
 import { calculateAverages, normalizeReviewDataArray } from "./heatgridUtils";
-import styles from "./ViewTeamGrades.module.scss"

Or, if tbl_heat should use the module:

-      <table className="tbl_heat">
+      <table className={styles.tbl_heat}>
📝 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
import { calculateAverages, normalizeReviewDataArray } from "./heatgridUtils";
import styles from "./ViewTeamGrades.module.scss"
import { calculateAverages, normalizeReviewDataArray } from "./heatgridUtils";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/ViewTeamGrades/Statistics.tsx` around lines 3 - 4, The styles
import from ViewTeamGrades.module.scss is not being utilized in the Statistics
component. Either remove the unused styles import statement, or if the tbl_heat
class name (used in the table around line 40) should reference the styles
module, update the class reference from the plain string "tbl_heat" to
styles.tbl_heat to properly use the imported SCSS module.

Comment on lines +89 to +90
:global {
/* Null space in the table */

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resolve stylelint blockers in this SCSS module.

This file introduces lint errors (:global flagged as unknown pseudo-class, and deprecated word-wrap). If stylelint is gating, this will fail CI.

🔧 Proposed fix
+/* stylelint-disable selector-pseudo-class-no-unknown */
 :global {
   /* ... */
 }
+/* stylelint-enable selector-pseudo-class-no-unknown */

-  word-wrap: break-word;
+  overflow-wrap: break-word;

+/* stylelint-disable selector-pseudo-class-no-unknown */
 :global {
   /* ... */
 }
+/* stylelint-enable selector-pseudo-class-no-unknown */

Also applies to: 184-184, 329-330

🧰 Tools
🪛 Stylelint (17.13.0)

[error] 89-89: Unknown pseudo-class selector ":global" (selector-pseudo-class-no-unknown)

(selector-pseudo-class-no-unknown)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/pages/ViewTeamGrades/ViewTeamGrades.module.scss` around lines 89 - 90,
Resolve the stylelint errors in ViewTeamGrades.module.scss by addressing two
issues: first, fix the `:global` pseudo-class syntax error around line 89-90
(and line 184 and 329-330 as noted) by either wrapping the selector properly as
`:global(.className)` or adding a stylelint disable comment if intentional;
second, locate and replace the deprecated `word-wrap` property with
`overflow-wrap` throughout the file to resolve the deprecation warning. Verify
that all three locations mentioned in the comment have been corrected and that
stylelint no longer reports blocking errors.

Source: Linters/SAST tools

Comment on lines +7 to +8
export const capitalizeFirstWord = (str: string) => {
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard capitalizeFirstWord against nullish API values.

This helper can throw before caller fallbacks run if API data contains null/undefined.

Proposed fix
-export const capitalizeFirstWord = (str: string) => {
-    return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
+export const capitalizeFirstWord = (str?: string | null): string => {
+    if (!str) return "";
+    return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/dataFormatter.ts` around lines 7 - 8, The capitalizeFirstWord
function does not guard against null or undefined input values, which will cause
a runtime error when charAt() is called on a nullish parameter. Add a guard
clause at the beginning of the capitalizeFirstWord function to check if the str
parameter is null or undefined, and return a safe default value (such as an
empty string) in those cases before proceeding with the charAt(0) and slice
operations.

Comment on lines +17 to +27
export const formatDate = (dateString: string): string => {
const date = new Date(dateString);
const options: Intl.DateTimeFormatOptions = {
month: "short",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
hour12: true,
};
return date.toLocaleString("en-US", options);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Return an empty string for invalid dates instead of "Invalid Date".

toLocaleString on an invalid Date yields a truthy "Invalid Date" string, so downstream || "No deadline" fallbacks never trigger.

Proposed fix
-export const formatDate = (dateString: string): string => {
-    const date = new Date(dateString);
+export const formatDate = (dateString?: string | null): string => {
+    if (!dateString) return "";
+    const date = new Date(dateString);
+    if (Number.isNaN(date.getTime())) return "";
     const options: Intl.DateTimeFormatOptions = {
         month: "short",
         day: "numeric",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utils/dataFormatter.ts` around lines 17 - 27, The formatDate function
returns "Invalid Date" string from toLocaleString when given an invalid date,
which is truthy and prevents downstream fallback logic (like || "No deadline")
from executing. Add a validation check after creating the Date object to verify
if the date is valid using isNaN(date.getTime()). If the date is invalid, return
an empty string instead of calling toLocaleString, so that downstream
null-coalescing or OR operators can properly trigger their fallback values.

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.

1 participant