Skip to content

Conversation

Piyushrathoree
Copy link
Collaborator

Proposed change

Resolves #1765

created the frontend implementation for the user badges for user card with a count and all the badges on the user detail page with tooltip for its name and also the badges are sorted properly.

I have also attached the demo badges screenshots and the badges in the summary section will changes according to the css_class coming from backend.

Checklist

  • I've read and followed the contributing guidelines.
  • I've run make check-test locally; all checks and tests passed.
Screenshot From 2025-09-13 21-53-18 Screenshot From 2025-09-13 21-53-04

- Introduced BadgeNode for GraphQL representation of badges.
- Enhanced UserNode with badges and badge count fields.
- Updated UserCard to display badge count and integrated Badges component in UserDetailsPage.
- Added tests for badge display and functionality across components.
- Updated GraphQL queries to include badge data and counts.
- Improved formatting and readability in user_test.py by adjusting line breaks.
- Updated mockBadgeData.ts to enhance consistency in object formatting.
- Simplified Tooltip mock in Badges.test.tsx for better clarity.
- Minor adjustments in Badges.tsx for consistent className formatting.
Copy link
Contributor

coderabbitai bot commented Sep 13, 2025

Summary by CodeRabbit

  • New Features
    • User profiles now display badges with icons and tooltips.
    • Member cards show a badge count with a medal icon when available.
    • Badges are shown in a consistent, meaningful order.
  • Improvements
    • User data now includes badge lists and a badge count for richer displays.
  • Tests
    • Added comprehensive unit tests for badges, user cards, and user details.
  • Chores
    • Updated spell-check dictionary entries for icon-related terms.

Walkthrough

Adds backend badge_count resolver and adjusts badges resolver ordering/return items; expands GraphQL user selections to include badges and badgeCount; introduces frontend Badge component, types, UserCard badgeCount display, member page badge rendering, tests, fixtures, and cspell additions.

Changes

Cohort / File(s) Summary of Changes
Backend GraphQL: User badges & count
backend/apps/github/api/internal/nodes/user.py
Rewrote badges resolver to return user_badge.badge, removed is_active filter, ordered by -badge__weight, badge__name; added badge_count(self) -> int resolver counting distinct badge_id.
Backend tests: UserNode badges & count
backend/tests/apps/github/api/internal/nodes/user_test.py
Added BadgeNode import and tests for badge_count and badges resolvers across empty/single/multiple scenarios; assert queryset chaining (select_related, order_by) and returned badge sequences.
Frontend component: Badges
frontend/src/components/Badges.tsx
New default-export Badges component: parses cssClass, resolves FontAwesome icon via findIconDefinition (prefix 'fas'), renders FontAwesomeIconWrapper with optional Tooltip, falls back to a generic/question icon for invalid/missing classes.
Frontend UI: Member pages & UserCard integration
frontend/src/app/members/[memberKey]/page.tsx, frontend/src/app/members/page.tsx, frontend/src/components/UserCard.tsx
Member detail page renders badges list; members list passes badges and badgeCount to UserCard; UserCard props extended with badgeCount, imports faMedal, and displays medal + millified badgeCount when > 0.
Frontend GraphQL queries
frontend/src/server/queries/userQueries.ts
Extended GET_LEADER_DATA, GET_USER_DATA, and GET_USER_METADATA selections to include badges { id, name, description, cssClass, weight } and badgeCount.
Frontend types
frontend/src/types/badge.ts, frontend/src/types/card.ts, frontend/src/types/user.ts
Added Badge type and added optional badges?: Badge[] and badgeCount?: number fields to UserCardProps and User types.
Frontend tests & mocks
frontend/__tests__/unit/components/Badges.test.tsx, frontend/__tests__/unit/components/UserCard.test.tsx, frontend/__tests__/unit/pages/UserDetails.test.tsx
Added comprehensive Badges unit tests; updated UserCard tests to cover badgeCount rendering/formatting; enhanced UserDetails tests with improved FontAwesomeIcon mock, MockBadges, and badge display tests; route param mock switched to memberKey.
Frontend test data
frontend/__tests__/unit/data/mockBadgeData.ts, frontend/__tests__/unit/data/mockUserDetails.ts
Added mockBadgeData and response fixtures including badges and badgeCount; extended mockUserDetailsData with badges and badgeCount.
Tooling: Spelling dictionary
cspell/custom-dict.txt
Added Font Awesome tokens: fa-brands, fa-regular, fa-solid, fab, far, fas.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • arkid15r
  • kasya

Pre-merge checks and finishing touches

❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The pull request title “Task/badge implementation in frontend” includes branch naming and punctuation that obscures the actual feature being delivered and does not clearly convey that this change implements user badge display and badge counts in the frontend. It is related to the changeset but is not a concise, descriptive summary of the main functionality. A more precise title would improve clarity for reviewers and maintainers. Rename the title to something like “Implement user badge display and badge count in frontend” to clearly communicate the feature and scope of the PR.
Linked Issues Check ⚠️ Warning The implementation adds badge count on user cards and full badge display on the detail page with Font Awesome integration, custom fallback, tests, and screenshots, satisfying most objectives of issue #1765. However, it does not render a compact set of up to six badge icons on the user list/page as specified in the linked issue, leaving the first display requirement unaddressed. Implement the compact badge icon set display (up to six badges) on the user list/page to fully satisfy issue #1765.
Out of Scope Changes Check ⚠️ Warning This PR includes unrelated changes to the cspell/custom-dict.txt file and a refactor of the useParams mock signature, neither of which are required for displaying user badges per issue #1765. These modifications fall outside the functional objectives of the linked issue and should be separated from the badge feature work. Extract the cspell dictionary updates and useParams mock renaming into a separate commit or PR to keep the badge feature implementation focused and reviewable.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed The pull request description directly references issue #1765 and outlines the addition of badge count on user cards, full badge display with tooltips on the detail page, and sorting logic, accompanied by demonstration screenshots and CI checklist confirmation. It clearly describes the implemented frontend behavior and how to test it, matching the contents of the diff.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (15)
cspell/custom-dict.txt (1)

59-59: Consider adding other common FA tokens to avoid future cspell noise.
Add: far, fab, fa-solid, fa-regular, fa-brands.

 fas
+far
+fab
+fa-solid
+fa-regular
+fa-brands
frontend/src/types/badge.ts (1)

1-7: Make Badge props readonly to prevent accidental mutation across components.

