-
Notifications
You must be signed in to change notification settings - Fork 172
feat(table): add sorting icons and complete column sorting support #248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat(table): add sorting icons and complete column sorting support #248
Conversation
|
@pranay911 is attempting to deploy a commit to the AJEET PRATAP SINGH's projects Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughEnhanced ProjectsContainer with client-side sorting and filtering capabilities. Added sortable column headers with keyboard accessibility, visual sorting indicators, and multi-criteria filters (name search, language, stage, competition, activity, issue range, popularity). Implemented a two-stage data pipeline: filter then sort with deterministic tiebreakers. Added Reset button and improved empty state messaging. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ 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 |
|
|
1 similar comment
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/src/components/dashboard/ProjectsContainer.tsx (2)
1-21: Import organization doesn't follow guidelines.Per coding guidelines, imports should be organized: React → third-party → local components → utils → types. Consider reordering:
"use client"; -import React, { useMemo, useState } from "react"; +import React, { useMemo, useState } from "react"; + +import Image from "next/image"; +import { usePathname } from "next/navigation"; +import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { ChevronUpIcon, ChevronDownIcon, ArrowsUpDownIcon } from "@heroicons/react/24/solid"; + import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; + import { useProjectTitleStore } from "@/store/useProjectTitleStore"; -import { DashboardProjectsProps } from "@/types"; -import Image from "next/image"; import { useFilterStore } from "@/store/useFilterStore"; -import { usePathname } from "next/navigation"; -import { MagnifyingGlassIcon } from "@heroicons/react/24/outline"; -import { ChevronUpIcon, ChevronDownIcon, ArrowsUpDownIcon } from "@heroicons/react/24/solid"; + +import { DashboardProjectsProps } from "@/types";
168-231: Avoidanytype — use proper TypeScript types.The helper functions and dynamic property access use
anywhich violates coding guidelines. Consider typing more strictly:- const getStr = (v: any) => (v == null ? "" : String(v).toLowerCase()); - const getNum = (v: any) => { + const getStr = (v: unknown): string => (v == null ? "" : String(v).toLowerCase()); + const getNum = (v: unknown): number => { const n = Number(v); return Number.isFinite(n) ? n : 0; };For the dynamic property access on lines 218-219, consider using a type-safe approach:
case "stage": case "competition": case "activity": { - const A = getStr((a as any)[sortColumn]); - const B = getStr((b as any)[sortColumn]); + const key = sortColumn as keyof Pick<DashboardProjectsProps, "stage" | "competition" | "activity">; + const A = getStr(a[key]); + const B = getStr(b[key]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/src/components/dashboard/ProjectsContainer.tsx(6 hunks)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx,js,jsx}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
apps/web/src/**/*.{ts,tsx}: Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
NEVER use hardcoded hex values (e.g.,#5519f7) directly in components; ALWAYS reference colors from the design token system using Tailwind classes
Use semantic color names that describe purpose, not appearance
Usefont-sansfor standard UI text (Geist Sans) andfont-monofor code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale (0.25rem increments); for section padding use mobilep-4(1rem) and desktopp-[60px]
Use appropriate border radius: small elementsrounded-lg, mediumrounded-xl, largerounded-2xl, buttonsrounded-[16px]
Use animation durations: fastduration-100(0.1s), normalduration-300(0.3s), slowduration-600(0.6s)
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{tsx,ts}: Prefer functional components with TypeScript and use proper TypeScript types, avoidany
Extract reusable logic into custom hooks
Use descriptive prop names and define prop types using TypeScript interfaces or types
Prefer controlled components over uncontrolled
Use zustand for global state (located insrc/store/)
Use absolute imports from@/prefix when available
Include proper aria labels for accessibility
Ensure keyboard navigation works
Maintain proper heading hierarchy
Provide alt text for images
Avoid unnecessary re-renders
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (.cursorrules)
Organize imports: react → third-party → local components → utils → types
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
**/*[A-Z]*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Use PascalCase for component file names (e.g.,
UserProfile.tsx)
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{ts,tsx}: Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Memoize expensive computations
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (.cursorrules)
Optimize images using next/image
apps/web/src/**/*.{tsx,ts}: Use Zustand for global state, located insrc/store/
Use PascalCase for types and interfaces with descriptive names
Use dynamic imports for code splitting when appropriate
Optimize images using next/image
Memoize expensive computations
Define a type when defining const functions
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}
📄 CodeRabbit inference engine (.cursor/rules/general_rules.mdc)
**/*.{js,jsx,ts,tsx,py,java,go,rb,php}: Always use lowercase when writing comments
Avoid unnecessary comments; code should be self-documenting when possible
Use comments to explain 'why', not 'what'
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/components/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts,jsx,js}: Never use hardcoded hex values directly in components; always reference colors from the design token system using Tailwind classes
Use semantic color names from the design token system that describe purpose, not appearance (e.g., bg-brand-purple, bg-surface-primary, text-text-primary)
Use font-sans for standard UI text (Geist Sans) and font-mono for code, technical content, or monospace needs (DM Mono)
Follow Tailwind's spacing scale for section padding: p-4 (1rem) on mobile, p-[60px] on desktop
Use rounded-lg (0.5rem) for small elements, rounded-xl (1rem) for medium elements, rounded-2xl (1.5rem) for large elements, and rounded-[16px] for buttons
Use duration-100 (0.1s) for fast transitions, duration-300 (0.3s) for normal transitions, and duration-600 (0.6s) for slow transitions
Use available custom animations: animate-accordion-down, animate-accordion-up, animate-scrollRight, animate-scrollLeft, animate-customspin, animate-spin-slow, animate-spin-slow-reverse, animate-marquee, animate-marquee-vertical, animate-shine
Prefer functional components with TypeScript
Extract reusable logic into custom hooks
Prefer controlled components over uncontrolled
Include proper aria labels for accessibility
Ensure keyboard navigation works in interactive components
Maintain proper heading hierarchy in page components
Provide alt text for images
Use 'class:' instead of the ternary operator in class tags whenever possible
Implement accessibility features on interactive elements (e.g., tabindex='0', aria-label, onClick, onKeyDown)
Always follow the design system defined inapps/web/src/lib/design-tokens.tsandapps/web/tailwind.config.ts
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/components/**/*.{tsx,ts}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/components/**/*.{tsx,ts}: Use proper TypeScript types and avoid usinganytype
Use descriptive prop names and define prop types using TypeScript interfaces or types
Name components using PascalCase (e.g., UserProfile.tsx)
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
apps/web/src/**/*.{tsx,ts,jsx,js}
📄 CodeRabbit inference engine (apps/web/.cursor/rules/frontend_rules.mdc)
apps/web/src/**/*.{tsx,ts,jsx,js}: Organize imports in order: React → third-party → local components → utils → types
Use absolute imports from@/prefix when available
Remove unused imports
Use UPPER_SNAKE_CASE for constants
Use camelCase for functions and variables
Always use Tailwind classes for styling HTML elements; avoid using CSS or style tags
Use descriptive variable and function names; name event functions with a 'handle' prefix (e.g., handleClick, handleKeyDown)
Use const with arrow functions instead of function declarations (e.g., 'const toggle = () =>')
Files:
apps/web/src/components/dashboard/ProjectsContainer.tsx
🔇 Additional comments (7)
apps/web/src/components/dashboard/ProjectsContainer.tsx (7)
46-54: LGTM!Clean column definition structure with sortable metadata. This supports the sorting feature requirements well.
62-94: State initialization looks good.Sensible defaults with issues sorted descending. Filter state is well-organized for the multiple filter criteria.
67-83: Keyboard accessibility properly implemented.The
handleHeaderKeycorrectly handles both Enter and Space keys withpreventDefault()to avoid scroll behavior. Sort toggle logic is sound.
396-433: Excellent accessibility implementation for sortable headers.Good use of
role="button",tabIndex,aria-sort, and keyboard event handling. The implementation correctly:
- Sets
aria-sortto "ascending", "descending", or "none"- Makes only sortable columns focusable with
tabIndex={0}- Handles both click and keyboard interactions
Minor: The type cast on line 420
(e as React.KeyboardEvent, col.key)is unnecessary sinceonKeyDownalready provides the correct event type.
245-254: LGTM!Clear visual feedback with distinct icons for unsorted (↕), ascending (▲), and descending (▼) states. The reduced opacity on unsorted columns appropriately indicates interactivity without drawing attention.
436-475: Table body correctly uses sorted data.The table rows iterate over the
sortedarray which applies filters first, then sorting — maintaining the correct data pipeline as described in the objectives.
374-376: Remove theas anycast on Button variant.The
variant={"ghost" as any}violates TypeScript best practices and should not use type assertions. Verify that "ghost" is a valid variant in the Button component's type definition. If valid, remove the cast; if invalid, use a variant that exists in the component's types.
| // Issues range | ||
| const issues = Number(p.totalIssueCount ?? 0); | ||
| if (minIssues !== "") { | ||
| const mi = Number(minIssues); | ||
| if (!Number.isFinite(mi) || issues < mi) return false; | ||
| } | ||
| if (maxIssues !== "") { | ||
| const ma = Number(maxIssues); | ||
| if (!Number.isFinite(ma) || issues > ma) return false; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invalid numeric input silently filters out all results.
If a user enters non-numeric text (e.g., "abc") in min/max issues fields, Number("abc") returns NaN, causing !Number.isFinite(mi) to be true, which filters out all projects. Consider ignoring invalid values instead:
if (minIssues !== "") {
const mi = Number(minIssues);
- if (!Number.isFinite(mi) || issues < mi) return false;
+ if (Number.isFinite(mi) && issues < mi) return false;
}
if (maxIssues !== "") {
const ma = Number(maxIssues);
- if (!Number.isFinite(ma) || issues > ma) return false;
+ if (Number.isFinite(ma) && issues > ma) return false;
}This way invalid input is effectively ignored rather than hiding all results.
🤖 Prompt for AI Agents
In apps/web/src/components/dashboard/ProjectsContainer.tsx around lines 140-149,
the current logic treats non-numeric min/max inputs as invalid and returns false
(filtering out all projects). Change the checks so that if Number(minIssues) or
Number(maxIssues) produces NaN (i.e., not finite) you simply skip that
particular min/max check instead of returning false; specifically, parse the
value to a number, only apply the comparison when Number.isFinite(parsed) is
true, and otherwise ignore the filter (no early return) so invalid text input
does not hide all results.
This PR introduces complete column sorting support along with sorting icons for enhanced usability and accessibility. Previously, the project table supported partial sorting without any visual indication, making it unclear to users which column was currently sorted.
This update adds:
Related Issues
Closes #245
Screenshots

Summary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings.