Merge remote-tracking branch 'origin' into CPP-153

This commit is contained in:
tedraykov
2024-06-20 14:52:30 +03:00
39 changed files with 1035 additions and 149 deletions

View File

@@ -1,9 +1,13 @@
import productFragment from './product';
import imageFragment from './image';
const cartFragment = /* GraphQL */ `
fragment cart on Cart {
id
checkoutUrl
attributes {
key
value
}
cost {
subtotalAmount {
amount
@@ -38,11 +42,22 @@ const cartFragment = /* GraphQL */ `
value
}
product {
...product
featuredImage {
...image
}
handle
title
productType
}
coreVariantId: metafield(key: "coreVariant", namespace: "custom") {
value
}
addOnQuantity: metafield(namespace: "custom", key: "add_on_quantity") {
value
}
addOnProductId: metafield(namespace: "custom", key: "add_on") {
value
}
}
}
}
@@ -50,7 +65,7 @@ const cartFragment = /* GraphQL */ `
}
totalQuantity
}
${productFragment}
${imageFragment}
`;
export default cartFragment;

View File

@@ -64,6 +64,12 @@ const productFragment = /* GraphQL */ `
condition: metafield(namespace: "custom", key: "condition") {
value
}
addOnQuantity: metafield(namespace: "custom", key: "add_on_quantity") {
value
}
addOnProductId: metafield(namespace: "custom", key: "add_on") {
value
}
}
}
}
@@ -76,6 +82,21 @@ const productFragment = /* GraphQL */ `
fuelType: metafield(namespace: "custom", key: "fuel") {
value
}
transmissionType: metafield(namespace: "custom", key: "transmission_type") {
value
}
transmissionSpeeds: metafield(namespace: "custom", key: "transmission_speeds") {
value
}
driveType: metafield(namespace: "custom", key: "drive_type") {
value
}
transmissionCode: metafield(namespace: "custom", key: "transmission_code") {
value
}
transmissionTag: metafield(namespace: "custom", key: "transmission_tag") {
value
}
images(first: 20) {
edges {
node {

View File

@@ -1,4 +1,5 @@
import {
ADD_ON_PRODUCT_TYPES,
AVAILABILITY_FILTER_ID,
HIDDEN_PRODUCT_TAG,
MAKE_FILTER_ID,
@@ -41,7 +42,6 @@ import {
Address,
Cart,
CartAttributeInput,
CartItem,
Collection,
Connection,
Customer,
@@ -84,6 +84,7 @@ import {
ShopifyRemoveFromCartOperation,
ShopifySetCartAttributesOperation,
ShopifyUpdateCartOperation,
TransmissionType,
ShopifyCustomer,
ShopifyOrder,
ShopifyAddress,
@@ -260,7 +261,7 @@ const reshapeCart = (cart: ShopifyCart): Cart => {
...lineItem,
merchandise: {
...lineItem.merchandise,
product: reshapeProduct(lineItem.merchandise.product)
product: lineItem.merchandise.product
}
}))
};
@@ -273,6 +274,7 @@ const reshapeCollection = (collection: ShopifyCollection): Collection | undefine
return {
...collection,
helpfulLinks: parseMetaFieldValue<string[]>(collection.helpfulLinks),
path: `/search/${collection.handle}`
};
};
@@ -374,18 +376,29 @@ const reshapeImages = (images: Connection<Image>, productTitle: string) => {
};
const reshapeVariants = (variants: ShopifyProductVariant[]): ProductVariant[] => {
return variants.map((variant) => ({
return variants.map(({ addOnProductId, addOnQuantity, ...variant }) => ({
...variant,
waiverAvailable: parseMetaFieldValue<boolean>(variant.waiverAvailable),
coreVariantId: variant.coreVariantId?.value || null,
coreCharge: parseMetaFieldValue<Money>(variant.coreCharge),
mileage: variant.mileage?.value ?? null,
estimatedDelivery: variant.estimatedDelivery?.value || null,
condition: variant.condition?.value || null
condition: variant.condition?.value || null,
...(addOnProductId
? {
addOnProduct: {
id: addOnProductId.value,
quantity: addOnQuantity?.value ? Number(addOnQuantity.value) : 1
}
}
: {})
}));
};
const reshapeProduct = (product: ShopifyProduct, filterHiddenProducts: boolean = true) => {
const reshapeProduct = (
product: ShopifyProduct,
filterHiddenProducts: boolean = true
): Product | undefined => {
if (!product || (filterHiddenProducts && product.tags.includes(HIDDEN_PRODUCT_TAG))) {
return undefined;
}
@@ -393,6 +406,13 @@ const reshapeProduct = (product: ShopifyProduct, filterHiddenProducts: boolean =
const { images, variants, ...rest } = product;
return {
...rest,
transmissionCode: parseMetaFieldValue<string[]>(product.transmissionCode),
transmissionSpeeds: parseMetaFieldValue<number[]>(product.transmissionSpeeds),
transmissionTag: parseMetaFieldValue<string[]>(product.transmissionTag),
driveType: parseMetaFieldValue<string[]>(product.driveType),
transmissionType: product.transmissionType
? (product.transmissionType.value as TransmissionType)
: null,
engineCylinders: parseMetaFieldValue<number[]>(product.engineCylinders),
fuelType: product.fuelType?.value || null,
images: reshapeImages(images, product.title),
@@ -633,20 +653,34 @@ export async function getCart(cartId: string): Promise<Cart | undefined> {
const cart = reshapeCart(res.body.data.cart);
// attach core charge as an additional attribute of a cart line, and remove the core charge line from cart
const extendedCartLines = cart?.lines.reduce((lines, item) => {
const coreVariantId = item.merchandise.coreVariantId?.value;
if (coreVariantId) {
const relatedCoreCharge = cart.lines.find((line) => line.merchandise.id === coreVariantId);
return lines.concat([
{
...item,
coreCharge: relatedCoreCharge
}
]);
}
const extendedCartLines = cart?.lines
.map((item) => {
const coreVariantId = item.merchandise.coreVariantId?.value;
const addOnProductId = item.merchandise.addOnProductId;
const _item = { ...item };
return lines;
}, [] as CartItem[]);
if (coreVariantId) {
const relatedCoreCharge = cart.lines.find((line) => line.merchandise.id === coreVariantId);
_item.coreCharge = relatedCoreCharge;
}
if (addOnProductId) {
const relatedAddOnProduct = cart.lines.find(
(line) => line.merchandise.id === addOnProductId.value
);
_item.addOnProduct = relatedAddOnProduct
? {
...relatedAddOnProduct,
quantity: item.merchandise.addOnQuantity
? Number(item.merchandise.addOnQuantity.value)
: 1
}
: undefined;
}
return _item;
})
// core charge shouldn't present as a dedicated product as it's tightly coupled with the product
.filter((item) => item.merchandise.product.productType !== ADD_ON_PRODUCT_TYPES.coreCharge);
const totalQuantity = extendedCartLines.reduce((sum, line) => sum + line.quantity, 0);
@@ -730,7 +764,8 @@ export async function getCollections(): Promise<Collection[]> {
description: 'All products'
},
path: '/search',
updatedAt: new Date().toISOString()
updatedAt: new Date().toISOString(),
helpfulLinks: null
},
// Filter out the `hidden` collections.
// Collections that start with `hidden-*` need to be hidden on the search page.

View File

@@ -9,6 +9,9 @@ const collectionFragment = /* GraphQL */ `
seo {
...seo
}
helpfulLinks: metafield(namespace: "custom", key: "helpful_links") {
value
}
updatedAt
}
${seoFragment}

View File

@@ -25,14 +25,24 @@ export type CartItem = {
name: string;
value: string;
}[];
product: Product;
product: {
id: string;
handle: string;
title: string;
featuredImage: Image;
productType: string;
};
coreVariantId: { value: string } | null;
addOnQuantity: { value: string } | null;
addOnProductId: { value: string } | null;
};
coreCharge?: CartItem;
addOnProduct?: CartItem & { quantity: number };
};
export type Collection = ShopifyCollection & {
export type Collection = Omit<ShopifyCollection, 'helpfulLinks'> & {
path: string;
helpfulLinks: string[] | null;
};
export type Customer = {
@@ -379,14 +389,29 @@ export type Metaobject = {
[key: string]: string;
};
export type TransmissionType = 'Automatic' | 'Manual';
export type Product = Omit<
ShopifyProduct,
'variants' | 'images' | 'fuelType' | 'engineCylinders'
| 'variants'
| 'images'
| 'fuelType'
| 'engineCylinders'
| 'driveType'
| 'transmissionType'
| 'transmissionSpeeds'
| 'transmissionCode'
| 'transmissionTag'
> & {
variants: ProductVariant[];
images: Image[];
fuelType: string | null;
engineCylinders: number[] | null;
driveType: string[] | null;
transmissionType: TransmissionType | null;
transmissionSpeeds: number[] | null;
transmissionCode: string[] | null;
transmissionTag: string[] | null;
};
export type ProductOption = {
@@ -414,6 +439,10 @@ export type ProductVariant = {
condition: string | null;
engineCylinders: string | null;
fuelType: string | null;
addOnProduct?: {
quantity: number;
id: string;
};
};
export type ShopifyCartProductVariant = {
@@ -432,7 +461,13 @@ export type CartProductVariant = Omit<ShopifyCartProductVariant, 'coreVariantId'
export type ShopifyProductVariant = Omit<
ProductVariant,
'coreCharge' | 'waiverAvailable' | 'coreVariantId' | 'mileage' | 'estimatedDelivery' | 'condition'
| 'coreCharge'
| 'waiverAvailable'
| 'coreVariantId'
| 'mileage'
| 'estimatedDelivery'
| 'condition'
| 'addOnProduct'
> & {
waiverAvailable: { value: string };
coreVariantId: { value: string } | null;
@@ -440,6 +475,8 @@ export type ShopifyProductVariant = Omit<
mileage: { value: number } | null;
estimatedDelivery: { value: string } | null;
condition: { value: string } | null;
addOnProductId: { value: string } | null;
addOnQuantity: { value: string } | null;
};
export type SEO = {
@@ -450,6 +487,7 @@ export type SEO = {
export type ShopifyCart = {
id: string;
checkoutUrl: string;
attributes: { key: string; value: string }[];
cost: {
subtotalAmount: Money;
totalAmount: Money;
@@ -465,6 +503,7 @@ export type ShopifyCollection = {
description: string;
seo: SEO;
updatedAt: string;
helpfulLinks: { value: string } | null;
};
export type ShopifyProduct = {
@@ -493,6 +532,11 @@ export type ShopifyProduct = {
};
engineCylinders: { value: string } | null;
fuelType: { value: string } | null;
transmissionType: { value: string } | null;
transmissionTag: { value: string } | null;
transmissionCode: { value: string } | null;
driveType: { value: string } | null;
transmissionSpeeds: { value: string } | null;
};
export type ShopifyCartOperation = {