Conversation
… mod merge into main
… mod merge into main
… mod merge into main
… organization-fixes merge into main
…into organization-fixes
… hackathon-details fix: merge into main
… hackathon-details Merge into main
… hackathon-analytics merge into main
… hackathon-analytics merge into main
… hackathon-analytics merge into main
…ouncement features
… judging-dashboard Merge into main
… judging-dashboard Merge into main
|
@Benjtalkshow is attempting to deploy a commit to the Threadflow Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📝 WalkthroughWalkthroughWires aggregated judging results and summaries from the API into the UI, adds criteria-aware components and per-judge scoring flows, threads currentUserId/hackathon through submissions flows, updates request shapes to include judgeId, and enhances tooltips and error handling across judging and submissions components. Changes
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Page as Judging Page
participant API as Judging API
participant Table as JudgingResultsTable
participant Criteria as AggregatedCriteriaBreakdown
participant Scores as IndividualScoresBreakdown
User->>Page: Open judging page
Page->>API: GET /judging/results & /judging/winners
API-->>Page: AggregatedJudgingResults (results, summaries, metadata)
Page->>Table: render(results[], criteria[])
loop per result
Table->>Table: render row, status badges
alt has criteriaBreakdown
Table->>Criteria: pass criteriaBreakdown + criteria
Criteria-->>Table: render ranges & averages
end
alt has individualScores
Table->>Scores: pass initialScores
Scores->>API: GET detailed per-judge criteria (if needed)
API-->>Scores: detailed scores
Scores-->>Table: render per-judge breakdown with tooltips
end
end
Table-->>User: display aggregated metrics, rows, and expanded details
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly Related PRs
Suggested Reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (2 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: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (5)
components/organization/hackathons/submissions/SubmissionsManagement.tsx (1)
124-144:⚠️ Potential issue | 🔴 Critical
handleBulkActiondoesn't guard oncurrentUserId, unlikehandleReviewandhandleDisqualify.
handleReview(Line 101) andhandleDisqualify(Line 110) both early-return whencurrentUserIdis falsy, buthandleBulkActiononly checksorganizationId,hackathonId, andselectedIds. This means bulk actions can fire withjudgeId: ''(Line 138), which is likely invalid on the backend.🐛 Proposed fix
const handleBulkAction = async ( action: 'SHORTLISTED' | 'SUBMITTED' | 'DISQUALIFIED', reason?: string ) => { - if (!organizationId || !hackathonId || selectedIds.length === 0) return; + if (!organizationId || !hackathonId || !currentUserId || selectedIds.length === 0) return; if (action === 'DISQUALIFIED' && !reason) { setShowBulkDisqualifyDialog(true); return; } await performBulkAction(organizationId, hackathonId, { submissionIds: selectedIds, action, - judgeId: currentUserId || '', + judgeId: currentUserId, reason, });components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx (2)
78-81:⚠️ Potential issue | 🟠 Major
avgTotalScorewill beNaNwhen usinginitialScoresfallback.
initialScoresobjects have ascorefield, nottotalScore. Sos.totalScoreisundefined, making the sumNaN. This silently breaks the discrepancy detection at Lines 113 and 135, though it doesn't crash.🐛 Proposed fix
const avgTotalScore = scores.length > 0 - ? scores.reduce((sum, s) => sum + s.totalScore, 0) / scores.length + ? scores.reduce((sum, s) => sum + (s.totalScore ?? s.score ?? 0), 0) / scores.length : 0;
40-69:⚠️ Potential issue | 🟠 Major
initialScoresin the dependency array may cause re-fetch loops.If the parent component doesn't memoize the
initialScoresarray (e.g., viauseMemo), a new array reference is created on each render, causing thisuseEffectto re-fire indefinitely and spam the API.Consider removing
initialScoresfrom the dependency array (it's only used as a fallback, not as a trigger) or ensuring the parent memoizes it.lib/api/hackathons/judging.ts (1)
440-450:⚠️ Potential issue | 🟠 MajorUnsafe fallback: casting
{}asGetJudgingResultsResponsewhenres.datais nullish.Line 449 falls through to
(res.data || {}) as GetJudgingResultsResponse. Ifres.datais nullish, consumers get{}typed as having.success,.data.results, etc., which will crash on access. The same pattern exists ingetJudgingWinnersat Line 525.🛡️ Proposed fix — return a well-typed empty response
- return (res.data || {}) as GetJudgingResultsResponse; + return { + success: false, + message: 'Unexpected response format', + data: undefined, + } as unknown as GetJudgingResultsResponse;Or better yet, throw an error to surface the issue early:
- return (res.data || {}) as GetJudgingResultsResponse; + throw new Error('Unexpected response format from judging results API');app/(landing)/organizations/[id]/hackathons/[hackathonId]/judging/page.tsx (1)
132-151: 🛠️ Refactor suggestion | 🟠 Major
currentUserIdlocal variable shadows the state variable of the same name (line 63).Line 134 declares
const currentUserIdwhich shadows the state variable fromuseState<string | null>(null)on line 63. This works today but is fragile — any future code in this callback referencingcurrentUserIdwill get the local, not the state. Rename the local to disambiguate.Suggested fix
- const currentUserId = session?.user?.id; - if (currentUserId && finalMembers.length > 0) { + const sessionUserId = session?.user?.id; + if (sessionUserId && finalMembers.length > 0) { const me = finalMembers.find( - (m: any) => m.userId === currentUserId || m.id === currentUserId + (m: any) => m.userId === sessionUserId || m.id === sessionUserId ); setCurrentUserRole(me?.role || null); const isJudge = judges.some( - (j: any) => j.userId === currentUserId || j.id === currentUserId + (j: any) => j.userId === sessionUserId || j.id === sessionUserId ); setIsCurrentUserJudge(isJudge); } - if (currentUserId) { - setCurrentUserId(currentUserId); + if (sessionUserId) { + setCurrentUserId(sessionUserId); }
🤖 Fix all issues with AI agents
In `@app/`(landing)/organizations/[id]/hackathons/[hackathonId]/judging/page.tsx:
- Line 160: Remove the development `console.log('Judging Results Structure
Verification:', res)` from the Judging page component; locate the logging call
that prints the `res` response in the rendering or data-fetching logic (the
console.log that includes "Judging Results Structure Verification") and delete
it, or replace it with a proper server-side or debug-only logger if you need
persisted/filtered diagnostic output ( gated by an environment/debug flag ).
In `@components/hackathons/hackathonNavTabs.tsx`:
- Line 1: The file imports unused React hooks useState and useEffect; remove
these unused imports from the import line (replace "import { useState, useEffect
} from 'react';" with a plain React import or remove entirely if not needed) so
that the component no longer includes unused symbols and ESLint/compiler
warnings go away; locate the import statement at the top of
components/hackathons/hackathonNavTabs.tsx and update it to only import what the
file actually uses.
In
`@components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx`:
- Line 34: The scores state is typed as any[] which hides a mismatch: API items
use totalScore while initialScores use score, causing avgTotalScore and the
discrepancy checks to break; update the scores typing to a discriminated union
or a proper interface (e.g., ScoreApi { totalScore: number; ... } | ScoreInitial
{ score: number; ... }) and normalize data when calling setScores — either map
the API response into the internal shape expected by avgTotalScore (convert
totalScore -> score or vice versa) or when falling back to initialScores, map
its items to match the API shape used by avgTotalScore and discrepancy detection
(references: scores, setScores, initialScores, avgTotalScore).
In `@components/organization/hackathons/judging/AggregatedCriteriaBreakdown.tsx`:
- Around line 25-34: The component AggregatedCriteriaBreakdown currently assumes
numeric fields (variance, averageScore, min, max) are non-null and calls
.toFixed(), which can throw if the API returns null/undefined; update the
rendering logic in AggregatedCriteriaBreakdown (and any helpers like
getScoreColor usage points) to coerce these values to safe numbers before
formatting (e.g., use nullish coalescing or Number(...) with a default like 0)
and only call .toFixed() on the safe fallback value, applying the same defensive
checks for variance, averageScore, min and max wherever they are formatted.
In `@components/organization/hackathons/judging/JudgingResultsTable.tsx`:
- Around line 190-191: In JudgingResultsTable (the JSX that renders the judge
counts), the expression "{result.judgeCount} / {result.expectedJudgeCount ||
totalJudges || '?'}" incorrectly treats an expectedJudgeCount of 0 as falsy;
change the fallback chain to use the nullish coalescing operator so it becomes
"{result.judgeCount} / {result.expectedJudgeCount ?? totalJudges ?? '?'}"
(referencing result.judgeCount, result.expectedJudgeCount and totalJudges) to
preserve zero values while still falling back when expectedJudgeCount is null or
undefined.
- Line 106: The rank display currently uses the falsy check "result.rank ||
index + 1" which treats a valid numeric rank 0 as missing; update the fallback
to use nullish coalescing so only null/undefined fall back: replace the
expression in JudgingResultsTable (the span rendering result.rank) with
"result.rank ?? index + 1" ensuring result.rank (from the result object) remains
typed as number and preserves 0 correctly.
🧹 Nitpick comments (11)
components/ui/shadcn-io/announcement-editor/index.tsx (1)
366-387: Inconsistent styling across sibling dialogs.The
mb-2on the Image URL label (line 366) andtext-backgroundon the Image Insert button (line 387) aren't applied to the structurally identical Link and Embed dialogs:
- Labels: Link Text (line 308), URL (line 320), and Embed URL (line 412) all lack
mb-2.- Insert buttons: Link Insert (line 341) and Embed Insert (line 433) use
text-whiteinstead oftext-background.If these are intentional fixes, apply them consistently to all three dialogs.
♻️ Suggested diff for consistency
- <Label htmlFor='link-text' className='text-white'> + <Label htmlFor='link-text' className='mb-2 text-white'>- <Label htmlFor='link-url' className='text-white'> + <Label htmlFor='link-url' className='mb-2 text-white'>- <Label htmlFor='embed-url' className='text-white'> + <Label htmlFor='embed-url' className='mb-2 text-white'>- className='bg-primary hover:bg-primary/90 text-white' + className='bg-primary hover:bg-primary/90 text-background'(Apply to Insert buttons on lines 341 and 433.)
components/hackathons/hackathonNavTabs.tsx (2)
16-20: Preferconstarrow function with explicit type annotation.As per coding guidelines, "Prefer const arrow functions with explicit type annotations over function declarations."
Proposed fix
-export function HackathonNavTabs({ - tabs, - activeTab, - onTabChange, -}: HackathonNavTabsProps) { +export const HackathonNavTabs: React.FC<HackathonNavTabsProps> = ({ + tabs, + activeTab, + onTabChange, +}) => {
36-36: Useclsx(orcn) for conditional classes instead of a ternary in a template literal.This improves readability and aligns with the project convention. As per coding guidelines, "For conditional classes, prefer clsx or similar helper functions over ternary operators in JSX."
Proposed fix (using clsx)
- className={`relative px-4 py-4 text-sm font-medium whitespace-nowrap transition-colors duration-200 ${isActive ? 'text-[`#a7f950`]' : 'text-gray-400 hover:text-white'} `} + className={clsx( + 'relative px-4 py-4 text-sm font-medium whitespace-nowrap transition-colors duration-200', + isActive ? 'text-[`#a7f950`]' : 'text-gray-400 hover:text-white', + )}And add the import:
+import clsx from 'clsx';components/organization/hackathons/judging/AggregatedCriteriaBreakdown.tsx (1)
101-118: Visual layering: average bar renders on top of range bar — is this intentional?Both the range bar (gray, Lines 103-109) and the average marker (colored, Lines 111-117) are absolutely positioned children. The average bar uses
widthfrom 0, meaning it overlays the range bar from the left edge rather than being a point marker at the average position. If the intent is to show a filled bar up to the average and a separate range indicator, this works. If the intent is a narrow marker at the average point, you'd need a thin element positioned atleft: averageScore * 10%instead.app/(landing)/organizations/[id]/hackathons/[hackathonId]/submissions/page.tsx (1)
34-49: Consider separatingfetchHackathonDetailsinto its ownuseEffect.
fetchHackathonDetailsis embedded inside the sameuseEffectasfetchSubmissions, but they serve different purposes and have different lifecycles. The hackathon details likely only need fetching once, whereas submissions may be re-fetched (viarefresh). Extracting it to a dedicated effect improves clarity and avoids re-fetching hackathon details iffetchSubmissionschanges identity.components/organization/hackathons/submissions/SubmissionsList.tsx (1)
182-184: Usecn()for conditional classes instead of template literal ternaries.Lines 184 and 500 use template literal ternaries for conditional class names. The project already imports
cnin other components, and the coding guidelines requireclsxor similar helpers over ternary operators in JSX.♻️ Example for Line 184
- className={`group hover:border-primary/50 relative cursor-pointer overflow-hidden border-gray-800/50 bg-gray-900/20 transition-all hover:bg-gray-900/40 ${selectedIds?.includes(subData.id) ? 'border-primary/50 bg-primary/5' : ''}`} + className={cn( + 'group hover:border-primary/50 relative cursor-pointer overflow-hidden border-gray-800/50 bg-gray-900/20 transition-all hover:bg-gray-900/40', + selectedIds?.includes(subData.id) && 'border-primary/50 bg-primary/5' + )}Apply the same pattern to Line 500. As per coding guidelines, "For conditional classes, prefer clsx or similar helper functions over ternary operators in JSX".
lib/api/hackathons/judging.ts (1)
430-450: Duplicated dual-format response handling betweengetJudgingResultsandgetJudgingWinners.Both functions share the same pattern: check for
'results' in res.data, wrap in success response or fall through. Consider extracting this into a shared helper to reduce duplication.♻️ Suggested helper
const normalizeAggregatedResponse = ( resData: AggregatedJudgingResults | ApiResponse<AggregatedJudgingResults> | undefined, fallbackMessage: string ): GetJudgingResultsResponse => { if (resData && 'results' in resData) { return { success: true, data: resData as AggregatedJudgingResults, message: fallbackMessage, } as GetJudgingResultsResponse; } if (resData && 'success' in resData) { return resData as GetJudgingResultsResponse; } throw new Error('Unexpected response format'); };Also applies to: 507-526
components/organization/hackathons/judging/JudgingResultsTable.tsx (2)
4-4: Consolidate imports from the same module.
JudgingResult(line 4) andJudgingCriterion(line 23) are both imported from@/lib/api/hackathons/judging. Merge them into a single import statement.Suggested fix
-import { JudgingResult } from '@/lib/api/hackathons/judging'; +import { JudgingResult, JudgingCriterion } from '@/lib/api/hackathons/judging'; ... import AggregatedCriteriaBreakdown from './AggregatedCriteriaBreakdown'; -import { JudgingCriterion } from '@/lib/api/hackathons/judging';Also applies to: 22-23
49-54: RenametoggleRowtohandleToggleRowto follow the event handler naming convention.As per coding guidelines, "Event handlers should start with 'handle' prefix (e.g., handleClick, handleSubmit)".
app/(landing)/organizations/[id]/hackathons/[hackathonId]/judging/page.tsx (2)
168-170: Avoidas anycast — type the API response properly or use optional chaining.If the response type doesn't include
messageon the failure path, consider extending the type or using a type guard rather than casting toany.
197-199: Fire-and-forget calls are intentional but worth a brief comment.
fetchJudges()andfetchResults()run in parallel withoutawait, meaningisLoading(set tofalsein thefinallyblock) only reflects submissions/criteria completion. This is fine since judges and results have their own loading states, but a brief inline comment would help future readers understand this is deliberate.
app/(landing)/organizations/[id]/hackathons/[hackathonId]/judging/page.tsx
Outdated
Show resolved
Hide resolved
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx
Outdated
Show resolved
Hide resolved
components/organization/hackathons/judging/AggregatedCriteriaBreakdown.tsx
Show resolved
Hide resolved
components/organization/hackathons/judging/JudgingResultsTable.tsx
Outdated
Show resolved
Hide resolved
components/organization/hackathons/judging/JudgingResultsTable.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/(landing)/organizations/[id]/hackathons/[hackathonId]/judging/page.tsx (1)
300-303:⚠️ Potential issue | 🟡 Minor
fetchResults()is called twice on success.
handleSuccesscallsfetchData()(which internally firesfetchResults()on line 198) and then callsfetchResults()again on line 302. This results in a redundant network request every time a judge submits scores.🐛 Proposed fix
const handleSuccess = () => { fetchData(); - fetchResults(); // Refresh results to update metrics/table };Since
fetchDataalready triggersfetchResults()internally, the explicit call is unnecessary.
🤖 Fix all issues with AI agents
In
`@components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx`:
- Line 97: The useEffect inside the IndividualScoresBreakdown component
currently includes initialScores in its dependency array which can trigger
unnecessary re-fetches when the parent recreates that array; remove
initialScores from the dependency array (keep [organizationId, hackathonId,
participantId]) and treat initialScores only as a fallback inside the effect, or
if you prefer value-based tracking, replace the dependency with a stable
signature (e.g., a JSON.stringify(initialScores) or a memoized/stableRef) so the
effect only reruns on meaningful changes; update the useEffect associated with
loading individual scores accordingly.
- Around line 64-66: res.data is an array of IndividualJudgeScore[] but
setScores expects JudgeScore[] which requires a totalScore; map res.data before
calling setScores (or change the state type) by computing totalScore from each
IndividualJudgeScore's criteriaScores (e.g., sum or average of
criteriaScores[].score) and produce the JudgeScore shape, then call
setScores(mappedArray); update any uses of JudgeScore (references at lines where
totalScore is accessed) if you choose to change the state type instead.
🧹 Nitpick comments (7)
components/hackathons/hackathonNavTabs.tsx (2)
15-15: Preferconstarrow function with explicit type annotation.As per coding guidelines, prefer
constarrow functions with explicit type annotations over function declarations.♻️ Proposed fix
-export function HackathonNavTabs({ +export const HackathonNavTabs: React.FC<HackathonNavTabsProps> = ({ tabs, activeTab, onTabChange, -}: HackathonNavTabsProps) { +}) => {(Add
import React from 'react'or use the return type inline if preferred.)
35-35: Useclsx(orcn) for conditional classes instead of a ternary in the template literal.As per coding guidelines: "For conditional classes, prefer clsx or similar helper functions over ternary operators in JSX."
♻️ Proposed fix
+import { cn } from '@/lib/utils'; // or clsx ... - className={`relative px-4 py-4 text-sm font-medium whitespace-nowrap transition-colors duration-200 ${isActive ? 'text-[`#a7f950`]' : 'text-gray-400 hover:text-white'} `} + className={cn( + 'relative px-4 py-4 text-sm font-medium whitespace-nowrap transition-colors duration-200', + isActive ? 'text-[`#a7f950`]' : 'text-gray-400 hover:text-white' + )}components/organization/hackathons/judging/AggregatedCriteriaBreakdown.tsx (1)
29-34:getScoreColoris duplicated across components.This identical helper exists in both
AggregatedCriteriaBreakdown(here) andIndividualScoresBreakdown(line 111). Consider extracting it into a shared utility (e.g., inlib/utils.tsor a judging-specific utils file) to keep things DRY.components/organization/hackathons/judging/JudgingResultsTable.tsx (1)
49-54: Event handler naming convention:toggleRow→handleToggleRow.Per coding guidelines, event handlers should use the
handleprefix. As per coding guidelines, "Event handlers should start with 'handle' prefix (e.g., handleClick, handleSubmit)".♻️ Proposed rename
- const toggleRow = (id: string) => { + const handleToggleRow = (id: string) => { setExpandedRows(prev => ({ ...prev, [id]: !prev[id], })); };And update the usage on line 101:
- onClick={() => toggleRow(result.submissionId)} + onClick={() => handleToggleRow(result.submissionId)}app/(landing)/organizations/[id]/hackathons/[hackathonId]/judging/page.tsx (1)
36-36: Page component usesfunctiondeclaration instead ofconstarrow function.The coding guidelines prefer const arrow functions with explicit type annotations. This is a common Next.js pattern though, so flagging as optional.
As per coding guidelines, "Prefer const arrow functions with explicit type annotations over function declarations".
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx (2)
65-76: DuplicatedinitialScoresnormalization logic.The same mapping from
initialScorestoJudgeScore[]appears in both theelse ifbranch (lines 70-76) and thecatchblock (lines 83-89). Extract it to avoid drift.♻️ Proposed refactor
useEffect(() => { + const normalizeInitialScores = (): JudgeScore[] | null => { + if (!initialScores) return null; + return initialScores.map(s => ({ + judgeId: s.judgeId, + judgeName: s.judgeName, + totalScore: s.score, + score: s.score, + })); + }; + const fetchScores = async () => { setIsLoading(true); try { const res = await getSubmissionScores( organizationId, hackathonId, participantId ); if (res.success && Array.isArray(res.data)) { setScores(res.data); - } else if (initialScores) { - const normalizedScores: JudgeScore[] = initialScores.map(s => ({ - judgeId: s.judgeId, - judgeName: s.judgeName, - totalScore: s.score, - score: s.score, - })); - setScores(normalizedScores); + } else { + const fallback = normalizeInitialScores(); + if (fallback) setScores(fallback); } } catch (err) { console.error('Failed to fetch individual scores:', err); - if (initialScores) { - const normalizedScores: JudgeScore[] = initialScores.map(s => ({ - judgeId: s.judgeId, - judgeName: s.judgeName, - totalScore: s.score, - score: s.score, - })); - setScores(normalizedScores); - } + const fallback = normalizeInitialScores(); + if (fallback) setScores(fallback); } finally { setIsLoading(false); } };Also applies to: 78-90
240-240: Avoidanytype for criteria scores.
score.criteriaScoresis already typed in theJudgeScoreinterface (lines 34-39), so the(c: any, idx: number)annotation is unnecessary and weakens type safety.♻️ Proposed fix
- {score.criteriaScores.map((c: any, idx: number) => ( + {score.criteriaScores.map((c, idx) => (
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx
Outdated
Show resolved
Hide resolved
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx (1)
250-286:⚠️ Potential issue | 🟡 Minor"Criteria Breakdown" label renders even when there are no criteria.
The
<label>at Line 252 is always shown inside the expanded section, while the criteria grid is conditionally rendered only whenscore.criteriaScores?.length > 0. For scores originating from theinitialScoresfallback (which never hascriteriaScores), the user sees a heading with nothing beneath it.🔧 Proposed fix — wrap both the label and the grid in the same conditional
- <div> - <label className='mb-2 block text-[10px] font-bold text-gray-400 uppercase'> - Criteria Breakdown - </label> - {score.criteriaScores && - score.criteriaScores.length > 0 && ( + {score.criteriaScores && score.criteriaScores.length > 0 && ( + <div> + <label className='mb-2 block text-[10px] font-bold text-gray-400 uppercase'> + Criteria Breakdown + </label> <div className='grid grid-cols-1 gap-x-6 gap-y-3 md:grid-cols-2'> ... </div> - )} - </div> + </div> + )}
🤖 Fix all issues with AI agents
In
`@components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx`:
- Around line 268-276: The progress-bar width in IndividualScoresBreakdown uses
`c.score * 10` which assumes a 0–10 scale and lets values >10 produce >100%
widths; change the calculation to normalise and clamp the score against a max
(preferably criteria metadata, otherwise a default like 10) before computing
percentage, e.g. compute a maxScore (from criteria metadata or default 10),
clamp c.score to [0, maxScore] and set width = (clampedScore / maxScore) * 100%;
update the JSX where `style={{ width: `${c.score * 10}%` }}` is set and ensure
`getScoreColor(c.score)` either receives the clamped/normalized value or is
adapted accordingly.
- Around line 255-283: score.criteriaScores.map is using the array index as the
React key and `c: any`, which loses typing and can cause reconciliation bugs;
change the map callback to use the existing unique identifier (`criterionId`) as
the key (e.g., key={c.criterionId}) and replace the any with the proper type for
the item (use the CriteriaScore type/interface from the surrounding types or
props) in the map signature (e.g., (c: CriteriaScore, idx: number) => ...) and
optionally guard/fallback if criterionId can be missing.
🧹 Nitpick comments (3)
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx (3)
84-107: Extract duplicateinitialScoresnormalization into a helper.The normalization of
initialScoresintoJudgeScore[]is duplicated verbatim in the success-fallback path (Lines 87–92) and the catch-fallback path (Lines 100–105). Extract it to a small helper to keep the effect body DRY.♻️ Proposed refactor
Define once above or inside the effect:
+ const normalizeInitial = ( + initial: NonNullable<typeof initialScores> + ): JudgeScore[] => + initial.map(s => ({ + judgeId: s.judgeId, + judgeName: s.judgeName, + totalScore: s.score, + score: s.score, + }));Then replace both blocks:
} else if (initialScores) { - const normalizedScores: JudgeScore[] = initialScores.map(s => ({ - judgeId: s.judgeId, - judgeName: s.judgeName, - totalScore: s.score, - score: s.score, - })); - setScores(normalizedScores); + setScores(normalizeInitial(initialScores)); } } catch (err) { console.error('Failed to fetch individual scores:', err); if (initialScores) { - const normalizedScores: JudgeScore[] = initialScores.map(s => ({ - judgeId: s.judgeId, - judgeName: s.judgeName, - totalScore: s.score, - score: s.score, - })); - setScores(normalizedScores); + setScores(normalizeInitial(initialScores)); }
68-82: Use the importedIndividualJudgeScoretype instead ofany.
IndividualJudgeScoreis imported at Line 6 but never used — the mapping at Line 68 castsitemtoany, losing all type safety on the API response shape. The same applies toc: anyat Line 75. Using the real types lets the compiler catch field renames or shape drift.♻️ Proposed fix
- const mappedScores: JudgeScore[] = res.data.map((item: any) => ({ + const mappedScores: JudgeScore[] = res.data.map((item: IndividualJudgeScore) => ({ judgeId: item.judgeId, judgeName: item.judgeName, totalScore: item.totalScore ?? - item.criteriaScores?.reduce( - (sum: number, c: any) => sum + (c.score || 0), + item.criteriaScores?.reduce( + (sum, c) => sum + (c.score || 0), 0 ) ?? 0,If
IndividualJudgeScoredoesn't have atotalScorefield, that's a signal the mapping logic needs adjustment rather than being papered over withany.
117-122: Event handler naming: preferhandleprefix.Per the project's coding guidelines, event handlers should start with
handle(e.g.,handleToggleExpand).toggleExpandreads more like a utility than a handler.As per coding guidelines, "Event handlers should start with 'handle' prefix (e.g., handleClick, handleSubmit)".
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx
Show resolved
Hide resolved
| <div className='h-1.5 w-full overflow-hidden rounded-full bg-gray-800'> | ||
| <div | ||
| className={cn( | ||
| 'h-full transition-all', | ||
| getScoreColor(c.score) | ||
| )} | ||
| style={{ width: `${c.score * 10}%` }} | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
Progress bar width assumes a 0–10 scoring scale with no clamp.
c.score * 10 produces a percentage, so a score of 12 would yield 120%. The parent's overflow-hidden clips the visual overflow, but the bar silently becomes "full" for any score above 10, hiding real data. Clamp or normalise to make intent explicit and future-proof against different max scores.
🔧 Proposed fix
- style={{ width: `${c.score * 10}%` }}
+ style={{ width: `${Math.min(c.score * 10, 100)}%` }}Ideally the max score would come from criteria metadata rather than being hard-coded to 10.
🤖 Prompt for AI Agents
In
`@components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx`
around lines 268 - 276, The progress-bar width in IndividualScoresBreakdown uses
`c.score * 10` which assumes a 0–10 scale and lets values >10 produce >100%
widths; change the calculation to normalise and clamp the score against a max
(preferably criteria metadata, otherwise a default like 10) before computing
percentage, e.g. compute a maxScore (from criteria metadata or default 10),
clamp c.score to [0, maxScore] and set width = (clampedScore / maxScore) * 100%;
update the JSX where `style={{ width: `${c.score * 10}%` }}` is set and ensure
`getScoreColor(c.score)` either receives the clamped/normalized value or is
adapted accordingly.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In
`@components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx`:
- Around line 84-107: Extract the duplicated initialScores normalization into a
helper function (e.g., normalizeInitialScores) and use it in both branches;
specifically, create a function above the effect that accepts initialScores and
returns JudgeScore[] by mapping each s to { judgeId: s.judgeId, judgeName:
s.judgeName, totalScore: s.score, score: s.score }, then replace the two inline
map blocks in the effect with setScores(normalizeInitialScores(initialScores)).
Ensure the helper is used in both the successful-else branch and the catch
fallback so setScores is only called with the normalized result.
🧹 Nitpick comments (4)
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx (4)
28-40: LocalJudgeScoreshadows the API-layer type of the same name.
lib/api/hackathons/judging.ts(andlib/api/hackathons.ts) both export aJudgeScoreinterface with a completely different shape (nestedjudgeobject,weightedScore,scores: CriterionScore[], etc.). Naming the local interface identically will confuse anyone navigating between these files. Consider renaming to something likeMappedJudgeScoreorJudgeScoreSummary.
68-82:anytypes in the mapping callback defeat the purpose of the localJudgeScoreinterface.
item: any(Line 68) andc: any(Line 75) drop all type safety. Since the API returnsIndividualJudgeScore[](already imported), use that as the parameter type — or typeres.dataexplicitly — so the compiler catches field-name mismatches.♻️ Suggested fix
- const mappedScores: JudgeScore[] = res.data.map((item: any) => ({ + const mappedScores: JudgeScore[] = res.data.map((item: IndividualJudgeScore) => ({ judgeId: item.judgeId, judgeName: item.judgeName, totalScore: item.totalScore ?? item.criteriaScores?.reduce( - (sum: number, c: any) => sum + (c.score || 0), + (sum: number, c: { score?: number }) => sum + (c.score || 0), 0 ) ?? 0,
117-122: RenametoggleExpand→handleToggleExpandto match the naming convention.♻️ Suggested fix
- const toggleExpand = (judgeId: string) => { + const handleToggleExpand = (judgeId: string) => {And update the call site on Line 195:
- onClick={() => toggleExpand(score.judgeId)} + onClick={() => handleToggleExpand(score.judgeId)}As per coding guidelines, "Event handlers should start with 'handle' prefix (e.g., handleClick, handleSubmit)".
224-228: Defensive score display with fallback chain — minor note.The
typeof score.totalScore === 'number'guard is redundant given thatJudgeScore.totalScoreis typed asnumber(not optional). It's harmless but adds cognitive noise; if the type is trusted,score.totalScore.toFixed(1)suffices.
components/organization/cards/JudgingParticipant/IndividualScoresBreakdown.tsx
Show resolved
Hide resolved
* Judging dashboard (#382) * fix: modify api.ts * fix: remove google auth buttom * fix: fixes responsive fixes on organization * fix: minor fixes * fix: modify create organization * fix: modify create organization * fix: fix organization permission * fix: merge into main * feat: hackathon overview page * feat: hackathon overview page * feat: implement participant overview * feat: implement participant overview * feat: implement resources tab * feat: implement the submission tab * feat: implement comment tab * fix: implement provider for hackathon * fix: implement provider for hackathon * fix: minor fixes * fix: hackathon banner * fix: hackathon banner * fix: fix organization page * fix: fix organization page * fix: use transform * fix: add tagline * fix: add tagline * fix: minor fixes * fix: minor fixes * fix: fix timeline and prizes * fix: correct timeline events * fix: implement registration deadline policy * fix: implement registration deadline policy * feat: implement leave hackathon * feat: implement leave hackathon * fix: delete hackathon * fix: implement invite participants * fix: implement participant profile viewing * feat: fetch participants team * fix: redesign hackathon banner * fix: fix hackthon card * fix: fix search bar in blog page * fix: fix search bar in blog page * fix: fix search bar in blog page * fix: fix error in fetching team posts * feat: implement create team, get my team * feat: implement create team, get my team * feat: implement hackathon project submission flow * feat: implement voting for submission * fix: team formation updates * fix: implement team invitation * feat: hackathon submissions bulk actions, ranking and ui refinements * fix: implement empty state for hackathons page * feat: Implement submission visibility and explore submissions * feat: Implement winners tab for hackathon winners display * feat: implement hackathon analytics * fix: fix coderabbit corrections * fix: fix coderabbit corrections * fix: fix coderabbit corrections * fix: fix organization settings data persistence, hackathondrafts and population * feat: fix user profile * feat: Implemented the participant-facing and hackathon organizers announcement features * feat: Implement judging dashboard and detailed breakdowns * feat: Implement judging dashboard and detailed breakdowns * fix: fix coderabbit corrections * Refactor/updated the timeline tab (#383) * feat: enhance hackathon timeline management and publishing flow - Updated HackathonPublishedModal to utilize new publish response structure. - Refactored TimelineSection to display additional timeline details including judging start/end and winner announcement dates. - Introduced DateTimeInput component for better date and time selection. - Added FieldLabel component for improved form labeling with tooltips. - Created timelineConstants for standardized tooltips and timezone options. - Modified timelineSchema to include new fields for judging start, end, and winner announcement dates with validation. - Enhanced TimelineSettingsTab to support new timeline fields and improved user experience with time inputs. - Updated use-hackathon-publish hook to handle new publish response format and manage state accordingly. - Adjusted use-hackathons hook to ensure proper handling of publish responses. - Updated API interfaces and utility functions to accommodate new timeline structure. - Improved validation logic for hackathon steps to ensure all necessary dates are set correctly. - Enhanced timeline calculation logic to reflect new judging and announcement phases. * chore: update markdown-it to version 14.1.1 and remove framer-motion dependency * refactor: clean up ReviewTab and HackathonPublishedModal components, improve DateTimeInput logic, and update timeline constants * refactor: update timeline calculation logic to ensure phases are only created with non-zero duration and add endDate to HackathonTimeline interface * Judging dashboard (#384) * fix: modify api.ts * fix: remove google auth buttom * fix: fixes responsive fixes on organization * fix: minor fixes * fix: modify create organization * fix: modify create organization * fix: fix organization permission * fix: merge into main * feat: hackathon overview page * feat: hackathon overview page * feat: implement participant overview * feat: implement participant overview * feat: implement resources tab * feat: implement the submission tab * feat: implement comment tab * fix: implement provider for hackathon * fix: implement provider for hackathon * fix: minor fixes * fix: hackathon banner * fix: hackathon banner * fix: fix organization page * fix: fix organization page * fix: use transform * fix: add tagline * fix: add tagline * fix: minor fixes * fix: minor fixes * fix: fix timeline and prizes * fix: correct timeline events * fix: implement registration deadline policy * fix: implement registration deadline policy * feat: implement leave hackathon * feat: implement leave hackathon * fix: delete hackathon * fix: implement invite participants * fix: implement participant profile viewing * feat: fetch participants team * fix: redesign hackathon banner * fix: fix hackthon card * fix: fix search bar in blog page * fix: fix search bar in blog page * fix: fix search bar in blog page * fix: fix error in fetching team posts * feat: implement create team, get my team * feat: implement create team, get my team * feat: implement hackathon project submission flow * feat: implement voting for submission * fix: team formation updates * fix: implement team invitation * feat: hackathon submissions bulk actions, ranking and ui refinements * fix: implement empty state for hackathons page * feat: Implement submission visibility and explore submissions * feat: Implement winners tab for hackathon winners display * feat: implement hackathon analytics * fix: fix coderabbit corrections * fix: fix coderabbit corrections * fix: fix coderabbit corrections * fix: fix organization settings data persistence, hackathondrafts and population * feat: fix user profile * feat: Implemented the participant-facing and hackathon organizers announcement features * feat: Implement judging dashboard and detailed breakdowns * feat: Implement judging dashboard and detailed breakdowns * fix: fix coderabbit corrections * fix: submission management ux refinements * fix: submission management ux refinements * fix: submission management ux refinements * fix: submission management ux refinements * fix: submission management ux refinements * feat: implement organizer override functionality for judging scores a… (#385) * feat: implement organizer override functionality for judging scores and enhance judging UI * fix: update response handling in score submission and enhance submissions list styling * fix: update eslint dependencies to latest versions for improved linting * fix: update ajv and json-schema-traverse dependencies in package-lock.json * fix: update * fix: update security audit level to high in pre-push checks * fix: update eslint dependencies and ensure security audit fails on error --------- Co-authored-by: Collins Ikechukwu <collinschristroa@gmail.com>
* Judging dashboard (#382) * fix: modify api.ts * fix: remove google auth buttom * fix: fixes responsive fixes on organization * fix: minor fixes * fix: modify create organization * fix: modify create organization * fix: fix organization permission * fix: merge into main * feat: hackathon overview page * feat: hackathon overview page * feat: implement participant overview * feat: implement participant overview * feat: implement resources tab * feat: implement the submission tab * feat: implement comment tab * fix: implement provider for hackathon * fix: implement provider for hackathon * fix: minor fixes * fix: hackathon banner * fix: hackathon banner * fix: fix organization page * fix: fix organization page * fix: use transform * fix: add tagline * fix: add tagline * fix: minor fixes * fix: minor fixes * fix: fix timeline and prizes * fix: correct timeline events * fix: implement registration deadline policy * fix: implement registration deadline policy * feat: implement leave hackathon * feat: implement leave hackathon * fix: delete hackathon * fix: implement invite participants * fix: implement participant profile viewing * feat: fetch participants team * fix: redesign hackathon banner * fix: fix hackthon card * fix: fix search bar in blog page * fix: fix search bar in blog page * fix: fix search bar in blog page * fix: fix error in fetching team posts * feat: implement create team, get my team * feat: implement create team, get my team * feat: implement hackathon project submission flow * feat: implement voting for submission * fix: team formation updates * fix: implement team invitation * feat: hackathon submissions bulk actions, ranking and ui refinements * fix: implement empty state for hackathons page * feat: Implement submission visibility and explore submissions * feat: Implement winners tab for hackathon winners display * feat: implement hackathon analytics * fix: fix coderabbit corrections * fix: fix coderabbit corrections * fix: fix coderabbit corrections * fix: fix organization settings data persistence, hackathondrafts and population * feat: fix user profile * feat: Implemented the participant-facing and hackathon organizers announcement features * feat: Implement judging dashboard and detailed breakdowns * feat: Implement judging dashboard and detailed breakdowns * fix: fix coderabbit corrections * Refactor/updated the timeline tab (#383) * feat: enhance hackathon timeline management and publishing flow - Updated HackathonPublishedModal to utilize new publish response structure. - Refactored TimelineSection to display additional timeline details including judging start/end and winner announcement dates. - Introduced DateTimeInput component for better date and time selection. - Added FieldLabel component for improved form labeling with tooltips. - Created timelineConstants for standardized tooltips and timezone options. - Modified timelineSchema to include new fields for judging start, end, and winner announcement dates with validation. - Enhanced TimelineSettingsTab to support new timeline fields and improved user experience with time inputs. - Updated use-hackathon-publish hook to handle new publish response format and manage state accordingly. - Adjusted use-hackathons hook to ensure proper handling of publish responses. - Updated API interfaces and utility functions to accommodate new timeline structure. - Improved validation logic for hackathon steps to ensure all necessary dates are set correctly. - Enhanced timeline calculation logic to reflect new judging and announcement phases. * chore: update markdown-it to version 14.1.1 and remove framer-motion dependency * refactor: clean up ReviewTab and HackathonPublishedModal components, improve DateTimeInput logic, and update timeline constants * refactor: update timeline calculation logic to ensure phases are only created with non-zero duration and add endDate to HackathonTimeline interface * Judging dashboard (#384) * fix: modify api.ts * fix: remove google auth buttom * fix: fixes responsive fixes on organization * fix: minor fixes * fix: modify create organization * fix: modify create organization * fix: fix organization permission * fix: merge into main * feat: hackathon overview page * feat: hackathon overview page * feat: implement participant overview * feat: implement participant overview * feat: implement resources tab * feat: implement the submission tab * feat: implement comment tab * fix: implement provider for hackathon * fix: implement provider for hackathon * fix: minor fixes * fix: hackathon banner * fix: hackathon banner * fix: fix organization page * fix: fix organization page * fix: use transform * fix: add tagline * fix: add tagline * fix: minor fixes * fix: minor fixes * fix: fix timeline and prizes * fix: correct timeline events * fix: implement registration deadline policy * fix: implement registration deadline policy * feat: implement leave hackathon * feat: implement leave hackathon * fix: delete hackathon * fix: implement invite participants * fix: implement participant profile viewing * feat: fetch participants team * fix: redesign hackathon banner * fix: fix hackthon card * fix: fix search bar in blog page * fix: fix search bar in blog page * fix: fix search bar in blog page * fix: fix error in fetching team posts * feat: implement create team, get my team * feat: implement create team, get my team * feat: implement hackathon project submission flow * feat: implement voting for submission * fix: team formation updates * fix: implement team invitation * feat: hackathon submissions bulk actions, ranking and ui refinements * fix: implement empty state for hackathons page * feat: Implement submission visibility and explore submissions * feat: Implement winners tab for hackathon winners display * feat: implement hackathon analytics * fix: fix coderabbit corrections * fix: fix coderabbit corrections * fix: fix coderabbit corrections * fix: fix organization settings data persistence, hackathondrafts and population * feat: fix user profile * feat: Implemented the participant-facing and hackathon organizers announcement features * feat: Implement judging dashboard and detailed breakdowns * feat: Implement judging dashboard and detailed breakdowns * fix: fix coderabbit corrections * fix: submission management ux refinements * fix: submission management ux refinements * fix: submission management ux refinements * fix: submission management ux refinements * fix: submission management ux refinements * feat: implement organizer override functionality for judging scores a… (#385) * feat: implement organizer override functionality for judging scores and enhance judging UI * fix: update response handling in score submission and enhance submissions list styling * fix: update eslint dependencies to latest versions for improved linting * fix: update ajv and json-schema-traverse dependencies in package-lock.json * fix: update * fix: update security audit level to high in pre-push checks * fix: update eslint dependencies and ensure security audit fails on error * refactor: Dynamically determine Stellar network and centralize wallet utility functions, including explorer URLs and API key handling. --------- Co-authored-by: Nnaji Benjamin <60315147+Benjtalkshow@users.noreply.github.com>
Summary by CodeRabbit
New Features
UI/UX Improvements
Bug Fixes