diff --git a/app/search/[collection]/loading.tsx b/app/search/[collection]/loading.tsx
new file mode 100644
index 000000000..b2461e304
--- /dev/null
+++ b/app/search/[collection]/loading.tsx
@@ -0,0 +1,31 @@
+import BreadcrumbHome from 'components/breadcrumb/breadcrumb-home';
+import { YMMFiltersPlaceholder } from 'components/filters';
+import { FiltersListPlaceholder } from 'components/layout/search/filters/filters-container';
+import { HeaderPlaceholder } from 'components/layout/search/header';
+import ProductsGridPlaceholder from 'components/layout/search/placeholder';
+
+const Loading = () => {
+ return (
+
+ );
+};
+
+export default Loading;
diff --git a/app/search/[collection]/page.tsx b/app/search/[collection]/page.tsx
index 52dfb94e9..68788900d 100644
--- a/app/search/[collection]/page.tsx
+++ b/app/search/[collection]/page.tsx
@@ -18,6 +18,9 @@ import Header, { HeaderPlaceholder } from 'components/layout/search/header';
import HelpfulLinks from 'components/layout/search/helpful-links';
import ProductsGridPlaceholder from 'components/layout/search/placeholder';
import SortingMenu from 'components/layout/search/sorting-menu';
+import TransmissionCode from 'components/transmission-codes';
+import TransmissionModels from 'components/transmission-model';
+import { MAKE_FILTER_ID } from 'lib/constants';
import { Suspense } from 'react';
export async function generateMetadata({
@@ -79,6 +82,7 @@ export default async function CategorySearchPage(props: {
params: { collection: string };
searchParams?: { [key: string]: string | string[] | undefined };
}) {
+ const collectionHandle = props.params.collection;
return (
<>
@@ -90,44 +94,49 @@ export default async function CategorySearchPage(props: {
-
+
Filters
- }
- key={`filters-${props.params.collection}`}
- >
-
-
+ } key={`filters-${collectionHandle}`}>
+
+
- } key={`breadcrumb-${props.params.collection}`}>
-
+ } key={`breadcrumb-${collectionHandle}`}>
+
-
} key={`header-${props.params.collection}`}>
-
+
} key={`header-${collectionHandle}`}>
+
-
}
- key={`products-${props.params.collection}`}
- >
+
} key={`products-${collectionHandle}`}>
+ {collectionHandle.startsWith('transmissions') && (
+ <>
+
+
+
+
+
+
+ >
+ )}
>
diff --git a/components/layout/products-list/index.tsx b/components/layout/products-list/index.tsx
index c41f9b5c0..799c1f33c 100644
--- a/components/layout/products-list/index.tsx
+++ b/components/layout/products-list/index.tsx
@@ -54,7 +54,7 @@ const ProductsList = ({
return (
<>
- {products.map((product) => (
+ {products.map((product, index) => (
10 ? false : true}
/>
))}
diff --git a/components/manufacturers-grid/index.tsx b/components/manufacturers-grid/index.tsx
index 76ac4f462..faa71a3c1 100644
--- a/components/manufacturers-grid/index.tsx
+++ b/components/manufacturers-grid/index.tsx
@@ -36,7 +36,7 @@ const ManufacturersGrid = ({ manufacturers, variant = 'home' }: ManufacturersGri
)}
{variant === 'home' && }
- ))}{' '}
+ ))}
>
diff --git a/components/transmission-codes/index.tsx b/components/transmission-codes/index.tsx
new file mode 100644
index 000000000..5edbdb1c6
--- /dev/null
+++ b/components/transmission-codes/index.tsx
@@ -0,0 +1,52 @@
+import { StarIcon } from '@heroicons/react/24/outline';
+import Tag from 'components/tag';
+import { MAKE_FILTER_ID, TRANSMISSION_CODE_FILTER_ID } from 'lib/constants';
+import { getProductFilters } from 'lib/shopify';
+import { getCollectionUrl } from 'lib/utils';
+import Link from 'next/link';
+
+const TransmissionCode = async ({
+ collectionHandle,
+ make
+}: {
+ collectionHandle: string;
+ make?: string;
+}) => {
+ const transmissionCodes = await getProductFilters(
+ { collection: collectionHandle, make },
+ TRANSMISSION_CODE_FILTER_ID
+ );
+
+ if (!transmissionCodes || transmissionCodes.values.length === 0) {
+ return null;
+ }
+
+ return (
+
+
+
+
{`Browse By Transmission Code`}
+
+
+
+ Popular Transmission Codes
+
+
+ {transmissionCodes.values.map((transmissionCode) => (
+
+
+ {transmissionCode.label}
+
+
+ ))}
+
+
+
+
+ );
+};
+
+export default TransmissionCode;
diff --git a/components/transmission-model/index.tsx b/components/transmission-model/index.tsx
new file mode 100644
index 000000000..b7c37020e
--- /dev/null
+++ b/components/transmission-model/index.tsx
@@ -0,0 +1,55 @@
+import { GlobeAltIcon } from '@heroicons/react/24/outline';
+import { MAKE_FILTER_ID, MODEL_FILTER_ID } from 'lib/constants';
+import { getProductFilters } from 'lib/shopify';
+import { getCollectionUrl } from 'lib/utils';
+import Link from 'next/link';
+
+const TransmissionModels = async ({
+ collectionHandle,
+ make
+}: {
+ collectionHandle: string;
+ make?: string;
+}) => {
+ // eg: collectionHandle = transmission-bmw-x5
+ const makeFromCollectionHandle = collectionHandle.split('-')[1];
+
+ if (!makeFromCollectionHandle && !make) {
+ return null;
+ }
+
+ const transmissionModels = await getProductFilters(
+ { collection: collectionHandle, make },
+ MODEL_FILTER_ID
+ );
+
+ if (!transmissionModels || transmissionModels.values.length === 0) {
+ return null;
+ }
+
+ return (
+
+
+
Browse By Transmission Models
+
+
+
+ Models
+
+
+ {transmissionModels.values.map((model) => (
+
+
{model.label}
+
+ ))}
+
+
+
+
+ );
+};
+
+export default TransmissionModels;
diff --git a/lib/constants.ts b/lib/constants.ts
index 5029b37ba..2cb898961 100644
--- a/lib/constants.ts
+++ b/lib/constants.ts
@@ -42,6 +42,7 @@ export const SHOPIFY_GRAPHQL_ADMIN_ADMIN_API_ENDPOINT = '/admin/api/2024-04/grap
export const CORE_WAIVER = 'core-waiver';
export const CORE_VARIANT_ID_KEY = 'coreVariantId';
+export const TRANSMISSION_CODE_FILTER_ID = 'filter.p.m.custom.transmission_code';
export const AVAILABILITY_FILTER_ID = 'filter.v.availability';
export const PRICE_FILTER_ID = 'filter.v.price';
export const MAKE_FILTER_ID = 'filter.p.m.custom.make_composite';
diff --git a/lib/shopify/index.ts b/lib/shopify/index.ts
index 2f20d88a3..0ffc280f1 100644
--- a/lib/shopify/index.ts
+++ b/lib/shopify/index.ts
@@ -38,7 +38,8 @@ import { getCartQuery } from './queries/cart';
import {
getCollectionProductsQuery,
getCollectionQuery,
- getCollectionsQuery
+ getCollectionsQuery,
+ getTransmissionCodesQuery
} from './queries/collection';
import { getCustomerQuery } from './queries/customer';
import { getMenuQuery } from './queries/menu';
@@ -373,10 +374,10 @@ const reshapeCollections = (collections: ShopifyCollection[]) => {
return reshapedCollections;
};
-const reshapeFilters = (filters: ShopifyFilter[]): Filter[] => {
+const reshapeFilters = (filters: ShopifyFilter[], excludeYMM = true): Filter[] => {
const reshapedFilters = [];
- const excludedYMMFilters = filters.filter(
- (filter) => ![MODEL_FILTER_ID, MAKE_FILTER_ID, YEAR_FILTER_ID].includes(filter.id)
+ const excludedYMMFilters = filters.filter((filter) =>
+ excludeYMM ? ![MODEL_FILTER_ID, MAKE_FILTER_ID, YEAR_FILTER_ID].includes(filter.id) : true
);
for (const filter of excludedYMMFilters) {
const values = filter.values
@@ -1174,3 +1175,32 @@ export const getFile = async (id: string) => {
return res.body.data.node;
};
+
+export async function getProductFilters(
+ { collection, make }: { collection: string; make?: string },
+ filterId: string
+): Promise {
+ const [namespace, metafieldKey] = MAKE_FILTER_ID.split('.').slice(-2);
+
+ const res = await shopifyFetch({
+ query: getTransmissionCodesQuery,
+ tags: [TAGS.collections, TAGS.products],
+ variables: {
+ handle: collection,
+ ...(make
+ ? {
+ filters: [{ productMetafield: { namespace, key: metafieldKey, value: make } }]
+ }
+ : {})
+ }
+ });
+
+ if (!res.body.data.collection) {
+ console.log(`No collection found for \`${collection}\``);
+ return null;
+ }
+
+ const filters = res.body.data.collection.products.filters;
+ const selectedFilters = filters.find((filter) => filter.id === filterId);
+ return selectedFilters ? reshapeFilters([selectedFilters], false)[0] : null;
+}
diff --git a/lib/shopify/queries/collection.ts b/lib/shopify/queries/collection.ts
index 306e3cf9e..23a403d62 100644
--- a/lib/shopify/queries/collection.ts
+++ b/lib/shopify/queries/collection.ts
@@ -78,3 +78,22 @@ export const getCollectionProductsQuery = /* GraphQL */ `
}
${productFragment}
`;
+
+export const getTransmissionCodesQuery = /* GraphQL */ `
+ query getTransmissionCodes($handle: String!, $filters: [ProductFilter!]) {
+ collection(handle: $handle) {
+ products(first: 1, filters: $filters) {
+ filters {
+ id
+ label
+ type
+ values {
+ id
+ input
+ label
+ }
+ }
+ }
+ }
+ }
+`;