tweaks to product mocks

This commit is contained in:
Ghita Lucian 2023-08-14 12:46:08 +02:00
parent 176fc0ea42
commit e513d3b490
8 changed files with 236 additions and 97 deletions

View File

@ -6,7 +6,7 @@ import { Suspense } from 'react';
export const runtime = 'edge'; export const runtime = 'edge';
export const metadata = { export const metadata = {
description: 'High-performance ecommerce store built with Next.js, Vercel, and Shopify.', description: 'High-performance ecommerce store built with Next.js, Vercel.',
openGraph: { openGraph: {
type: 'website' type: 'website'
} }

View File

@ -4,29 +4,30 @@ import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/
import { cookies } from 'next/headers'; import { cookies } from 'next/headers';
export const addItem = async (variantId: string | undefined): Promise<String | undefined> => { export const addItem = async (variantId: string | undefined): Promise<String | undefined> => {
let cartId = cookies().get('cartId')?.value; // let cartId = cookies().get('cartId')?.value;
let cart; // let cart;
//
if (cartId) { // if (cartId) {
cart = await getCart(cartId); // cart = await getCart(cartId);
} // }
//
if (!cartId || !cart) { // if (!cartId || !cart) {
cart = await createCart(); // cart = await createCart();
cartId = cart.id; // cartId = cart.id;
// TODO: this is not working under older Next.js versions // // TODO: this is not working under older Next.js versions
// cookies().set('cartId', cartId); // // cookies().set('cartId', cartId);
} // }
//
if (!variantId) { // if (!variantId) {
return 'Missing product variant ID'; // return 'Missing product variant ID';
} // }
//
try { // try {
await addToCart(cartId, [{ merchandiseId: variantId, quantity: 1 }]); // await addToCart(cartId, [{ merchandiseId: variantId, quantity: 1 }]);
} catch (e) { // } catch (e) {
return 'Error adding item to cart'; // return 'Error adding item to cart';
} // }
return undefined;
}; };
export const removeItem = async (lineId: string): Promise<String | undefined> => { export const removeItem = async (lineId: string): Promise<String | undefined> => {

View File

@ -31,7 +31,7 @@ export function GridTileImage({
{props.src ? ( {props.src ? (
// eslint-disable-next-line jsx-a11y/alt-text -- `alt` is inherited from `props`, which is being enforced with TypeScript // eslint-disable-next-line jsx-a11y/alt-text -- `alt` is inherited from `props`, which is being enforced with TypeScript
<Image <Image
className={clsx('relative h-full w-full object-contain', { className={clsx('relative h-full w-full object-cover', {
'transition duration-300 ease-in-out group-hover:scale-105': isInteractive 'transition duration-300 ease-in-out group-hover:scale-105': isInteractive
})} })}
{...props} {...props}

View File

@ -5,7 +5,10 @@ import LogoSquare from 'components/logo-square';
import { getMenu } from 'lib/shopify'; import { getMenu } from 'lib/shopify';
import { Suspense } from 'react'; import { Suspense } from 'react';
const { COMPANY_NAME, SITE_NAME } = process.env; // const { COMPANY_NAME, SITE_NAME } = process.env;
const COMPANY_NAME = 'WKND';
const SITE_NAME = 'WKND Adventures Commerce';
export default async function Footer() { export default async function Footer() {
const currentYear = new Date().getFullYear(); const currentYear = new Date().getFullYear();
@ -37,17 +40,17 @@ export default async function Footer() {
> >
<FooterMenu menu={menu} /> <FooterMenu menu={menu} />
</Suspense> </Suspense>
<div className="md:ml-auto"> {/*<div className="md:ml-auto">*/}
<a {/* <a*/}
className="flex h-8 w-max flex-none items-center justify-center rounded-md border border-neutral-200 bg-white text-xs text-black dark:border-neutral-700 dark:bg-black dark:text-white" {/* className="flex h-8 w-max flex-none items-center justify-center rounded-md border border-neutral-200 bg-white text-xs text-black dark:border-neutral-700 dark:bg-black dark:text-white"*/}
aria-label="Deploy on Vercel" {/* aria-label="Deploy on Vercel"*/}
href="https://vercel.com/templates/next.js/nextjs-commerce" {/* href="https://vercel.com/templates/next.js/nextjs-commerce"*/}
> {/* >*/}
<span className="px-3"></span> {/* <span className="px-3">▲</span>*/}
<hr className="h-full border-r border-neutral-200 dark:border-neutral-700" /> {/* <hr className="h-full border-r border-neutral-200 dark:border-neutral-700" />*/}
<span className="px-3">Deploy</span> {/* <span className="px-3">Deploy</span>*/}
</a> {/* </a>*/}
</div> {/*</div>*/}
</div> </div>
<div className="border-t border-neutral-200 py-6 text-sm dark:border-neutral-700"> <div className="border-t border-neutral-200 py-6 text-sm dark:border-neutral-700">
<div className="mx-auto flex w-full max-w-7xl flex-col items-center gap-1 px-4 md:flex-row md:gap-0 md:px-4 xl:px-0"> <div className="mx-auto flex w-full max-w-7xl flex-col items-center gap-1 px-4 md:flex-row md:gap-0 md:px-4 xl:px-0">
@ -57,12 +60,12 @@ export default async function Footer() {
</p> </p>
<hr className="mx-4 hidden h-4 w-[1px] border-l border-neutral-400 md:inline-block" /> <hr className="mx-4 hidden h-4 w-[1px] border-l border-neutral-400 md:inline-block" />
<p>Designed in California</p> <p>Designed in California</p>
<p className="md:ml-auto"> {/*<p className="md:ml-auto">*/}
Crafted by{' '} {/* Crafted by{' '}*/}
<a href="https://vercel.com" className="text-black dark:text-white"> {/* <a href="https://vercel.com" className="text-black dark:text-white">*/}
Vercel {/* ▲ Vercel*/}
</a> {/* </a>*/}
</p> {/*</p>*/}
</div> </div>
</div> </div>
</footer> </footer>

View File

@ -31,7 +31,7 @@ export function Gallery({ images }: { images: { src: string; altText: string }[]
<div className="relative aspect-square h-full max-h-[550px] w-full overflow-hidden"> <div className="relative aspect-square h-full max-h-[550px] w-full overflow-hidden">
{images[imageIndex] && ( {images[imageIndex] && (
<Image <Image
className="h-full w-full object-contain" className="h-full w-full object-cover"
fill fill
sizes="(min-width: 1024px) 66vw, 100vw" sizes="(min-width: 1024px) 66vw, 100vw"
alt={images[imageIndex]?.altText as string} alt={images[imageIndex]?.altText as string}

View File

@ -1,5 +1,3 @@
import * as console from 'console';
const baseImagePath = 'https://publish-p64257-e147834-cmstg.adobeaemcloud.com/'; const baseImagePath = 'https://publish-p64257-e147834-cmstg.adobeaemcloud.com/';
const adventures = [ const adventures = [
@ -571,7 +569,7 @@ export function transformToProduct(adventure: any): Product {
width: adventure.primaryImage.width, width: adventure.primaryImage.width,
height: adventure.primaryImage.height height: adventure.primaryImage.height
}, },
images: [], // Only one image is provided, so not including that in the images array images: [],
seo: { seo: {
title: adventure.title, title: adventure.title,
description: adventure.description.html description: adventure.description.html
@ -581,16 +579,107 @@ export function transformToProduct(adventure: any): Product {
updatedAt: new Date().toISOString() updatedAt: new Date().toISOString()
}; };
product.variants.push(variant);
product.images.push(product.featuredImage);
return product; return product;
} }
export const adventureProducts = adventures.map(transformToProduct); export const adventureProducts: Product[] = adventures.map(transformToProduct) as Product[];
export const adventureProductNodes = adventureProducts.map((product) => ({ export const adventureProductNodes = adventureProducts.map((product) => ({
node: product node: product
})); }));
// console.log(adventureProductNodes); export function getProductNodesByKeyword(keyword: string | undefined): { node: Product }[] {
return getProductsByKeyword(keyword).map((product) => ({
node: product
}));
}
// const product = transformToProduct(adventure); export function getProductByHandle(handle: string): Product | undefined {
// console.log(product); const res = adventureProducts.find((product) => product.handle === handle);
return res;
}
export function getProductsByKeyword(keyword: string | undefined): Product[] {
//if keyword is empty, return all products
if (!keyword || keyword === undefined) {
return adventureProducts;
}
keyword = keyword || '';
if (keyword.includes('all')) {
return adventureProducts;
}
if (keyword.includes('hidden-homepage-featured-items')) {
// @ts-ignore
return [
adventureProducts[0] as Product,
adventureProducts[1] as Product,
adventureProducts[2] as Product
];
}
if (keyword.includes('hidden-homepage-carousel')) {
// @ts-ignore
return [
adventureProducts[4] as Product,
adventureProducts[5] as Product,
adventureProducts[6] as Product,
adventureProducts[7] as Product,
adventureProducts[8] as Product
];
}
//if keyword contains a dash, split it into an array of words, and use the first word
if (keyword.includes('-')) {
// @ts-ignore
keyword = keyword.split('-')[0];
}
keyword = keyword || '';
keyword = keyword.toLowerCase();
if (keyword.includes('winter')) {
return adventureProducts.filter(
(product) =>
product.title.toLowerCase().includes('ski') ||
product.title.toLowerCase().includes('winter')
);
}
if (keyword.includes('summer')) {
return adventureProducts.filter(
(product) =>
product.title.toLowerCase().includes('surf') ||
product.title.toLowerCase().includes('climbing') ||
product.title.toLowerCase().includes('summer') ||
product.title.toLowerCase().includes('hiking') ||
product.title.toLowerCase().includes('camping') ||
product.title.toLowerCase().includes('rafting') ||
product.title.toLowerCase().includes('tasting') ||
product.title.toLowerCase().includes('cycling') ||
product.title.toLowerCase().includes('gastro') ||
product.title.toLowerCase().includes('backpacking')
);
}
if (keyword.includes('europe')) {
return adventureProducts.filter(
(product) =>
product.title.toLowerCase().includes('tuscany') ||
product.title.toLowerCase().includes('marais') ||
product.title.toLowerCase().includes('basel') ||
product.title.toLowerCase().includes('mont')
);
}
return adventureProducts.filter(
(product) =>
product.title.toLowerCase().includes(<string>keyword) ||
product.description.toLowerCase().includes(<string>keyword)
);
}

View File

@ -7,8 +7,11 @@ import {
mockShopifyProduct, mockShopifyProduct,
mockCartItem, mockCartItem,
mockShopifyCart, mockShopifyCart,
mockShopifyCollection, winterCollection,
mockPage summerCollection,
europeCollection,
mockPage,
collections
} from './mock'; } from './mock';
import { import {
Cart, Cart,
@ -26,7 +29,7 @@ import {
import { getCollectionsQuery } from './queries/collection'; import { getCollectionsQuery } from './queries/collection';
import { TAGS } from '../constants'; import { TAGS } from '../constants';
import { shopifyFetch } from './index_old'; import { shopifyFetch } from './index_old';
import { adventureProductNodes } from './adventures'; import { adventureProductNodes, getProductByHandle, getProductNodesByKeyword } from './adventures';
const HIDDEN_PRODUCT_TAG = 'hidden'; const HIDDEN_PRODUCT_TAG = 'hidden';
@ -39,8 +42,13 @@ const mockFetchResponse = (data) => ({
}); });
// @ts-ignore // @ts-ignore
const removeEdgesAndNodes = (connection) => const removeEdgesAndNodes = (connection) => {
connection?.edges ? connection?.edges.map((edge) => edge.node) : []; if (!connection?.edges) {
return connection;
}
return connection?.edges ? connection?.edges.map((edge: any) => edge.node) : [];
};
export const createCart = async (): Promise<Cart> => { export const createCart = async (): Promise<Cart> => {
const res = mockFetchResponse({ const res = mockFetchResponse({
@ -93,7 +101,7 @@ export const getCart = async (cartId: string): Promise<Cart | undefined> => {
export const getCollection = async (handle: string): Promise<Collection | undefined> => { export const getCollection = async (handle: string): Promise<Collection | undefined> => {
const res = mockFetchResponse({ const res = mockFetchResponse({
collection: mockShopifyCollection collection: collections.find((collection) => collection.handle === handle)
}); });
return reshapeCollection(res.body.data.collection); return reshapeCollection(res.body.data.collection);
}; };
@ -110,8 +118,7 @@ export const getCollectionProducts = async ({
const res = mockFetchResponse({ const res = mockFetchResponse({
collection: { collection: {
products: { products: {
edges: adventureProductNodes edges: getProductNodesByKeyword(collection)
// edges: [{ node: mockShopifyProduct }]
} }
} }
}); });
@ -125,7 +132,7 @@ export async function getCollections(): Promise<Collection[]> {
// }); // });
const res = mockFetchResponse({ const res = mockFetchResponse({
collections: { collections: {
edges: [{ node: mockShopifyCollection }] edges: [{ node: winterCollection }, { node: summerCollection }, { node: europeCollection }]
} }
}); });
const shopifyCollections = removeEdgesAndNodes(res.body?.data?.collections); const shopifyCollections = removeEdgesAndNodes(res.body?.data?.collections);
@ -138,7 +145,7 @@ export async function getCollections(): Promise<Collection[]> {
title: 'All', title: 'All',
description: 'All products' description: 'All products'
}, },
path: '/search', path: '/search/',
updatedAt: new Date().toISOString() updatedAt: new Date().toISOString()
}, },
// Filter out the `hidden` collections. // Filter out the `hidden` collections.
@ -156,8 +163,20 @@ export const getMenu = async (handle: string): Promise<Menu[]> => {
menu: { menu: {
items: [ items: [
{ {
title: 'Sample Menu', title: 'All',
path: 'https://example.com/sample-menu' path: '/'
},
{
title: 'Summer',
path: '/search/summer-collection'
},
{
title: 'Winter',
path: '/search/winter-collection'
},
{
title: 'Europe',
path: '/search/europe-collection'
} }
] ]
} }
@ -183,14 +202,19 @@ export const getPages = async (): Promise<Page[]> => {
export const getProduct = async (handle: string): Promise<Product | undefined> => { export const getProduct = async (handle: string): Promise<Product | undefined> => {
const res = mockFetchResponse({ const res = mockFetchResponse({
product: mockShopifyProduct product: getProductByHandle(handle)
}); });
return reshapeProduct(res.body.data.product, false); return reshapeProduct(res.body.data.product, false);
}; };
export const getProductRecommendations = async (productId: string): Promise<Product[]> => { export const getProductRecommendations = async (productId: string): Promise<Product[]> => {
const res = mockFetchResponse({ const res = mockFetchResponse({
productRecommendations: [mockShopifyProduct] productRecommendations: [
getProductByHandle('climbing-new-zealand'),
getProductByHandle('ski-touring-mont-blanc'),
getProductByHandle('downhill-skiing-wyoming'),
getProductByHandle('cycling-tuscany')
]
}); });
return reshapeProducts(res.body.data.productRecommendations); return reshapeProducts(res.body.data.productRecommendations);
}; };
@ -206,7 +230,7 @@ export const getProducts = async ({
}): Promise<Product[]> => { }): Promise<Product[]> => {
const res = mockFetchResponse({ const res = mockFetchResponse({
products: { products: {
edges: [{ node: mockShopifyProduct }] edges: getProductNodesByKeyword(query)
} }
}); });
return reshapeProducts(removeEdgesAndNodes(res.body.data.products)); return reshapeProducts(removeEdgesAndNodes(res.body.data.products));
@ -254,11 +278,6 @@ const reshapeCollections = (collections: ShopifyCollection[]) => {
}; };
const reshapeImages = (images: Connection<Image>, productTitle: string) => { const reshapeImages = (images: Connection<Image>, productTitle: string) => {
try {
console.log('images', images);
} catch (e) {
// console.log('error', e);
}
const flattened = removeEdgesAndNodes(images); const flattened = removeEdgesAndNodes(images);
// @ts-ignore // @ts-ignore
@ -272,7 +291,8 @@ const reshapeImages = (images: Connection<Image>, productTitle: string) => {
}; };
const reshapeProduct = (product: ShopifyProduct, filterHiddenProducts: boolean = true) => { const reshapeProduct = (product: ShopifyProduct, filterHiddenProducts: boolean = true) => {
if (!product || (filterHiddenProducts && product.tags.includes(HIDDEN_PRODUCT_TAG))) { // if (!product || (filterHiddenProducts && product.tags.includes(HIDDEN_PRODUCT_TAG))) {
if (!product) {
return undefined; return undefined;
} }

View File

@ -1,25 +1,25 @@
// Mock data for the defined types // Mock data for the defined types
const { adventureProducts } = require('./adventures'); const { adventureProducts } = require('./adventures');
const mockMoney = { export const mockMoney = {
amount: '100.00', amount: '100.00',
currencyCode: 'USD' currencyCode: 'USD'
}; };
const mockImage = { export const mockImage = {
url: 'https://ssc-sparkle.vercel.app/_next/image?url=https%3A%2F%2Fpublish-p64257-e147834-cmstg.adobeaemcloud.com%2Fcontent%2Fdam%2Faem-demo-assets%2Fen%2Fadventures%2Fcycling-tuscany%2FAdobeStock_261097343.jpeg&w=2048&q=75', url: 'https://ssc-sparkle.vercel.app/_next/image?url=https%3A%2F%2Fpublish-p64257-e147834-cmstg.adobeaemcloud.com%2Fcontent%2Fdam%2Faem-demo-assets%2Fen%2Fadventures%2Fcycling-tuscany%2FAdobeStock_261097343.jpeg&w=2048&q=75',
altText: 'Sample Image', altText: 'Sample Image',
width: 500, width: 500,
height: 500 height: 500
}; };
const mockProductOption = { export const mockProductOption = {
id: 'option1', id: 'option1',
name: 'Color', name: 'Color',
values: ['Red', 'Blue', 'Green'] values: ['Red', 'Blue', 'Green']
}; };
const mockProductVariant = { export const mockProductVariant = {
id: 'variant1', id: 'variant1',
title: 'Red Variant', title: 'Red Variant',
availableForSale: true, availableForSale: true,
@ -32,7 +32,7 @@ const mockProductVariant = {
price: mockMoney price: mockMoney
}; };
const mockShopifyProduct = adventureProducts[0]; export const mockShopifyProduct = adventureProducts[0];
// const mockShopifyProductOld = { // const mockShopifyProductOld = {
// id: 'product1', // id: 'product1',
@ -57,7 +57,7 @@ const mockShopifyProduct = adventureProducts[0];
// updatedAt: '2023-08-10T00:00:00Z' // updatedAt: '2023-08-10T00:00:00Z'
// }; // };
const mockCartItem = { export const mockCartItem = {
id: 'item1', id: 'item1',
quantity: 1, quantity: 1,
cost: { totalAmount: mockMoney }, cost: { totalAmount: mockMoney },
@ -74,7 +74,7 @@ const mockCartItem = {
} }
}; };
const mockShopifyCart = { export const mockShopifyCart = {
id: 'cart1', id: 'cart1',
checkoutUrl: 'https://example.com/checkout', checkoutUrl: 'https://example.com/checkout',
cost: { cost: {
@ -86,18 +86,40 @@ const mockShopifyCart = {
totalQuantity: 1 totalQuantity: 1
}; };
const mockShopifyCollection = { export const winterCollection = {
handle: 'sample-collection', handle: 'winter-collection',
title: 'Sample Collection', title: 'Winter',
description: 'This is a sample collection.', description: 'Adventures for the winter.',
seo: { seo: {
title: 'Sample Collection', title: 'Winter Collection',
description: 'This is a sample collection.' description: 'Adventures for the winter.'
}, },
updatedAt: '2023-08-10T00:00:00Z' updatedAt: '2023-08-10T00:00:00Z'
}; };
const mockPage = { export const summerCollection = {
handle: 'summer-collection',
title: 'Summer',
description: 'Adventures for the summer.',
seo: {
title: 'Summer Collection',
description: 'Adventures for the summer.'
},
updatedAt: '2023-08-10T00:00:00Z'
};
export const europeCollection = {
handle: 'europe-collection',
title: 'Europe',
description: 'Adventures in Europe.',
seo: {
title: 'Europe Collection',
description: 'Adventures in Europe.'
},
updatedAt: '2023-08-10T00:00:00Z'
};
export const mockPage = {
id: 'page1', id: 'page1',
title: 'Sample Page', title: 'Sample Page',
handle: 'sample-page', handle: 'sample-page',
@ -113,14 +135,18 @@ const mockPage = {
// Exporting the mock data // Exporting the mock data
module.exports = { export const collections = [winterCollection, summerCollection, europeCollection];
mockMoney, //
mockImage, // module.exports = {
mockProductOption, // mockMoney,
mockProductVariant, // mockImage,
mockShopifyProduct, // mockProductOption,
mockCartItem, // mockProductVariant,
mockShopifyCart, // mockShopifyProduct,
mockShopifyCollection, // mockCartItem,
mockPage // mockShopifyCart,
}; // winterCollection: winterCollection,
// summerCollection: summerCollection,
// europeCollection: europeCollection,
// mockPage
// };