diff --git a/components/breadcrumb/index.tsx b/components/breadcrumb/index.tsx
index 046df568e..168be64db 100644
--- a/components/breadcrumb/index.tsx
+++ b/components/breadcrumb/index.tsx
@@ -1,4 +1,5 @@
import { getCollection, getMenu, getProduct } from 'lib/shopify';
+import { findParentCollection, getCollectionUrl } from 'lib/utils';
import { Fragment } from 'react';
import {
Breadcrumb,
@@ -8,7 +9,6 @@ import {
BreadcrumbPage,
BreadcrumbSeparator
} from './breadcrumb-list';
-import { findParentCollection } from 'lib/utils';
type BreadcrumbProps = {
type: 'product' | 'collection';
@@ -25,7 +25,7 @@ const BreadcrumbComponent = async ({ type, handle }: BreadcrumbProps) => {
if (collection) {
items.push({
- href: `/search/${collection.handle}`,
+ href: getCollectionUrl(collection.handle),
title: collection.title
});
}
@@ -42,16 +42,17 @@ const BreadcrumbComponent = async ({ type, handle }: BreadcrumbProps) => {
const [collection, menu] = await Promise.all([collectionData, menuData]);
if (!collection) return null;
const parentCollection = findParentCollection(menu, handle);
- if (parentCollection && parentCollection.path !== `/search/${handle}`) {
+
+ if (parentCollection && parentCollection.path !== `/${handle}`) {
items.push({
- href: `${parentCollection.path}`,
+ href: getCollectionUrl(parentCollection.path, false),
title: parentCollection.title
});
}
items.push({
title: collection.title,
- href: `/search/${collection.handle}`
+ href: getCollectionUrl(collection.handle)
});
}
diff --git a/components/grid/three-items.tsx b/components/grid/three-items.tsx
deleted file mode 100644
index a36a051f6..000000000
--- a/components/grid/three-items.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { GridTileImage } from 'components/grid/tile';
-import { getCollectionProducts } from 'lib/shopify';
-import type { Product } from 'lib/shopify/types';
-
-function ThreeItemGridItem({
- item,
- size,
- priority
-}: {
- item: Product;
- size: 'full' | 'half';
- priority?: boolean;
-}) {
- return (
-
-
-
- );
-}
-
-export async function ThreeItemGrid() {
- // Collections that start with `hidden-*` are hidden from the search page.
- const { products: homepageItems } = await getCollectionProducts({
- collection: 'hidden-homepage-featured-items'
- });
-
- if (!homepageItems[0] || !homepageItems[1] || !homepageItems[2]) return null;
-
- const [firstProduct, secondProduct, thirdProduct] = homepageItems;
-
- return (
-
- );
-}
diff --git a/components/layout/navbar/mobile-menu.tsx b/components/layout/navbar/mobile-menu.tsx
index 87e486ad4..f45efb254 100644
--- a/components/layout/navbar/mobile-menu.tsx
+++ b/components/layout/navbar/mobile-menu.tsx
@@ -1,6 +1,14 @@
'use client';
-import { Dialog, Disclosure, Transition } from '@headlessui/react';
+import {
+ Dialog,
+ DialogPanel,
+ Disclosure,
+ DisclosureButton,
+ DisclosurePanel,
+ Transition,
+ TransitionChild
+} from '@headlessui/react';
import Link from 'next/link';
import { usePathname, useSearchParams } from 'next/navigation';
import { Fragment, Suspense, useEffect, useState } from 'react';
@@ -41,7 +49,7 @@ export default function MobileMenu({ menu }: { menu: Menu[] }) {
>
diff --git a/components/layout/search/filters/sub-menu.tsx b/components/layout/search/filters/sub-menu.tsx
index b4adc3bac..e88cbca8c 100644
--- a/components/layout/search/filters/sub-menu.tsx
+++ b/components/layout/search/filters/sub-menu.tsx
@@ -1,10 +1,10 @@
import { getMenu } from 'lib/shopify';
+import { getCollectionUrl } from 'lib/utils';
import Link from 'next/link';
const SubMenu = async ({ collection }: { collection: string }) => {
const menu = await getMenu('main-menu');
-
- const subMenu = menu.find((item) => item.path === `/search/${collection}`)?.items || [];
+ const subMenu = menu.find((item) => item.path === getCollectionUrl(collection))?.items || [];
return subMenu.length ? (
diff --git a/components/manufacturers-grid/button-group.tsx b/components/manufacturers-grid/button-group.tsx
index a9385b685..6532f6685 100644
--- a/components/manufacturers-grid/button-group.tsx
+++ b/components/manufacturers-grid/button-group.tsx
@@ -13,7 +13,7 @@ const ButtonGroup = ({ manufacturer }: { manufacturer: Metaobject }) => {
const handleClick = (type: 'engines' | 'transmissions') => {
_newSearchParams.set(MAKE_FILTER_ID, manufacturer.id);
- router.push(createUrl(`/search/${type}`, _newSearchParams));
+ router.push(createUrl(`/${type}`, _newSearchParams));
};
return (
diff --git a/components/manufacturers-grid/index.tsx b/components/manufacturers-grid/index.tsx
index 14b558b8c..76ac4f462 100644
--- a/components/manufacturers-grid/index.tsx
+++ b/components/manufacturers-grid/index.tsx
@@ -30,8 +30,8 @@ const ManufacturersGrid = ({ manufacturers, variant = 'home' }: ManufacturersGri
) : (
)}
{variant === 'home' && }
@@ -56,8 +56,8 @@ const ManufacturersGrid = ({ manufacturers, variant = 'home' }: ManufacturersGri
) : (
)}
{variant === 'home' && }
diff --git a/lib/shopify/index.ts b/lib/shopify/index.ts
index daab9ebed..2f20d88a3 100644
--- a/lib/shopify/index.ts
+++ b/lib/shopify/index.ts
@@ -15,7 +15,13 @@ import {
YEAR_FILTER_ID
} from 'lib/constants';
import { isShopifyError } from 'lib/type-guards';
-import { ensureStartsWith, normalizeUrl, parseJSON, parseMetaFieldValue } from 'lib/utils';
+import {
+ ensureStartsWith,
+ getCollectionUrl,
+ normalizeUrl,
+ parseJSON,
+ parseMetaFieldValue
+} from 'lib/utils';
import { revalidatePath, revalidateTag } from 'next/cache';
import { headers } from 'next/headers';
import { NextRequest, NextResponse } from 'next/server';
@@ -38,6 +44,7 @@ import { getCustomerQuery } from './queries/customer';
import { getMenuQuery } from './queries/menu';
import { getMetaobjectQuery, getMetaobjectsQuery } from './queries/metaobject';
import { getFileQuery, getImageQuery, getMetaobjectsByIdsQuery } from './queries/node';
+import getCustomerOrderQuery from './queries/order';
import { getCustomerOrdersQuery } from './queries/orders';
import { getPageQuery, getPagesQuery } from './queries/page';
import {
@@ -109,7 +116,6 @@ import {
UploadInput,
WarrantyStatus
} from './types';
-import getCustomerOrderQuery from './queries/order';
const domain = process.env.SHOPIFY_STORE_DOMAIN
? ensureStartsWith(process.env.SHOPIFY_STORE_DOMAIN, 'https://')
@@ -347,7 +353,7 @@ const reshapeCollection = (collection: ShopifyCollection): Collection | undefine
...collection,
helpfulLinks: parseMetaFieldValue(collection.helpfulLinks),
helpfulLinksTop: parseMetaFieldValue(collection.helpfulLinksTop),
- path: `/search/${collection.handle}`
+ path: getCollectionUrl(collection.handle)
};
};
@@ -833,26 +839,9 @@ export async function getCollections(): Promise {
tags: [TAGS.collections]
});
const shopifyCollections = removeEdgesAndNodes(res.body?.data?.collections);
- const collections = [
- {
- handle: '',
- title: 'All',
- description: 'All products',
- seo: {
- title: 'All',
- description: 'All products'
- },
- path: '/search',
- updatedAt: new Date().toISOString(),
- helpfulLinks: null,
- helpfulLinksTop: null
- },
- // Filter out the `hidden` collections.
- // Collections that start with `hidden-*` need to be hidden on the search page.
- ...reshapeCollections(shopifyCollections).filter(
- (collection) => !collection.handle.startsWith('hidden')
- )
- ];
+ const collections = reshapeCollections(shopifyCollections).filter(
+ (collection) => !collection.handle.startsWith('hidden')
+ );
return collections;
}
diff --git a/lib/utils.ts b/lib/utils.ts
index b5715b9d3..e42f43804 100644
--- a/lib/utils.ts
+++ b/lib/utils.ts
@@ -82,7 +82,13 @@ export function cn(...inputs: ClassValue[]) {
}
export function normalizeUrl(domain: string, url: string) {
- return url.replace(domain, '').replace('/collections', '/search').replace('/pages', '');
+ const cleanUrl = url.replace(domain, '');
+
+ if (cleanUrl.startsWith('/collections')) {
+ return getCollectionUrl(cleanUrl.replace('/collections', ''), false);
+ }
+
+ return cleanUrl.replace('/pages', '');
}
export const parseMetaFieldValue = (field: { value: string } | null): T | null => {
@@ -97,7 +103,9 @@ export const findParentCollection = (menu: Menu[], collection: string): Menu | n
let parentCollection: Menu | null = null;
for (const item of menu) {
if (item.items.length) {
- const hasParent = item.items.some((subItem) => subItem.path.includes(collection));
+ const hasParent = item.items.some((subItem) =>
+ subItem.path.includes(getCollectionUrl(collection))
+ );
if (hasParent) {
return item;
} else {
@@ -135,3 +143,9 @@ export const isBeforeToday = (date?: string | null) => {
return compareDate <= today;
};
+
+export const getCollectionUrl = (handle: string, includeSlashPrefix = true) => {
+ const rewriteUrl = handle.split('-').filter(Boolean).join('/');
+
+ return includeSlashPrefix ? `/${rewriteUrl}` : rewriteUrl;
+};
diff --git a/middleware.ts b/middleware.ts
index 032b2ae80..f3249e899 100644
--- a/middleware.ts
+++ b/middleware.ts
@@ -1,15 +1,37 @@
import { getOrigin, isLoggedIn } from 'lib/shopify/auth';
-import type { NextRequest } from 'next/server';
+import { NextRequest, NextResponse } from 'next/server';
+
+const URL_PREFIXES = ['/transmissions', '/engines', '/transfer-cases', '/remanufactured-engines'];
// This function can be marked `async` if using `await` inside
export async function middleware(request: NextRequest) {
if (request.nextUrl.pathname.startsWith('/account')) {
console.log('Running Account middleware');
const origin = getOrigin(request);
+
return await isLoggedIn(request, origin);
}
+
+ if (URL_PREFIXES.some((url) => request.nextUrl.pathname.startsWith(url))) {
+ // /transmissions/bmw/x5 would turn into /transmissions-bmw-x5
+ const requestPathname = request.nextUrl.pathname.split('/').filter(Boolean).join('-');
+ const searchString = request.nextUrl.search;
+
+ return NextResponse.rewrite(
+ new URL(
+ searchString ? `/search/${requestPathname}${searchString}` : `/search/${requestPathname}`,
+ request.url
+ )
+ );
+ }
}
export const config = {
- matcher: ['/account/:path*']
+ matcher: [
+ '/account/:path*',
+ '/transmissions/:path*',
+ '/engines/:path*',
+ '/transfer-cases/:path*',
+ '/remanufactured-engines/:path*'
+ ]
};