E2602 - Reimplement frontend of student task view#182
Conversation
|
Warning Review limit reached
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 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 configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (10)
📝 WalkthroughWalkthroughThe PR adds a Student Tasks dashboard that replaces the topic-signup-sheet workflow with a ChangesStudent Tasks Dashboard and Detail Page
ViewTeamGrades Heatgrid and FeedbackTable Refactor
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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 18
🧹 Nitpick comments (1)
src/pages/ViewTeamGrades/ReviewTableRow.tsx (1)
73-99: 💤 Low valueMove
cellContentdeclaration inside the map callback.The
cellContentvariable is declared at line 76 outside themap()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
📒 Files selected for processing (28)
src/App.tsxsrc/components/Table/Table.tsxsrc/css-modules.d.tssrc/pages/ReviewTableau/ScoreWidgets.tsxsrc/pages/StudentTasks/StudentTaskDetail.module.csssrc/pages/StudentTasks/StudentTaskDetail.tsxsrc/pages/StudentTasks/StudentTasks.module.csssrc/pages/StudentTasks/StudentTasks.tsxsrc/pages/StudentTasks/StudentTasksList.module.csssrc/pages/StudentTasks/StudentTasksList.tsxsrc/pages/ViewTeamGrades/App.tsxsrc/pages/ViewTeamGrades/Data/authorFeedback.jsonsrc/pages/ViewTeamGrades/Data/dummyData.jsonsrc/pages/ViewTeamGrades/Data/heatMapData.jsonsrc/pages/ViewTeamGrades/Data/teammateData.jsonsrc/pages/ViewTeamGrades/FeedbackTable.tsxsrc/pages/ViewTeamGrades/ReviewTable.tsxsrc/pages/ViewTeamGrades/ReviewTableRow.tsxsrc/pages/ViewTeamGrades/RoundSelector.tsxsrc/pages/ViewTeamGrades/ShowReviews.tsxsrc/pages/ViewTeamGrades/Statistics.tsxsrc/pages/ViewTeamGrades/ViewTeamGrades.module.scsssrc/pages/ViewTeamGrades/__tests__/ReviewTable.test.tsxsrc/pages/ViewTeamGrades/__tests__/ReviewTableRow.test.tsxsrc/pages/ViewTeamGrades/__tests__/ShowReviews.test.tsxsrc/pages/ViewTeamGrades/__tests__/utils.test.tssrc/pages/ViewTeamGrades/heatgridUtils.tssrc/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
| <span style={{ marginLeft: "5px" }} onClick={toggleGlobalFilter}> | ||
| <FaSearch style={{ cursor: "pointer" }} /> | ||
| {isGlobalFilterVisible ? " Hide" : " Show"} | ||
| </span>*/} | ||
| </Row> | ||
| </Container> | ||
| )} | ||
| <Container> | ||
| <Row style={{ flex: 1 }}> | ||
| </span> | ||
| )} |
There was a problem hiding this comment.
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} />} |
There was a problem hiding this comment.
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.
| {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'; | |||
There was a problem hiding this comment.
🧩 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.tsxRepository: 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.tsxRepository: 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 -20Repository: 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 -50Repository: 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 -30Repository: 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' srcRepository: 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.scssRepository: 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 c0–c5, 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.
| 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]); |
There was a problem hiding this comment.
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.
| 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.
| 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`; | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| useEffect(() => { | ||
| fetchBackend(assignmentId); | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, []); |
There was a problem hiding this comment.
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.
| 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.
| import { calculateAverages, normalizeReviewDataArray } from "./heatgridUtils"; | ||
| import styles from "./ViewTeamGrades.module.scss" |
There was a problem hiding this comment.
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.
| 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.
| :global { | ||
| /* Null space in the table */ |
There was a problem hiding this comment.
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
| export const capitalizeFirstWord = (str: string) => { | ||
| return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); |
There was a problem hiding this comment.
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.
| 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); |
There was a problem hiding this comment.
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.
Summary
Changes
src/pages/ViewTeamGrades/ViewTeamGrades.module.scss (renamed from ReviewTable.module.scss)
src/css-modules.d.ts
src/pages/ViewTeamGrades/ReviewTable.tsx
src/pages/ViewTeamGrades/ReviewTableRow.tsx
src/pages/ViewTeamGrades/heatgridUtils.ts
src/pages/ViewTeamGrades/FeedbackTable.tsx
src/pages/ViewTeamGrades/App.tsx
src/pages/ViewTeamGrades/Statistics.tsx
src/pages/StudentTasks/StudentTasks.tsx
src/pages/StudentTasks/StudentTasksList.tsx
src/pages/StudentTasks/StudentTaskDetail.tsx
src/pages/StudentTasks/StudentTasks.module.css
src/pages/ViewTeamGrades/RoundSelector.tsx
Frontend View:
Summary by CodeRabbit
Release Notes