-
Notifications
You must be signed in to change notification settings - Fork 0
Add wishlist feature for saving favorite products #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Create WishlistContext with localStorage persistence - Add WishlistItem component for displaying saved items - Create /wishlist page with add-all-to-cart and clear functionality - Update ProductCard with heart toggle button - Add wishlist icon with badge to Navbar
|
Warning
|
| Cohort / File(s) | Summary |
|---|---|
Context & Provider Setup src/context/WishlistContext.tsx |
New React context with WishlistProvider and useWishlist hook; manages wishlist items with add, remove, toggle, clear operations; includes localStorage persistence with hydration-safe initialization; implements isInWishlist query utility. |
Layout Integration src/app/layout.tsx |
Wraps layout tree with WishlistProvider nested inside CartProvider to make wishlist context available throughout the application. |
Wishlist Page src/app/wishlist/page.tsx |
New client-side page component rendering wishlist UI with mounting state for skeleton loading, empty state with browse link, header with item count, WishlistItem list rendering, "Add All to Cart" action with batch add functionality, and "Clear All" action with confirmation modal. |
Navigation Updates src/components/Navbar.tsx |
Adds wishlist icon/link with badge displaying wishlist count (capped at 99+); integrates into desktop and mobile menus alongside existing cart icon; updates cart badge logic and adds aria-labels for accessibility. |
Product Card Enhancement src/components/ProductCard.tsx |
Adds wishlist toggle button at top-right of product card with dynamic styling; integrates useWishlist hook to track and manage wishlist state; repositions Featured badge to accommodate new button. |
Wishlist Item Component src/components/WishlistItem.tsx |
New component rendering individual wishlist entries with product image, name, category, 5-star rating, reviews count, pricing (with computed discount badge), stock status, and action buttons (Add to Cart, Remove); includes product page navigation link. |
Sequence Diagram
sequenceDiagram
participant User
participant ProductCard
participant WishlistContext as Wishlist Context
participant WishlistPage
participant CartContext as Cart Context
User->>ProductCard: Click Wishlist Button
ProductCard->>WishlistContext: toggleWishlist(product)
WishlistContext->>WishlistContext: Update items in state
WishlistContext->>ProductCard: Re-render with isWishlisted
ProductCard->>User: Show updated button state
User->>ProductCard: Navigate to Wishlist
User->>WishlistPage: View wishlist page
WishlistPage->>WishlistContext: useWishlist() hook
WishlistContext->>WishlistPage: Return items & actions
WishlistPage->>User: Render WishlistItem list
User->>WishlistPage: Click "Add to Cart"
WishlistPage->>CartContext: addToCart(product)
CartContext->>CartContext: Update cart items
CartContext->>User: Cart updated (badge refreshes)
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Poem
🐰 A wishlist of wonders, so carefully curated,
From ProductCard toggles to items curated,
Click, save, and cart them—context flows free,
A warren of wishes, as far as you see! 🌟
🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The pull request title directly and concisely describes the main feature being added: a wishlist capability for saving favorite products, which aligns with all the changes across context, components, pages, and UI elements. |
✏️ Tip: You can configure your own custom pre-merge checks in the settings.
✨ Finishing touches
- 📝 Generate docstrings
Comment @coderabbitai help to get the list of available commands and usage tips.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@src/app/wishlist/page.tsx`:
- Around line 153-157: Update the copy in the wishlist page paragraph to avoid
promising an unimplemented sale-alert feature: edit the paragraph element with
className "text-gray-600 text-sm" in the wishlist page component
(src/app/wishlist/page.tsx) to remove or rephrase the sentence "Keep an eye on
prices – we'll show you when items go on sale!" so it no longer claims sale
notifications exist; keep the rest of the explanatory text about browser-saved
wishlist and moving items to cart.
- Around line 19-23: The handleAddAllToCart currently iterates over items and
calls addToCart for every product, which adds out-of-stock items; update
handleAddAllToCart to first filter items by product.inStock (e.g.,
items.filter(p => p.inStock)) and call addToCart only for those in-stock
products, and optionally collect/skipped product names to surface user feedback
or a toast for items that were not added so the user knows why some items were
skipped.
In `@src/components/Navbar.tsx`:
- Around line 194-198: The mobile wishlist badge in Navbar.tsx is rendering the
raw wishlistItems value instead of applying the same "99+" cap used by the
desktop badge; update the JSX that renders the mobile badge (the span within the
conditional that checks wishlistItems > 0) to display wishlistItems > 99 ? "99+"
: wishlistItems (or the existing helper used for the desktop badge) so the
mobile and desktop badges show consistent capped values.
In `@src/components/WishlistItem.tsx`:
- Around line 17-23: Prevent adding out-of-stock items by updating
handleAddToCart to check product.inStock and return (or show feedback) if false,
and also reflect this in the UI by disabling the Add to Cart button when
product.inStock is false; specifically, add a guard in handleAddToCart that does
not call addToCart(product) for !product.inStock and wire the button's disabled
prop (and visual/aria state) to product.inStock, optionally invoking a
user-facing message function (e.g., showToast or onError) when the user attempts
to add an out-of-stock product.
🧹 Nitpick comments (5)
src/context/WishlistContext.tsx (2)
31-42: Consider validating localStorage data structure.Parsed JSON from localStorage is directly assigned to state without schema validation. If the stored data is malformed or from an older schema, this could cause runtime errors in consuming components.
🔧 Suggested validation
useEffect(() => { const savedWishlist = localStorage.getItem(STORAGE_KEY); if (savedWishlist) { try { - setItems(JSON.parse(savedWishlist)); + const parsed = JSON.parse(savedWishlist); + if (Array.isArray(parsed)) { + setItems(parsed.filter((item): item is Product => + item && typeof item.id === 'number' + )); + } } catch (e) { console.error("Failed to parse wishlist from localStorage:", e); } } setIsInitialized(true); }, []);
65-70:isInWishlistrecreates on everyitemschange, potentially causing unnecessary re-renders.Since
isInWishlisthasitemsin its dependency array, it gets a new reference wheneveritemschanges. Components that destructureisInWishlistwill re-render even if they don't use the result. Consider usinguseMemofor the lookup or documenting this behavior.src/components/WishlistItem.tsx (2)
25-29: Discount calculation is duplicated.This exact calculation exists in
ProductCard.tsx(line 30-32). Consider extracting to a shared utility function.
61-79: Star rating SVG is duplicated across components.The rating display with the star SVG path appears identically in
ProductCard.tsx. Consider extracting a reusableStarRatingcomponent.src/app/wishlist/page.tsx (1)
101-127: Modal lacks keyboard accessibility.The confirmation modal doesn't trap focus, handle Escape key to close, or have proper ARIA attributes (
role="dialog",aria-modal,aria-labelledby).♻️ Suggested improvements
{showClearConfirm && ( - <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50"> - <div className="bg-white rounded-lg p-6 max-w-sm mx-4 shadow-xl"> + <div + className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50" + onClick={() => setShowClearConfirm(false)} + onKeyDown={(e) => e.key === 'Escape' && setShowClearConfirm(false)} + > + <div + className="bg-white rounded-lg p-6 max-w-sm mx-4 shadow-xl" + role="dialog" + aria-modal="true" + aria-labelledby="clear-dialog-title" + onClick={(e) => e.stopPropagation()} + > <h3 className="text-lg font-bold text-gray-900 mb-2"> + id="clear-dialog-title" Clear Wishlist? </h3>
| const handleAddAllToCart = () => { | ||
| items.forEach((product) => { | ||
| addToCart(product); | ||
| }); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Add All to Cart" adds out-of-stock items.
The handler adds all wishlist items to cart without checking product.inStock. Consider filtering or providing user feedback.
🐛 Proposed fix
const handleAddAllToCart = () => {
- items.forEach((product) => {
+ const inStockItems = items.filter((product) => product.inStock);
+ inStockItems.forEach((product) => {
addToCart(product);
});
+ // Optionally notify user if some items were skipped
};🤖 Prompt for AI Agents
In `@src/app/wishlist/page.tsx` around lines 19 - 23, The handleAddAllToCart
currently iterates over items and calls addToCart for every product, which adds
out-of-stock items; update handleAddAllToCart to first filter items by
product.inStock (e.g., items.filter(p => p.inStock)) and call addToCart only for
those in-stock products, and optionally collect/skipped product names to surface
user feedback or a toast for items that were not added so the user knows why
some items were skipped.
| <p className="text-gray-600 text-sm"> | ||
| Items in your wishlist are saved to your browser. You can easily move | ||
| them to your cart when you're ready to purchase. Keep an eye on | ||
| prices – we'll show you when items go on sale! | ||
| </p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tips text promises a feature that doesn't exist.
The text says "we'll show you when items go on sale" but this functionality isn't implemented. Consider removing this claim to avoid misleading users.
🐛 Proposed fix
<p className="text-gray-600 text-sm">
- Items in your wishlist are saved to your browser. You can easily move
- them to your cart when you're ready to purchase. Keep an eye on
- prices – we'll show you when items go on sale!
+ Items in your wishlist are saved to your browser. You can easily move
+ them to your cart when you're ready to purchase.
</p>📝 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.
| <p className="text-gray-600 text-sm"> | |
| Items in your wishlist are saved to your browser. You can easily move | |
| them to your cart when you're ready to purchase. Keep an eye on | |
| prices – we'll show you when items go on sale! | |
| </p> | |
| <p className="text-gray-600 text-sm"> | |
| Items in your wishlist are saved to your browser. You can easily move | |
| them to your cart when you're ready to purchase. | |
| </p> |
🤖 Prompt for AI Agents
In `@src/app/wishlist/page.tsx` around lines 153 - 157, Update the copy in the
wishlist page paragraph to avoid promising an unimplemented sale-alert feature:
edit the paragraph element with className "text-gray-600 text-sm" in the
wishlist page component (src/app/wishlist/page.tsx) to remove or rephrase the
sentence "Keep an eye on prices – we'll show you when items go on sale!" so it
no longer claims sale notifications exist; keep the rest of the explanatory text
about browser-saved wishlist and moving items to cart.
| {wishlistItems > 0 && ( | ||
| <span className="bg-red-500 text-white text-xs font-bold rounded-full px-2 py-0.5"> | ||
| {wishlistItems} | ||
| </span> | ||
| )} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mobile wishlist badge missing 99+ cap.
The desktop wishlist badge caps at "99+" (line 77), but the mobile badge renders {wishlistItems} without the cap, creating an inconsistency.
🐛 Proposed fix
{wishlistItems > 0 && (
<span className="bg-red-500 text-white text-xs font-bold rounded-full px-2 py-0.5">
- {wishlistItems}
+ {wishlistItems > 99 ? "99+" : wishlistItems}
</span>
)}📝 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.
| {wishlistItems > 0 && ( | |
| <span className="bg-red-500 text-white text-xs font-bold rounded-full px-2 py-0.5"> | |
| {wishlistItems} | |
| </span> | |
| )} | |
| {wishlistItems > 0 && ( | |
| <span className="bg-red-500 text-white text-xs font-bold rounded-full px-2 py-0.5"> | |
| {wishlistItems > 99 ? "99+" : wishlistItems} | |
| </span> | |
| )} |
🤖 Prompt for AI Agents
In `@src/components/Navbar.tsx` around lines 194 - 198, The mobile wishlist badge
in Navbar.tsx is rendering the raw wishlistItems value instead of applying the
same "99+" cap used by the desktop badge; update the JSX that renders the mobile
badge (the span within the conditional that checks wishlistItems > 0) to display
wishlistItems > 99 ? "99+" : wishlistItems (or the existing helper used for the
desktop badge) so the mobile and desktop badges show consistent capped values.
| const handleAddToCart = () => { | ||
| addToCart(product); | ||
| }; | ||
|
|
||
| const handleRemove = () => { | ||
| removeFromWishlist(product.id); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add to Cart should respect stock status.
handleAddToCart allows adding out-of-stock items to the cart. Consider disabling the button or showing feedback when product.inStock is false.
🐛 Proposed fix
const handleAddToCart = () => {
+ if (!product.inStock) return;
addToCart(product);
};Also update the button to show disabled state:
<button
onClick={handleAddToCart}
- className="px-4 py-2 bg-indigo-600 text-white text-sm font-medium rounded-lg hover:bg-indigo-700 transition-colors"
+ disabled={!product.inStock}
+ className={`px-4 py-2 text-sm font-medium rounded-lg transition-colors ${
+ product.inStock
+ ? "bg-indigo-600 text-white hover:bg-indigo-700"
+ : "bg-gray-300 text-gray-500 cursor-not-allowed"
+ }`}
>
Add to Cart
</button>🤖 Prompt for AI Agents
In `@src/components/WishlistItem.tsx` around lines 17 - 23, Prevent adding
out-of-stock items by updating handleAddToCart to check product.inStock and
return (or show feedback) if false, and also reflect this in the UI by disabling
the Add to Cart button when product.inStock is false; specifically, add a guard
in handleAddToCart that does not call addToCart(product) for !product.inStock
and wire the button's disabled prop (and visual/aria state) to product.inStock,
optionally invoking a user-facing message function (e.g., showToast or onError)
when the user attempts to add an out-of-stock product.
Summary by CodeRabbit
New Features
✏️ Tip: You can customize this high-level summary in your review settings.