mirror of
https://github.com/vercel/commerce.git
synced 2025-05-12 12:47:50 +00:00
wip
This commit is contained in:
parent
b94e46d796
commit
8b1218fc35
@ -1,6 +1,6 @@
|
|||||||
import { HIDDEN_PRODUCT_TAG, SHOPIFY_GRAPHQL_API_ENDPOINT, TAGS } from 'lib/constants';
|
import { SHOPIFY_GRAPHQL_API_ENDPOINT, TAGS } from 'lib/constants';
|
||||||
import { find } from 'lib/shopify/payload';
|
import { find, findByID } from 'lib/shopify/payload';
|
||||||
import { Media, Option, Product } from 'lib/shopify/payload-types';
|
import { Media, Option, Product, Tag } from 'lib/shopify/payload-types';
|
||||||
import { isShopifyError } from 'lib/type-guards';
|
import { isShopifyError } from 'lib/type-guards';
|
||||||
import { ensureStartsWith } from 'lib/utils';
|
import { ensureStartsWith } from 'lib/utils';
|
||||||
import { revalidateTag } from 'next/cache';
|
import { revalidateTag } from 'next/cache';
|
||||||
@ -15,11 +15,6 @@ import {
|
|||||||
import { getCartQuery } from './queries/cart';
|
import { getCartQuery } from './queries/cart';
|
||||||
import { getCollectionQuery, getCollectionsQuery } from './queries/collection';
|
import { getCollectionQuery, getCollectionsQuery } from './queries/collection';
|
||||||
import { getPageQuery, getPagesQuery } from './queries/page';
|
import { getPageQuery, getPagesQuery } from './queries/page';
|
||||||
import {
|
|
||||||
getProductQuery,
|
|
||||||
getProductRecommendationsQuery,
|
|
||||||
getProductsQuery
|
|
||||||
} from './queries/product';
|
|
||||||
import {
|
import {
|
||||||
Cart,
|
Cart,
|
||||||
Collection,
|
Collection,
|
||||||
@ -30,6 +25,7 @@ import {
|
|||||||
Money,
|
Money,
|
||||||
Page,
|
Page,
|
||||||
ProductOption,
|
ProductOption,
|
||||||
|
ProductVariant,
|
||||||
ShopifyAddToCartOperation,
|
ShopifyAddToCartOperation,
|
||||||
ShopifyCart,
|
ShopifyCart,
|
||||||
ShopifyCartOperation,
|
ShopifyCartOperation,
|
||||||
@ -39,10 +35,6 @@ import {
|
|||||||
ShopifyCreateCartOperation,
|
ShopifyCreateCartOperation,
|
||||||
ShopifyPageOperation,
|
ShopifyPageOperation,
|
||||||
ShopifyPagesOperation,
|
ShopifyPagesOperation,
|
||||||
ShopifyProduct,
|
|
||||||
ShopifyProductOperation,
|
|
||||||
ShopifyProductRecommendationsOperation,
|
|
||||||
ShopifyProductsOperation,
|
|
||||||
ShopifyRemoveFromCartOperation,
|
ShopifyRemoveFromCartOperation,
|
||||||
ShopifyUpdateCartOperation
|
ShopifyUpdateCartOperation
|
||||||
} from './types';
|
} from './types';
|
||||||
@ -156,48 +148,6 @@ const reshapeCollections = (collections: ShopifyCollection[]) => {
|
|||||||
return reshapedCollections;
|
return reshapedCollections;
|
||||||
};
|
};
|
||||||
|
|
||||||
const reshapeImages = (images: Connection<Image>, productTitle: string) => {
|
|
||||||
const flattened = removeEdgesAndNodes(images);
|
|
||||||
|
|
||||||
return flattened.map((image) => {
|
|
||||||
const filename = image.url.match(/.*\/(.*)\..*/)[1];
|
|
||||||
return {
|
|
||||||
...image,
|
|
||||||
altText: image.altText || `${productTitle} - ${filename}`
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const reshapeProduct = (product: ShopifyProduct, filterHiddenProducts: boolean = true) => {
|
|
||||||
if (!product || (filterHiddenProducts && product.tags.includes(HIDDEN_PRODUCT_TAG))) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { images, variants, ...rest } = product;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...rest,
|
|
||||||
images: reshapeImages(images, product.title),
|
|
||||||
variants: removeEdgesAndNodes(variants)
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const reshapeProducts = (products: ShopifyProduct[]) => {
|
|
||||||
const reshapedProducts = [];
|
|
||||||
|
|
||||||
for (const product of products) {
|
|
||||||
if (product) {
|
|
||||||
const reshapedProduct = reshapeProduct(product);
|
|
||||||
|
|
||||||
if (reshapedProduct) {
|
|
||||||
reshapedProducts.push(reshapedProduct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reshapedProducts;
|
|
||||||
};
|
|
||||||
|
|
||||||
export async function createCart(): Promise<Cart> {
|
export async function createCart(): Promise<Cart> {
|
||||||
const res = await shopifyFetch<ShopifyCreateCartOperation>({
|
const res = await shopifyFetch<ShopifyCreateCartOperation>({
|
||||||
query: createCartMutation,
|
query: createCartMutation,
|
||||||
@ -282,7 +232,9 @@ export async function getCollection(handle: string): Promise<Collection | undefi
|
|||||||
const reshapeImage = (media: Media): Image => {
|
const reshapeImage = (media: Media): Image => {
|
||||||
return {
|
return {
|
||||||
url: media.url!,
|
url: media.url!,
|
||||||
altText: media.alt
|
altText: media.alt,
|
||||||
|
width: media.width,
|
||||||
|
height: media.height
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -293,24 +245,49 @@ type Price = {
|
|||||||
|
|
||||||
const reshapePrice = (price: Price): Money => {
|
const reshapePrice = (price: Price): Money => {
|
||||||
return {
|
return {
|
||||||
amount: (price.amount / 100).toString(),
|
amount: price.amount.toString(),
|
||||||
currencyCode: price.currencyCode
|
currencyCode: price.currencyCode
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const reshapeP = (product: Product): ExProduct => {
|
const reshapeOptions = (variants: Product['variants']): ProductOption[] => {
|
||||||
const options: ProductOption[] = [];
|
const options = new Map<string, Option>();
|
||||||
const map = new Map();
|
|
||||||
|
|
||||||
product.variants.forEach((variant) => {
|
variants.forEach((variant) => {
|
||||||
variant.selectedOptions?.forEach((selectedOption) => {
|
variant.selectedOptions?.forEach((selectedOption) => {
|
||||||
const option = selectedOption.option as Option;
|
const option = selectedOption.option as Option;
|
||||||
map.set(option.id, option.values);
|
options.set(option.id, option);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.log(map);
|
return Array.from(options, ([id, option]) => ({
|
||||||
|
id,
|
||||||
|
name: option.name,
|
||||||
|
values: option.values.map((value) => value.label)
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const reshapeVariants = (variants: Product['variants']): ProductVariant[] => {
|
||||||
|
return variants.map((variant) => ({
|
||||||
|
id: variant.id!,
|
||||||
|
title: `${variant.price.amount} ${variant.price.currencyCode}`,
|
||||||
|
availableForSale: true,
|
||||||
|
selectedOptions: (variant.selectedOptions ?? []).map((selectedOption) => {
|
||||||
|
const option = selectedOption.option as Option;
|
||||||
|
return {
|
||||||
|
name: option.name,
|
||||||
|
value: option.values.find(({ value }) => value === selectedOption.value)?.label!
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
price: reshapePrice(variant.price)
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const reshapeTags = (tags: Tag[]): string[] => {
|
||||||
|
return tags.map((tag) => tag.name);
|
||||||
|
};
|
||||||
|
|
||||||
|
const reshapeProduct = (product: Product): ExProduct => {
|
||||||
return {
|
return {
|
||||||
id: product.id,
|
id: product.id,
|
||||||
handle: product.id,
|
handle: product.id,
|
||||||
@ -318,20 +295,20 @@ const reshapeP = (product: Product): ExProduct => {
|
|||||||
title: product.title,
|
title: product.title,
|
||||||
description: product.description,
|
description: product.description,
|
||||||
descriptionHtml: product.description,
|
descriptionHtml: product.description,
|
||||||
options,
|
options: reshapeOptions(product.variants),
|
||||||
priceRange: {
|
priceRange: {
|
||||||
maxVariantPrice: reshapePrice(product.variants[0]?.price!),
|
maxVariantPrice: reshapePrice(product.variants[0]?.price!),
|
||||||
minVariantPrice: reshapePrice(product.variants[0]?.price!)
|
minVariantPrice: reshapePrice(product.variants[0]?.price!)
|
||||||
},
|
},
|
||||||
featuredImage: {} as any,
|
featuredImage: reshapeImage(product.media as Media),
|
||||||
images: [],
|
images: [],
|
||||||
seo: {
|
seo: {
|
||||||
title: product.title,
|
title: product.title,
|
||||||
description: product.description
|
description: product.description
|
||||||
},
|
},
|
||||||
// tags: product.tags ?? [],
|
tags: reshapeTags(product.tags as Tag[]),
|
||||||
updatedAt: product.updatedAt,
|
variants: reshapeVariants(product.variants),
|
||||||
createdAt: product.createdAt
|
updatedAt: product.updatedAt
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -344,19 +321,8 @@ export async function getCollectionProducts({
|
|||||||
reverse?: boolean;
|
reverse?: boolean;
|
||||||
sortKey?: string;
|
sortKey?: string;
|
||||||
}): Promise<ExProduct[]> {
|
}): Promise<ExProduct[]> {
|
||||||
const m = await find<Product>('products', {
|
const products = await find<Product>('products', {});
|
||||||
where: {
|
return products.docs.map(reshapeProduct);
|
||||||
title: {
|
|
||||||
equals: 'test'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const products: ExProduct[] = m.docs.map(reshapeP);
|
|
||||||
|
|
||||||
console.log(products);
|
|
||||||
|
|
||||||
return products;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getCollections(): Promise<Collection[]> {
|
export async function getCollections(): Promise<Collection[]> {
|
||||||
@ -425,27 +391,12 @@ export async function getPages(): Promise<Page[]> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getProduct(handle: string): Promise<ExProduct | undefined> {
|
export async function getProduct(handle: string): Promise<ExProduct | undefined> {
|
||||||
const res = await shopifyFetch<ShopifyProductOperation>({
|
const product = await findByID<Product>('products', handle);
|
||||||
query: getProductQuery,
|
return reshapeProduct(product);
|
||||||
tags: [TAGS.products],
|
|
||||||
variables: {
|
|
||||||
handle
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return reshapeProduct(res.body.data.product, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getProductRecommendations(productId: string): Promise<ExProduct[]> {
|
export async function getProductRecommendations(productId: string): Promise<ExProduct[]> {
|
||||||
const res = await shopifyFetch<ShopifyProductRecommendationsOperation>({
|
return [];
|
||||||
query: getProductRecommendationsQuery,
|
|
||||||
tags: [TAGS.products],
|
|
||||||
variables: {
|
|
||||||
productId
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return reshapeProducts(res.body.data.productRecommendations);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getProducts({
|
export async function getProducts({
|
||||||
@ -457,17 +408,8 @@ export async function getProducts({
|
|||||||
reverse?: boolean;
|
reverse?: boolean;
|
||||||
sortKey?: string;
|
sortKey?: string;
|
||||||
}): Promise<ExProduct[]> {
|
}): Promise<ExProduct[]> {
|
||||||
const res = await shopifyFetch<ShopifyProductsOperation>({
|
const products = await find<Product>('products', {});
|
||||||
query: getProductsQuery,
|
return products.docs.map(reshapeProduct);
|
||||||
tags: [TAGS.products],
|
|
||||||
variables: {
|
|
||||||
query,
|
|
||||||
reverse,
|
|
||||||
sortKey
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return reshapeProducts(removeEdgesAndNodes(res.body.data.products));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called from `app/api/revalidate.ts` so providers can control revalidation logic.
|
// This is called from `app/api/revalidate.ts` so providers can control revalidation logic.
|
||||||
|
@ -59,3 +59,8 @@ export const find = <T>(collection: string, params: FindParams) => {
|
|||||||
const url = `${process.env.CMS_URL}/api/${collection}${query}`;
|
const url = `${process.env.CMS_URL}/api/${collection}${query}`;
|
||||||
return ajax<PaginatedDocs<T>>('GET', url);
|
return ajax<PaginatedDocs<T>>('GET', url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const findByID = <T>(collection: string, id: string) => {
|
||||||
|
const url = `${process.env.CMS_URL}/api/${collection}/${id}`;
|
||||||
|
return ajax<T>('GET', url);
|
||||||
|
};
|
||||||
|
@ -36,8 +36,8 @@ export type Collection = ShopifyCollection & {
|
|||||||
export type Image = {
|
export type Image = {
|
||||||
url: string;
|
url: string;
|
||||||
altText: string;
|
altText: string;
|
||||||
width?: number;
|
width?: number | null;
|
||||||
height?: number;
|
height?: number | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Menu = {
|
export type Menu = {
|
||||||
|
@ -5,12 +5,10 @@ module.exports = {
|
|||||||
ignoreDuringBuilds: true
|
ignoreDuringBuilds: true
|
||||||
},
|
},
|
||||||
images: {
|
images: {
|
||||||
formats: ['image/avif', 'image/webp'],
|
|
||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
protocol: 'https',
|
protocol: 'http',
|
||||||
hostname: 'cdn.shopify.com',
|
hostname: 'localhost'
|
||||||
pathname: '/s/files/**'
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user