Feat/badges#195
Conversation
) Adds year selector pills (current year minus 5) above the heatmap. Clicking a year fetches that year's contribution data via a new API route and re-renders the heatmap and streak counts. Changes: - New API route: src/app/api/[username]/contributions/route.ts - New client component: src/components/profile/HeatmapWithYearNav.tsx - Modified: src/lib/github.ts (added optional 'from' param to fetchContributionCalendar) - Modified: src/components/profile/ProfileView.tsx (replaced inline heatmap with HeatmapWithYearNav) Year pills use pill-tag-green for active and pill-tag-soft for inactive per DESIGN.md. Signed-off-by: Adit Jain <aditjain2005@gmail.com>
Addresses CodeRabbit review: - API route: validate year is 4-digit number in acceptable range, return 400 for bad input - Client component: skip fetch when clicking the already-selected year Signed-off-by: Adit Jain <aditjain2005@gmail.com>
Changed guard from (year === selectedYear) to (year === selectedYear && weeks.length > 0) so users can click the same year to retry after a network failure. Signed-off-by: Adit Jain <aditjain2005@gmail.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds badge storage to ChangesProfile Badges Feature
Sequence Diagram(s)sequenceDiagram
participant ProfileOwner
participant ProfileView
participant Supabase
ProfileOwner->>ProfileView: open add-badge dialog
ProfileView->>ProfileView: showModal()
ProfileOwner->>ProfileView: choose program and year
ProfileView->>Supabase: upsert profiles.badges
Supabase-->>ProfileView: success or error
ProfileView->>ProfileView: update badgesList
ProfileOwner->>ProfileView: remove badge
ProfileView->>Supabase: upsert filtered badges
Supabase-->>ProfileView: success or error
ProfileView->>ProfileView: update badgesList
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/`[username]/page.tsx:
- Around line 112-130: The badges handling in the profile page still trusts
Array.isArray(profileRow.badges), which allows malformed entries through and can
break ProfileView when it reads BadgeItem fields. Update the badges parsing in
the page component to validate and filter each entry from profileRow.badges into
a real BadgeItem[] before assigning it, rejecting nulls and objects with invalid
program/years values so only well-formed badges are passed onward.
In `@src/components/profile/ProfileView.tsx`:
- Around line 1189-1205: The dialog in ProfileView.tsx needs an accessible name
so screen readers do not announce it as only “dialog”. Update the <dialog>
element used in the add-program-badge flow to reference the visible heading in
that same block (the h3 “Add Program Badge”) with aria-labelledby, or provide an
equivalent aria-label, so the dialog is properly labeled without changing its
visual behavior.
- Around line 142-149: Move the badge synchronization logic out of the render
path in ProfileView.tsx: the current `if (badges !== prevBadges)` block updates
state during render and can cause extra re-renders or loops when `badges` is a
new array reference. Remove `prevBadges` entirely and use an effect to sync
`badgesList` from `badges` in `ProfileView`, keeping the state update inside the
effect instead of directly in the component body.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: ea8a0a22-d221-4aa9-a615-04e3a45cb16c
📒 Files selected for processing (6)
src/app/[username]/page.tsxsrc/app/globals.csssrc/components/profile/ProfileView.tsxsrc/types/index.tssupabase/migrations/20260623000000_add_badges_to_profiles.sqlsupabase/schema.sql
| <dialog | ||
| ref={dialogRef} | ||
| style={{ | ||
| border: "1px solid var(--color-hairline)", | ||
| borderRadius: "12px", | ||
| padding: "24px", | ||
| backgroundColor: "var(--color-canvas)", | ||
| color: "var(--color-ink)", | ||
| maxWidth: "400px", | ||
| width: "calc(100% - 32px)", | ||
| boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)", | ||
| }} | ||
| > | ||
| <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}> | ||
| <h3 style={{ fontSize: "18px", fontWeight: 600, margin: 0, color: "var(--color-ink)", letterSpacing: "-0.2px" }}> | ||
| Add Program Badge | ||
| </h3> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Give the dialog an accessible name.
Screen readers will currently announce this as just “dialog”. Link it to the heading with aria-labelledby or add an aria-label.
Suggested fix
<dialog
ref={dialogRef}
+ aria-labelledby="add-badge-title"
style={{
...
- <h3 style={{ fontSize: "18px", fontWeight: 600, margin: 0, color: "var(--color-ink)", letterSpacing: "-0.2px" }}>
+ <h3 id="add-badge-title" style={{ fontSize: "18px", fontWeight: 600, margin: 0, color: "var(--color-ink)", letterSpacing: "-0.2px" }}>
Add Program Badge
</h3>📝 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.
| <dialog | |
| ref={dialogRef} | |
| style={{ | |
| border: "1px solid var(--color-hairline)", | |
| borderRadius: "12px", | |
| padding: "24px", | |
| backgroundColor: "var(--color-canvas)", | |
| color: "var(--color-ink)", | |
| maxWidth: "400px", | |
| width: "calc(100% - 32px)", | |
| boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)", | |
| }} | |
| > | |
| <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}> | |
| <h3 style={{ fontSize: "18px", fontWeight: 600, margin: 0, color: "var(--color-ink)", letterSpacing: "-0.2px" }}> | |
| Add Program Badge | |
| </h3> | |
| <dialog | |
| ref={dialogRef} | |
| aria-labelledby="add-badge-title" | |
| style={{ | |
| border: "1px solid var(--color-hairline)", | |
| borderRadius: "12px", | |
| padding: "24px", | |
| backgroundColor: "var(--color-canvas)", | |
| color: "var(--color-ink)", | |
| maxWidth: "400px", | |
| width: "calc(100% - 32px)", | |
| boxShadow: "0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)", | |
| }} | |
| > | |
| <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}> | |
| <h3 id="add-badge-title" style={{ fontSize: "18px", fontWeight: 600, margin: 0, color: "var(--color-ink)", letterSpacing: "-0.2px" }}> | |
| Add Program Badge | |
| </h3> |
🧰 Tools
🪛 React Doctor (0.5.8)
[warning] 1189-1189: This dialog has no accessible name, so screen readers announce it as just “dialog.” Add aria-label or point aria-labelledby at its heading.
Give every <dialog> / role="dialog" an accessible name with aria-label or aria-labelledby (referencing the dialog's title element).
(dialog-has-accessible-name)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/components/profile/ProfileView.tsx` around lines 1189 - 1205, The dialog
in ProfileView.tsx needs an accessible name so screen readers do not announce it
as only “dialog”. Update the <dialog> element used in the add-program-badge flow
to reference the visible heading in that same block (the h3 “Add Program Badge”)
with aria-labelledby, or provide an equivalent aria-label, so the dialog is
properly labeled without changing its visual behavior.
Source: Linters/SAST tools
|
@abhilasha2101 pls review and fix the coderabbit comments |
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 (2)
src/components/profile/ProfileView.tsx (2)
203-209: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winRemove the auth debug log before shipping.
This logs internal user/profile identifiers in production browsers. It’s easy to drop now and avoids leaking auth metadata through client logs.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` around lines 203 - 209, Remove the auth debug logging from ProfileView before shipping, since it exposes internal user/profile identifiers in the browser. Delete the console.log in ProfileView that references profileId, authUser, user.login, and isOwner, and keep the surrounding owner-check logic unchanged.
747-768: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAdd an accessible name to the remove button.
titleis not a reliable accessible name, and the visible×is ambiguous. Addaria-labelso screen-reader users know which badge will be removed.Proposed fix
onClick={() => handleRemoveBadge(badge.program)} title={`Remove ${badge.program} badge`} + aria-label={`Remove ${badge.program} badge`}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` around lines 747 - 768, The remove badge button in ProfileView lacks a reliable accessible name because it only uses the ambiguous “×” glyph and title. Update the button in the badge removal UI to add an aria-label that clearly names the badge being removed, using the existing badge.program value so screen readers announce the specific action. Keep the button behavior and title as-is, but ensure the accessible name comes from aria-label on the remove button element.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/profile/ProfileView.tsx`:
- Around line 1038-1070: The heatmap month-label row in ProfileView is laid out
as a sibling of the week columns, so the labels render beside the chart instead
of above it. Update the markup around the heatmap block to use a vertical
wrapper for the labels and the week grid, keeping the month-label mapping logic
in the same ProfileView component but rendering the week columns in a separate
row beneath it.
- Line 972: The language indicator in ProfileView uses an invalid fallback color
for unknown languages. Update the fallback in the span style next to the
language label so the dot uses a valid CSS hex value, replacing the current
malformed fallback with the intended gray value; keep the change localized to
the LANG_COLORS lookup in ProfileView.
---
Outside diff comments:
In `@src/components/profile/ProfileView.tsx`:
- Around line 203-209: Remove the auth debug logging from ProfileView before
shipping, since it exposes internal user/profile identifiers in the browser.
Delete the console.log in ProfileView that references profileId, authUser,
user.login, and isOwner, and keep the surrounding owner-check logic unchanged.
- Around line 747-768: The remove badge button in ProfileView lacks a reliable
accessible name because it only uses the ambiguous “×” glyph and title. Update
the button in the badge removal UI to add an aria-label that clearly names the
badge being removed, using the existing badge.program value so screen readers
announce the specific action. Keep the button behavior and title as-is, but
ensure the accessible name comes from aria-label on the remove button element.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b0aa4441-23a0-49ff-a8d1-00a2f478202d
📒 Files selected for processing (1)
src/components/profile/ProfileView.tsx
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
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 (2)
src/components/profile/ProfileView.tsx (2)
203-209: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick winRemove the auth debug log before shipping.
This logs internal user/profile identifiers in production browsers. It’s easy to drop now and avoids leaking auth metadata through client logs.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` around lines 203 - 209, Remove the auth debug logging from ProfileView before shipping, since it exposes internal user/profile identifiers in the browser. Delete the console.log in ProfileView that references profileId, authUser, user.login, and isOwner, and keep the surrounding owner-check logic unchanged.
747-768: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winAdd an accessible name to the remove button.
titleis not a reliable accessible name, and the visible×is ambiguous. Addaria-labelso screen-reader users know which badge will be removed.Proposed fix
onClick={() => handleRemoveBadge(badge.program)} title={`Remove ${badge.program} badge`} + aria-label={`Remove ${badge.program} badge`}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` around lines 747 - 768, The remove badge button in ProfileView lacks a reliable accessible name because it only uses the ambiguous “×” glyph and title. Update the button in the badge removal UI to add an aria-label that clearly names the badge being removed, using the existing badge.program value so screen readers announce the specific action. Keep the button behavior and title as-is, but ensure the accessible name comes from aria-label on the remove button element.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/profile/ProfileView.tsx`:
- Around line 1038-1070: The heatmap month-label row in ProfileView is laid out
as a sibling of the week columns, so the labels render beside the chart instead
of above it. Update the markup around the heatmap block to use a vertical
wrapper for the labels and the week grid, keeping the month-label mapping logic
in the same ProfileView component but rendering the week columns in a separate
row beneath it.
- Line 972: The language indicator in ProfileView uses an invalid fallback color
for unknown languages. Update the fallback in the span style next to the
language label so the dot uses a valid CSS hex value, replacing the current
malformed fallback with the intended gray value; keep the change localized to
the LANG_COLORS lookup in ProfileView.
---
Outside diff comments:
In `@src/components/profile/ProfileView.tsx`:
- Around line 203-209: Remove the auth debug logging from ProfileView before
shipping, since it exposes internal user/profile identifiers in the browser.
Delete the console.log in ProfileView that references profileId, authUser,
user.login, and isOwner, and keep the surrounding owner-check logic unchanged.
- Around line 747-768: The remove badge button in ProfileView lacks a reliable
accessible name because it only uses the ambiguous “×” glyph and title. Update
the button in the badge removal UI to add an aria-label that clearly names the
badge being removed, using the existing badge.program value so screen readers
announce the specific action. Keep the button behavior and title as-is, but
ensure the accessible name comes from aria-label on the remove button element.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b0aa4441-23a0-49ff-a8d1-00a2f478202d
📒 Files selected for processing (1)
src/components/profile/ProfileView.tsx
🛑 Comments failed to post (2)
src/components/profile/ProfileView.tsx (2)
972-972: 🎯 Functional Correctness | 🟡 Minor
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Verify hex color literals have valid CSS lengths: 3, 4, 6, or 8 digits. python - <<'PY' from pathlib import Path import re path = Path("src/components/profile/ProfileView.tsx") for match in re.finditer(r"#[0-9A-Fa-f]+", path.read_text()): digits = len(match.group()) - 1 if digits not in {3, 4, 6, 8}: print(f"{path}:{match.start()}: invalid hex literal {match.group()}") PYRepository: PRODHOSH/ossfolio
Length of output: 228
Use a valid fallback color here.
#9a9aais not a valid CSS hex value, so unknown languages can lose the dot color; use#9a9a9ainstead.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` at line 972, The language indicator in ProfileView uses an invalid fallback color for unknown languages. Update the fallback in the span style next to the language label so the dot uses a valid CSS hex value, replacing the current malformed fallback with the intended gray value; keep the change localized to the LANG_COLORS lookup in ProfileView.
1038-1070: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Fix the heatmap month-label layout.
The month-label row is currently the first flex child next to the week columns, so labels render beside the heatmap instead of above it. Wrap labels and weeks in a vertical container, then render the weeks in their own row.
🧰 Tools
🪛 React Doctor (0.5.8)
[warning] 1050-1050: Your users strain to read 11px text, so use at least 12px for body text, & 16px is best.
Use at least 12px for body text, and 16px is best. Small text is hard to read, especially on phones.
(no-tiny-text)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` around lines 1038 - 1070, The heatmap month-label row in ProfileView is laid out as a sibling of the week columns, so the labels render beside the chart instead of above it. Update the markup around the heatmap block to use a vertical wrapper for the labels and the week grid, keeping the month-label mapping logic in the same ProfileView component but rendering the week columns in a separate row beneath it.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/components/profile/ProfileView.tsx (2)
135-135: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winGenerate badge years from the current year.
The hard-coded
2026default/options will stop allowing current-year badges after 2026.Proposed fix
+ const currentYear = new Date().getFullYear(); const [isBadgeModalOpen, setIsBadgeModalOpen] = useState(false); const [selectedProgram, setSelectedProgram] = useState("GSSoC"); - const [selectedYear, setSelectedYear] = useState(2026); + const [selectedYear, setSelectedYear] = useState(() => new Date().getFullYear());- {[2026, 2025, 2024, 2023, 2022, 2021, 2020].map((y) => ( + {Array.from({ length: currentYear - 2020 + 1 }, (_, i) => currentYear - i).map((y) => ( <option key={y} value={y}>{y}</option> ))}Also applies to: 1305-1307
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` at line 135, The hard-coded year value in ProfileView should be derived from the current year instead of fixed to 2026 so badge filtering stays valid in future years. Update the selectedYear state initialization and any related year options logic in ProfileView (including the badge-year generation around the referenced lines) to compute years dynamically from the current date, keeping the existing behavior but removing the static cutoff.
206-239: 🗄️ Data Integrity & Integration | 🟠 MajorAvoid inserting partial profile rows from badge edits.
profileId || authUser?.idlets both badge handlersupserta newprofilesrow when none exists yet. That row is missing score/stats, so later profile reads can pick up the defaulted stored values instead of the live profile data. Gate badge edits on an existingprofileId, or create the complete profile row upstream first.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` around lines 206 - 239, Badge edits in ProfileView are allowing a partial profiles upsert when no existing profile row exists. Update the badge save flow in the relevant handler(s) to require an existing profileId before calling supabase.from("profiles").upsert, or otherwise ensure the full profile record is created upstream before badge updates. Use the targetProfileId logic in ProfileView and the upsert call on profiles to locate the fix, and keep badge updates from creating new rows with only badges/updated_at/username.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/profile/ProfileView.tsx`:
- Line 1044: The month-label text in ProfileView is too small and should be
increased to improve readability. Update the inline style used for the heatmap
month labels in ProfileView so the fontSize is at least 12px, keeping the
existing layout and styling otherwise unchanged.
---
Outside diff comments:
In `@src/components/profile/ProfileView.tsx`:
- Line 135: The hard-coded year value in ProfileView should be derived from the
current year instead of fixed to 2026 so badge filtering stays valid in future
years. Update the selectedYear state initialization and any related year options
logic in ProfileView (including the badge-year generation around the referenced
lines) to compute years dynamically from the current date, keeping the existing
behavior but removing the static cutoff.
- Around line 206-239: Badge edits in ProfileView are allowing a partial
profiles upsert when no existing profile row exists. Update the badge save flow
in the relevant handler(s) to require an existing profileId before calling
supabase.from("profiles").upsert, or otherwise ensure the full profile record is
created upstream before badge updates. Use the targetProfileId logic in
ProfileView and the upsert call on profiles to locate the fix, and keep badge
updates from creating new rows with only badges/updated_at/username.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 34decffa-47e4-48e1-972b-44e20187523a
📒 Files selected for processing (1)
src/components/profile/ProfileView.tsx
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/components/profile/ProfileView.tsx (2)
167-195: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winRe-run dialog listener setup when the owner-only dialog mounts.
This effect runs before
authUserresolves, when the{isOwner && <dialog>}is not mounted, sodialogRef.currentisnulland the close/backdrop listeners are never attached. Pressing Escape can close the native dialog while leavingisBadgeModalOpenstucktrue.Proposed fix
- }, []); + }, [isOwner]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` around lines 167 - 195, The badge modal dialog listeners in ProfileView are only attached once, so when the owner-only dialog mounts after authUser resolves, dialogRef.current was previously null and the close/click handlers never get registered. Update the useEffect around dialogRef and setIsBadgeModalOpen so it reruns when the dialog becomes available (and when the open state changes if needed), ensuring the native dialog’s close/backdrop events always sync the modal state.
713-746: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winNormalize JSONB badges before rendering.
src/app/[username]/page.tsxonly checksArray.isArray(profileRow.badges)before passing JSON intoProfileView, but this render path assumesbadge.years.joinalways exists. A malformed/old row can crash public profile rendering; sanitize to validBadgeItem[]before storing inbadgesList.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/profile/ProfileView.tsx` around lines 713 - 746, Normalize and validate the badges payload before rendering in ProfileView so malformed JSONB rows cannot crash the public profile page. Update the badges handling that feeds badgesList and the render path in ProfileView to ensure each item is a valid BadgeItem with a years array before using badge.years.join, and filter or coerce invalid entries in the page.tsx data flow before passing them into the component.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/profile/ProfileView.tsx`:
- Around line 1312-1314: The participation year dropdown in ProfileView is
artificially capped to only the current year and previous six years, blocking
valid older entries. Update the year options generation in the dropdown map so
it supports older self-reported badge years instead of hardcoding a 7-year
range, while keeping the existing option rendering and value handling intact.
---
Outside diff comments:
In `@src/components/profile/ProfileView.tsx`:
- Around line 167-195: The badge modal dialog listeners in ProfileView are only
attached once, so when the owner-only dialog mounts after authUser resolves,
dialogRef.current was previously null and the close/click handlers never get
registered. Update the useEffect around dialogRef and setIsBadgeModalOpen so it
reruns when the dialog becomes available (and when the open state changes if
needed), ensuring the native dialog’s close/backdrop events always sync the
modal state.
- Around line 713-746: Normalize and validate the badges payload before
rendering in ProfileView so malformed JSONB rows cannot crash the public profile
page. Update the badges handling that feeds badgesList and the render path in
ProfileView to ensure each item is a valid BadgeItem with a years array before
using badge.years.join, and filter or coerce invalid entries in the page.tsx
data flow before passing them into the component.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: dafd69eb-c001-44bc-903a-60bba2a5eac0
📒 Files selected for processing (1)
src/components/profile/ProfileView.tsx
|
fix the merge conflicts @abhilasha2101 |
|
@PRODHOSH I have resolved merge conflicts |
|
🎉 Your PR just got merged, @abhilasha2101 — thank you for contributing to OSSfolio! Your work is now part of the project. Here's what to do next:
We really appreciate you taking the time. See you in the next PR! 🚀 |
Summary
This PR implements a profile badges feature that allows users to showcase their participation in various open-source programs (like GSoC, Hacktoberfest, GSSoC, etc.) on their profile page. Profile owners can add new badges with specific years via an interactive dialog modal, and easily remove them if needed.
Related Issue
Closes #138
Type of Change
Changes Made
20260623000000_add_badges_to_profiles.sqlto add abadgesjsonbcolumn (defaulting to[]) to theprofilestable.supabase/schema.sqlto keep the base schema structure in sync.BadgeIteminterface tosrc/types/index.ts.ProfileView.tsxto render a list of badges with custom gradient styling corresponding to the program.<dialog>element allowing selection of the program (GSoC, MLH, Hacktoberfest, SWoC, GSSoC, EluSoC) and year (2020-2026).AI Usage
Screenshots (if UI change)
Checklist
mainconsole.logleft insrc/schema.sqland a new migration file are includedDESIGN.mdand followed the design system (colors, spacing, typography, components)feat:,fix:,docs:, etc.)Summary by CodeRabbit
Summary
New Features
Bug Fixes
Style