Skip to content

(SP 1) [Shop] Canonicalize legacy filters + fix cart CTA/badge UX#274

Merged
ViktorSvertoka merged 21 commits intodevelopfrom
lso/feat/shop-design
Feb 5, 2026
Merged

(SP 1) [Shop] Canonicalize legacy filters + fix cart CTA/badge UX#274
ViktorSvertoka merged 21 commits intodevelopfrom
lso/feat/shop-design

Conversation

@liudmylasovetovs
Copy link
Collaborator

@liudmylasovetovs liudmylasovetovs commented Feb 5, 2026

Description

This PR fixes two Shop UX issues:

  1. legacy “View all” pagination now uses canonical filtering to avoid inconsistent results across pages,
  2. cart interactions are tightened by preventing the checkout CTA label from wrapping/expanding and ensuring the cart badge renders above the icon on hover.

Related Issue

Issue: #<issue_number>


Changes

  • Canonicalized legacy filter/pagination behavior for “View all” to keep results consistent across pages.
  • Prevented checkout CTA label wrapping that caused button height/line-break shifts while loading.
  • Fixed header cart badge layering so the counter stays on the topmost layer (including hover state).

Database Changes (if applicable)

  • Schema migration required
  • Seed data updated
  • Breaking changes to existing queries
  • Transaction-safe migration
  • Migration tested locally on Neon

How Has This Been Tested?

  • Tested locally
  • Verified in development environment
  • Checked responsive layout (if UI-related)
  • Tested accessibility (keyboard / screen reader)

Screenshots (if applicable)

  • Add before/after screenshots for pagination behavior and cart CTA/badge hover states.

Checklist

Before submitting

  • Code has been self-reviewed
  • No TypeScript or console errors
  • Code follows project conventions
  • Scope is limited to this feature/fix
  • No unrelated refactors included
  • English used in code, commits, and docs
  • New dependencies discussed with team
  • Database migration tested locally (if applicable)
  • GitHub Projects card moved to In Review

Reviewers

Summary by CodeRabbit

  • New Features

    • Stock-aware quantity controls prevent over-ordering.
    • Checkout shows a loading spinner and exposes screen-reader status.
  • Bug Fixes

    • Improved header/badge stacking to prevent overlay issues.
    • "View All" now shows newest items by default.
  • Improvements

    • Unified badge styling across product displays.
    • Legacy filter handling for smoother redirects/canonical URLs.
    • Minor styling tweaks (select behavior) and shortened checkout translation.

@vercel
Copy link
Contributor

vercel bot commented Feb 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
devlovers-net Ready Ready Preview, Comment Feb 5, 2026 7:53am

@netlify
Copy link

netlify bot commented Feb 5, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit 8ef0ad2
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/69844c329cec2c00087b94b6
😎 Deploy Preview https://deploy-preview-274--develop-devlovers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Stabilize checkout button layout with a spinner and SR text, add stock-aware quantity limits and UI states, normalize legacy filter=newsort=newest with canonical redirects, simplify badge styling, and add minor z-index and select styling tweaks.

Changes

Cohort / File(s) Summary
Checkout UX & i18n
frontend/app/[locale]/shop/cart/CartPageClient.tsx, frontend/messages/uk.json
Add Loader2 spinner and a non-wrapping/truncated checkout label; expose screen-reader-only "placing" text when checking out. Shorten Ukrainian checkout.placing string.
Shop Filter / Catalog API
frontend/app/[locale]/shop/page.tsx, frontend/app/[locale]/shop/products/page.tsx, frontend/app/api/shop/catalog/route.ts
Introduce optional filter param and legacy handling: map filter=newsort=newest; implement canonical redirect that omits legacy filter and default sort when needed; adjust redirect import to locale-aware router.
Product Composition & Badge
frontend/app/[locale]/shop/products/[slug]/page.tsx, frontend/components/shop/ProductCard.tsx
Shallow-merge publicProduct with result.product into final product; derive badge separately and replace per-badge conditional classes with a single uniform badge class and updated visibility check.
Cart Quantity / Add To Cart
frontend/components/shop/AddToCartButton.tsx
Parse stock, compute maxQty, clamp added quantity to [1,maxQty], update quantity state when clamped, add disabled states for inc/dec controls, and show max-stock translation message; use SHOP_DISABLED styling.
Header & Sort UI
frontend/components/shared/HeaderButton.tsx, frontend/components/shop/ProductSort.tsx
Add z-index classes (z-0 container, z-20 badge) to fix stacking; add peer class to the product sort <select> for sibling styling hooks.
Misc / Manifest
package.json
Minor package manifest edits included in diff (lines changed small).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • AM1007

Poem

"🐇 I spin a tiny loader bright,
I keep the label snug and tight.
I count the stock, I clamp the hop,
I tidy badges, fix the top.
Hops and bytes — the shop's delight!"

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning 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 title clearly captures the two main changes: canonicalizing legacy filters and fixing cart CTA/badge UX issues, which are well-represented in the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch lso/feat/shop-design

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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/app/[locale]/shop/products/page.tsx (1)

40-61: ⚠️ Potential issue | 🟠 Major

Avoid stripping pagination from canonical redirects.

needsCanonical triggers on any page, and the redirect removes page from the query, so /shop/products?page=2 will always canonicalize to page 1. This breaks pagination deep links and conflicts with catalogQuerySchema parsing of page.

🔧 Proposed fix (canonicalize only legacy filter and preserve page)
-  const needsCanonical =
-    !!resolvedSearchParams.page || !!resolvedSearchParams.filter;
+  const hasLegacyFilter = resolvedSearchParams.filter === 'new';
+  const needsCanonical = hasLegacyFilter;

   if (needsCanonical) {
     const qsParams = new URLSearchParams();

     for (const [k, v] of Object.entries(resolvedSearchParams)) {
       if (!v) continue;
-      if (k === 'page') continue;
       if (k === 'filter') continue;
       qsParams.set(k, v);
     }

     // support legacy ?filter=new => sort=newest
-    if (resolvedSearchParams.filter === 'new' && !resolvedSearchParams.sort) {
+    if (hasLegacyFilter && !resolvedSearchParams.sort) {
       qsParams.set('sort', 'newest');
     }

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/app/[locale]/shop/products/page.tsx (1)

56-59: ⚠️ Potential issue | 🔴 Critical

Import and use the i18n-aware redirect function from @/i18n/routing.

The redirect uses the standard Next.js redirect from next/navigation, but should use the custom i18n-aware redirect from @/i18n/routing. The app's routing config has localePrefix: 'always', meaning locale must always be in the URL. The locale is already available from params and should be passed to the redirect function.

Compare with dashboard/page.tsx, which correctly imports and uses:

import { redirect } from '@/i18n/routing';
redirect({ href: '/login', locale });
Proposed fix
-import { redirect } from 'next/navigation';
+import { redirect } from '@/i18n/routing';

Then update the redirect call:

-    redirect(qs ? `${basePath}?${qs}` : basePath);
+    redirect({ href: qs ? `${basePath}?${qs}` : basePath, locale });

@ViktorSvertoka ViktorSvertoka merged commit cdf4460 into develop Feb 5, 2026
10 checks passed
@ViktorSvertoka ViktorSvertoka deleted the lso/feat/shop-design branch February 5, 2026 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants