From 5d2ecec17c83277ab0e39a4053c97813d21855d9 Mon Sep 17 00:00:00 2001 From: Filip Cichorek Date: Mon, 30 Mar 2026 09:47:13 +0200 Subject: [PATCH 1/2] Use Link components in MobileMenu and fix filter skeleton flash (#91) * Use Link components in MobileMenu and fix filter skeleton flash - Replace button + router.push with Next.js Link components in MobileMenu for proper client-side navigation and prefetching - Only show filter skeleton on initial load, not on subsequent filter updates Co-Authored-By: Claude Opus 4.6 (1M context) * Remove unused useRouter import from MobileMenu Co-Authored-By: Claude Opus 4.6 (1M context) --------- Co-authored-by: Claude Opus 4.6 (1M context) --- src/components/layout/MobileMenu.tsx | 65 +++++++------------ .../products/filters/ProductFilters.tsx | 25 +++---- 2 files changed, 38 insertions(+), 52 deletions(-) diff --git a/src/components/layout/MobileMenu.tsx b/src/components/layout/MobileMenu.tsx index 0996d0da..cb43dbf8 100644 --- a/src/components/layout/MobileMenu.tsx +++ b/src/components/layout/MobileMenu.tsx @@ -3,7 +3,6 @@ import type { Category } from "@spree/sdk"; import { ArrowLeft, Check, ChevronRight, User, X } from "lucide-react"; import Link from "next/link"; -import { useRouter } from "next/navigation"; import { useRef, useState } from "react"; import { flushSync } from "react-dom"; import { Button } from "@/components/ui/button"; @@ -46,7 +45,6 @@ export function MobileMenu({ rootCategories, basePath }: MobileMenuProps) { const timeoutRef = useRef(null); const { country, currency, countries } = useStore(); - const router = useRouter(); const { isCountryNavigating, handleCountrySelect } = useCountrySwitch({ currentCountry: country, onBeforeNavigate: () => setOpen(false), @@ -98,11 +96,6 @@ export function MobileMenu({ rootCategories, basePath }: MobileMenuProps) { } }; - const handleNavigate = (href: string) => { - setOpen(false); - router.push(href); - }; - // Flatten root categories: show their children directly instead of taxonomy names const menuCategories = rootCategories.flatMap((root) => root.children ?? []); @@ -225,20 +218,20 @@ export function MobileMenu({ rootCategories, basePath }: MobileMenuProps) { }`} > {/* Footer: Country switcher (mobile + tablet) + Account (mobile only) */} @@ -342,33 +333,27 @@ export function MobileMenu({ rootCategories, basePath }: MobileMenuProps) { ) : ( - + ), )} {/* "View all" at the bottom */}
- +
); diff --git a/src/components/products/filters/ProductFilters.tsx b/src/components/products/filters/ProductFilters.tsx index 32f76917..268e50e3 100644 --- a/src/components/products/filters/ProductFilters.tsx +++ b/src/components/products/filters/ProductFilters.tsx @@ -131,20 +131,21 @@ export const FilterBar = memo(function FilterBar({ const activeSortBy = activeFilters.sortBy || filtersData?.default_sort; - if (filtersLoading) { - return ( -
-
-
-
-
-
-
- ); + if (!filtersData) { + if (filtersLoading) { + return ( +
+
+
+
+
+
+
+ ); + } + return null; } - if (!filtersData) return null; - const availabilityFilter = filtersData.filters.find( (f) => f.type === "availability", ) as AvailabilityFilter | undefined; From e1c2b236d4bdbd9b1888d1acfd5727412eb01251 Mon Sep 17 00:00:00 2001 From: Damian Legawiec Date: Mon, 30 Mar 2026 09:48:36 +0200 Subject: [PATCH 2/2] Revert "Use Link components in MobileMenu and fix filter skeleton flash (#91)" This reverts commit 5d2ecec17c83277ab0e39a4053c97813d21855d9. --- src/components/layout/MobileMenu.tsx | 65 ++++++++++++------- .../products/filters/ProductFilters.tsx | 25 ++++--- 2 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/components/layout/MobileMenu.tsx b/src/components/layout/MobileMenu.tsx index cb43dbf8..0996d0da 100644 --- a/src/components/layout/MobileMenu.tsx +++ b/src/components/layout/MobileMenu.tsx @@ -3,6 +3,7 @@ import type { Category } from "@spree/sdk"; import { ArrowLeft, Check, ChevronRight, User, X } from "lucide-react"; import Link from "next/link"; +import { useRouter } from "next/navigation"; import { useRef, useState } from "react"; import { flushSync } from "react-dom"; import { Button } from "@/components/ui/button"; @@ -45,6 +46,7 @@ export function MobileMenu({ rootCategories, basePath }: MobileMenuProps) { const timeoutRef = useRef(null); const { country, currency, countries } = useStore(); + const router = useRouter(); const { isCountryNavigating, handleCountrySelect } = useCountrySwitch({ currentCountry: country, onBeforeNavigate: () => setOpen(false), @@ -96,6 +98,11 @@ export function MobileMenu({ rootCategories, basePath }: MobileMenuProps) { } }; + const handleNavigate = (href: string) => { + setOpen(false); + router.push(href); + }; + // Flatten root categories: show their children directly instead of taxonomy names const menuCategories = rootCategories.flatMap((root) => root.children ?? []); @@ -218,20 +225,20 @@ export function MobileMenu({ rootCategories, basePath }: MobileMenuProps) { }`} > {/* Footer: Country switcher (mobile + tablet) + Account (mobile only) */} @@ -333,27 +342,33 @@ export function MobileMenu({ rootCategories, basePath }: MobileMenuProps) { ) : ( - setOpen(false)} + type="button" + onClick={() => + handleNavigate(`${basePath}/c/${child.permalink}`) + } className={linkClass} > {child.name} - + ), )} {/* "View all" at the bottom */}
- setOpen(false)} - className="block w-full text-center text-sm text-gray-500 hover:text-gray-900 py-2 transition-colors" +
); diff --git a/src/components/products/filters/ProductFilters.tsx b/src/components/products/filters/ProductFilters.tsx index 268e50e3..32f76917 100644 --- a/src/components/products/filters/ProductFilters.tsx +++ b/src/components/products/filters/ProductFilters.tsx @@ -131,21 +131,20 @@ export const FilterBar = memo(function FilterBar({ const activeSortBy = activeFilters.sortBy || filtersData?.default_sort; - if (!filtersData) { - if (filtersLoading) { - return ( -
-
-
-
-
-
-
- ); - } - return null; + if (filtersLoading) { + return ( +
+
+
+
+
+
+
+ ); } + if (!filtersData) return null; + const availabilityFilter = filtersData.filters.find( (f) => f.type === "availability", ) as AvailabilityFilter | undefined;