mirror of
https://github.com/vercel/commerce.git
synced 2025-05-14 13:47:49 +00:00
add inlinks for engine sites
Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
parent
87a6fe188c
commit
37c603f64b
@ -4,6 +4,7 @@ import { notFound } from 'next/navigation';
|
|||||||
|
|
||||||
import Breadcrumb from 'components/breadcrumb';
|
import Breadcrumb from 'components/breadcrumb';
|
||||||
import BreadcrumbHome from 'components/breadcrumb/breadcrumb-home';
|
import BreadcrumbHome from 'components/breadcrumb/breadcrumb-home';
|
||||||
|
import EngineSizes from 'components/engine-sizes';
|
||||||
import FAQ from 'components/faq';
|
import FAQ from 'components/faq';
|
||||||
import YMMFilters, { YMMFiltersPlaceholder } from 'components/filters';
|
import YMMFilters, { YMMFiltersPlaceholder } from 'components/filters';
|
||||||
import Manufacturers from 'components/home-page/manufacturers';
|
import Manufacturers from 'components/home-page/manufacturers';
|
||||||
@ -18,8 +19,8 @@ import Header, { HeaderPlaceholder } from 'components/layout/search/header';
|
|||||||
import HelpfulLinks from 'components/layout/search/helpful-links';
|
import HelpfulLinks from 'components/layout/search/helpful-links';
|
||||||
import ProductsGridPlaceholder from 'components/layout/search/placeholder';
|
import ProductsGridPlaceholder from 'components/layout/search/placeholder';
|
||||||
import SortingMenu from 'components/layout/search/sorting-menu';
|
import SortingMenu from 'components/layout/search/sorting-menu';
|
||||||
|
import Models from 'components/models';
|
||||||
import TransmissionCode from 'components/transmission-codes';
|
import TransmissionCode from 'components/transmission-codes';
|
||||||
import TransmissionModels from 'components/transmission-model';
|
|
||||||
import { MAKE_FILTER_ID } from 'lib/constants';
|
import { MAKE_FILTER_ID } from 'lib/constants';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
@ -119,21 +120,30 @@ export default async function CategorySearchPage(props: {
|
|||||||
</div>
|
</div>
|
||||||
<FAQ handle="plp-faqs" />
|
<FAQ handle="plp-faqs" />
|
||||||
{collectionHandle.startsWith('transmissions') && (
|
{collectionHandle.startsWith('transmissions') && (
|
||||||
<>
|
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<TransmissionCode
|
<TransmissionCode
|
||||||
collectionHandle={collectionHandle}
|
collectionHandle={collectionHandle}
|
||||||
make={props.searchParams?.[MAKE_FILTER_ID] as string | undefined}
|
make={props.searchParams?.[MAKE_FILTER_ID]}
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
<Suspense>
|
|
||||||
<TransmissionModels
|
|
||||||
collectionHandle={collectionHandle}
|
|
||||||
make={props.searchParams?.[MAKE_FILTER_ID] as string | undefined}
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
</>
|
|
||||||
)}
|
)}
|
||||||
|
{['transmissions', 'engines', 'remanufactured-engines'].some((url) =>
|
||||||
|
collectionHandle.startsWith(url)
|
||||||
|
) && (
|
||||||
|
<Suspense>
|
||||||
|
<Models collectionHandle={collectionHandle} make={props.searchParams?.[MAKE_FILTER_ID]} />
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{['engines', 'remanufactured-engines'].some((url) => collectionHandle.startsWith(url)) && (
|
||||||
|
<Suspense>
|
||||||
|
<EngineSizes
|
||||||
|
collectionHandle={collectionHandle}
|
||||||
|
make={props.searchParams?.[MAKE_FILTER_ID]}
|
||||||
|
/>
|
||||||
|
</Suspense>
|
||||||
|
)}
|
||||||
|
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<Manufacturers
|
<Manufacturers
|
||||||
variant={(collectionHandle as string).includes('engines') ? 'engines' : 'transmissions'}
|
variant={(collectionHandle as string).includes('engines') ? 'engines' : 'transmissions'}
|
||||||
|
51
components/engine-sizes/index.tsx
Normal file
51
components/engine-sizes/index.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { ENGINE_SIZE_FILTER_ID, MAKE_FILTER_ID } from 'lib/constants';
|
||||||
|
import { getProductFilters } from 'lib/shopify';
|
||||||
|
import { getCollectionUrl } from 'lib/utils';
|
||||||
|
import Link from 'next/link';
|
||||||
|
|
||||||
|
const EngineSizes = async ({
|
||||||
|
collectionHandle,
|
||||||
|
make
|
||||||
|
}: {
|
||||||
|
collectionHandle: string;
|
||||||
|
make?: string | string[];
|
||||||
|
}) => {
|
||||||
|
// eg: collectionHandle = transmission-bmw-x5
|
||||||
|
const makeFromCollectionHandle = collectionHandle.split('-')[1];
|
||||||
|
|
||||||
|
if (!makeFromCollectionHandle && !make) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const engineSizes = await getProductFilters(
|
||||||
|
{ collection: collectionHandle, make },
|
||||||
|
ENGINE_SIZE_FILTER_ID
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!engineSizes || engineSizes.values.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="px-6 pt-10">
|
||||||
|
<div className="mx-auto max-w-7xl">
|
||||||
|
<h3 className="mb-6 text-3xl font-semibold lg:text-4xl">Browse Engines By Engine Sizes</h3>
|
||||||
|
<div className="h-auto max-h-[700px] w-full overflow-auto rounded px-10 py-6 shadow">
|
||||||
|
<div className="mt-6 grid grid-cols-2 gap-x-12 gap-y-5 md:grid-cols-3 md:gap-y-8 lg:grid-cols-4 xl:grid-cols-5">
|
||||||
|
{engineSizes.values.map((engineSize) => (
|
||||||
|
<Link
|
||||||
|
href={`${getCollectionUrl(collectionHandle)}?${ENGINE_SIZE_FILTER_ID}=${engineSize.value}${make ? `&${MAKE_FILTER_ID}=${make}` : ''}`}
|
||||||
|
key={engineSize.id}
|
||||||
|
>
|
||||||
|
<div className="rounded border border-primary px-2 py-1 text-sm">
|
||||||
|
{engineSize.label}
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default EngineSizes;
|
@ -4,12 +4,12 @@ import { getProductFilters } from 'lib/shopify';
|
|||||||
import { getCollectionUrl } from 'lib/utils';
|
import { getCollectionUrl } from 'lib/utils';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
const TransmissionModels = async ({
|
const Models = async ({
|
||||||
collectionHandle,
|
collectionHandle,
|
||||||
make
|
make
|
||||||
}: {
|
}: {
|
||||||
collectionHandle: string;
|
collectionHandle: string;
|
||||||
make?: string;
|
make?: string | string[];
|
||||||
}) => {
|
}) => {
|
||||||
// eg: collectionHandle = transmission-bmw-x5
|
// eg: collectionHandle = transmission-bmw-x5
|
||||||
const makeFromCollectionHandle = collectionHandle.split('-')[1];
|
const makeFromCollectionHandle = collectionHandle.split('-')[1];
|
||||||
@ -17,7 +17,6 @@ const TransmissionModels = async ({
|
|||||||
if (!makeFromCollectionHandle && !make) {
|
if (!makeFromCollectionHandle && !make) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const transmissionModels = await getProductFilters(
|
const transmissionModels = await getProductFilters(
|
||||||
{ collection: collectionHandle, make },
|
{ collection: collectionHandle, make },
|
||||||
MODEL_FILTER_ID
|
MODEL_FILTER_ID
|
||||||
@ -27,10 +26,12 @@ const TransmissionModels = async ({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const prefix = collectionHandle.startsWith('transmissions') ? 'Transmissions' : 'Engines';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="px-6 pt-20">
|
<div className="px-6 pt-20">
|
||||||
<div className="mx-auto max-w-7xl">
|
<div className="mx-auto max-w-7xl">
|
||||||
<h3 className="mb-6 text-3xl font-semibold lg:text-4xl">Browse By Transmission Models</h3>
|
<h3 className="mb-6 text-3xl font-semibold lg:text-4xl">{`Browse ${prefix} By Model`}</h3>
|
||||||
<div className="h-auto max-h-[700px] w-full overflow-auto rounded px-10 py-6 shadow">
|
<div className="h-auto max-h-[700px] w-full overflow-auto rounded px-10 py-6 shadow">
|
||||||
<p className="flex items-center gap-2">
|
<p className="flex items-center gap-2">
|
||||||
<GlobeAltIcon className="size-4" />
|
<GlobeAltIcon className="size-4" />
|
||||||
@ -52,4 +53,4 @@ const TransmissionModels = async ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TransmissionModels;
|
export default Models;
|
@ -10,7 +10,7 @@ const TransmissionCode = async ({
|
|||||||
make
|
make
|
||||||
}: {
|
}: {
|
||||||
collectionHandle: string;
|
collectionHandle: string;
|
||||||
make?: string;
|
make?: string | string[];
|
||||||
}) => {
|
}) => {
|
||||||
const transmissionCodes = await getProductFilters(
|
const transmissionCodes = await getProductFilters(
|
||||||
{ collection: collectionHandle, make },
|
{ collection: collectionHandle, make },
|
||||||
|
@ -43,6 +43,7 @@ export const CORE_WAIVER = 'core-waiver';
|
|||||||
export const CORE_VARIANT_ID_KEY = 'coreVariantId';
|
export const CORE_VARIANT_ID_KEY = 'coreVariantId';
|
||||||
|
|
||||||
export const TRANSMISSION_CODE_FILTER_ID = 'filter.p.m.custom.transmission_code';
|
export const TRANSMISSION_CODE_FILTER_ID = 'filter.p.m.custom.transmission_code';
|
||||||
|
export const ENGINE_SIZE_FILTER_ID = 'filter.p.m.custom.engine_size';
|
||||||
export const AVAILABILITY_FILTER_ID = 'filter.v.availability';
|
export const AVAILABILITY_FILTER_ID = 'filter.v.availability';
|
||||||
export const PRICE_FILTER_ID = 'filter.v.price';
|
export const PRICE_FILTER_ID = 'filter.v.price';
|
||||||
export const MAKE_FILTER_ID = 'filter.p.m.custom.make_composite';
|
export const MAKE_FILTER_ID = 'filter.p.m.custom.make_composite';
|
||||||
@ -69,3 +70,10 @@ export const WARRANTY_FIELDS = [
|
|||||||
'warranty_activation_vin',
|
'warranty_activation_vin',
|
||||||
'warranty_activation_mileage'
|
'warranty_activation_mileage'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const URL_PREFIXES = [
|
||||||
|
'/transmissions',
|
||||||
|
'/engines',
|
||||||
|
'/transfer-cases',
|
||||||
|
'/remanufactured-engines'
|
||||||
|
];
|
||||||
|
@ -1177,19 +1177,22 @@ export const getFile = async (id: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function getProductFilters(
|
export async function getProductFilters(
|
||||||
{ collection, make }: { collection: string; make?: string },
|
{ collection, make }: { collection: string; make?: string | string[] },
|
||||||
filterId: string
|
filterId: string
|
||||||
): Promise<Filter | null | undefined> {
|
): Promise<Filter | null | undefined> {
|
||||||
const [namespace, metafieldKey] = MAKE_FILTER_ID.split('.').slice(-2);
|
const [namespace, metafieldKey] = MAKE_FILTER_ID.split('.').slice(-2);
|
||||||
|
const _make = Array.isArray(make) ? make : make ? [make] : undefined;
|
||||||
|
|
||||||
const res = await shopifyFetch<ShopifyCollectionProductsOperation>({
|
const res = await shopifyFetch<ShopifyCollectionProductsOperation>({
|
||||||
query: getTransmissionCodesQuery,
|
query: getTransmissionCodesQuery,
|
||||||
tags: [TAGS.collections, TAGS.products],
|
tags: [TAGS.collections, TAGS.products],
|
||||||
variables: {
|
variables: {
|
||||||
handle: collection,
|
handle: collection,
|
||||||
...(make
|
...(_make
|
||||||
? {
|
? {
|
||||||
filters: [{ productMetafield: { namespace, key: metafieldKey, value: make } }]
|
filters: _make.map((make) => ({
|
||||||
|
productMetafield: { namespace, key: metafieldKey, value: make }
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
: {})
|
: {})
|
||||||
}
|
}
|
||||||
@ -1202,5 +1205,6 @@ export async function getProductFilters(
|
|||||||
|
|
||||||
const filters = res.body.data.collection.products.filters;
|
const filters = res.body.data.collection.products.filters;
|
||||||
const selectedFilters = filters.find((filter) => filter.id === filterId);
|
const selectedFilters = filters.find((filter) => filter.id === filterId);
|
||||||
|
|
||||||
return selectedFilters ? reshapeFilters([selectedFilters], false)[0] : null;
|
return selectedFilters ? reshapeFilters([selectedFilters], false)[0] : null;
|
||||||
}
|
}
|
||||||
|
18
lib/utils.ts
18
lib/utils.ts
@ -145,7 +145,23 @@ export const isBeforeToday = (date?: string | null) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getCollectionUrl = (handle: string, includeSlashPrefix = true) => {
|
export const getCollectionUrl = (handle: string, includeSlashPrefix = true) => {
|
||||||
const rewriteUrl = handle.split('-').filter(Boolean).join('/');
|
let rewriteUrl = '';
|
||||||
|
const enginesPattern = /^\/?remanufactured-engines(-.+)?$/;
|
||||||
|
const transferCasesPattern = /^\/?transfer-cases(-.+)?$/;
|
||||||
|
|
||||||
|
if (enginesPattern.test(handle)) {
|
||||||
|
rewriteUrl = handle
|
||||||
|
.replace(/-/g, '/')
|
||||||
|
.replace('/engines/', '-engines/')
|
||||||
|
.replace('/engines', '-engines');
|
||||||
|
} else if (transferCasesPattern.test(handle)) {
|
||||||
|
rewriteUrl = handle
|
||||||
|
.replace(/-/g, '/')
|
||||||
|
.replace('/cases/', '-cases/')
|
||||||
|
.replace('/cases', '-cases');
|
||||||
|
} else {
|
||||||
|
rewriteUrl = handle.split('-').filter(Boolean).join('/');
|
||||||
|
}
|
||||||
|
|
||||||
return includeSlashPrefix ? `/${rewriteUrl}` : rewriteUrl;
|
return includeSlashPrefix ? `/${rewriteUrl}` : rewriteUrl;
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
|
import { URL_PREFIXES } from 'lib/constants';
|
||||||
import { getOrigin, isLoggedIn } from 'lib/shopify/auth';
|
import { getOrigin, isLoggedIn } from 'lib/shopify/auth';
|
||||||
import { NextRequest, NextResponse } 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
|
// This function can be marked `async` if using `await` inside
|
||||||
export async function middleware(request: NextRequest) {
|
export async function middleware(request: NextRequest) {
|
||||||
if (request.nextUrl.pathname.startsWith('/account')) {
|
if (request.nextUrl.pathname.startsWith('/account')) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user