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*' + ] };