Skip to content

Commit

Permalink
fix: product-carousel and product-list now sort properly, included ab…
Browse files Browse the repository at this point in the history
…ility to append or prepend
  • Loading branch information
drewpledger committed Nov 15, 2024
1 parent defe9ab commit befabf9
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { removeEdgesAndNodes } from '@bigcommerce/catalyst-client';
import {
Checkbox,
Combobox,
Image,
Link,
Expand Down Expand Up @@ -42,6 +43,7 @@ interface MSProductsCarouselProps {
className: string;
collection: 'none' | 'bestSelling' | 'newest' | 'featured';
products: Product[];
append: boolean;
}

const fetcher = async (url: string): Promise<{ products: GetProductsResponse }> => {
Expand All @@ -59,6 +61,7 @@ runtime.registerComponent(
function MSProductsCarousel({
className,
collection,
append,
products,
...props
}: MSProductsCarouselProps) {
Expand All @@ -67,7 +70,7 @@ runtime.registerComponent(
const productIds = products.map(({ entityId }) => entityId ?? '');

const { data, isLoading } = useSWR([collection, productIds], async () => {
const apiResults =
const collectionResults =
collection !== 'none'
? await fetcher(`/api/products/group/${collection}`)
: { products: [] };
Expand All @@ -76,18 +79,40 @@ runtime.registerComponent(

searchParams.append('ids', productIds.join(','));

const additionalProducts = await fetcher(`/api/products/ids?${searchParams.toString()}`);
const additionalResults = await fetcher(`/api/products/ids?${searchParams.toString()}`);

return [...apiResults.products, ...additionalProducts.products];
return { collection: collectionResults.products, fromIds: additionalResults.products };
});

if (isLoading) {
return <ProductsCarouselSkeleton className={className} />;
}

const listedProducts = products
.filter((p) => !p.entityId)
.map(({ title, link, imageSrc, imageAlt, subtitle, badge, priceOne, priceTwo, type }) => {
const listedProducts = products.map(
(
{ entityId, title, link, imageSrc, imageAlt, subtitle, badge, priceOne, priceTwo, type },
index,
) => {
if (data?.fromIds && entityId) {
const idData = data.fromIds.find(
(product) => product.entityId === parseInt(entityId, 10),
);

if (idData)
return {
id: idData.entityId.toString(),
title: idData.name,
href: idData.path,
image: idData.defaultImage
? { src: idData.defaultImage.url, alt: idData.defaultImage.altText }
: undefined,
subtitle: removeEdgesAndNodes(idData.categories)
.map((category) => category.name)
.join(', '),
price: pricesTransformer(idData.prices, format),
};
}

let price: Price;

switch (type) {
Expand Down Expand Up @@ -116,7 +141,7 @@ runtime.registerComponent(
}

return {
id: title ?? '',
id: index.toString(),
title: title ?? '',
href: link?.href ?? '',
image: imageSrc ? { src: imageSrc, alt: imageAlt } : undefined,
Expand All @@ -125,10 +150,11 @@ runtime.registerComponent(
badge: badge ?? '',
type,
};
});
},
);

const apiProducts = data
? data.map(({ entityId, name, prices, defaultImage, path, categories }) => {
const collectionData = data?.collection
? data.collection.map(({ entityId, name, prices, defaultImage, path, categories }) => {
return {
id: entityId.toString(),
title: name,
Expand All @@ -142,7 +168,9 @@ runtime.registerComponent(
})
: [];

const allProducts = [...apiProducts, ...listedProducts];
const allProducts = append
? [...collectionData, ...listedProducts]
: [...listedProducts, ...collectionData];

return <ProductsCarousel {...props} className={className} products={allProducts} />;
},
Expand All @@ -162,6 +190,7 @@ runtime.registerComponent(
],
defaultValue: 'bestSelling',
}),
append: Checkbox({ label: 'Append additional products', defaultValue: true }),
products: List({
label: 'Products',
type: Shape({
Expand Down Expand Up @@ -189,7 +218,6 @@ runtime.registerComponent(
imageAlt: TextInput({ label: 'Image alt', defaultValue: 'Product image' }),
subtitle: TextInput({ label: 'Subtitle', defaultValue: 'Product subtitle' }),
badge: TextInput({ label: 'Badge', defaultValue: 'New' }),

type: Select({
options: [
{ value: 'single', label: 'Single' },
Expand All @@ -203,6 +231,10 @@ runtime.registerComponent(
},
}),
getItemLabel(product) {
if (product?.entityId) {
return product.entityId.label;
}

return product?.title || 'Product';
},
}),
Expand Down
76 changes: 57 additions & 19 deletions core/makeswift/components/products-list/products-list.makeswift.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface Product {
interface MSProductsListProps {
className: string;
collection: 'none' | 'bestSelling' | 'newest' | 'featured';
append: boolean;
products: Product[];
showCompare: boolean;
compareLabel: string;
Expand All @@ -56,13 +57,19 @@ const fetcher = async (url: string): Promise<{ products: GetProductsResponse }>
};

runtime.registerComponent(
function MSProductsList({ className, collection, products, ...props }: MSProductsListProps) {
function MSProductsList({
className,
collection,
append,
products,
...props
}: MSProductsListProps) {
const format = useFormatter();

const productIds = products.map(({ entityId }) => entityId ?? '');

const { data, isLoading } = useSWR([collection, productIds], async () => {
const apiResults =
const { data } = useSWR([collection, productIds], async () => {
const collectionResults =
collection !== 'none'
? await fetcher(`/api/products/group/${collection}`)
: { products: [] };
Expand All @@ -71,22 +78,46 @@ runtime.registerComponent(

searchParams.append('ids', productIds.join(','));

const additionalProducts = await fetcher(`/api/products/ids?${searchParams.toString()}`);
const additionalResults = await fetcher(`/api/products/ids?${searchParams.toString()}`);

return [...apiResults.products, ...additionalProducts.products];
return { collection: collectionResults.products, fromIds: additionalResults.products };
});

if (isLoading) {
return <ProductsListSkeleton className={className} />;
}

if (products.length === 0 && data && data.length === 0) {
if (
products.length === 0 &&
data &&
data.collection.length === 0 &&
data.fromIds.length === 0
) {
return <ProductsListSkeleton className={className} message="No products found" />;
}

const listedProducts = products
.filter((p) => !p.entityId)
.map(({ title, link, imageSrc, imageAlt, subtitle, badge, priceOne, priceTwo, type }) => {
const listedProducts = products.map(
(
{ entityId, title, link, imageSrc, imageAlt, subtitle, badge, priceOne, priceTwo, type },
index,
) => {
// If entity ID is provided, use the data from SWR
if (data?.fromIds && entityId) {
const idData = data.fromIds.find(
(product) => product.entityId === parseInt(entityId, 10),
);

if (idData)
return {
id: idData.entityId.toString(),
title: idData.name,
href: idData.path,
image: idData.defaultImage
? { src: idData.defaultImage.url, alt: idData.defaultImage.altText }
: undefined,
subtitle: removeEdgesAndNodes(idData.categories)
.map((category) => category.name)
.join(', '),
price: pricesTransformer(idData.prices, format),
};
}

let price: Price;

switch (type) {
Expand Down Expand Up @@ -115,7 +146,7 @@ runtime.registerComponent(
}

return {
id: title ?? '',
id: index.toString(),
title: title ?? '',
href: link?.href ?? '',
image: imageSrc ? { src: imageSrc, alt: imageAlt } : undefined,
Expand All @@ -124,10 +155,11 @@ runtime.registerComponent(
badge: badge ?? '',
type,
};
});
},
);

const apiProducts = data
? data.map(({ entityId, name, prices, defaultImage, path, categories }) => {
const collectionData = data?.collection
? data.collection.map(({ entityId, name, prices, defaultImage, path, categories }) => {
return {
id: entityId.toString(),
title: name,
Expand All @@ -141,7 +173,9 @@ runtime.registerComponent(
})
: [];

const allProducts = [...apiProducts, ...listedProducts];
const allProducts = append
? [...collectionData, ...listedProducts]
: [...listedProducts, ...collectionData];

return <ProductsList {...props} className={className} products={allProducts} />;
},
Expand All @@ -163,6 +197,7 @@ runtime.registerComponent(
],
defaultValue: 'bestSelling',
}),
append: Checkbox({ label: 'Append additional products', defaultValue: true }),
products: List({
label: 'Additional products',
type: Shape({
Expand Down Expand Up @@ -190,7 +225,6 @@ runtime.registerComponent(
imageAlt: TextInput({ label: 'Image alt', defaultValue: 'Product image' }),
subtitle: TextInput({ label: 'Subtitle', defaultValue: 'Product subtitle' }),
badge: TextInput({ label: 'Badge', defaultValue: 'New' }),

type: Select({
options: [
{ value: 'single', label: 'Single' },
Expand All @@ -204,6 +238,10 @@ runtime.registerComponent(
},
}),
getItemLabel(product) {
if (product?.entityId) {
return product.entityId.label;
}

return product?.title || 'Product Title';
},
}),
Expand Down

0 comments on commit befabf9

Please sign in to comment.