-export type Badge = {
+export type Badge = {
-  id: string
-  name: string
-  cssClass?: string
-  description?: string
-  weight: number
+  readonly id: string
+  readonly name: string
+  readonly cssClass?: string
+  readonly description?: string
+  readonly weight: number
 }
frontend/src/app/members/[memberKey]/page.tsx (1)

212-226: Ensure icon fallback includes a style prefix and apply deterministic client-side sort as a safety net.
If backend sorting changes or a badge lacks cssClass, this keeps order and rendering stable.

-        {user?.badges && user.badges.length > 0 && (
+        {user?.badges && user.badges.length > 0 && (
           <div className="mt-2 flex flex-wrap gap-2">
             <span className="text-sm text-gray-500 dark:text-gray-400">Badges:</span>
-            {user.badges.map((badge) => (
+            {user.badges
+              .slice()
+              .sort((a, b) => (b.weight - a.weight) || a.name.localeCompare(b.name))
+              .map((badge) => (
               <Badges
                 key={badge.id}
                 name={badge.name}
-                cssClass={badge.cssClass || 'fa-medal'}
+                cssClass={badge.cssClass || 'fa-solid fa-medal'}
                 description={badge.description || ''}
                 weight={badge.weight}
                 showTooltip={true}
               />
             ))}
           </div>
         )}
frontend/src/app/members/page.tsx (1)

44-45: Tiny stylistic nit.
Use nullish coalescing for arrays as well.

-        badges={user.badges || []}
+        badges={user.badges ?? []}
backend/tests/apps/github/api/internal/nodes/user_test.py (1)

18-44: Add a schema-level test to assert camelCased GraphQL fields (badgeCount, cssClass).

Backend types use snake_case (badge_count, css_class) while the frontend queries use camelCase; Strawberry will auto-convert snake_case to camelCase by default — add a small SDL/schema test that asserts the presence of "badgeCount" and "cssClass" in the generated schema. (github.com)

Relevant files to check: backend/settings/graphql.py, backend/apps/github/api/internal/nodes/user.py (badge_count), backend/apps/nest/api/internal/nodes/badge.py (css_class), frontend/src/server/queries/userQueries.ts.

frontend/src/components/UserCard.tsx (2)

72-77: Add accessible label and remove stray space.

Provide an aria label for the medal icon and drop the trailing {' '} to avoid rendering a superfluous text node.

-            {badgeCount > 0 && (
-              <p className="mt-1 max-w-[250px] truncate text-sm text-gray-600 sm:text-base dark:text-gray-400">
-                <FontAwesomeIcon icon={faMedal} className="mr-1 h-4 w-4" />
-                {millify(badgeCount, { precision: 1 })}{' '}
-              </p>
-            )}
+            {badgeCount > 0 && (
+              <p className="mt-1 max-w=[250px] truncate text-sm text-gray-600 sm:text-base dark:text-gray-400">
+                <FontAwesomeIcon icon={faMedal} className="mr-1 h-4 w-4" aria-label="badges" />
+                {millify(badgeCount, { precision: 1 })}
+              </p>
+            )}

36-36: Next/Image: use style for object-fit (Next 13+).

objectFit prop is deprecated; set via style to avoid console warnings.

-            <Image fill src={`${avatar}&s=160`} alt={name || 'user'} objectFit="cover" />
+            <Image fill src={`${avatar}&s=160`} alt={name || 'user'} style={{ objectFit: 'cover' }} />
backend/apps/github/api/internal/nodes/user.py (1)

41-45: Guard against duplicate rows in count.

If the through table ever allows duplicates (migration or data drift), .count() could overstate. Using .values("badge_id").distinct().count() is safer at minimal cost.

-        return self.badges.filter(is_active=True).count()
+        return (
+            self.badges.filter(is_active=True)
+            .values("badge_id")
+            .distinct()
+            .count()
+        )
frontend/__tests__/unit/components/UserCard.test.tsx (1)

113-142: Add assertion for medal icon in full-props case.

Minor but helps ensure medal isn’t accidentally dropped when other stats render.

       render(<UserCard {...fullProps} />)
@@
       expect(screen.getByText('25')).toBeInTheDocument()
+      expect(screen.getByTestId('icon-medal')).toBeInTheDocument()
frontend/src/server/queries/userQueries.ts (1)

89-97: Consider over-fetching on some views.

If certain pages only need badgeCount, consider gating the badges { ... } selection via separate queries or fragments to keep payloads small. Not blocking.

frontend/src/components/Badges.tsx (2)

1-7: Bundle size caution: adding the entire fas pack is heavy.

Registering all solid icons bloats the client bundle. If feasible, maintain a small allowlist (e.g., map backend cssClass to a curated set) and add only those, or lazy-load uncommon icons.


16-21: Normalize multiple prefixes and odd inputs.

Small hardening: strip repeated fa- prefixes and convert underscores to dashes to match FA naming.

-  const safeCssClass = cssClass || 'fa-medal'
-  const iconName = String(safeCssClass).replace(/^fa-/, '') as IconName
+  const safeCssClass = (cssClass ?? 'fa-medal') as string
+  const iconName = String(safeCssClass).trim().replace(/^(?:fa-)+/, '').replace(/_/g, '-') as IconName
frontend/__tests__/unit/pages/UserDetails.test.tsx (3)

18-29: Broaden FontAwesome mock to cover all IconProp shapes and avoid future brittleness

Support string icons too and keep rest props separate from DOM-unsafe ones. This keeps the mock resilient to upstream changes.

-jest.mock('@fortawesome/react-fontawesome', () => ({
-  FontAwesomeIcon: ({
-    icon,
-    className,
-    ...props
-  }: {
-    icon: string[] | { iconName: string }
-    className?: string
-    [key: string]: unknown
-  }) => {
-    const iconName = Array.isArray(icon) ? icon[1] : icon.iconName
-    return <span data-testid={`icon-${iconName}`} className={className} {...props} />
-  },
-}))
+jest.mock('@fortawesome/react-fontawesome', () => ({
+  FontAwesomeIcon: ({
+    icon,
+    className,
+    ...rest
+  }: {
+    icon: string | [string, string] | { iconName: string }
+    className?: string
+    [key: string]: unknown
+  }) => {
+    const iconName = Array.isArray(icon)
+      ? icon[1]
+      : typeof icon === 'string'
+      ? icon
+      : icon.iconName
+    return <span data-testid={`icon-${iconName}`} className={className} {...rest} />
+  },
+}))

32-56: Stabilize badge test-id slugging to reduce selector brittleness

Current slug only replaces whitespace; special chars remain (e.g., “badge-&-more!”). Consider mirroring production slugging (strip non-alphanumerics, collapse dashes) to avoid fragile selectors and potential collisions.

-  const MockBadges = ({
+  const MockBadges = ({
     name,
     cssClass,
     showTooltip,
   }: {
     name: string
     cssClass: string
     showTooltip?: boolean
   }) => (
-    <div
-      data-testid={`badge-${name.toLowerCase().replace(/\s+/g, '-')}`}
+    <div
+      data-testid={`badge-${name
+        .toLowerCase()
+        .replace(/[^a-z0-9]+/g, '-')
+        .replace(/^-+|-+$/g, '')}`}
       data-css-class={cssClass}
       data-show-tooltip={showTooltip}
     >
       <span data-testid={`icon-${cssClass.replace('fa-', '')}`} />
     </div>
   )

If you adopt this, please update the two tests that assert special-char IDs accordingly.


676-703: Optional: prefer a safer test-id for special characters

Using raw special characters in data-testid can be error-prone in selectors and tooling. If you keep them, consider also asserting by visible name or role to reduce coupling to test-id formatting.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88cc6dd and f22d2e0.

📒 Files selected for processing (17)
  • backend/apps/github/api/internal/nodes/user.py (2 hunks)
  • backend/apps/nest/api/internal/nodes/badge.py (1 hunks)
  • backend/tests/apps/github/api/internal/nodes/user_test.py (3 hunks)
  • cspell/custom-dict.txt (1 hunks)
  • frontend/__tests__/unit/components/Badges.test.tsx (1 hunks)
  • frontend/__tests__/unit/components/UserCard.test.tsx (3 hunks)
  • frontend/__tests__/unit/data/mockBadgeData.ts (1 hunks)
  • frontend/__tests__/unit/data/mockUserDetails.ts (1 hunks)
  • frontend/__tests__/unit/pages/UserDetails.test.tsx (2 hunks)
  • frontend/src/app/members/[memberKey]/page.tsx (2 hunks)
  • frontend/src/app/members/page.tsx (1 hunks)
  • frontend/src/components/Badges.tsx (1 hunks)
  • frontend/src/components/UserCard.tsx (3 hunks)
  • frontend/src/server/queries/userQueries.ts (3 hunks)
  • frontend/src/types/badge.ts (1 hunks)
  • frontend/src/types/card.ts (2 hunks)
  • frontend/src/types/user.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-11T15:57:56.648Z
Learnt from: Rajgupta36
PR: OWASP/Nest#1717
File: backend/apps/mentorship/graphql/queries/module.py:39-50
Timestamp: 2025-07-11T15:57:56.648Z
Learning: In the OWASP Nest mentorship GraphQL queries, Strawberry GraphQL automatically converts between Django Module instances and ModuleNode types, so methods can return Module instances directly without manual conversion even when typed as ModuleNode.

Applied to files:

  • backend/apps/nest/api/internal/nodes/badge.py
🧬 Code graph analysis (7)
frontend/src/types/card.ts (1)
frontend/src/types/badge.ts (1)
  • Badge (1-7)
frontend/src/types/user.ts (1)
frontend/src/types/badge.ts (1)
  • Badge (1-7)
backend/apps/github/api/internal/nodes/user.py (1)
backend/apps/nest/api/internal/nodes/badge.py (1)
  • BadgeNode (18-19)
backend/apps/nest/api/internal/nodes/badge.py (1)
frontend/src/types/badge.ts (1)
  • Badge (1-7)
backend/tests/apps/github/api/internal/nodes/user_test.py (2)
backend/apps/nest/api/internal/nodes/badge.py (1)
  • BadgeNode (18-19)
backend/apps/github/api/internal/nodes/user.py (3)
  • badges (32-39)
  • UserNode (28-69)
  • badge_count (42-44)
frontend/__tests__/unit/data/mockBadgeData.ts (1)
frontend/src/types/badge.ts (1)
  • Badge (1-7)
frontend/__tests__/unit/pages/UserDetails.test.tsx (2)
frontend/__tests__/unit/data/mockUserDetails.ts (1)
  • mockUserDetailsData (1-83)
backend/apps/github/api/internal/nodes/user.py (1)
  • badges (32-39)
🔇 Additional comments (14)
cspell/custom-dict.txt (1)

59-59: LGTM — avoids false positives for Font Awesome style token.

frontend/src/types/card.ts (1)

3-3: LGTM — props surface aligned with types and pages.

Also applies to: 80-82

frontend/__tests__/unit/data/mockUserDetails.ts (1)

16-33: Confirm Font Awesome version and update icon class.
fa-shield-alt is FA5; in FA6 the icon is shield-halved — use "fa-solid fa-shield-halved" (or "fas fa-shield-halved"); update frontend/tests/unit/data/mockUserDetails.ts (lines 16–33) to replace 'fa-shield-alt' or enable FA6 legacy aliases.

frontend/src/app/members/page.tsx (1)

37-46: Prefer backend-provided badgeCount with nullish coalescing; verify Algolia 'users' index has the field.

Use backend badgeCount when present; fall back to badges.length.

File: frontend/src/app/members/page.tsx (lines ~37-46)

-    const badgeCount = user.badges?.length || 0
+    const badgeCount = user.badgeCount ?? user.badges?.length ?? 0

Ensure the Algolia "users" index includes badgeCount (or keep the fallback).

frontend/src/types/user.ts (1)

1-1: Type additions look good — GraphQL camelCase is enabled by default.
Schema is instantiated in backend/settings/graphql.py (schema = strawberry.Schema(...)) with no explicit auto_camel_case override; Strawberry converts snake_case field names to camelCase by default, so frontend fields (badgeCount, badges, avatarUrl) will be exposed as expected. (github.com)

frontend/src/components/UserCard.tsx (1)

17-27: LGTM: prop addition and wiring look correct.

badgeCount is optional, default-falsy behavior is fine and won’t render when absent/0. Tests cover negative/undefined scenarios.

backend/apps/nest/api/internal/nodes/badge.py (1)

1-20: LGTM: schema surface matches frontend needs.

Fields map cleanly to GraphQL (auto-camelCase → cssClass), and read-only exposure is appropriate.

frontend/__tests__/unit/components/UserCard.test.tsx (1)

385-420: LGTM: badge count test coverage is solid.

Positive, zero, negative, and large-number formatting cases are covered alongside combined metrics.

frontend/src/server/queries/userQueries.ts (2)

10-18: LGTM: server–client field naming aligns.

badges { id name description cssClass weight } and badgeCount match backend’s auto-camelCased fields.


111-111: LGTM: metadata query exposes badgeCount for lightweight needs.

frontend/__tests__/unit/data/mockBadgeData.ts (1)

1-64: LGTM: concise fixtures match type surface.

Covers both with/without badges and aligns with Badge shape.

backend/apps/github/api/internal/nodes/user.py (1)

31-40: Confirm relation semantics for self.badges (through-model vs direct M2M)

Sandbox verification failed; confirm whether self.badges is a through-model (e.g., UserBadge) with is_active and a ForeignKey named badge (so user_badge.badge is valid). If it's a direct ManyToMany to Badge, select_related("badge") and user_badge.badge are incorrect and the resolver should be adjusted accordingly.

File: backend/apps/github/api/internal/nodes/user.py (lines 31–40)

frontend/__tests__/unit/pages/UserDetails.test.tsx (2)

521-533: Good coverage: presence of badges section and basic rendering

This validates the high-level rendering path without overspecifying implementation details. Nicely scoped.


598-656: Fallback cssClass behavior is exercised well

Both undefined and empty string cases are covered; assertions on the propagated prop keep the test focused on UI contract rather than implementation.

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

Please fix the conflicts and address bot's suggestions first.

@arkid15r arkid15r marked this pull request as draft September 13, 2025 18:48
@Piyushrathoree
Copy link
Collaborator Author

Please fix the conflicts and address bot's suggestions first.

Got it , I'll be doing it in morning

@Piyushrathoree Piyushrathoree marked this pull request as ready for review September 14, 2025 08:31
Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

Nice start! Left some requests.

// Fallback to a default icon if the specified icon doesn't exist
return (
<div className="inline-flex items-center">
{showTooltip ? (
Copy link
Collaborator

Choose a reason for hiding this comment

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

With this approach there's a code duplication for the same icon.
Tooltip component from heroui has isDisabled property that we can use instead and have just one line of code.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@Piyushrathoree why was this resolved? 😮 I don't see changes I requested in this comment.

You don't need a showTooltip ternary logic here. You can use have Tooltip wrapper around a single FA icon element and pass in showTooltip to isDisabled property in the Tooltip


return (
<div className="inline-flex items-center">
{showTooltip ? (
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here for code duplication.

Comment on lines 31 to 36
try {
findIconDefinition(lookup)
iconFound = true
} catch {
iconFound = false
}
Copy link
Collaborator

@kasya kasya Sep 14, 2025

Choose a reason for hiding this comment

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

You should be able to simplify this without having to set iconFound separately. If icon is found - it's true else I believe it returns null (you'll need to verify though!)
So you could just return result of findIconDefinition() here

Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here - this should not be marked as resoled if it wasn't addressed.
Did you try this out? If it's not possible - you need to respond with why this has not been applied

@{user?.login}
</Link>
<p className="text-gray-600 dark:text-gray-400">{formattedBio}</p>
{user?.badges && user.badges.length > 0 && (
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we use badgeCount here instead? 🤔

@kasya
Copy link
Collaborator

kasya commented Sep 14, 2025

Also please run make check before pushing your changes 👌🏼

@Piyushrathoree
Copy link
Collaborator Author

Also please run make check before pushing your changes 👌🏼

thanks for this kate , I'll be solving all the issues soon and make sure this for next issues

@Piyushrathoree Piyushrathoree marked this pull request as ready for review September 19, 2025 11:59
@Piyushrathoree
Copy link
Collaborator Author

image it is looking like this , please check it again . I've fixed it

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

@Piyushrathoree I unresolved all my comments that I left after last review - none of those were addressed but for some reason they were marked as resolved.

Please do not resolve the comments - those are for PR reviewers to resolve only after they were addressed.
Feel free to resolve any bot's comments (and this is actually required), but not reviewer's comments.

// Fallback to a default icon if the specified icon doesn't exist
return (
<div className="inline-flex items-center">
{showTooltip ? (
Copy link
Collaborator

Choose a reason for hiding this comment

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

@Piyushrathoree why was this resolved? 😮 I don't see changes I requested in this comment.

You don't need a showTooltip ternary logic here. You can use have Tooltip wrapper around a single FA icon element and pass in showTooltip to isDisabled property in the Tooltip

Comment on lines 31 to 36
try {
findIconDefinition(lookup)
iconFound = true
} catch {
iconFound = false
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same here - this should not be marked as resoled if it wasn't addressed.
Did you try this out? If it's not possible - you need to respond with why this has not been applied

@kasya
Copy link
Collaborator

kasya commented Sep 20, 2025

Also, these two blocks need to be aligned. This is how they look in staging right now compared to your changes:
Screenshot 2025-09-20 at 3 32 59 PM
Screenshot 2025-09-20 at 3 32 07 PM

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (10)
backend/apps/github/api/internal/nodes/user.py (1)

41-44: Prefer Count(distinct=True) aggregation for clarity.

Functionally equivalent to values().distinct().count(), but more idiomatic and expresses COUNT(DISTINCT) directly.

+from django.db.models import Count
@@
     def badge_count(self) -> int:
         """Resolve badge count."""
-        return self.user_badges.filter(is_active=True).values("badge_id").distinct().count()
+        return (
+            self.user_badges.filter(is_active=True)
+            .aggregate(n=Count("badge_id", distinct=True))["n"]
+        )
backend/tests/apps/github/api/internal/nodes/user_test.py (2)

86-100: Tighten interaction assertions for badge_count.

Add an assertion that count() was invoked once to fully validate the call chain.

         result = UserNode.badge_count(mock_user)
         assert result == 3
         mock_badges_queryset.filter.assert_called_once_with(is_active=True)
         mock_badges_queryset.filter.return_value.values.assert_called_once_with("badge_id")
         mock_badges_queryset.filter.return_value.values.return_value.distinct.assert_called_once()
+        mock_badges_queryset.filter.return_value.values.return_value.distinct.return_value.count.assert_called_once_with()

129-191: Optional: avoid coupling test doubles to BadgeNode spec.

Using spec=BadgeNode while setting .weight/.name may become brittle if the GraphQL type changes. Plain Mock objects suffice since sorting is exercised via queryset ordering, not object attributes.

-        mock_badge_high_weight = Mock(spec=BadgeNode)
+        mock_badge_high_weight = Mock()
@@
-        mock_badge_medium_weight_a = Mock(spec=BadgeNode)
+        mock_badge_medium_weight_a = Mock()
@@
-        mock_badge_medium_weight_b = Mock(spec=BadgeNode)
+        mock_badge_medium_weight_b = Mock()
@@
-        mock_badge_low_weight = Mock(spec=BadgeNode)
+        mock_badge_low_weight = Mock()
frontend/__tests__/unit/pages/UserDetails.test.tsx (7)

18-29: Harden FontAwesomeIcon mock to handle all IconProp cases

Covers string icons and avoids undefined testids.

-  }: {
-    icon: string[] | { iconName: string }
+  }: {
+    icon: string | string[] | { iconName?: string }
     className?: string
     [key: string]: unknown
   }) => {
-    const iconName = Array.isArray(icon) ? icon[1] : icon.iconName
-    return <span data-testid={`icon-${iconName}`} className={className} {...props} />
+    const iconName =
+      Array.isArray(icon) ? icon[1] : typeof icon === 'string' ? icon : icon?.iconName
+    return <span data-testid={`icon-${iconName ?? 'unknown'}`} className={className} {...props} />
   },

32-56: Make MockBadges resilient (no crash on undefined cssClass) and use a safer slug

Prevents .replace on undefined and stabilizes testids when names include punctuation.

-    <div
-      data-testid={`badge-${name.toLowerCase().replace(/\s+/g, '-')}`}
+    <div
+      data-testid={`badge-${name
+        .toLowerCase()
+        .replace(/[^a-z0-9]+/g, '-')
+        .replace(/^-|-$/g, '')}`}
       data-css-class={cssClass}
       data-show-tooltip={showTooltip}
     >
-      <span data-testid={`icon-${cssClass.replace('fa-', '')}`} />
+      <span data-testid={`icon-${(cssClass ?? '').replace(/^fa-/, '')}`} />

274-276: Inconsistent heatmap mock shape vs beforeEach

BeforeEach returns { contributions: { years: [...] } }; this test returns { years: [...] }. Align to one schema to avoid brittle tests.

-    ;(fetchHeatmapData as jest.Mock).mockResolvedValue({
-      years: [{ year: '2023' }], // Provide years data to satisfy condition in component
-    })
+    ;(fetchHeatmapData as jest.Mock).mockResolvedValue({
+      contributions: { years: [{ year: '2023' }] }, // Align with beforeEach
+    })

554-571: Also assert icon rendering to fully verify props → icon mapping

Strengthens the test without coupling to implementation.

       const contributorBadge = screen.getByTestId('badge-contributor')
       expect(contributorBadge).toHaveAttribute('data-css-class', 'fa-medal')
       expect(contributorBadge).toHaveAttribute('data-show-tooltip', 'true')
+      expect(screen.getByTestId('icon-medal')).toBeInTheDocument()

       const securityBadge = screen.getByTestId('badge-security-expert')
       expect(securityBadge).toHaveAttribute('data-css-class', 'fa-shield-alt')
       expect(securityBadge).toHaveAttribute('data-show-tooltip', 'true')
+      expect(screen.getByTestId('icon-shield-alt')).toBeInTheDocument()

573-593: Prefer queryAllByTestId with length assertions

Avoids false positives and supports multiple matches cleanly.

-        expect(screen.queryByTestId(/^badge-/)).not.toBeInTheDocument()
+        expect(screen.queryAllByTestId(/^badge-/)).toHaveLength(0)

595-615: Same here: use queryAllByTestId

Keeps the pattern consistent.

-        expect(screen.queryByTestId(/^badge-/)).not.toBeInTheDocument()
+        expect(screen.queryAllByTestId(/^badge-/)).toHaveLength(0)

696-724: Stabilize testid for special characters

If you adopt the safer slug in MockBadges, update this expectation accordingly.

-        expect(screen.getByTestId('badge-badge-&-more!')).toBeInTheDocument()
+        expect(screen.getByTestId('badge-badge-more')).toBeInTheDocument()
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1121d26 and cc30ab4.

📒 Files selected for processing (4)
  • backend/apps/github/api/internal/nodes/user.py (1 hunks)
  • backend/tests/apps/github/api/internal/nodes/user_test.py (3 hunks)
  • frontend/__tests__/unit/pages/UserDetails.test.tsx (3 hunks)
  • frontend/src/app/members/[memberKey]/page.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/app/members/[memberKey]/page.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
backend/tests/apps/github/api/internal/nodes/user_test.py (2)
backend/apps/nest/api/internal/nodes/badge.py (1)
  • BadgeNode (18-19)
backend/apps/github/api/internal/nodes/user.py (3)
  • UserNode (28-69)
  • badge_count (42-44)
  • badges (32-39)
frontend/__tests__/unit/pages/UserDetails.test.tsx (2)
frontend/__tests__/unit/data/mockUserDetails.ts (1)
  • mockUserDetailsData (1-83)
backend/apps/github/api/internal/nodes/user.py (1)
  • badges (32-39)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run frontend e2e tests
🔇 Additional comments (11)
backend/apps/github/api/internal/nodes/user.py (2)

41-44: Thanks for fixing the .value(...) bug flagged earlier.

The switch to .values("badge_id").distinct().count() resolves the runtime error noted previously.


33-39: Badges resolver OK — uniqueness enforced

UserBadge defines unique_together = ("badge", "user") in backend/apps/nest/models/user_badge.py (and migration backend/apps/nest/migrations/0004_userbadge.py); no deduping or model change required.

backend/tests/apps/github/api/internal/nodes/user_test.py (4)

21-24: Schema field coverage updated correctly.

Including badge_count in expected_field_names matches the new resolver.


101-112: Empty badges path covered.

Good guard ensuring graceful degradation when no badges exist.


113-128: Single badge path covered.

Mocks and expectations are clear.


193-206: Active-only filter validated.

Good verification that is_active=True is applied.

frontend/__tests__/unit/pages/UserDetails.test.tsx (5)

539-552: Badges presence test LGTM

Validates both badges render for users with badges.


617-645: Fallback cssClass test LGTM

Ensures production fallback is applied when cssClass is missing.

Confirm the page passes the fallback, not the mock, to avoid masking regressions later.


647-675: Empty cssClass fallback test LGTM

Covers the empty-string edge case.


677-694: Order assertion now matches backend sort (weight desc, then name asc)

This resolves the earlier note about reversed order.


725-755: Long-name badge test LGTM

Good coverage for rendering long labels.

...jest.requireActual('next/navigation'),
useRouter: jest.fn(() => mockRouter),
useParams: () => ({ userKey: 'test-user' }),
useParams: () => ({ memberKey: 'test-user' }),
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

🧩 Analysis chain

Route param change LGTM; verify no stale tests use userKey

Looks consistent with [memberKey] routes.


🏁 Script executed:

#!/bin/bash
# Find mocks/usages still referencing userKey
rg -nP -C2 '\buseParams\([^)]*\)\s*=>\s*\(\s*{[^}]*userKey' --type ts --type tsx
rg -nP '\[userKey\]|\buserKey\b' --type ts --type tsx

Length of output: 55


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search repo for any references to `userKey` or legacy route segments and show context.
rg -n -S -C2 'userKey' || true
rg -n -S -C2 'useParams' || true
rg -n -S -C2 '\[userKey\]' || true
rg -n -S -C2 'memberKey' || true

Length of output: 36351


Route param change LGTM — tests still mock userKey; update to memberKey

Found tests mocking useParams with userKey; change those mocks to memberKey to match the route rename.

  • frontend/tests/unit/pages/Users.test.tsx — useParams: () => ({ userKey: 'test-user' })
  • frontend/tests/unit/pages/Projects.test.tsx — useParams: () => ({ userKey: 'test-user' })
🤖 Prompt for AI Agents
In frontend/__tests__/unit/pages/UserDetails.test.tsx around line 69 (and also
update frontend/__tests__/unit/pages/Users.test.tsx and
frontend/__tests__/unit/pages/Projects.test.tsx where useParams is mocked), the
tests still mock the route param as userKey; change those mocks to return
memberKey instead (e.g. useParams: () => ({ memberKey: 'test-user' })) so they
match the renamed route parameter.

Copy link
Collaborator

@arkid15r arkid15r left a comment

Choose a reason for hiding this comment

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

This AI generated code needs a lot of clean up:

Comment on lines 33 to 37
"""List badges assigned to the user sorted by weight and name."""
user_badges = (
self.user_badges.select_related("badge")
.filter(is_active=True)
.order_by(
"badge__weight",
"badge__name",
)
self.user_badges.filter(is_active=True)
.select_related("badge")
.order_by("-badge__weight", "badge__name")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please revert if you don't introduce any changes here

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i have removed the is_active field and the -badge_weight is for sorting it from big to small

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why these changes?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

got it , fixed them

</Link>
<p className="text-gray-600 dark:text-gray-400">{formattedBio}</p>
{user?.badges && user.badges.length > 0 && (
<div className="mt-2 flex flex-wrap gap-2">
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why do you need to sort them here is they come sorted from the backend?

onclick: () => handleButtonClick(user),
}

const badgeCount = user.badges?.length || 0
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's use backend endpoint value instead.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't see any need for such complex logic for badges. It looks to me like ai-generated code and tbh it's a bad one. I also recommend checking FontAwesomeIconWrapper we have.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

got it , and also handled it properly and also used fontAwesomeIconWrapper properly

const UserCard = ({
avatar,
button,
badgeCount,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

because in the user cards I'm displaying a single badge with the count of how many badge a user have .

Copy link
Collaborator

Choose a reason for hiding this comment

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

@Piyushrathoree I'm pretty sure Ark meant "why bAdgeCount comes after bUtton" :)
Let's sort these alphabetically - this is something we try to keep in mind at all times.

@Piyushrathoree
Copy link
Collaborator Author

Piyushrathoree commented Sep 21, 2025

Hey @arkid15r @kasya , I'm really sorry I missed a lot of things , some of them are suggested by coderabbit ,
I'll address the issues ASAP and make sure there were no problem raise again and no ai generate code too

root and others added 3 commits September 21, 2025 10:45
- Updated UserNode to remove unnecessary filters for badge retrieval and count.
- Modified BadgeNode to inherit from Node and adjusted fields accordingly.
- Enhanced unit tests for UserNode to reflect changes in badge logic.
- Simplified Badges component by removing FontAwesome dependencies and using a wrapper for icon rendering.
- Improved UserDetailsPage to utilize badgeCount directly from user data.
- Adjusted UsersPage to reference badgeCount instead of calculating length.
- Updated GraphQL types to ensure BadgeNode extends Node for consistency.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
frontend/src/components/Badges.tsx (2)

12-20: Add accessible label when tooltip is disabled.

Screen readers get no name when isDisabled is true.

If you prefer minimal change without the refactor above, add aria-label to each icon:

-          <FontAwesomeIconWrapper icon={'fa-medal'} className="h-4 w-4" />
+          <FontAwesomeIconWrapper icon={'fa-medal'} className="h-4 w-4" aria-label={name} />
@@
-          <FontAwesomeIconWrapper icon={'fa-question'} className="h-4 w-4" />
+          <FontAwesomeIconWrapper icon={'fa-question'} className="h-4 w-4" aria-label={name} />
@@
-        <FontAwesomeIconWrapper icon={cssClass} className="h-4 w-4" />
+        <FontAwesomeIconWrapper icon={cssClass} className="h-4 w-4" aria-label={name} />

Also applies to: 35-41


11-11: Component renders a single badge; consider renaming to 'Badge'.

Improves clarity for future callers; export alias can remain for backwards compatibility.

backend/apps/github/api/internal/nodes/user.py (2)

33-33: Clarify sort directions in the docstring (nit).

-        """List badges assigned to the user sorted by weight and name."""
+        """List badges assigned to the user sorted by weight (desc) then name (asc)."""

39-42: Optional: use aggregate Count(distinct=...) for clarity.

Add import and switch to aggregate:

@@
-import strawberry
+import strawberry
+from django.db.models import Count
@@
     def badge_count(self) -> int:
         """Resolve badge count."""
-        return self.user_badges.values("badge_id").distinct().count()
+        return self.user_badges.aggregate(
+            n=Count("badge_id", distinct=True)
+        )["n"]
backend/tests/apps/github/api/internal/nodes/user_test.py (1)

131-191: Sorted ordering test mirrors the resolver contract well. Consider a lightweight helper to reduce repetition.

Tests are good. If you want to DRY them, extract a small factory for mock_user_badge and a fixture for mock_badges_queryset.

Example helper (optional, in the test module):

def make_user_badge(badge):
    ub = Mock()
    ub.badge = badge
    return ub
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc30ab4 and f429071.

⛔ Files ignored due to path filters (1)
  • frontend/src/types/__generated__/graphql.ts is excluded by !**/__generated__/**
📒 Files selected for processing (7)
  • backend/apps/github/api/internal/nodes/user.py (1 hunks)
  • backend/tests/apps/github/api/internal/nodes/user_test.py (3 hunks)
  • frontend/__tests__/unit/components/Badges.test.tsx (1 hunks)
  • frontend/__tests__/unit/pages/UserDetails.test.tsx (3 hunks)
  • frontend/src/app/members/[memberKey]/page.tsx (3 hunks)
  • frontend/src/app/members/page.tsx (1 hunks)
  • frontend/src/components/Badges.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • frontend/src/app/members/page.tsx
  • frontend/tests/unit/pages/UserDetails.test.tsx
  • frontend/src/app/members/[memberKey]/page.tsx
  • frontend/tests/unit/components/Badges.test.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
backend/tests/apps/github/api/internal/nodes/user_test.py (3)
backend/apps/nest/api/internal/nodes/badge.py (1)
  • BadgeNode (19-20)
frontend/src/types/__generated__/graphql.ts (2)
  • BadgeNode (40-47)
  • UserNode (859-881)
backend/apps/github/api/internal/nodes/user.py (3)
  • UserNode (28-67)
  • badge_count (40-42)
  • badges (32-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: CodeQL
🔇 Additional comments (9)
frontend/src/components/Badges.tsx (2)

22-41: Fix FA style detection and guard lookup; skip FA check for custom icons.

  • Hard‑coding 'fas' breaks 'far'/'fab' and tokens like 'fa-solid fa-crown'.
  • findIconDefinition throws when missing; current code can crash the render.
  • Custom/local (non‑FA) cssClass (OWASP‑specific) should render as‑is, not be forced to 'fa-question'.

Apply this diff to robustly parse style+icon, guard the lookup, and avoid false fallbacks for custom icons. Also dedup the JSX and add aria-label for a11y:

-  const iconDef = findIconDefinition({
-    prefix: 'fas',
-    iconName: cssClass.split(' ').pop().replace('fa-', '') as IconName,
-  })
-  if (!iconDef) {
-    return (
-      <div className="inline-flex items-center">
-        <Tooltip content={name} isDisabled={!showTooltip}>
-          <FontAwesomeIconWrapper icon={'fa-question'} className="h-4 w-4" />
-        </Tooltip>
-      </div>
-    )
-  }
-  return (
-    <div className="inline-flex items-center">
-      <Tooltip content={name} isDisabled={!showTooltip}>
-        <FontAwesomeIconWrapper icon={cssClass} className="h-4 w-4" />
-      </Tooltip>
-    </div>
-  )
+  // Parse FA tokens; support 'fas/fa-solid', 'far/fa-regular', 'fab/fa-brands'.
+  const safeCss = String(cssClass).trim()
+  const tokens = safeCss.split(/\s+/)
+  const styleToken = tokens.find((t) => /^(?:fa-(solid|regular|brands)|fas|far|fab)$/i.test(t))
+  const stylePrefix =
+    styleToken?.toLowerCase() === 'far' || styleToken?.toLowerCase() === 'fa-regular'
+      ? 'far'
+      : styleToken?.toLowerCase() === 'fab' || styleToken?.toLowerCase() === 'fa-brands'
+        ? 'fab'
+        : 'fas'
+  const faIconToken = tokens.find(
+    (t) => /^fa-[a-z0-9-]+$/i.test(t) && !/^fa-(solid|regular|brands)$/i.test(t),
+  )
+
+  // Default: trust custom/local classes; only FA‑lookup when we actually have an FA token.
+  let iconToRender = cssClass
+  if (faIconToken) {
+    const iconName = faIconToken.replace(/^fa-/, '') as IconName
+    try {
+      findIconDefinition({ prefix: stylePrefix, iconName })
+    } catch {
+      iconToRender = 'fa-question'
+    }
+  }
+
+  return (
+    <div className="inline-flex items-center">
+      <Tooltip content={name} isDisabled={!showTooltip}>
+        <FontAwesomeIconWrapper icon={iconToRender} className="h-4 w-4" aria-label={name} />
+      </Tooltip>
+    </div>
+  )

1-3: Confirmed — FontAwesome icons are registered; no action required.

frontend/src/utils/data.ts calls library.add(...) (line 36) and imports from @fortawesome/free-solid-svg-icons, @fortawesome/free-regular-svg-icons and @fortawesome/free-brands-svg-icons; unit tests also call library.add.

backend/apps/github/api/internal/nodes/user.py (2)

39-42: Fix confirmed: distinct count now uses .values(...).distinct().count().


33-37: Good resolver — uniqueness confirmed

select_related + ordering is correct. UserBadge.Meta declares unique_together = ("badge", "user") in backend/apps/nest/models/user_badge.py (also present in backend/apps/nest/migrations/0004_userbadge.py), so duplicates are prevented at the DB level.

backend/tests/apps/github/api/internal/nodes/user_test.py (5)

8-8: Importing BadgeNode for spec typing is appropriate.


21-24: Schema field list updated correctly to include badge_count.


86-98: badge_count test is precise and verifies the intended queryset chain.


99-112: Empty badges case covered; also asserts select_related/order_by usage.


113-130: Single-badge path exercised; spec usage keeps mocks tight.

@Piyushrathoree
Copy link
Collaborator Author

hey @arkid15r , I've addressed the problems and also tested it , please review it and please share your feedback.

Copy link
Collaborator

@kasya kasya left a comment

Choose a reason for hiding this comment

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

Left some comments ⬇️

const UserCard = ({
avatar,
button,
badgeCount,
Copy link
Collaborator

Choose a reason for hiding this comment

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

@Piyushrathoree I'm pretty sure Ark meant "why bAdgeCount comes after bUtton" :)
Let's sort these alphabetically - this is something we try to keep in mind at all times.

name
description
cssClass
weight
Copy link
Collaborator

Choose a reason for hiding this comment

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

Where do we use badge weight on the frontend? 🤔

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f429071 and 74f7704.

📒 Files selected for processing (1)
  • frontend/src/components/Badges.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend unit tests

Comment on lines 22 to 30
const iconDef = findIconDefinition({
prefix: 'fas',
iconName: cssClass.split(' ').pop().replace('fa-', '') as IconName,
})
return (
<div className="inline-flex items-center">
<Tooltip content={name} isDisabled={!showTooltip}>
<FontAwesomeIconWrapper icon={iconDef ? cssClass : 'fa-question'} className="h-4 w-4" />
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Respect badge style classes when resolving icons.

findIconDefinition is hard-coded to 'fas', so any fa-regular/fa-brands badge (e.g., fa-brands fa-github) fails the lookup and we always fall back to the question mark. That breaks the requirement to render the exact badge supplied by the backend.

Please derive the prefix from the class list (map fa-solid/fa-regular/fa-brands or their short aliases to 'fas' | 'far' | 'fab') and normalize the icon token instead of assuming the last segment. For example:

-  const iconDef = findIconDefinition({
-    prefix: 'fas',
-    iconName: cssClass.split(' ').pop().replace('fa-', '') as IconName,
-  })
+  const tokens = cssClass.trim().split(/\s+/).filter(Boolean)
+  let prefix: 'fas' | 'far' | 'fab' = 'fas'
+  for (const token of tokens) {
+    const normalized = token.toLowerCase()
+    if (normalized === 'fa-regular' || normalized === 'far') {
+      prefix = 'far'
+    } else if (normalized === 'fa-brands' || normalized === 'fab') {
+      prefix = 'fab'
+    } else if (normalized === 'fa-solid' || normalized === 'fas') {
+      prefix = 'fas'
+    }
+  }
+  const iconToken =
+    [...tokens]
+      .reverse()
+      .find((token) => /^fa-[a-z0-9-]+$/i.test(token) && !/^fa-(solid|regular|brands)$/i.test(token)) ?? 'fa-medal'
+  const iconName = iconToken.replace(/^fa-/, '').replace(/_/g, '-') as IconName
+
+  const iconDef = findIconDefinition({
+    prefix,
+    iconName,
+  })

That ensures brand and regular badges render instead of degrading to the fallback.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const iconDef = findIconDefinition({
prefix: 'fas',
iconName: cssClass.split(' ').pop().replace('fa-', '') as IconName,
})
return (
<div className="inline-flex items-center">
<Tooltip content={name} isDisabled={!showTooltip}>
<FontAwesomeIconWrapper icon={iconDef ? cssClass : 'fa-question'} className="h-4 w-4" />
// Derive style prefix and icon name from the full cssClass tokens
const tokens = cssClass.trim().split(/\s+/).filter(Boolean)
let prefix: 'fas' | 'far' | 'fab' = 'fas'
for (const token of tokens) {
const normalized = token.toLowerCase()
if (normalized === 'fa-regular' || normalized === 'far') {
prefix = 'far'
} else if (normalized === 'fa-brands' || normalized === 'fab') {
prefix = 'fab'
} else if (normalized === 'fa-solid' || normalized === 'fas') {
prefix = 'fas'
}
}
const iconToken =
[...tokens]
.reverse()
.find((t) => /^fa-[a-z0-9-]+$/i.test(t) && !/^fa-(solid|regular|brands)$/i.test(t))
?? 'fa-medal'
const iconName = iconToken.replace(/^fa-/, '').replace(/_/g, '-') as IconName
const iconDef = findIconDefinition({
prefix,
iconName,
})
return (
<div className="inline-flex items-center">
<Tooltip content={name} isDisabled={!showTooltip}>
<FontAwesomeIconWrapper icon={iconDef ? cssClass : 'fa-question'} className="h-4 w-4" />
🤖 Prompt for AI Agents
In frontend/src/components/Badges.tsx around lines 22 to 29, the code always
uses prefix 'fas' when calling findIconDefinition which breaks
fa-regular/fa-brands badges; parse the cssClass string for the FontAwesome style
token (accept full names fa-solid/fa-regular/fa-brands and the short aliases
fa-solid->'fas', fa-regular->'far', fa-brands->'fab'), determine the correct
prefix to pass to findIconDefinition, and normalize the icon name by stripping
any leading 'fa-' and taking the token that represents the icon (not always
simply .split(' ').pop()). Keep the existing fallback to the question mark if
the resolved iconDefinition is missing.

@Piyushrathoree Piyushrathoree force-pushed the task/badge-implementation-in-frontend branch from 74f7704 to ac27f26 Compare September 25, 2025 11:46
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74f7704 and ac27f26.

⛔ Files ignored due to path filters (1)
  • frontend/src/types/__generated__/userQueries.generated.ts is excluded by !**/__generated__/**
📒 Files selected for processing (3)
  • frontend/src/components/Badges.tsx (1 hunks)
  • frontend/src/components/UserCard.tsx (3 hunks)
  • frontend/src/server/queries/userQueries.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/components/UserCard.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run backend tests
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
🔇 Additional comments (6)
frontend/src/server/queries/userQueries.ts (5)

10-16: Confirm backend exposure of badges selection.

Pulling badges { id name description cssClass } from the user field assumes every backend GetLeaderData resolver now fetches and authorises this nested relation. Please double-check the matching GraphQL schema/resolvers before merging so we don’t ship a query that 500s in production.


16-16: badgeCount must exist on the backend schema.

Same concern here—if the backend has not yet deployed the badgeCount field on User, this addition will break the query at runtime. Please verify the field is live (or keep the change behind a feature flag).


88-94: Ensure badges is included in User resolver.

The broader GET_USER_DATA payload now fetches badge metadata. Confirm the backend resolvers and permissions expose this for the authenticated viewer; otherwise we’ll regress this query.


94-94: Verify badgeCount resolver availability.

Same as above—the badgeCount field needs to be in the deployed schema; please validate before shipping.


109-109: badgeCount field must exist in the metadata path.

Fetching badgeCount here will fail if the metadata resolver path was not updated. Double-check backend parity.

frontend/src/components/Badges.tsx (1)

22-25: Respect Font Awesome style prefixes.

findIconDefinition is hard-coded to the solid prefix ('fas'). Brand and regular badges (e.g., fa-brands fa-github, fa-regular fa-heart) will be treated as missing and always fall back to the question icon, breaking the badge display. Parse cssClass to derive the correct prefix ('fas' | 'far' | 'fab') before the lookup.

-  const iconDef = findIconDefinition({
-    prefix: 'fas',
-    iconName: cssClass.split(' ').pop().replace('fa-', '') as IconName,
-  })
+  const tokens = cssClass.trim().split(/\s+/).filter(Boolean)
+  let prefix: 'fas' | 'far' | 'fab' = 'fas'
+  for (const token of tokens) {
+    if (/^(fa-solid|fas)$/i.test(token)) prefix = 'fas'
+    else if (/^(fa-regular|far)$/i.test(token)) prefix = 'far'
+    else if (/^(fa-brands|fab)$/i.test(token)) prefix = 'fab'
+  }
+  const iconToken =
+    [...tokens]
+      .reverse()
+      .find((token) => /^fa-[a-z0-9-]+$/i.test(token) && !/^(fa-solid|fa-regular|fa-brands|fas|far|fab)$/i.test(token)) ?? 'fa-medal'
+  const iconName = iconToken.replace(/^fa-/, '') as IconName
+  const iconDef = findIconDefinition({ prefix, iconName })

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
frontend/src/components/Badges.tsx (1)

5-12: Align prop typing with runtime checks and backend data.

cssClass is required in the type but you handle it as optional/null at runtime. Make it optional to match upstream models and remove type noise at call sites.

-type BadgeProps = {
-  name: string
-  cssClass: string
-  showTooltip?: boolean
-}
+type BadgeProps = {
+  name: string
+  cssClass?: string | null
+  showTooltip?: boolean
+}
 
-const Badges = ({ name, cssClass, showTooltip = true }: BadgeProps) => {
+const Badges = ({ name, cssClass, showTooltip = true }: BadgeProps) => {
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac27f26 and 7535bc9.

📒 Files selected for processing (1)
  • frontend/src/components/Badges.tsx (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
frontend/src/components/Badges.tsx

[error] 37-37: Expected an expression but instead found '<'.

Expected an expression here.

(parse)

🪛 GitHub Actions: Run CI/CD
frontend/src/components/Badges.tsx

[error] 37-37: Declaration or statement expected. (SyntaxError) in Badges.tsx while running 'prettier --log-level warn --write .'.

🔇 Additional comments (2)
frontend/src/components/Badges.tsx (2)

1-4: Register all FA packs used by badges so lookups don’t always fall back.

Only solid ('fas') is implied; without registering 'far' and 'fab', findIconDefinition will fail for regular/brands, causing false fallbacks.

Apply:

-import { IconName, findIconDefinition } from '@fortawesome/fontawesome-svg-core'
-import { Tooltip } from '@heroui/tooltip'
-import FontAwesomeIconWrapper from 'wrappers/FontAwesomeIconWrapper'
+import { IconName, IconLookup, findIconDefinition, library } from '@fortawesome/fontawesome-svg-core'
+import { fas } from '@fortawesome/free-solid-svg-icons'
+import { far } from '@fortawesome/free-regular-svg-icons'
+import { fab } from '@fortawesome/free-brands-svg-icons'
+import { Tooltip } from '@heroui/tooltip'
+import FontAwesomeIconWrapper from 'wrappers/FontAwesomeIconWrapper'
+
+// Register packs so findIconDefinition works for all styles
+library.add(fas, far, fab)

If packs are already added globally, keep this out and confirm registry is in a shared module.

To verify global registration and avoid duplicate adds, run:

#!/bin/bash
rg -nP --type=ts -C2 "library\.add\s*\(" 
rg -nP --type=ts "@fortawesome/free-(solid|regular|brands)-svg-icons"

22-25: Don’t hard-code 'fas' or rely on split().pop(); parse tokens robustly.

Current logic breaks for 'fa-regular/fa-brands' or when the last token is a style token. The combined patch above (Lines 27–39) replaces this with style-aware parsing.

return (
<div className="inline-flex items-center">
<Tooltip content={name} isDisabled={!showTooltip}>
<FontAwesomeIconWrapper icon={'fa-medal'} className="h-4 w-4" />
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Ensure fallback includes a style prefix.

Use a full class with style to avoid ambiguous rendering.

-          <FontAwesomeIconWrapper icon={'fa-medal'} className="h-4 w-4" />
+          <FontAwesomeIconWrapper icon={'fa-solid fa-medal'} className="h-4 w-4" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<FontAwesomeIconWrapper icon={'fa-medal'} className="h-4 w-4" />
<FontAwesomeIconWrapper icon={'fa-solid fa-medal'} className="h-4 w-4" />
🤖 Prompt for AI Agents
In frontend/src/components/Badges.tsx around line 16, the fallback icon class
'fa-medal' is missing a FontAwesome style prefix which can cause ambiguous
rendering; update the icon prop to include the full style class (e.g., 'fas
fa-medal' or 'fa-solid fa-medal' to match the project's FA version) so the
fallback uses the correct style, and ensure any other fallback usages follow the
same prefixed pattern.

Comment on lines 27 to 39
return (
<div className="inline-flex items-center">
<Tooltip content={name} isDisabled={!showTooltip}>
<FontAwesomeIconWrapper
icon={iconDef ? `${prefix} fa-${iconName}` : 'fa-solid fa-question'}
className="h-4 w-4"
/>
</Tooltip>
</div>
)
</div>
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix JSX syntax errors and undefined identifiers in render block.

There are stray closing tags (Lines 37–38) and usage of undefined variables prefix and iconName (Line 31), causing the build to fail. Replace the lookup/render logic to derive and use well-defined variables and close JSX properly.

Apply:

-  const iconDef = findIconDefinition({
-    prefix: 'fas',
-    iconName: cssClass.split(' ').pop().replace('fa-', '') as IconName,
-  })
-
-  return (
-    <div className="inline-flex items-center">
-      <Tooltip content={name} isDisabled={!showTooltip}>
-        <FontAwesomeIconWrapper
-          icon={iconDef ? `${prefix} fa-${iconName}` : 'fa-solid fa-question'}
-          className="h-4 w-4"
-        />
-      </Tooltip>
-    </div>
-  )
-    </div>
-  )
+  // Parse cssClass to derive FA style + icon
+  const safeCss = String(cssClass).trim()
+  const tokens = safeCss.split(/\s+/).filter(Boolean)
+
+  // Map style tokens to lookup prefix and CSS prefix
+  let faLookupPrefix: 'fas' | 'far' | 'fab' = 'fas'
+  let cssPrefix = 'fa-solid'
+  for (const t of tokens) {
+    const n = t.toLowerCase()
+    if (n === 'fa-regular' || n === 'far') {
+      faLookupPrefix = 'far'
+      cssPrefix = 'fa-regular'
+    } else if (n === 'fa-brands' || n === 'fab') {
+      faLookupPrefix = 'fab'
+      cssPrefix = 'fa-brands'
+    } else if (n === 'fa-solid' || n === 'fas') {
+      faLookupPrefix = 'fas'
+      cssPrefix = 'fa-solid'
+    }
+  }
+
+  // Pick an icon token (ignore style tokens), default to medal
+  const iconToken =
+    [...tokens].reverse().find((t) => /^fa-[a-z0-9-]+$/i.test(t) && !/^fa-(solid|regular|brands)$/i.test(t)) ??
+    'fa-medal'
+  const iconName = iconToken.replace(/^fa-/, '').replace(/_/g, '-') as IconName
+  const renderClass = `${cssPrefix} fa-${iconName}`
+
+  // Will be null/undefined if not found; boolean check is enough
+  const iconDef = findIconDefinition({ prefix: faLookupPrefix as IconLookup['prefix'], iconName })
+
+  return (
+    <div className="inline-flex items-center">
+      <Tooltip content={name} isDisabled={!showTooltip}>
+        <FontAwesomeIconWrapper icon={iconDef ? renderClass : 'fa-solid fa-question'} className="h-4 w-4" />
+      </Tooltip>
+    </div>
+  )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
<div className="inline-flex items-center">
<Tooltip content={name} isDisabled={!showTooltip}>
<FontAwesomeIconWrapper
icon={iconDef ? `${prefix} fa-${iconName}` : 'fa-solid fa-question'}
className="h-4 w-4"
/>
</Tooltip>
</div>
)
</div>
)
}
// Parse cssClass to derive FA style + icon
const safeCss = String(cssClass).trim()
const tokens = safeCss.split(/\s+/).filter(Boolean)
// Map style tokens to lookup prefix and CSS prefix
let faLookupPrefix: 'fas' | 'far' | 'fab' = 'fas'
let cssPrefix = 'fa-solid'
for (const t of tokens) {
const n = t.toLowerCase()
if (n === 'fa-regular' || n === 'far') {
faLookupPrefix = 'far'
cssPrefix = 'fa-regular'
} else if (n === 'fa-brands' || n === 'fab') {
faLookupPrefix = 'fab'
cssPrefix = 'fa-brands'
} else if (n === 'fa-solid' || n === 'fas') {
faLookupPrefix = 'fas'
cssPrefix = 'fa-solid'
}
}
// Pick an icon token (ignore style tokens), default to medal
const iconToken =
[...tokens]
.reverse()
.find((t) => /^fa-[a-z0-9-]+$/i.test(t) && !/^fa-(solid|regular|brands)$/i.test(t)) ??
'fa-medal'
const iconName = iconToken.replace(/^fa-/, '').replace(/_/g, '-') as IconName
const renderClass = `${cssPrefix} fa-${iconName}`
// Will be null/undefined if not found; boolean check is enough
const iconDef = findIconDefinition({
prefix: faLookupPrefix as IconLookup['prefix'],
iconName,
})
return (
<div className="inline-flex items-center">
<Tooltip content={name} isDisabled={!showTooltip}>
<FontAwesomeIconWrapper
icon={iconDef ? renderClass : 'fa-solid fa-question'}
className="h-4 w-4"
/>
</Tooltip>
</div>
)
🧰 Tools
🪛 Biome (2.1.2)

[error] 37-37: Expected an expression but instead found '<'.

Expected an expression here.

(parse)

🪛 GitHub Actions: Run CI/CD

[error] 37-37: Declaration or statement expected. (SyntaxError) in Badges.tsx while running 'prettier --log-level warn --write .'.

🤖 Prompt for AI Agents
In frontend/src/components/Badges.tsx around lines 27 to 39, the render block
contains stray closing tags and references undefined identifiers `prefix` and
`iconName`; fix by deriving a single well-defined iconClass variable from the
incoming prop (e.g., if iconDef exists use `${iconDef.prefix}
fa-${iconDef.iconName}` else fallback to 'fa-solid fa-question'), remove the
extra two closing JSX tags so the component returns one properly closed root
element, and use iconClass in the FontAwesomeIconWrapper; ensure any dependent
props (showTooltip, name, iconDef) are referenced as they are declared in the
component signature.

…n (e.g., fa-crown for fa-solid). The frontend dynamically extracts the correct prefix for lookup and rendering. This is a critical design for backend compatibility,they are only fa-solid icons so badges.tsx only checks for fa-solid not anyother families.

fix the coderabbit issue with syntax.
also run make check-test
Copy link

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
frontend/src/components/Badges.tsx (2)

1-1: Remove unused svg-core import.

After dropping the lookup, this import is dead and should be deleted.

Apply this diff:

-import { IconName, findIconDefinition } from '@fortawesome/fontawesome-svg-core'

11-36: Optional: collapse to a single return with a resolved icon.

Removes branching and avoids future duplication.

Apply this diff:

-const Badges = ({ name, cssClass, showTooltip = true }: BadgeProps) => {
-  if (!cssClass || typeof cssClass !== 'string') {
-    return (
-      <div className="inline-flex items-center">
-        <Tooltip content={name} isDisabled={!showTooltip}>
-          <FontAwesomeIconWrapper icon={'fa-solid fa-medal'} className="h-4 w-4" />
-        </Tooltip>
-      </div>
-    )
-  }
-
-  const iconDef = findIconDefinition({
-    prefix: 'fas',
-    iconName: cssClass.split(' ').pop().replace('fa-', '') as IconName,
-  })
-
-  return (
-    <div className="inline-flex items-center">
-      <Tooltip content={name} isDisabled={!showTooltip}>
-        <FontAwesomeIconWrapper
-          icon={iconDef ? `fa-solid ${cssClass}` : 'fa-solid fa-question'}
-          className="h-4 w-4"
-        />
-      </Tooltip>
-    </div>
-  )
-}
+const Badges = ({ name, cssClass, showTooltip = true }: BadgeProps) => {
+  const resolvedIcon =
+    typeof cssClass === 'string' && cssClass.trim().length > 0 ? cssClass.trim() : 'fa-solid fa-medal'
+  return (
+    <div className="inline-flex items-center">
+      <Tooltip content={name} isDisabled={!showTooltip}>
+        <FontAwesomeIconWrapper icon={resolvedIcon} className="h-4 w-4" />
+      </Tooltip>
+    </div>
+  )
+}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7535bc9 and fb1e403.

📒 Files selected for processing (1)
  • frontend/src/components/Badges.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run frontend e2e tests
  • GitHub Check: Run frontend unit tests
  • GitHub Check: Run backend tests
🔇 Additional comments (3)
frontend/src/components/Badges.tsx (3)

12-20: Fallback path looks good.

Gracefully falls back to a solid medal when cssClass is absent or invalid.


22-25: Remove svg-core lookup; it’s unsafe here and breaks brands/custom icons.

findIconDefinition assumes icons are registered via library.add(...) and defaults to 'fas', so it will (a) throw/not find icons when packs aren’t registered and (b) mis-handle fa-regular/fa-brands and any custom/local icons — violating the PR objective to support custom/OWASP icons. Prefer passing the provided class straight to the wrapper and only fall back when cssClass is absent.

Apply this diff:

-  const iconDef = findIconDefinition({
-    prefix: 'fas',
-    iconName: cssClass.split(' ').pop().replace('fa-', '') as IconName,
-  })

Based on learnings


27-35: Don’t hard-code ‘fa-solid’; render the provided class as-is.

Prepending fa-solid creates invalid combos like fa-solid fa-brands fa-github. Also, the iconDef check is unnecessary after removing the lookup; just pass cssClass.

Apply this diff:

-      <Tooltip content={name} isDisabled={!showTooltip}>
-        <FontAwesomeIconWrapper
-          icon={iconDef ? `fa-solid ${cssClass}` : 'fa-solid fa-question'}
-          className="h-4 w-4"
-        />
-      </Tooltip>
+      <Tooltip content={name} isDisabled={!showTooltip}>
+        <FontAwesomeIconWrapper icon={cssClass} className="h-4 w-4" />
+      </Tooltip>

@Piyushrathoree
Copy link
Collaborator Author

@kasya done with the changes and the heatmap is aligned with its skeleton

@Piyushrathoree
Copy link
Collaborator Author

@arkid15r please take a look here

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Display user badges on frontend
3 participants