mirror of
https://github.com/vercel/commerce.git
synced 2025-05-09 19:27:53 +00:00
fix(refactor): refactor code for isolation
This commit is contained in:
parent
dfa42c2552
commit
4ffb965688
@ -3,78 +3,34 @@ import OpenCart from 'components/cart/open-cart';
|
|||||||
import { GridTileImage } from 'components/grid/tile';
|
import { GridTileImage } from 'components/grid/tile';
|
||||||
import { Gallery } from 'components/product/gallery';
|
import { Gallery } from 'components/product/gallery';
|
||||||
import { ProductDescription } from 'components/product/product-description';
|
import { ProductDescription } from 'components/product/product-description';
|
||||||
import { getProductById, getProductRecommendations } from 'lib/shopify';
|
import { getContentLandingPageConfig } from 'lib/aspire';
|
||||||
import { ContentLandingPages, Image, Store } from 'lib/shopify/types';
|
import { Store } from 'lib/aspire/types';
|
||||||
|
import { getProductRecommendations } from 'lib/shopify';
|
||||||
|
import { Image } from 'lib/shopify/types';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
|
|
||||||
const lookupContentLandingPage = async (contentLandingPageId: string) => {
|
|
||||||
const contentLandingPages: ContentLandingPages = {
|
|
||||||
ABC: {
|
|
||||||
contentLandingPageId: 'ABC',
|
|
||||||
content: {
|
|
||||||
contentId: 'ABC-123',
|
|
||||||
contentUrl: 'https://vercel.com'
|
|
||||||
},
|
|
||||||
brand: {
|
|
||||||
brandId: '123456789',
|
|
||||||
companyName: 'Vercel'
|
|
||||||
},
|
|
||||||
store: {
|
|
||||||
domain: 'https://test-app-furie.myshopify.com',
|
|
||||||
key: '30f0c9b2ee5c69d6c0de2e7a048eb6b4'
|
|
||||||
},
|
|
||||||
productId: 'gid://shopify/Product/8587441176812'
|
|
||||||
},
|
|
||||||
'123': {
|
|
||||||
contentLandingPageId: '123',
|
|
||||||
content: {
|
|
||||||
contentId: '123-ABC',
|
|
||||||
contentUrl: 'https://vercel.com'
|
|
||||||
},
|
|
||||||
brand: {
|
|
||||||
brandId: '123456789',
|
|
||||||
companyName: 'Vercel'
|
|
||||||
},
|
|
||||||
store: {
|
|
||||||
domain: 'https://quickstart-ba952e54.myshopify.com',
|
|
||||||
key: '8efbd119747c632000b04ed68313abf1'
|
|
||||||
},
|
|
||||||
productId: 'gid://shopify/Product/7913032548543'
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const contentLandingPage = contentLandingPages[contentLandingPageId];
|
|
||||||
|
|
||||||
if (!contentLandingPage) {
|
|
||||||
throw new Error('Content Landing Page not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
const product = await getProductById(contentLandingPage.store, contentLandingPage?.productId);
|
|
||||||
return { ...contentLandingPage, product };
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function Page({ params }: { params: { ContentLandingPage: string } }) {
|
export default async function Page({ params }: { params: { ContentLandingPage: string } }) {
|
||||||
const instance = await lookupContentLandingPage(params.ContentLandingPage);
|
const config = await getContentLandingPageConfig(params.ContentLandingPage);
|
||||||
|
|
||||||
if (!instance.product) {
|
if (!config.product) {
|
||||||
return <div>Product not found</div>;
|
return <div>Product not found</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const productJsonLd = {
|
const productJsonLd = {
|
||||||
'@context': 'https://schema.org',
|
'@context': 'https://schema.org',
|
||||||
'@type': 'Product',
|
'@type': 'Product',
|
||||||
name: instance.product.title,
|
name: config.product.title,
|
||||||
description: instance.product.description,
|
description: config.product.description,
|
||||||
image: instance.product.featuredImage.url,
|
image: config.product.featuredImage.url,
|
||||||
offers: {
|
offers: {
|
||||||
'@type': 'AggregateOffer',
|
'@type': 'AggregateOffer',
|
||||||
availability: instance.product.availableForSale
|
availability: config.product.availableForSale
|
||||||
? 'https://schema.org/InStock'
|
? 'https://schema.org/InStock'
|
||||||
: 'https://schema.org/OutOfStock',
|
: 'https://schema.org/OutOfStock',
|
||||||
priceCurrency: instance.product.priceRange.minVariantPrice.currencyCode,
|
priceCurrency: config.product.priceRange.minVariantPrice.currencyCode,
|
||||||
highPrice: instance.product.priceRange.maxVariantPrice.amount,
|
highPrice: config.product.priceRange.maxVariantPrice.amount,
|
||||||
lowPrice: instance.product.priceRange.minVariantPrice.amount
|
lowPrice: config.product.priceRange.minVariantPrice.amount
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -93,7 +49,7 @@ export default async function Page({ params }: { params: { ContentLandingPage: s
|
|||||||
<div className="flex w-full items-center">
|
<div className="flex w-full items-center">
|
||||||
<div className="flex justify-end md:w-1/3">
|
<div className="flex justify-end md:w-1/3">
|
||||||
<Suspense fallback={<OpenCart />}>
|
<Suspense fallback={<OpenCart />}>
|
||||||
<Cart store={instance.store} />
|
<Cart store={config.store} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -107,7 +63,7 @@ export default async function Page({ params }: { params: { ContentLandingPage: s
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Gallery
|
<Gallery
|
||||||
images={instance.product.images.map((image: Image) => ({
|
images={config.product.images.map((image: Image) => ({
|
||||||
src: image.url,
|
src: image.url,
|
||||||
altText: image.altText
|
altText: image.altText
|
||||||
}))}
|
}))}
|
||||||
@ -116,10 +72,10 @@ export default async function Page({ params }: { params: { ContentLandingPage: s
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="basis-full lg:basis-2/6">
|
<div className="basis-full lg:basis-2/6">
|
||||||
<ProductDescription product={instance.product} store={instance.store} />
|
<ProductDescription product={config.product} store={config.store} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<RelatedProducts id={instance.product.id} store={instance.store} />
|
<RelatedProducts id={config.product.id} store={config.store} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import { Store } from 'lib/aspire/types';
|
||||||
import { getCollectionProducts } from 'lib/shopify';
|
import { getCollectionProducts } from 'lib/shopify';
|
||||||
import { Store } from 'lib/shopify/types';
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { GridTileImage } from './grid/tile';
|
import { GridTileImage } from './grid/tile';
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
'use server';
|
'use server';
|
||||||
|
|
||||||
|
import { Store } from 'lib/aspire/types';
|
||||||
import { TAGS } from 'lib/constants';
|
import { TAGS } from 'lib/constants';
|
||||||
import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/shopify';
|
import { addToCart, createCart, getCart, removeFromCart, updateCart } from 'lib/shopify';
|
||||||
import { Store } from 'lib/shopify/types';
|
|
||||||
import { revalidateTag } from 'next/cache';
|
import { revalidateTag } from 'next/cache';
|
||||||
import { cookies } from 'next/headers';
|
import { cookies } from 'next/headers';
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ import { PlusIcon } from '@heroicons/react/24/outline';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { addItem } from 'components/cart/actions';
|
import { addItem } from 'components/cart/actions';
|
||||||
import LoadingDots from 'components/loading-dots';
|
import LoadingDots from 'components/loading-dots';
|
||||||
import { ProductVariant, Store } from 'lib/shopify/types';
|
import { Store } from 'lib/aspire/types';
|
||||||
|
import { ProductVariant } from 'lib/shopify/types';
|
||||||
import { useSearchParams } from 'next/navigation';
|
import { useSearchParams } from 'next/navigation';
|
||||||
import { useFormState, useFormStatus } from 'react-dom';
|
import { useFormState, useFormStatus } from 'react-dom';
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ import { XMarkIcon } from '@heroicons/react/24/outline';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { removeItem } from 'components/cart/actions';
|
import { removeItem } from 'components/cart/actions';
|
||||||
import LoadingDots from 'components/loading-dots';
|
import LoadingDots from 'components/loading-dots';
|
||||||
import type { CartItem, Store } from 'lib/shopify/types';
|
import { Store } from 'lib/aspire/types';
|
||||||
|
import type { CartItem } from 'lib/shopify/types';
|
||||||
import { useFormState, useFormStatus } from 'react-dom';
|
import { useFormState, useFormStatus } from 'react-dom';
|
||||||
|
|
||||||
function SubmitButton() {
|
function SubmitButton() {
|
||||||
|
@ -4,7 +4,8 @@ import { MinusIcon, PlusIcon } from '@heroicons/react/24/outline';
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { updateItemQuantity } from 'components/cart/actions';
|
import { updateItemQuantity } from 'components/cart/actions';
|
||||||
import LoadingDots from 'components/loading-dots';
|
import LoadingDots from 'components/loading-dots';
|
||||||
import type { CartItem, Store } from 'lib/shopify/types';
|
import { Store } from 'lib/aspire/types';
|
||||||
|
import type { CartItem } from 'lib/shopify/types';
|
||||||
import { useFormState, useFormStatus } from 'react-dom';
|
import { useFormState, useFormStatus } from 'react-dom';
|
||||||
|
|
||||||
function SubmitButton({ type }: { type: 'plus' | 'minus' }) {
|
function SubmitButton({ type }: { type: 'plus' | 'minus' }) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
|
import { Store } from 'lib/aspire/types';
|
||||||
import { getCart } from 'lib/shopify';
|
import { getCart } from 'lib/shopify';
|
||||||
import { Store } from 'lib/shopify/types';
|
|
||||||
import { cookies } from 'next/headers';
|
import { cookies } from 'next/headers';
|
||||||
import CartModal from './modal';
|
import CartModal from './modal';
|
||||||
|
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
import { Dialog, Transition } from '@headlessui/react';
|
import { Dialog, Transition } from '@headlessui/react';
|
||||||
import { ShoppingCartIcon } from '@heroicons/react/24/outline';
|
import { ShoppingCartIcon } from '@heroicons/react/24/outline';
|
||||||
import Price from 'components/price';
|
import Price from 'components/price';
|
||||||
|
import { Store } from 'lib/aspire/types';
|
||||||
import { DEFAULT_OPTION } from 'lib/constants';
|
import { DEFAULT_OPTION } from 'lib/constants';
|
||||||
import type { Cart, Store } from 'lib/shopify/types';
|
import type { Cart } from 'lib/shopify/types';
|
||||||
import { createUrl } from 'lib/utils';
|
import { createUrl } from 'lib/utils';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { GridTileImage } from 'components/grid/tile';
|
import { GridTileImage } from 'components/grid/tile';
|
||||||
|
import { Store } from 'lib/aspire/types';
|
||||||
import { getCollectionProducts } from 'lib/shopify';
|
import { getCollectionProducts } from 'lib/shopify';
|
||||||
import type { Product, Store } from 'lib/shopify/types';
|
import type { Product } from 'lib/shopify/types';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
|
||||||
function ThreeItemGridItem({
|
function ThreeItemGridItem({
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { Suspense } from 'react';
|
import { Store } from 'lib/aspire/types';
|
||||||
|
|
||||||
import { getCollections } from 'lib/shopify';
|
import { getCollections } from 'lib/shopify';
|
||||||
import { Store } from 'lib/shopify/types';
|
import { Suspense } from 'react';
|
||||||
import FilterList from './filter';
|
import FilterList from './filter';
|
||||||
|
|
||||||
async function CollectionList({ store }: { store: Store }) {
|
async function CollectionList({ store }: { store: Store }) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { AddToCart } from 'components/cart/add-to-cart';
|
import { AddToCart } from 'components/cart/add-to-cart';
|
||||||
import Price from 'components/price';
|
import Price from 'components/price';
|
||||||
import Prose from 'components/prose';
|
import Prose from 'components/prose';
|
||||||
import { Product, Store } from 'lib/shopify/types';
|
import { Store } from 'lib/aspire/types';
|
||||||
|
import { Product } from 'lib/shopify/types';
|
||||||
import { Suspense } from 'react';
|
import { Suspense } from 'react';
|
||||||
import { VariantSelector } from './variant-selector';
|
import { VariantSelector } from './variant-selector';
|
||||||
|
|
||||||
|
53
lib/aspire/index.ts
Normal file
53
lib/aspire/index.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { getProductById } from 'lib/shopify';
|
||||||
|
import { ContentLandingPages } from './types';
|
||||||
|
|
||||||
|
export async function getContentLandingPageConfig(contentLandingPageId: string) {
|
||||||
|
const contentLandingPages: ContentLandingPages = {
|
||||||
|
ABC: {
|
||||||
|
contentLandingPageId: '01J39NYS5HKXE9J4R0BMDKH845',
|
||||||
|
slug: 'ABC',
|
||||||
|
content: {
|
||||||
|
contentId: '01J39NY002BQ5FDH6BFJR78V8E',
|
||||||
|
contentUrl: 'https://vercel.com'
|
||||||
|
},
|
||||||
|
brand: {
|
||||||
|
brandId: '01J39NXQGAKT82JQWEYXP9MFE3',
|
||||||
|
companyName: 'Vercel'
|
||||||
|
},
|
||||||
|
store: {
|
||||||
|
storeId: '01J39NYCJY8ZW27ES9BB7KEVXN',
|
||||||
|
domain: 'https://test-app-furie.myshopify.com',
|
||||||
|
key: '30f0c9b2ee5c69d6c0de2e7a048eb6b4'
|
||||||
|
},
|
||||||
|
productId: 'gid://shopify/Product/8587441176812'
|
||||||
|
},
|
||||||
|
'123': {
|
||||||
|
contentLandingPageId: '123',
|
||||||
|
slug: '123',
|
||||||
|
content: {
|
||||||
|
contentId: '01J39P1K9DY9XM2B5Y9T5RVJNP',
|
||||||
|
contentUrl: 'https://vercel.com'
|
||||||
|
},
|
||||||
|
brand: {
|
||||||
|
brandId: '123456789',
|
||||||
|
companyName: 'Vercel'
|
||||||
|
},
|
||||||
|
store: {
|
||||||
|
storeId: 'quickstart-ba952e54',
|
||||||
|
domain: 'https://quickstart-ba952e54.myshopify.com',
|
||||||
|
key: '8efbd119747c632000b04ed68313abf1'
|
||||||
|
},
|
||||||
|
productId: 'gid://shopify/Product/7913032548543'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const contentLandingPage = contentLandingPages[contentLandingPageId];
|
||||||
|
|
||||||
|
if (!contentLandingPage) {
|
||||||
|
throw new Error('Content Landing Page not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const product = await getProductById(contentLandingPage.store, contentLandingPage?.productId);
|
||||||
|
|
||||||
|
return { ...contentLandingPage, product };
|
||||||
|
}
|
28
lib/aspire/types.ts
Normal file
28
lib/aspire/types.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
export type Brand = {
|
||||||
|
brandId: string;
|
||||||
|
companyName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Content = {
|
||||||
|
contentId: string;
|
||||||
|
contentUrl: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ContentLandingPage = {
|
||||||
|
contentLandingPageId: string;
|
||||||
|
slug: string;
|
||||||
|
content: Content;
|
||||||
|
brand: Brand;
|
||||||
|
store: Store;
|
||||||
|
productId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ContentLandingPages = {
|
||||||
|
[key: string]: ContentLandingPage;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Store = {
|
||||||
|
storeId: string;
|
||||||
|
domain: string;
|
||||||
|
key: string;
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Store } from 'lib/aspire/types';
|
||||||
import { HIDDEN_PRODUCT_TAG, SHOPIFY_GRAPHQL_API_ENDPOINT, TAGS } from 'lib/constants';
|
import { HIDDEN_PRODUCT_TAG, SHOPIFY_GRAPHQL_API_ENDPOINT, TAGS } from 'lib/constants';
|
||||||
import { isShopifyError } from 'lib/type-guards';
|
import { isShopifyError } from 'lib/type-guards';
|
||||||
import { revalidateTag } from 'next/cache';
|
import { revalidateTag } from 'next/cache';
|
||||||
@ -47,8 +48,7 @@ import {
|
|||||||
ShopifyProductRecommendationsOperation,
|
ShopifyProductRecommendationsOperation,
|
||||||
ShopifyProductsOperation,
|
ShopifyProductsOperation,
|
||||||
ShopifyRemoveFromCartOperation,
|
ShopifyRemoveFromCartOperation,
|
||||||
ShopifyUpdateCartOperation,
|
ShopifyUpdateCartOperation
|
||||||
Store
|
|
||||||
} from './types';
|
} from './types';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,33 +8,6 @@ export type Edge<T> = {
|
|||||||
node: T;
|
node: T;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Brand = {
|
|
||||||
brandId: string;
|
|
||||||
companyName: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Content = {
|
|
||||||
contentId: string;
|
|
||||||
contentUrl: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ContentLandingPage = {
|
|
||||||
contentLandingPageId: string;
|
|
||||||
content: Content;
|
|
||||||
brand: Brand;
|
|
||||||
store: Store;
|
|
||||||
productId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ContentLandingPages = {
|
|
||||||
[key: string]: ContentLandingPage;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Store = {
|
|
||||||
domain: string;
|
|
||||||
key: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Cart = Omit<ShopifyCart, 'lines'> & {
|
export type Cart = Omit<ShopifyCart, 'lines'> & {
|
||||||
lines: CartItem[];
|
lines: CartItem[];
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user