Skip to content

Unify headers and clean up removed shop components#96

Merged
ViktorSvertoka merged 3 commits into
developfrom
lso/feat/shop
Jan 1, 2026
Merged

Unify headers and clean up removed shop components#96
ViktorSvertoka merged 3 commits into
developfrom
lso/feat/shop

Conversation

@liudmylasovetovs
Copy link
Copy Markdown
Collaborator

@liudmylasovetovs liudmylasovetovs commented Jan 1, 2026

Description

This PR unifies the platform and shop headers into a single, reusable header system and removes legacy duplicated header/shell components that were causing inconsistent behavior and broken imports after refactors.

Key goals:

  • Eliminate duplicated header implementations (platform vs shop) and route-switching logic scattered across components.
  • Standardize navigation/menu behavior across platform and shop.
  • Reduce risk of future import breakage by consolidating UI entrypoints.

Related Issue

Issue: #<issue_number>


Changes

  • Introduced a unified header architecture (single UnifiedHeader with variant="platform" | "shop") and centralized rendering via AppChrome to ensure consistent behavior per route segment.
  • Removed legacy header switcher + old platform/shop header components and updated imports/usages across the app to prevent references to deleted files.
  • Updated shop pages/components to align with the unified navigation setup and ensured the shop scope still provides cart context via CartProvider.

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)

Notes:

  • npm run build passes successfully.
  • npx vitest run passes successfully.

Screenshots (if applicable)

N/A (no screenshots attached in this PR).


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

    • Unified header that adapts between platform and shop, with variant-aware cart and actions
    • Improved mobile menu with accessible toggle, shop-specific links, and admin link support
  • Refactor

    • Simplified header/navigation structure and flattened shop layout wrappers
    • Pages and components now use centralized, locale-aware routing for cleaner shop paths
  • Tests

    • Updated price-related tests to use minor-unit fields

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 1, 2026

📝 Walkthrough

Walkthrough

Replaces legacy header and shop wrappers with AppChrome and UnifiedHeader, removes several old header/shop components, adds MainSwitcher and AppMobileMenu, migrates many Link imports to @/i18n/routing, and updates a price test to minor-unit field names.

Changes

