feat: add org wishlist with heart toggle, localStorage persistence an…#1438
feat: add org wishlist with heart toggle, localStorage persistence an…#1438Harkiratcodess wants to merge 3 commits into
Conversation
|
Hi @Harkiratcodess, thanks for contributing to InternHack! 🎉 I have automatically:
Our workflows will now analyze your changes to classify:
Tip Ensure your PR description references the issue it resolves (e.g. Happy coding! 🚀 |
📝 WalkthroughWalkthroughAdds a persistent localStorage-backed wishlist feature to GSoCReposPage that allows users to mark favorite organizations via Heart buttons on cards and modals. Includes wishlist state management via a custom hook, filtering UI that shows only wishlisted organizations, and wiring throughout to pass wishlist state to components. Also includes non-semantic JSX restructuring for code clarity. ChangesOrganization Wishlist Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
client/src/module/student/opensource/GSoCReposPage.tsx (2)
785-798: 💤 Low valueConsider using the shared
Buttoncomponent for consistency.Per coding guidelines, new buttons should use the reusable
Buttoncomponent fromclient/src/components/ui/button.tsx. This applies to both the wishlist filter button here and the heart toggle inGSoCOrgCard.🤖 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 `@client/src/module/student/opensource/GSoCReposPage.tsx` around lines 785 - 798, Replace this inline button with the shared Button component to match the app UI: use the Button from client/src/components/ui/button.tsx instead of the raw <button>, wiring its onClick to setShowWishlist and rendering the Heart icon and label based on showWishlist and wishlist.length; update className/variant props on Button to reproduce the conditional styles now handled by showWishlist (use variant/intent or className prop as available) and make the same change in GSoCOrgCard for the heart toggle so both controls reuse the shared Button component.
189-199: ⚡ Quick winWrap
GSoCOrgCardwithReact.memoto optimize list re-renders.
GSoCOrgCardis rendered in a list and receives props that don't change frequently (org data, wishlisted boolean). Wrapping it withReact.memousing the named function form would prevent unnecessary re-renders when parent state changes. Based on learnings: "Wrap list-rendered child components (cards, badges, list items) withReact.memowhen they receive stable props and don't have frequently changing internal state; use named function form."Proposed fix
-function GSoCOrgCard({ +const GSoCOrgCard = React.memo(function GSoCOrgCard({ org, onClick, wishlisted, onWishlistToggle, }: { org: GSoCOrganization; onClick: () => void; wishlisted: boolean; onWishlistToggle: (e: React.MouseEvent) => void; }) { // ... component body -} +});Also add
Reactto the import or usememodirectly:-import { useState, type ReactNode } from "react"; +import { useState, memo, type ReactNode } from "react";Also applies to: 835-852
🤖 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 `@client/src/module/student/opensource/GSoCReposPage.tsx` around lines 189 - 199, Wrap the GSoCOrgCard named function with React.memo to prevent unnecessary re-renders when rendered in lists: modify the export/definition so the component is memoized (e.g., export default React.memo(GSoCOrgCard) or const MemoGSoCOrgCard = React.memo(GSoCOrgCard) and use that in the parent), and ensure React is imported (or import memo directly) so memo is available; keep the function signature and props unchanged to preserve identity checks for memoization.
🤖 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 `@client/src/module/student/opensource/GSoCReposPage.tsx`:
- Around line 244-260: The nested interactive element issue: the wishlist toggle
button (onWishlistToggle / Heart / wishlisted span) is rendered inside the
card's clickable <button> (card click handler), which is invalid; refactor the
card wrapper (the element that currently is a clickable button in GSoCReposPage)
into a non-button container with role="button", tabIndex={0}, and keyboard
handlers (onKeyDown to handle Enter/Space) so the inner <button> can remain
interactive, or alternatively move the wishlist <button> (using
onWishlistToggle, Heart, wishlisted) outside the card button area and ensure
only one interactive control handles card activation; update any click handlers
that depended on the card <button> to use the new container's role/button
behavior.
- Around line 33-40: The initializer for useWishlist reads JSON from
localStorage but doesn't validate the parsed value; JSON.parse may return null
or a non-array which will make later calls like wishlist.includes() throw. In
the useWishlist initializer (the useState hook that sets wishlist and
setWishlist using WISHLIST_KEY), after JSON.parse check that the result is an
array (Array.isArray) and that its items are numbers (e.g., filter/validate
entries), otherwise return an empty array; ensure the state always receives a
number[] fallback.
---
Nitpick comments:
In `@client/src/module/student/opensource/GSoCReposPage.tsx`:
- Around line 785-798: Replace this inline button with the shared Button
component to match the app UI: use the Button from
client/src/components/ui/button.tsx instead of the raw <button>, wiring its
onClick to setShowWishlist and rendering the Heart icon and label based on
showWishlist and wishlist.length; update className/variant props on Button to
reproduce the conditional styles now handled by showWishlist (use variant/intent
or className prop as available) and make the same change in GSoCOrgCard for the
heart toggle so both controls reuse the shared Button component.
- Around line 189-199: Wrap the GSoCOrgCard named function with React.memo to
prevent unnecessary re-renders when rendered in lists: modify the
export/definition so the component is memoized (e.g., export default
React.memo(GSoCOrgCard) or const MemoGSoCOrgCard = React.memo(GSoCOrgCard) and
use that in the parent), and ensure React is imported (or import memo directly)
so memo is available; keep the function signature and props unchanged to
preserve identity checks for memoization.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 9618fb80-2ec1-44ea-862c-deab71b2f012
📒 Files selected for processing (1)
client/src/module/student/opensource/GSoCReposPage.tsx
closed #708
Summary
Adds a persistent wishlist feature to the GSoC Organizations page, allowing students to shortlist 3–5 orgs they plan to apply to without needing a separate Notion doc or text file.
Problem
Students browsing GSoC organizations had no way to mark favorites or track orgs they intended to apply to. They were forced to maintain external lists, creating friction in the application planning process.
Changes
useWishlistcustom hook that reads/writes org IDs tolocalStorageunder the keygsoc_wishlistas a JSON number arrayHearticon toggle button to each org card:Hearttoggle button in the org detail modal headerFiles Changed
client/src/module/student/opensource/GSoCReposPage.tsxHeartto lucide-react importsuseWishlistcustom hookGSoCOrgCardwithwishlistedandonWishlistTogglepropsGSoCOrgModalPropsinterface and modal componentuseWishlistinGSoCReposPagewithfilteredOrganizationsTesting
Summary by CodeRabbit
Release Notes