diff --git a/.env.example b/.env.example index 088014635..f11b18968 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,10 @@ -TWITTER_CREATOR="@vercel" +TWITTER_CREATOR="@BigCommerce" TWITTER_SITE="https://nextjs.org/commerce" -SITE_NAME="Next.js Commerce" -SHOPIFY_STOREFRONT_ACCESS_TOKEN= -SHOPIFY_STORE_DOMAIN= +SITE_NAME="Next.js Commerce by BigCommerce" +BIGCOMMERCE_ACCESS_TOKEN= +BIGCOMMERCE_CHANNEL_ID= +BIGCOMMERCE_STORE_HASH= +# Optional +BIGCOMMERCE_CANONICAL_STORE_DOMAIN="mybigcommerce.com" +BIGCOMMERCE_API_URL="https://api.bigcommerce.com" +BIGCOMMERCE_CDN_HOSTNAME="*.bigcommerce.com" diff --git a/app/[page]/page.tsx b/app/[page]/page.tsx index 7e0defed3..6132c07e0 100644 --- a/app/[page]/page.tsx +++ b/app/[page]/page.tsx @@ -1,7 +1,7 @@ import type { Metadata } from 'next'; import Prose from 'components/prose'; -import { getPage } from 'lib/shopify'; +import { getPage } from 'lib/bigcommerce'; import { notFound } from 'next/navigation'; export const runtime = 'edge'; diff --git a/app/api/cart/route.ts b/app/api/cart/route.ts index 15f5fb09f..ba5ef9049 100644 --- a/app/api/cart/route.ts +++ b/app/api/cart/route.ts @@ -1,8 +1,8 @@ import { cookies } from 'next/headers'; import { NextRequest, NextResponse } from 'next/server'; -import { addToCart, removeFromCart, updateCart } from 'lib/shopify'; -import { isShopifyError } from 'lib/type-guards'; +import { addToCart, removeFromCart, updateCart } from 'lib/bigcommerce'; +import { isVercelCommerceError } from 'lib/type-guards'; function formatErrorMessage(err: Error): string { return JSON.stringify(err, Object.getOwnPropertyNames(err)); @@ -10,16 +10,18 @@ function formatErrorMessage(err: Error): string { export async function POST(req: NextRequest): Promise { const cartId = cookies().get('cartId')?.value; - const { merchandiseId } = await req.json(); + const { merchandiseId, isBigCommerceAPI } = await req.json(); - if (!cartId?.length || !merchandiseId?.length) { + if ((!isBigCommerceAPI && !cartId?.length) || !merchandiseId?.length) { return NextResponse.json({ error: 'Missing cartId or variantId' }, { status: 400 }); + } else if (isBigCommerceAPI && !merchandiseId?.length) { + return NextResponse.json({ error: 'Missing variantId' }, { status: 400 }); } try { - await addToCart(cartId, [{ merchandiseId, quantity: 1 }]); + await addToCart(cartId || '', [{ merchandiseId, quantity: 1 }]); return NextResponse.json({ status: 204 }); } catch (e) { - if (isShopifyError(e)) { + if (isVercelCommerceError(e)) { return NextResponse.json({ message: formatErrorMessage(e.message) }, { status: e.status }); } @@ -47,7 +49,7 @@ export async function PUT(req: NextRequest): Promise { ]); return NextResponse.json({ status: 204 }); } catch (e) { - if (isShopifyError(e)) { + if (isVercelCommerceError(e)) { return NextResponse.json({ message: formatErrorMessage(e.message) }, { status: e.status }); } @@ -66,7 +68,7 @@ export async function DELETE(req: NextRequest): Promise { await removeFromCart(cartId, [lineId]); return NextResponse.json({ status: 204 }); } catch (e) { - if (isShopifyError(e)) { + if (isVercelCommerceError(e)) { return NextResponse.json({ message: formatErrorMessage(e.message) }, { status: e.status }); } diff --git a/app/page.tsx b/app/page.tsx index a928be52e..a56591cd3 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -6,7 +6,7 @@ import { Suspense } from 'react'; export const runtime = 'edge'; 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, and BigCommerce.', openGraph: { images: [ { diff --git a/app/product/[handle]/page.tsx b/app/product/[handle]/page.tsx index 612cd0236..a90c96ab3 100644 --- a/app/product/[handle]/page.tsx +++ b/app/product/[handle]/page.tsx @@ -10,8 +10,8 @@ import { Gallery } from 'components/product/gallery'; import { VariantSelector } from 'components/product/variant-selector'; import Prose from 'components/prose'; import { HIDDEN_PRODUCT_TAG } from 'lib/constants'; -import { getProduct, getProductRecommendations } from 'lib/shopify'; -import { Image } from 'lib/shopify/types'; +import { getProduct, getProductRecommendations } from 'lib/bigcommerce'; +import { Image } from 'lib/bigcommerce/types'; export const runtime = 'edge'; diff --git a/app/search/[collection]/page.tsx b/app/search/[collection]/page.tsx index 873701bf7..5374e5755 100644 --- a/app/search/[collection]/page.tsx +++ b/app/search/[collection]/page.tsx @@ -1,4 +1,4 @@ -import { getCollection, getCollectionProducts } from 'lib/shopify'; +import { getCollection, getCollectionProducts } from 'lib/bigcommerce'; import { Metadata } from 'next'; import { notFound } from 'next/navigation'; diff --git a/app/search/page.tsx b/app/search/page.tsx index 354a2022f..96afda4d7 100644 --- a/app/search/page.tsx +++ b/app/search/page.tsx @@ -1,7 +1,7 @@ import Grid from 'components/grid'; import ProductGridItems from 'components/layout/product-grid-items'; +import { getProducts } from 'lib/bigcommerce'; import { defaultSort, sorting } from 'lib/constants'; -import { getProducts } from 'lib/shopify'; export const runtime = 'edge'; diff --git a/app/sitemap.ts b/app/sitemap.ts index d8cdfd2ea..340cba3ea 100644 --- a/app/sitemap.ts +++ b/app/sitemap.ts @@ -1,4 +1,4 @@ -import { getCollections, getPages, getProducts } from 'lib/shopify'; +import { getCollections, getPages, getProducts } from 'lib/bigcommerce'; import { MetadataRoute } from 'next'; const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL diff --git a/components/carousel.tsx b/components/carousel.tsx index d86d17f45..5cec4d878 100644 --- a/components/carousel.tsx +++ b/components/carousel.tsx @@ -1,4 +1,4 @@ -import { getCollectionProducts } from 'lib/shopify'; +import { getCollectionProducts } from 'lib/bigcommerce'; import Image from 'next/image'; import Link from 'next/link'; diff --git a/components/cart/button.tsx b/components/cart/button.tsx index aed87ee7a..0899abb27 100644 --- a/components/cart/button.tsx +++ b/components/cart/button.tsx @@ -6,7 +6,7 @@ import { useCookies } from 'react-cookie'; import CartIcon from 'components/icons/cart'; import CartModal from './modal'; -import type { Cart } from 'lib/shopify/types'; +import type { VercelCart as Cart } from 'lib/bigcommerce/types'; export default function CartButton({ cart, diff --git a/components/cart/delete-item-button.tsx b/components/cart/delete-item-button.tsx index 789a87754..4fc5197f8 100644 --- a/components/cart/delete-item-button.tsx +++ b/components/cart/delete-item-button.tsx @@ -4,7 +4,7 @@ import { useRouter } from 'next/navigation'; import { startTransition, useState } from 'react'; import clsx from 'clsx'; -import type { CartItem } from 'lib/shopify/types'; +import type { VercelCartItem as CartItem } from 'lib/bigcommerce/types'; export default function DeleteItemButton({ item }: { item: CartItem }) { const router = useRouter(); diff --git a/components/cart/edit-item-quantity-button.tsx b/components/cart/edit-item-quantity-button.tsx index 2249bd1aa..fd1828536 100644 --- a/components/cart/edit-item-quantity-button.tsx +++ b/components/cart/edit-item-quantity-button.tsx @@ -4,7 +4,7 @@ import { startTransition, useState } from 'react'; import clsx from 'clsx'; import MinusIcon from 'components/icons/minus'; import PlusIcon from 'components/icons/plus'; -import type { CartItem } from 'lib/shopify/types'; +import type { VercelCartItem as CartItem } from 'lib/bigcommerce/types'; import LoadingDots from '../loading-dots'; export default function EditItemQuantityButton({ diff --git a/components/cart/index.tsx b/components/cart/index.tsx index 0e3ffcdc1..8d90c4e94 100644 --- a/components/cart/index.tsx +++ b/components/cart/index.tsx @@ -1,4 +1,4 @@ -import { createCart, getCart } from 'lib/shopify'; +import { createCart, getCart } from 'lib/bigcommerce'; import { cookies } from 'next/headers'; import CartButton from './button'; diff --git a/components/cart/modal.tsx b/components/cart/modal.tsx index 4220cfe94..6c4191525 100644 --- a/components/cart/modal.tsx +++ b/components/cart/modal.tsx @@ -7,7 +7,7 @@ import CloseIcon from 'components/icons/close'; import ShoppingBagIcon from 'components/icons/shopping-bag'; import Price from 'components/price'; import { DEFAULT_OPTION } from 'lib/constants'; -import type { Cart } from 'lib/shopify/types'; +import type { VercelCart as Cart } from 'lib/bigcommerce/types'; import { createUrl } from 'lib/utils'; import DeleteItemButton from './delete-item-button'; import EditItemQuantityButton from './edit-item-quantity-button'; diff --git a/components/grid/three-items.tsx b/components/grid/three-items.tsx index 2280de26e..511ea98d7 100644 --- a/components/grid/three-items.tsx +++ b/components/grid/three-items.tsx @@ -1,6 +1,6 @@ import { GridTileImage } from 'components/grid/tile'; -import { getCollectionProducts } from 'lib/shopify'; -import type { Product } from 'lib/shopify/types'; +import { getCollectionProducts } from 'lib/bigcommerce'; +import type { VercelProduct as Product } from 'lib/bigcommerce/types'; import Link from 'next/link'; function ThreeItemGridItem({ diff --git a/components/layout/footer.tsx b/components/layout/footer.tsx index 72e9e03fc..c48eb47c8 100644 --- a/components/layout/footer.tsx +++ b/components/layout/footer.tsx @@ -3,8 +3,8 @@ import Link from 'next/link'; import GitHubIcon from 'components/icons/github'; import LogoIcon from 'components/icons/logo'; import VercelIcon from 'components/icons/vercel'; -import { getMenu } from 'lib/shopify'; -import { Menu } from 'lib/shopify/types'; +import { getMenu } from 'lib/bigcommerce'; +import { VercelMenu as Menu } from 'lib/bigcommerce/types'; const { SITE_NAME } = process.env; diff --git a/components/layout/navbar/index.tsx b/components/layout/navbar/index.tsx index 537c450a1..0757d8bc0 100644 --- a/components/layout/navbar/index.tsx +++ b/components/layout/navbar/index.tsx @@ -4,18 +4,19 @@ import { Suspense } from 'react'; import Cart from 'components/cart'; import CartIcon from 'components/icons/cart'; import LogoIcon from 'components/icons/logo'; -import { getMenu } from 'lib/shopify'; -import { Menu } from 'lib/shopify/types'; +import { getMenu } from 'lib/bigcommerce'; +import { VercelMenu as Menu } from 'lib/bigcommerce/types'; import MobileMenu from './mobile-menu'; import Search from './search'; export default async function Navbar() { const menu = await getMenu('next-js-frontend-header-menu'); + const demoMenu = menu.slice(0, 4); return (