Cohort / File(s) Summary
Root layouts
frontend/app/[locale]/layout.tsx, frontend/app/[locale]/shop/layout.tsx
Replace HeaderSwitcher with AppChrome(MainSwitcher); add local flags userExists, showAdminNavLink; simplify shop layout (remove ShopShell, import shop-theme.css).
New header core
frontend/components/header/AppChrome.tsx, frontend/components/header/UnifiedHeader.tsx
Add AppChrome wrapper that selects header variant and CartProvider based on route; add UnifiedHeader supporting `platform
New mobile & main switcher
frontend/components/header/AppMobileMenu.tsx, frontend/components/header/MainSwitcher.tsx
Add variant-aware mobile menu component with accessibility and a MainSwitcher that conditionally wraps children in <main> for non-shop routes.
Removed legacy header modules
frontend/components/header/HeaderSwitcher.tsx, frontend/components/header/SiteHeader.tsx, frontend/components/header/SiteMobileHeader.tsx
Remove legacy header components and their exports (functionality consolidated into UnifiedHeader/AppChrome).
Removed shop wrappers & mobile nav
frontend/components/shop/shop-header.tsx, frontend/components/shop/shop-shell.tsx, frontend/components/shop/header/mobile-nav.tsx
Remove shop-specific header, ShopShell wrapper, and legacy MobileNav (functionality migrated to UnifiedHeader/AppMobileMenu).
Shop nav logic
frontend/components/shop/header/nav-links.tsx
Normalize NAV_LINKS, switch to i18n-aware pathname/searchParams, and compute active state using path + category query.
Link import migration (pages & components)
frontend/app/[locale]/shop/..., frontend/components/shop/*, frontend/components/...
Standardize Link imports from next/link@/i18n/routing; adjust several hrefs to remove locale prefix where applicable (admin/shop pages, cart/checkout, product/category components, footer, etc.).
Payment & checkout
frontend/app/[locale]/shop/checkout/...
Swap Link imports and update shop-specific hrefs in checkout error/payment/success pages and StripePaymentClient.
Tests
frontend/lib/tests/prices.test.ts
Rename test fields to priceMinor / originalPriceMinor and update test inputs accordingly.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Layout as app/[locale]/layout.tsx
    participant AppChrome
    participant Segments as useSelectedLayoutSegments
    participant CartProv as CartProvider
    participant UnifiedHeader
    participant MainSwitcher
    participant Page

    User->>Layout: request page
    Layout->>AppChrome: render(userExists, showAdminLink){children: MainSwitcher}
    AppChrome->>Segments: inspect layout segments
    alt route includes "shop"
        AppChrome->>CartProv: wrap children
        CartProv->>UnifiedHeader: render(variant=shop, userExists, showAdminLink)
        CartProv->>MainSwitcher: render(children)
    else non-shop
        AppChrome->>UnifiedHeader: render(variant=platform, userExists)
        AppChrome->>MainSwitcher: render(children)
    end
    MainSwitcher->>Page: wrap in <main> or return children
    Page->>User: render content
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • AM1007
  • ViktorSvertoka

Poem

🐰 I hopped through headers, cleaned every dome,
Built a shiny AppChrome to guide folks home.
Links now speak languages, shop finds its cart,
Unified rails and a mobile menu smart.
A rabbit’s small patch — tidy, swift, and art. ✨

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 accurately summarizes the main change: unifying header components and removing legacy shop component implementations.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 23964bc and c9daa28.

📒 Files selected for processing (7)
  • frontend/app/[locale]/shop/admin/orders/[id]/page.tsx
  • frontend/app/[locale]/shop/admin/orders/page.tsx
  • frontend/components/about/FeaturesSection.tsx
  • frontend/components/blog/BlogCard.tsx
  • frontend/components/dashboard/StatsCard.tsx
  • frontend/components/legal/LegalPageShell.tsx
  • frontend/components/shared/Footer.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/app/[locale]/shop/admin/orders/[id]/page.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: Redirect rules - develop-devlovers
  • GitHub Check: Header rules - develop-devlovers
  • GitHub Check: Pages changed - develop-devlovers
🔇 Additional comments (7)
frontend/components/legal/LegalPageShell.tsx (1)

1-1: LGTM: i18n routing migration.

The import change from next/link to @/i18n/routing aligns with the PR-wide Link migration. The usage is straightforward (href="/" on line 49) and compatible with i18n routing patterns.

frontend/components/about/FeaturesSection.tsx (1)

4-4: LGTM! Clean migration to localized routing.

The import update from next/link to @/i18n/routing is part of the broader refactor to support localized routing. The Link usage remains unchanged and compatible, which is the expected behavior.

frontend/components/dashboard/StatsCard.tsx (1)

1-1: LGTM! Link import migration is consistent.

The import change from next/link to @/i18n/routing is consistent with the PR-wide routing migration. The Link usage on lines 55 and 84 follows the standard API and should function correctly with the centralized routing abstraction.

frontend/components/shared/Footer.tsx (1)

3-3: LGTM! The migration from next/link to @/i18n/routing is correctly implemented. The routing module properly exports Link from createNavigation(routing), and both Link usages in this file (lines 56, 63) follow the standard Next.js API with the href prop. No remaining next/link imports detected in the codebase.

frontend/components/blog/BlogCard.tsx (1)

4-5: Import migration to i18n routing Link is correct.

The change from Next.js Link to @/i18n/routing's Link is properly implemented. This is the standard next-intl pattern—the Link component exported from createNavigation() automatically wraps Next.js Link with locale prefixing based on the routing configuration. The href format /blog/${post.slug.current} works correctly with this setup, and locale handling is preserved automatically.

frontend/app/[locale]/shop/admin/orders/page.tsx (2)

87-87: Locale prefix correctly removed from href.

Removing the /${locale} prefix is correct since the i18n-aware Link component from @/i18n/routing should handle locale prefixing automatically. The locale variable is still properly used elsewhere in the component for formatting purposes (lines 74, 76).


1-1: Link migration is correct.

The migration from Next.js's default Link to the i18n-aware Link from @/i18n/routing is properly implemented. The Link component is correctly exported from next-intl/navigation with routing configured to automatically add locale prefixes (localePrefix: 'always'), so removing the manual locale prefix from the href at line 87 is the right approach. The locale variable is still appropriately used for currency formatting.


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

@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 1, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit c9daa28
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/6955d209601e7700086ca94f
😎 Deploy Preview https://deploy-preview-96--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.

Copy link
Copy Markdown
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

Caution

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

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

116-136: Fix inconsistent link paths – missing /shop prefix in error page navigation.

Links at lines 117, 124, and 131 are missing the /shop prefix, causing navigation failures. All other error page links (lines 30–41, 60–71) correctly use /shop/cart and /shop/products, and this pattern is consistent across all other shop pages.

🔎 Required fix for consistent shop path prefixes
         <Link
-          href="/cart"
+          href="/shop/cart"
           className="inline-flex items-center justify-center rounded-md border border-border px-4 py-2 text-sm font-semibold uppercase tracking-wide text-foreground hover:bg-secondary"
         >
           Back to cart
         </Link>
         {isFailed && order.id && (
           <Link
-            href={`/checkout/payment/${order.id}`}
+            href={`/shop/checkout/payment/${order.id}`}
             className="inline-flex items-center justify-center rounded-md bg-accent px-4 py-2 text-sm font-semibold uppercase tracking-wide text-accent-foreground hover:bg-accent/90"
           >
             Retry payment
           </Link>
         )}
         <Link
-          href="/products"
+          href="/shop/products"
           className="inline-flex items-center justify-center rounded-md border border-border px-4 py-2 text-sm font-semibold uppercase tracking-wide text-foreground hover:bg-secondary"
         >
           Continue shopping
         </Link>
frontend/app/[locale]/shop/admin/products/page.tsx (1)

42-42: Remove redundant locale prefixes from lines 142 and 148.

The Link component from next-intl automatically injects the locale when localePrefix: 'always' is configured. Line 42 correctly uses href="/shop/admin/products/new", while lines 142 and 148 redundantly include the locale prefix explicitly. This is inconsistent with the rest of the codebase, where all other shop pages rely on automatic locale injection.

Change:

  • Line 142: href={/${locale}/shop/products/${product.slug}}href={/shop/products/${product.slug}}
  • Line 148: href={/${locale}/shop/admin/products/${product.id}/edit}href={/shop/admin/products/${product.id}/edit}
🧹 Nitpick comments (2)
frontend/lib/tests/prices.test.ts (1)

4-24: Consider optional test coverage for additional edge cases.

The current tests validate the core logic well. For more comprehensive coverage, consider adding tests for:

  • Null/undefined originalPriceMinor (should pass, since it's optional):

    it("accepts when originalPriceMinor is not provided", () => {
      const r = adminPriceRowSchema.safeParse({
        currency: "USD",
        priceMinor: 1000,
      });
      expect(r.success).toBe(true);
    });
  • originalPriceMinor < priceMinor (should fail, per the <= check):

    it("rejects originalPriceMinor < priceMinor", () => {
      const r = adminPriceRowSchema.safeParse({
        currency: "USD",
        priceMinor: 1000,
        originalPriceMinor: 800,
      });
      expect(r.success).toBe(false);
    });
frontend/components/header/AppChrome.tsx (1)

15-40: Consolidate shop detection to a single shared utility.

The component uses segments.includes('shop') via useSelectedLayoutSegments() while MainSwitcher uses isShopPath() that parses usePathname() with segments[0] === 'shop' || segments[1] === 'shop'. Both correctly detect shop routes under the current routing structure (/[locale]/shop/*), but the different detection methods introduce unnecessary complexity and maintenance risk if routing patterns change.

Consider extracting a shared isShopPath() utility (or using the existing one) in both components to ensure consistency and reduce the risk of detection misalignment during future refactors.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ecc820f and 772b008.

📒 Files selected for processing (30)
  • frontend/app/[locale]/layout.tsx
  • frontend/app/[locale]/shop/admin/layout.tsx
  • frontend/app/[locale]/shop/admin/orders/[id]/page.tsx
  • frontend/app/[locale]/shop/admin/orders/page.tsx
  • frontend/app/[locale]/shop/admin/page.tsx
  • frontend/app/[locale]/shop/admin/products/page.tsx
  • frontend/app/[locale]/shop/cart/page.tsx
  • frontend/app/[locale]/shop/checkout/error/page.tsx
  • frontend/app/[locale]/shop/checkout/payment/StripePaymentClient.tsx
  • frontend/app/[locale]/shop/checkout/payment/[orderId]/page.tsx
  • frontend/app/[locale]/shop/checkout/success/page.tsx
  • frontend/app/[locale]/shop/layout.tsx
  • frontend/app/[locale]/shop/page.tsx
  • frontend/components/header/AppChrome.tsx
  • frontend/components/header/AppMobileMenu.tsx
  • frontend/components/header/HeaderSwitcher.tsx
  • frontend/components/header/MainSwitcher.tsx
  • frontend/components/header/SiteHeader.tsx
  • frontend/components/header/SiteMobileHeader.tsx
  • frontend/components/header/UnifiedHeader.tsx
  • frontend/components/shop/category-tile.tsx
  • frontend/components/shop/header/cart-button.tsx
  • frontend/components/shop/header/mobile-nav.tsx
  • frontend/components/shop/header/nav-links.tsx
  • frontend/components/shop/product-card.tsx
  • frontend/components/shop/shop-footer.tsx
  • frontend/components/shop/shop-header.tsx
  • frontend/components/shop/shop-hero.tsx
  • frontend/components/shop/shop-shell.tsx
  • frontend/lib/tests/prices.test.ts
💤 Files with no reviewable changes (6)
  • frontend/components/shop/shop-header.tsx
  • frontend/components/header/SiteHeader.tsx
  • frontend/components/shop/shop-shell.tsx
  • frontend/components/header/SiteMobileHeader.tsx
  • frontend/components/shop/header/mobile-nav.tsx
  • frontend/components/header/HeaderSwitcher.tsx
🧰 Additional context used
🧬 Code graph analysis (4)
frontend/components/header/MainSwitcher.tsx (1)
frontend/components/header/HeaderSwitcher.tsx (1)
  • MainSwitcher (34-41)
frontend/components/header/UnifiedHeader.tsx (6)
frontend/components/shop/header/nav-links.tsx (1)
  • NavLinks (38-75)
frontend/lib/navigation.ts (1)
  • SITE_LINKS (1-9)
frontend/components/shared/LanguageSwitcher.tsx (1)
  • LanguageSwitcher (8-72)
frontend/components/shop/header/cart-button.tsx (1)
  • CartButton (9-28)
frontend/components/auth/logoutButton.tsx (1)
  • LogoutButton (12-44)
frontend/components/header/AppMobileMenu.tsx (1)
  • AppMobileMenu (19-121)
frontend/lib/tests/prices.test.ts (1)
frontend/lib/validation/shop.ts (1)
  • adminPriceRowSchema (173-198)
frontend/app/[locale]/layout.tsx (2)
frontend/components/header/AppChrome.tsx (1)
  • AppChrome (15-40)
frontend/components/header/MainSwitcher.tsx (1)
  • MainSwitcher (11-18)
⏰ 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: Redirect rules - develop-devlovers
  • GitHub Check: Header rules - develop-devlovers
  • GitHub Check: Pages changed - develop-devlovers
🔇 Additional comments (27)
frontend/components/shop/shop-hero.tsx (1)

1-1: LGTM! Import change aligns with i18n routing migration.

The switch from next/link to the custom @/i18n/routing module is consistent with the project-wide standardization described in the PR objectives. The component logic remains unchanged, and the Link API usage (href, className props) is compatible with the new routing system.

frontend/app/[locale]/shop/checkout/payment/[orderId]/page.tsx (1)

1-1: The custom routing module properly exports Link and is correctly implemented.

The @/i18n/routing module exports Link from next-intl/navigation, which provides i18n-aware routing as a drop-in replacement for Next.js Link. The import change is correct and all existing Link usages (lines 57, 62, 87, 92, 127, 133) are compatible with the new import.

frontend/lib/tests/prices.test.ts (2)

5-13: LGTM! Test correctly validates equal prices rejection.

The test accurately reflects the schema requirement that originalPriceMinor must be strictly greater than priceMinor. The use of numeric minor units (1000 = $10.00 in cents) is appropriate.


15-23: LGTM! Test correctly validates the valid discount case.

The test properly verifies that originalPriceMinor > priceMinor passes validation, representing a valid sale scenario ($12.00 → $10.00).

frontend/app/[locale]/shop/checkout/payment/StripePaymentClient.tsx (1)

4-5: The import change to @/i18n/routing is correct and compatible with the current href patterns. The Link component exported from @/i18n/routing uses next-intl's createNavigation with localePrefix: 'always' configuration. When href values already include the locale prefix (e.g., /${locale}/shop/cart), next-intl's Link intelligently recognizes the locale is already present and does not double-prefix. This manual locale prefixing pattern is consistently used across the entire codebase and functions correctly without causing double-prefixing issues.

Likely an incorrect or invalid review comment.

frontend/app/[locale]/shop/checkout/success/page.tsx (1)

1-1: No changes needed—import change is compatible with Next.js 16.0.7.

The Link component imported from @/i18n/routing is provided by the next-intl library via createNavigation(). The code uses the modern Link pattern (<Link href="...">text</Link> with className prop) that is fully compatible with Next.js 16.0.7. There are no nested <a> tags, legacyBehavior, or passHref props—the patterns that were breaking in Next.js 16. Since the build and tests pass, the compatibility is confirmed.

frontend/components/shop/shop-footer.tsx (1)

5-5: LGTM! Import migration to centralized routing module.

The change from next/link to @/i18n/routing aligns with the broader PR objective of standardizing navigation imports across the codebase. The component logic remains unchanged.

frontend/app/[locale]/shop/checkout/error/page.tsx (1)

1-1: LGTM! Import migration to centralized routing module.

Consistent with the broader refactor to use @/i18n/routing for all Link imports.

frontend/components/header/MainSwitcher.tsx (2)

6-9: LGTM! Shop path detection correctly handles localized routes.

The isShopPath helper correctly checks both segments[0] and segments[1] for 'shop', which accounts for both /shop and /[locale]/shop route patterns.


11-18: LGTM! Conditional wrapping logic is correct.

The component appropriately skips the <main> wrapper for shop paths (since shop layout provides its own) and applies the wrapper with appropriate styling for non-shop routes.

frontend/app/[locale]/shop/layout.tsx (1)

1-6: LGTM! Layout simplification aligns with the new architecture.

The removal of ShopShell and admin link logic, along with the addition of shop-theme.css, correctly delegates wrapping and conditional rendering to the new AppChrome and UnifiedHeader components introduced in this PR.

frontend/components/header/AppMobileMenu.tsx (3)

19-40: LGTM! State management and effects are well-structured.

The component correctly:

  • Manages menu open/closed state
  • Implements Escape key handling with proper cleanup
  • Memoizes link selection based on variant to avoid unnecessary recalculations

43-62: LGTM! Accessible toggle button and overlay implementation.

The toggle button includes proper ARIA attributes (aria-label, aria-expanded, aria-controls), and the overlay pattern for closing the menu is a standard and effective approach for mobile navigation.


63-120: LGTM! Navigation panel with variant-aware link rendering.

The mobile navigation correctly:

  • Renders appropriate link sets based on variant (SITE_LINKS vs NAV_LINKS)
  • Conditionally shows admin link when variant === 'shop' and showAdminLink === true
  • Handles authenticated vs unauthenticated states appropriately
  • Closes the menu when links are clicked
frontend/components/shop/header/nav-links.tsx (1)

64-75: LGTM: Admin link rendering is correct.

The conditional admin link rendering and navigation behavior are properly implemented.

frontend/components/shop/product-card.tsx (1)

3-3: LGTM: Link import standardization.

The import change aligns with the PR's objective to standardize routing through @/i18n/routing. The Link usage throughout the component remains unchanged and should work correctly in this client component context.

frontend/app/[locale]/shop/page.tsx (1)

5-5: LGTM: Consistent routing standardization.

The Link import change is consistent with the PR-wide routing refactor. This follows the same pattern as other server components in the PR.

frontend/app/[locale]/shop/admin/layout.tsx (1)

2-2: LGTM: Admin layout routing standardization.

The Link import change standardizes routing for the admin layout navigation. This is consistent with the PR's objective to use the custom i18n routing Link throughout the application.

frontend/app/[locale]/shop/admin/orders/page.tsx (1)

1-1: Custom Link fully supports Server Components.

The import change from next/link to @/i18n/routing is part of the routing standardization. The custom Link is sourced from next-intl/navigation, which has full Server Component support as a first-class feature since version 3.0. The page component uses Link correctly in a Server Component context with proper locale-based href resolution.

frontend/app/[locale]/shop/cart/page.tsx (1)

4-5: Link import successfully migrated.

The change aligns with the project-wide routing refactor. Note that Link usages at lines 112 and 157 use paths without the locale prefix (e.g., /shop/products), which differs from the admin pages pattern. This is expected if @/i18n/routing handles locale injection automatically.

frontend/components/shop/header/cart-button.tsx (1)

3-3: LGTM!

The import migration is correct and consistent with the cart page. The Link usage at line 16 follows the same locale-free path pattern (/shop/cart).

frontend/app/[locale]/shop/admin/products/page.tsx (1)

1-1: Link import migration completed.

frontend/components/shop/category-tile.tsx (1)

1-1: LGTM!

The Link import migration is correct and the usage at line 12 (including query parameters) is compatible with the custom routing module.

frontend/app/[locale]/shop/admin/page.tsx (1)

1-1: LGTM! Import standardization for i18n routing.

The switch from next/link to the project's @/i18n/routing Link aligns with the broader effort to unify localized navigation across the application.

frontend/app/[locale]/layout.tsx (2)

31-32: LGTM! Clean derivation of layout flags.

The local constants userExists and showAdminNavLink are derived correctly and improve readability of the AppChrome props.


42-44: LGTM! AppChrome composition centralizes header logic.

The new composition pattern cleanly separates concerns: AppChrome manages header variants and shop-specific context (CartProvider), while MainSwitcher handles the optional <main> wrapper based on route scope.

frontend/components/header/UnifiedHeader.tsx (1)

23-136: Component structure is clean and well-organized.

The unified header successfully consolidates platform and shop variants into a single component with clear separation of concerns across left, center, and right sections. The variant-based rendering logic is straightforward and the prop interface is well-defined.

@@ -1,4 +1,5 @@
import Link from "next/link";
import { Link } from '@/i18n/routing';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for any remaining imports from next/link across all JavaScript/TypeScript files
echo "=== Searching for next/link imports ==="
rg -n "from ['\"]next/link['\"]" --type tsx --type ts --type jsx --type js

echo ""
echo "=== Searching for require statements of next/link ==="
rg -n "require\(['\"]next/link['\"]" --type tsx --type ts --type jsx --type js

echo ""
echo "=== Total occurrences found ==="
rg "from ['\"]next/link['\"]|require\(['\"]next/link['\"]" --count-matches

Repository: DevLoversTeam/devlovers.net

Length of output: 492


🏁 Script executed:

#!/bin/bash
# Better search for next/link imports
echo "=== Searching for next/link imports ==="
rg "from ['\"]next/link['\"]" --no-heading

echo ""
echo "=== Count by file ==="
rg "from ['\"]next/link['\"]" -l | wc -l

echo ""
echo "=== Files containing next/link ==="
rg "from ['\"]next/link['\"]" -l

Repository: DevLoversTeam/devlovers.net

Length of output: 742


Complete the locale-aware Link migration across remaining files.

The import change to the custom routing module is correct, but the migration is incomplete. Five other files are still using Next.js's default next/link import and should be updated:

  • frontend/components/blog/BlogCard.tsx
  • frontend/components/shared/Footer.tsx
  • frontend/components/dashboard/StatsCard.tsx
  • frontend/components/about/FeaturesSection.tsx
  • frontend/components/legal/LegalPageShell.tsx

Update these files to use import { Link } from '@/i18n/routing' to fully centralize locale-aware navigation across the codebase.

🤖 Prompt for AI Agents
In frontend/app/[locale]/shop/admin/orders/[id]/page.tsx (and update the other
affected files listed below), the project has migrated to a custom locale-aware
Link but several components still import Next's Link; update imports in
frontend/components/blog/BlogCard.tsx, frontend/components/shared/Footer.tsx,
frontend/components/dashboard/StatsCard.tsx,
frontend/components/about/FeaturesSection.tsx, and
frontend/components/legal/LegalPageShell.tsx to use import { Link } from
'@/i18n/routing' instead of next/link; ensure you replace only the import line
and keep existing Link usage/props unchanged so routing remains locale-aware
across the app.

Comment thread frontend/components/header/UnifiedHeader.tsx
Comment thread frontend/components/shop/header/nav-links.tsx
Comment thread frontend/components/shop/header/nav-links.tsx
Copy link
Copy Markdown
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

♻️ Duplicate comments (3)
frontend/components/header/UnifiedHeader.tsx (1)

90-106: Search button placeholder is now properly disabled.

The search button correctly includes disabled, aria-disabled="true", a descriptive title, and a TODO comment. This addresses the previous review feedback about the non-functional search button confusing users.

frontend/components/shop/header/nav-links.tsx (2)

3-4: Correctly using i18n-aware usePathname now.

The import has been updated to use usePathname from @/i18n/routing which returns locale-stripped paths, eliminating the need for manual locale stripping. This addresses the previous review feedback.


38-48: Active link logic is now correct.

The implementation properly:

  1. Parses the link's query parameters to extract the category
  2. Compares both the pathname AND the category parameter
  3. Marks "All Products" active only when no category is in the URL
  4. Marks category links active only when the category matches

This resolves the critical bug where all category links were highlighted simultaneously.

🧹 Nitpick comments (2)
frontend/components/header/UnifiedHeader.tsx (2)

67-84: Platform navigation links lack active state highlighting.

The shop variant uses NavLinks which has active state logic, but the platform variant renders SITE_LINKS directly without any active highlighting. Users won't see visual feedback for the current page.

Consider extracting a similar active-state pattern or creating a shared component that both variants can use.

🔎 Example approach using pathname comparison
 export function UnifiedHeader({
   variant,
   userExists,
   showAdminLink = false,
   enableSearch = true,
 }: UnifiedHeaderProps) {
   const isShop = variant === 'shop';
+  const pathname = usePathname();

   return (
     // ...
           ) : (
             <div className="flex items-center gap-1">
               {SITE_LINKS.map(link => (
                 <Link
                   key={link.href}
                   href={link.href}
-                  className="rounded-md px-3 py-2 text-sm font-medium text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground"
+                  className={cn(
+                    'rounded-md px-3 py-2 text-sm font-medium transition-colors hover:bg-secondary hover:text-foreground',
+                    pathname === link.href ? 'text-foreground' : 'text-muted-foreground'
+                  )}
                 >
                   {link.label}
                 </Link>

You'd need to import usePathname from @/i18n/routing and cn from @/lib/utils.


55-63: Minor: Consider using cn() utility for conditional className.

The className construction using array join works but is inconsistent with other parts of the codebase that use the cn() utility.

🔎 Proposed change
             <span
-              className={[
-                'hidden rounded bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground sm:inline',
-                isShop ? '' : 'invisible',
-              ].join(' ')}
+              className={cn(
+                'hidden rounded bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground sm:inline',
+                !isShop && 'invisible'
+              )}
               aria-hidden={!isShop}
             >

You'd need to import cn from @/lib/utils.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 772b008 and 23964bc.

📒 Files selected for processing (4)
  • frontend/app/[locale]/shop/admin/products/page.tsx
  • frontend/app/[locale]/shop/checkout/error/page.tsx
  • frontend/components/header/UnifiedHeader.tsx
  • frontend/components/shop/header/nav-links.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/components/shop/header/nav-links.tsx (2)
frontend/lib/config/catalog.ts (1)
  • CATEGORIES (1-9)
frontend/lib/utils.ts (1)
  • cn (4-6)
frontend/components/header/UnifiedHeader.tsx (6)
frontend/components/shop/header/nav-links.tsx (1)
  • NavLinks (31-76)
frontend/lib/navigation.ts (1)
  • SITE_LINKS (1-9)
frontend/components/shared/LanguageSwitcher.tsx (1)
  • LanguageSwitcher (8-72)
frontend/components/shop/header/cart-button.tsx (1)
  • CartButton (9-28)
frontend/components/auth/logoutButton.tsx (1)
  • LogoutButton (12-44)
frontend/components/header/AppMobileMenu.tsx (1)
  • AppMobileMenu (19-121)
🔇 Additional comments (5)
frontend/components/header/UnifiedHeader.tsx (1)

23-150: Overall component structure is clean and well-organized.

The unified header successfully consolidates both platform and shop variants with:

  • Proper accessibility attributes (aria-label, aria-hidden)
  • Responsive design with separate desktop/mobile sections
  • Good separation of concerns via composed child components
frontend/components/shop/header/nav-links.tsx (2)

9-23: NAV_LINKS label lookup is computed at module load time.

The CATEGORIES.find() calls execute once when the module is imported, not on every render. This is efficient and correct.

One consideration: if a category slug doesn't exist in CATEGORIES, the fallback values ('Apparel', 'Lifestyle', 'Collectibles') ensure the nav still works, but this could mask a configuration mismatch.


31-76: Clean implementation of the NavLinks component.

The component correctly handles:

  • i18n-aware pathname matching
  • Query parameter parsing with safe fallback (linkQuery ?? '')
  • Proper active state styling using the cn utility
  • Optional admin link rendering
frontend/app/[locale]/shop/checkout/error/page.tsx (2)

31-31: The shop navigation paths are correctly updated.

All navigation hrefs have been properly updated from root paths to /shop/* prefixed paths. The updated routes exist in the app structure:

  • /shop/cartfrontend/app/[locale]/shop/cart/page.tsx
  • /shop/productsfrontend/app/[locale]/shop/products/page.tsx
  • /shop/checkout/payment/[orderId]frontend/app/[locale]/shop/checkout/payment/[orderId]/page.tsx

The changes are consistent across all occurrences and align with the shop-specific routing consolidation.

Also applies to: 37-37, 61-61, 67-67, 117-117, 124-124, 131-131


1-1: No changes needed. The import migration to @/i18n/routing uses the official next-intl library (v4.6.1), which exports the Link component via the standard createNavigation() pattern. The next-intl Link component is API-compatible with Next.js Link and handles automatic locale prefix management per the routing configuration. All usage in the file is correct.

@@ -1,4 +1,4 @@
import Link from 'next/link';
import { Link } from '@/i18n/routing';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that all shop admin pages consistently use @/i18n/routing Link
# and have removed explicit locale prefixes from hrefs

echo "=== Checking Link imports in shop admin pages ==="
rg --type=tsx --type=ts -n "^import.*Link.*from" frontend/app/\[locale\]/shop/admin/ -A 1

echo -e "\n=== Checking for any remaining locale-prefixed hrefs in shop admin ==="
rg --type=tsx --type=ts -n 'href=.*\$\{locale\}' frontend/app/\[locale\]/shop/admin/

Repository: DevLoversTeam/devlovers.net

Length of output: 265


🏁 Script executed:

#!/bin/bash
# Check the specific file to see the actual changes at lines 142, 148
echo "=== Checking products/page.tsx imports and Link usage ==="
head -5 frontend/app/\[locale\]/shop/admin/products/page.tsx

echo -e "\n=== Checking lines around 142, 148 for href changes ==="
sed -n '140,150p' frontend/app/\[locale\]/shop/admin/products/page.tsx

echo -e "\n=== All Link usages in the file ==="
rg --type=tsx -n "Link" frontend/app/\[locale\]/shop/admin/products/page.tsx

Repository: DevLoversTeam/devlovers.net

Length of output: 1105


🏁 Script executed:

#!/bin/bash
# Verify the @/i18n/routing module exists and exports Link
echo "=== Checking @/i18n/routing module ==="
find . -path "*/i18n/routing*" -type f | head -20

echo -e "\n=== Checking if Link is exported from @/i18n/routing ==="
rg -n "export.*Link" --type=tsx --type=ts | grep -i "i18n/routing"

Repository: DevLoversTeam/devlovers.net

Length of output: 239


🏁 Script executed:

#!/bin/bash
# Read the routing module to verify Link export
echo "=== Checking @/i18n/routing module for Link export ==="
cat ./frontend/i18n/routing.ts | head -50

echo -e "\n=== Verify if Link is exported ==="
grep -n "Link" ./frontend/i18n/routing.ts

Repository: DevLoversTeam/devlovers.net

Length of output: 567


🏁 Script executed:

#!/bin/bash
# Read the full file to see all Link usages
echo "=== Full content of products/page.tsx ==="
cat -n frontend/app/\[locale\]/shop/admin/products/page.tsx

Repository: DevLoversTeam/devlovers.net

Length of output: 7523


🏁 Script executed:

#!/bin/bash
# Check for Link imports and usage across shop admin pages without file type flags
echo "=== Link imports in shop admin pages ==="
grep -r "import.*Link" frontend/app/\[locale\]/shop/admin/ --include="*.ts" --include="*.tsx" -n

echo -e "\n=== Check for locale-prefixed hrefs in shop admin ==="
grep -r "href=.*\${locale}" frontend/app/\[locale\]/shop/admin/ --include="*.ts" --include="*.tsx" -n

Repository: DevLoversTeam/devlovers.net

Length of output: 840


Fix inconsistency in shop admin pages: remove explicit locale prefixes from orders pages.

The changes to products/page.tsx are correct—the import from @/i18n/routing and removal of explicit locale prefixes from hrefs are properly aligned with the custom Link component (configured via next-intl with localePrefix: 'always'). However, verification found that other shop admin pages still use explicit locale-prefixed hrefs:

  • orders/[id]/page.tsx:47: href={/${locale}/shop/admin/orders}
  • orders/page.tsx:87: href={/${locale}/shop/admin/orders/${order.id}}

Update these to match the pattern in products/page.tsx to complete the i18n routing unification across all shop admin pages.

🤖 Prompt for AI Agents
In frontend/app/[locale]/shop/admin/orders/[id]/page.tsx around line 47 and
frontend/app/[locale]/shop/admin/orders/page.tsx around line 87, fix
inconsistent locale-prefixed hrefs by removing the explicit `/${locale}` prefix
and using the project's custom Link behavior (ensure the file imports Link from
'@/i18n/routing' if not already). Replace
`href={`/${locale}/shop/admin/orders`}` with `href="/shop/admin/orders"` and
replace `href={`/${locale}/shop/admin/orders/${order.id}`}` with
`href={`/shop/admin/orders/${order.id}`}` (or the equivalent non-locale-prefixed
path), so the Link component handles locale-prefixing consistently across admin
shop pages.

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