feat: implement YMM filters

Signed-off-by: Chloe <pinkcloudvnn@gmail.com>
This commit is contained in:
Chloe
2024-05-15 20:53:22 +07:00
parent 57c5f42bf3
commit 7c60e4e7f4
12 changed files with 392 additions and 19 deletions

View File

@@ -20,6 +20,11 @@ export const sorting: SortFilterItem[] = [
{ title: 'Price: High to low', slug: 'price-desc', sortKey: 'PRICE', reverse: true }
];
export const PART_TYPES = [
{ label: 'Transmissions', value: 'transmissions' },
{ label: 'Engines', value: 'engines' }
];
export const TAGS = {
collections: 'collections',
products: 'products',
@@ -35,5 +40,8 @@ export const CORE_VARIANT_ID_KEY = 'coreVariantId';
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';
export const MODEL_FILTER_ID = 'filter.p.m.custom.make_model_composite';
export const YEAR_FILTER_ID = 'filter.p.m.custom.make_model_year_composite';
export const PRODUCT_METAFIELD_PREFIX = 'filter.p.m';
export const VARIANT_METAFIELD_PREFIX = 'filter.v.m';

View File

@@ -1,11 +1,14 @@
import {
AVAILABILITY_FILTER_ID,
HIDDEN_PRODUCT_TAG,
MAKE_FILTER_ID,
MODEL_FILTER_ID,
PRICE_FILTER_ID,
PRODUCT_METAFIELD_PREFIX,
SHOPIFY_GRAPHQL_API_ENDPOINT,
TAGS,
VARIANT_METAFIELD_PREFIX
VARIANT_METAFIELD_PREFIX,
YEAR_FILTER_ID
} from 'lib/constants';
import { isShopifyError } from 'lib/type-guards';
import { ensureStartsWith, normalizeUrl, parseMetaFieldValue } from 'lib/utils';
@@ -25,6 +28,7 @@ import {
getCollectionsQuery
} from './queries/collection';
import { getMenuQuery } from './queries/menu';
import { getMetaobjectsQuery } from './queries/metaobject';
import { getPageQuery, getPagesQuery } from './queries/page';
import {
getProductQuery,
@@ -38,6 +42,7 @@ import {
Filter,
Image,
Menu,
Metaobject,
Money,
Page,
PageInfo,
@@ -53,6 +58,8 @@ import {
ShopifyCreateCartOperation,
ShopifyFilter,
ShopifyMenuOperation,
ShopifyMetaobject,
ShopifyMetaobjectsOperation,
ShopifyPageOperation,
ShopifyPagesOperation,
ShopifyProduct,
@@ -181,7 +188,10 @@ const reshapeCollections = (collections: ShopifyCollection[]) => {
const reshapeFilters = (filters: ShopifyFilter[]): Filter[] => {
const reshapedFilters = [];
for (const filter of filters) {
const excludedYMMFilters = filters.filter(
(filter) => ![MODEL_FILTER_ID, MAKE_FILTER_ID, YEAR_FILTER_ID].includes(filter.id)
);
for (const filter of excludedYMMFilters) {
const values = filter.values
.map((valueItem) => {
if (filter.id === AVAILABILITY_FILTER_ID) {
@@ -222,6 +232,29 @@ const reshapeFilters = (filters: ShopifyFilter[]): Filter[] => {
return reshapedFilters;
};
const reshapeMetaobjects = (metaobjects: ShopifyMetaobject[]): Metaobject[] => {
return metaobjects.map(({ fields, id }) => {
const groupedFieldsByKey = fields.reduce(
(acc, field) => {
return {
...acc,
[field.key]: field.value
};
},
{} as {
[key: string]:
| {
value: string;
referenceId: string;
}
| string;
}
);
return { id, ...groupedFieldsByKey };
});
};
const reshapeImages = (images: Connection<Image>, productTitle: string) => {
const flattened = removeEdgesAndNodes(images);
@@ -447,6 +480,16 @@ export async function getMenu(handle: string): Promise<Menu[]> {
return formatMenuItems(res.body?.data?.menu?.items);
}
export async function getMetaobjects(type: string) {
const res = await shopifyFetch<ShopifyMetaobjectsOperation>({
query: getMetaobjectsQuery,
tags: [TAGS.collections, TAGS.products],
variables: { type }
});
return reshapeMetaobjects(removeEdgesAndNodes(res.body.data.metaobjects));
}
export async function getPage(handle: string): Promise<Page> {
const res = await shopifyFetch<ShopifyPageOperation>({
query: getPageQuery,

View File

@@ -0,0 +1,20 @@
export const getMetaobjectsQuery = /* GraphQL */ `
query getMetaobjects($type: String!) {
metaobjects(type: $type, first: 200) {
edges {
node {
id
fields {
reference {
... on Metaobject {
id
}
}
key
value
}
}
}
}
}
`;

View File

@@ -62,6 +62,22 @@ export type Page = {
updatedAt: string;
};
export type ShopifyMetaobject = {
id: string;
fields: Array<{
key: string;
value: string;
reference: {
id: string;
};
}>;
};
export type Metaobject = {
id: string;
[key: string]: string;
};
export type Product = Omit<ShopifyProduct, 'variants' | 'images'> & {
variants: ProductVariant[];
images: Image[];
@@ -269,6 +285,11 @@ export type ShopifyPageOperation = {
variables: { handle: string };
};
export type ShopifyMetaobjectsOperation = {
data: { metaobjects: Connection<ShopifyMetaobject> };
variables: { type: string };
};
export type ShopifyPagesOperation = {
data: {
pages: Connection<Page>;

View File

@@ -1,6 +1,7 @@
import clsx, { ClassValue } from 'clsx';
import { ReadonlyURLSearchParams } from 'next/navigation';
import { twMerge } from 'tailwind-merge';
import { Menu } from './shopify/types';
export const createUrl = (pathname: string, params: URLSearchParams | ReadonlyURLSearchParams) => {
const paramsString = params.toString();
@@ -55,3 +56,18 @@ export const parseMetaFieldValue = <T>(field: { value: string } | null): T | nul
return null;
}
};
export const findParentCollection = (menu: Menu[], collection: string): Menu | null => {
let parentCollection: Menu | null = null;
for (const item of menu) {
if (item.items.length) {
const hasParent = item.items.some((subItem) => subItem.path.includes(collection));
if (hasParent) {
return item;
} else {
parentCollection = findParentCollection(item.items, collection);
}
}
}
return parentCollection;
};