diff --git a/README.md b/README.md
index cd4351911..941b1699b 100644
--- a/README.md
+++ b/README.md
@@ -29,43 +29,10 @@ Next.js Commerce integrates out-of-the-box with BigCommerce and Shopify. We plan
## Considerations
- `framework/commerce` contains all types, helpers and functions to be used as base to build a new **provider**.
-- **Providers** live under `framework`'s root folder and they will extend Next.js Commerce types and functionality.
-- **Features API** is to ensure feature parity between the UI and the Provider. The UI should update accordingly and no extra code should be bundled. All extra configuration for features will live under `features` in `commerce.config.json` and if needed it can also be accessed programatically.
+- **Providers** live under `framework`'s root folder and they will extend Next.js Commerce types and functionality (`framework/commerce`).
+- We have a **Features API** to ensure feature parity between the UI and the Provider. The UI should update accordingly and no extra code should be bundled. All extra configuration for features will live under `features` in `commerce.config.json` and if needed it can also be accessed programatically.
- Each **provider** should add its corresponding `next.config.js` and `commerce.config.json` adding specific data related to the provider. For example in case of BigCommerce, the images CDN and additional API routes.
- **Providers don't depend on anything that's specific to the application they're used in**. They only depend on `framework/commerce`, on their own framework folder and on some dependencies included in `package.json`
-- We recommend that each **provider** ships with an `env.template` file and a `[readme.md](http://readme.md)` file.
-
-## Provider Structure
-
-Next.js Commerce provides a set of utilities and functions to create new providers. This is how a provider structure looks like.
-
-- `product`
- - usePrice
- - useSearch
- - getProduct
- - getAllProducts
-- `wishlist`
- - useWishlist
- - useAddItem
- - useRemoveItem
-- `auth`
- - useLogin
- - useLogout
- - useSignup
-- `customer`
- - useCustomer
- - getCustomerId
- - getCustomerWistlist
-- `cart`
- - useCart
- - useAddItem
- - useRemoveItem
- - useUpdateItem
-- `env.template`
-- `provider.ts`
-- `commerce.config.json`
-- `next.config.js`
-- `README.md`
## Configuration
@@ -95,15 +62,9 @@ Every provider defines the features that it supports under `framework/{provider}
### How to create a new provider
-We'd recommend to duplicate a provider folder and push your providers SDK.
+Follow our docs for [Adding a new Commerce Provider](framework/commerce/new-provider.md).
-If you succeeded building a provider, submit a PR so we can all enjoy it.
-
-## Work in progress
-
-We're using Github Projects to keep track of issues in progress and todo's. Here is our [Board](https://github.com/vercel/commerce/projects/1)
-
-People actively working on this project: @okbel & @lfades.
+If you succeeded building a provider, submit a PR with a valid demo and we'll review it asap.
## Contribute
@@ -113,11 +74,15 @@ Our commitment to Open Source can be found [here](https://vercel.com/oss).
2. Create a new branch `git checkout -b MY_BRANCH_NAME`
3. Install yarn: `npm install -g yarn`
4. Install the dependencies: `yarn`
-5. Duplicate `.env.template` and rename it to `.env.local`.
-6. Add proper store values to `.env.local`.
+5. Duplicate `.env.template` and rename it to `.env.local`
+6. Add proper store values to `.env.local`
7. Run `yarn dev` to build and watch for code changes
-8. The development branch is `canary` (this is the branch pull requests should be made against).
- On a release, `canary` branch is rebased into `master`.
+
+## Work in progress
+
+We're using Github Projects to keep track of issues in progress and todo's. Here is our [Board](https://github.com/vercel/commerce/projects/1)
+
+People actively working on this project: @okbel & @lfades.
## Troubleshoot
diff --git a/framework/bigcommerce/.env.template b/framework/bigcommerce/.env.template
index 43e85c046..2b91bc095 100644
--- a/framework/bigcommerce/.env.template
+++ b/framework/bigcommerce/.env.template
@@ -1,3 +1,5 @@
+COMMERCE_PROVIDER=bigcommerce
+
BIGCOMMERCE_STOREFRONT_API_URL=
BIGCOMMERCE_STOREFRONT_API_TOKEN=
BIGCOMMERCE_STORE_API_URL=
diff --git a/framework/bigcommerce/README.md b/framework/bigcommerce/README.md
index 2609b1544..7f62a5f3f 100644
--- a/framework/bigcommerce/README.md
+++ b/framework/bigcommerce/README.md
@@ -1,45 +1,34 @@
-# Table of Contents
+# Bigcommerce Provider
-- [BigCommerce Storefront Data Hooks](#bigcommerce-storefront-data-hooks)
- - [Installation](#installation)
- - [General Usage](#general-usage)
- - [CommerceProvider](#commerceprovider)
- - [useLogin hook](#uselogin-hook)
- - [useLogout](#uselogout)
- - [useCustomer](#usecustomer)
- - [useSignup](#usesignup)
- - [usePrice](#useprice)
- - [Cart Hooks](#cart-hooks)
- - [useCart](#usecart)
- - [useAddItem](#useadditem)
- - [useUpdateItem](#useupdateitem)
- - [useRemoveItem](#useremoveitem)
- - [Wishlist Hooks](#wishlist-hooks)
- - [Product Hooks and API](#product-hooks-and-api)
- - [useSearch](#usesearch)
- - [getAllProducts](#getallproducts)
- - [getProduct](#getproduct)
- - [More](#more)
+**Demo:** https://bigcommerce.demo.vercel.store/
-# BigCommerce Storefront Data Hooks
+With the deploy button below you'll be able to have a [BigCommerce](https://www.bigcommerce.com/) account and a store that works with this starter:
-> This project is under active development, new features and updates will be continuously added over time
+[](https://vercel.com/new/git/external?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fcommerce&project-name=commerce&repo-name=commerce&demo-title=Next.js%20Commerce&demo-description=An%20all-in-one%20starter%20kit%20for%20high-performance%20e-commerce%20sites.&demo-url=https%3A%2F%2Fdemo.vercel.store&demo-image=https%3A%2F%2Fbigcommerce-demo-asset-ksvtgfvnd.vercel.app%2Fbigcommerce.png&integration-ids=oac_MuWZiE4jtmQ2ejZQaQ7ncuDT)
-UI hooks and data fetching methods built from the ground up for e-commerce applications written in React, that use BigCommerce as a headless e-commerce platform. The package provides:
+If you already have a BigCommerce account and want to use your current store, then copy the `.env.template` file in this directory to `.env.local` in the main directory (which will be ignored by Git):
-- Code splitted hooks for data fetching using [SWR](https://swr.vercel.app/), and to handle common user actions
-- Code splitted data fetching methods for initial data population and static generation of content
-- Helpers to create the API endpoints that connect to the hooks, very well suited for Next.js applications
-
-## Installation
-
-To install:
-
-```
-yarn add storefront-data-hooks
+```bash
+cp framework/bigcommerce/.env.template .env.local
```
-After install, the first thing you do is: set your environment variables in `.env.local`
+Then, set the environment variables in `.env.local` to match the ones from your store.
+
+## Contribute
+
+Our commitment to Open Source can be found [here](https://vercel.com/oss).
+
+If you find an issue with the provider or want a new feature, feel free to open a PR or [create a new issue](https://github.com/vercel/commerce/issues).
+
+## Troubleshoot
+
+
+I already own a BigCommerce store. What should I do?
+
+First thing you do is: set your environment variables
+
+
+.env.local
```sh
BIGCOMMERCE_STOREFRONT_API_URL=<>
@@ -50,331 +39,21 @@ BIGCOMMERCE_STORE_API_CLIENT_ID=<>
BIGCOMMERCE_CHANNEL_ID=<>
```
-## General Usage
+If your project was started with a "Deploy with Vercel" button, you can use Vercel's CLI to retrieve these credentials.
-### CommerceProvider
+1. Install Vercel CLI: `npm i -g vercel`
+2. Link local instance with Vercel and Github accounts (creates .vercel file): `vercel link`
+3. Download your environment variables: `vercel env pull .env.local`
-This component is a provider pattern component that creates commerce context for it's children. It takes config values for the locale and an optional `fetcherRef` object for data fetching.
+Next, you're free to customize the starter. More updates coming soon. Stay tuned.
-```jsx
-...
-import { CommerceProvider } from '@bigcommerce/storefront-data-hooks'
+
-const App = ({ locale = 'en-US', children }) => {
- return (
-
- {children}
-
- )
-}
-...
-```
-
-### useLogin hook
-
-Hook for bigcommerce user login functionality, returns `login` function to handle user login.
-
-```jsx
-...
-import useLogin from '@bigcommerce/storefront-data-hooks/use-login'
-
-const LoginView = () => {
- const login = useLogin()
-
- const handleLogin = async () => {
- await login({
- email,
- password,
- })
- }
-
- return (
-
- )
-}
-```
-
-### useSignup
-
-Hook for bigcommerce user signup, returns `signup` function to handle user signups.
-
-```jsx
-...
-import useSignup from '@bigcommerce/storefront-data-hooks/use-login'
-
-const SignupView = () => {
- const signup = useSignup()
-
- const handleSignup = async () => {
- await signup({
- email,
- firstName,
- lastName,
- password,
- })
- }
-
- return (
-
- )
-}
-...
-```
-
-### usePrice
-
-Helper hook to format price according to commerce locale, and return discount if available.
-
-```jsx
-import usePrice from '@bigcommerce/storefront-data-hooks/use-price'
-...
- const { price, discount, basePrice } = usePrice(
- data && {
- amount: data.cart_amount,
- currencyCode: data.currency.code,
- }
- )
-...
-```
-
-## Cart Hooks
-
-### useCart
-
-Returns the current cart data for use
-
-```jsx
-...
-import useCart from '@bigcommerce/storefront-data-hooks/cart/use-cart'
-
-const countItem = (count: number, item: LineItem) => count + item.quantity
-
-const CartNumber = () => {
- const { data } = useCart()
- const itemsCount = data?.lineItems.reduce(countItem, 0) ?? 0
-
- return itemsCount > 0 ? {itemsCount} : null
-}
-```
-
-### useAddItem
-
-```jsx
-...
-import useAddItem from '@bigcommerce/storefront-data-hooks/cart/use-add-item'
-
-const AddToCartButton = ({ productId, variantId }) => {
- const addItem = useAddItem()
-
- const addToCart = async () => {
- await addItem({
- productId,
- variantId,
- })
- }
-
- return
-}
-...
-```
-
-### useUpdateItem
-
-```jsx
-...
-import useUpdateItem from '@bigcommerce/storefront-data-hooks/cart/use-update-item'
-
-const CartItem = ({ item }) => {
- const [quantity, setQuantity] = useState(item.quantity)
- const updateItem = useUpdateItem(item)
-
- const updateQuantity = async (e) => {
- const val = e.target.value
- await updateItem({ quantity: val })
- }
-
- return (
-
- )
-}
-...
-```
-
-### useRemoveItem
-
-Provided with a cartItemId, will remove an item from the cart:
-
-```jsx
-...
-import useRemoveItem from '@bigcommerce/storefront-data-hooks/cart/use-remove-item'
-
-const RemoveButton = ({ item }) => {
- const removeItem = useRemoveItem()
-
- const handleRemove = async () => {
- await removeItem({ id: item.id })
- }
-
- return
-}
-...
-```
-
-## Wishlist Hooks
-
-Wishlist hooks are similar to cart hooks. See the below example for how to use `useWishlist`, `useAddItem`, and `useRemoveItem`.
-
-```jsx
-import useAddItem from '@bigcommerce/storefront-data-hooks/wishlist/use-add-item'
-import useRemoveItem from '@bigcommerce/storefront-data-hooks/wishlist/use-remove-item'
-import useWishlist from '@bigcommerce/storefront-data-hooks/wishlist/use-wishlist'
-
-const WishlistButton = ({ productId, variant }) => {
- const addItem = useAddItem()
- const removeItem = useRemoveItem()
- const { data } = useWishlist()
- const { data: customer } = useCustomer()
- const itemInWishlist = data?.items?.find(
- (item) =>
- item.product_id === productId &&
- item.variant_id === variant?.node.entityId
- )
-
- const handleWishlistChange = async (e) => {
- e.preventDefault()
-
- if (!customer) {
- return
- }
-
- if (itemInWishlist) {
- await removeItem({ id: itemInWishlist.id! })
- } else {
- await addItem({
- productId,
- variantId: variant?.node.entityId!,
- })
- }
- }
-
- return (
-
- )
-}
-```
-
-## Product Hooks and API
-
-### useSearch
-
-`useSearch` handles searching the bigcommerce storefront product catalog by catalog, brand, and query string.
-
-```jsx
-...
-import useSearch from '@bigcommerce/storefront-data-hooks/products/use-search'
-
-const SearchPage = ({ searchString, category, brand, sortStr }) => {
- const { data } = useSearch({
- search: searchString || '',
- categoryId: category?.entityId,
- brandId: brand?.entityId,
- sort: sortStr || '',
- })
-
- return (
-
- {data.products.map(({ node }) => (
-
- ))}
-
- )
-}
-```
-
-### getAllProducts
-
-API function to retrieve a product list.
-
-```js
-import { getConfig } from '@bigcommerce/storefront-data-hooks/api'
-import getAllProducts from '@bigcommerce/storefront-data-hooks/api/operations/get-all-products'
-
-const { products } = await getAllProducts({
- variables: { field: 'featuredProducts', first: 6 },
- config,
- preview,
-})
-```
-
-### getProduct
-
-API product to retrieve a single product when provided with the product
-slug string.
-
-```js
-import { getConfig } from '@bigcommerce/storefront-data-hooks/api'
-import getProduct from '@bigcommerce/storefront-data-hooks/api/operations/get-product'
-
-const { product } = await getProduct({
- variables: { slug },
- config,
- preview,
-})
-```
-
-## More
-
-Feel free to read through the source for more usage, and check the commerce vercel demo and commerce repo for usage examples: ([demo.vercel.store](https://demo.vercel.store/)) ([repo](https://github.com/vercel/commerce))
+
+BigCommerce shows a Coming Soon page and requests a Preview Code
+
+After Email confirmation, Checkout should be manually enabled through BigCommerce platform. Look for "Review & test your store" section through BigCommerce's dashboard.
+
+
+BigCommerce team has been notified and they plan to add more detailed about this subject.
+
diff --git a/framework/commerce/README.md b/framework/commerce/README.md
new file mode 100644
index 000000000..ecdebb8c0
--- /dev/null
+++ b/framework/commerce/README.md
@@ -0,0 +1,334 @@
+# Commerce Framework
+
+- [Commerce Framework](#commerce-framework)
+ - [Commerce Hooks](#commerce-hooks)
+ - [CommerceProvider](#commerceprovider)
+ - [Authentication Hooks](#authentication-hooks)
+ - [useSignup](#usesignup)
+ - [useLogin](#uselogin)
+ - [useLogout](#uselogout)
+ - [Customer Hooks](#customer-hooks)
+ - [useCustomer](#usecustomer)
+ - [Product Hooks](#product-hooks)
+ - [usePrice](#useprice)
+ - [useSearch](#usesearch)
+ - [Cart Hooks](#cart-hooks)
+ - [useCart](#usecart)
+ - [useAddItem](#useadditem)
+ - [useUpdateItem](#useupdateitem)
+ - [useRemoveItem](#useremoveitem)
+ - [Wishlist Hooks](#wishlist-hooks)
+ - [Commerce API](#commerce-api)
+ - [More](#more)
+
+The commerce framework ships multiple hooks and a Node.js API, both using an underlying headless e-commerce platform, which we call commerce providers.
+
+The core features are:
+
+- Code splitted hooks for data fetching using [SWR](https://swr.vercel.app/), and to handle common user actions
+- A Node.js API for initial data population, static generation of content and for creating the API endpoints that connect to the hooks, if required.
+
+> 👩🔬 If you would like to contribute a new provider, check the docs for [Adding a new Commerce Provider](./new-provider.md).
+
+> 🚧 The core commerce framework is under active development, new features and updates will be continuously added over time. Breaking changes are expected while we finish the API.
+
+## Commerce Hooks
+
+A commerce hook is a [React hook](https://reactjs.org/docs/hooks-intro.html) that's connected to a commerce provider. They focus on user actions and data fetching of data that wasn't statically generated.
+
+Data fetching hooks use [SWR](https://swr.vercel.app/) underneath and you're welcome to use any of its [return values](https://swr.vercel.app/docs/options#return-values) and [options](https://swr.vercel.app/docs/options#options). For example, using the `useCustomer` hook:
+
+```jsx
+const { data, isLoading, error } = useCustomer({
+ swrOptions: {
+ revalidateOnFocus: true,
+ },
+})
+```
+
+### CommerceProvider
+
+This component adds the provider config and handlers to the context of your React tree for it's children. You can optionally pass the `locale` to it:
+
+```jsx
+import { CommerceProvider } from '@framework'
+
+const App = ({ locale = 'en-US', children }) => {
+ return {children}
+}
+```
+
+## Authentication Hooks
+
+### useSignup
+
+Returns a _signup_ function that can be used to sign up the current visitor:
+
+```jsx
+import useSignup from '@framework/auth/use-signup'
+
+const SignupView = () => {
+ const signup = useSignup()
+
+ const handleSignup = async () => {
+ await signup({
+ email,
+ firstName,
+ lastName,
+ password,
+ })
+ }
+
+ return
+}
+```
+
+### useLogin
+
+Returns a _login_ function that can be used to sign in the current visitor into an existing customer:
+
+```jsx
+import useLogin from '@framework/auth/use-login'
+
+const LoginView = () => {
+ const login = useLogin()
+ const handleLogin = async () => {
+ await login({
+ email,
+ password,
+ })
+ }
+
+ return
+}
+```
+
+### useLogout
+
+Returns a _logout_ function that signs out the current customer when called.
+
+```jsx
+import useLogout from '@framework/auth/use-logout'
+
+const LogoutButton = () => {
+ const logout = useLogout()
+ return (
+
+ )
+}
+```
+
+## Customer Hooks
+
+### useCustomer
+
+Fetches and returns the data of the signed in customer:
+
+```jsx
+import useCustomer from '@framework/customer/use-customer'
+
+const Profile = () => {
+ const { data, isLoading, error } = useCustomer()
+
+ if (isLoading) return
Loading...
+ if (error) return
{error.message}
+ if (!data) return null
+
+ return
Hello, {data.firstName}
+}
+```
+
+## Product Hooks
+
+### usePrice
+
+Helper hook to format price according to the commerce locale and currency code. It also handles discounts:
+
+```jsx
+import useCart from '@framework/cart/use-cart'
+import usePrice from '@framework/product/use-price'
+
+// ...
+const { data } = useCart()
+const { price, discount, basePrice } = usePrice(
+ data && {
+ amount: data.subtotalPrice,
+ currencyCode: data.currency.code,
+ // If `baseAmount` is used, a discount will be calculated
+ // baseAmount: number,
+ }
+)
+// ...
+```
+
+### useSearch
+
+Fetches and returns the products that match a set of filters:
+
+```jsx
+import useSearch from '@framework/product/use-search'
+
+const SearchPage = ({ searchString, category, brand, sortStr }) => {
+ const { data } = useSearch({
+ search: searchString || '',
+ categoryId: category?.entityId,
+ brandId: brand?.entityId,
+ sort: sortStr,
+ })
+
+ return (
+
+ {data.products.map((product) => (
+
+ ))}
+
+ )
+}
+```
+
+## Cart Hooks
+
+### useCart
+
+Fetches and returns the data of the current cart:
+
+```jsx
+import useCart from '@framework/cart/use-cart'
+
+const CartTotal = () => {
+ const { data, isLoading, isEmpty, error } = useCart()
+
+ if (isLoading) return
Loading...
+ if (error) return
{error.message}
+ if (isEmpty) return
The cart is empty
+
+ return
The cart total is {data.totalPrice}
+}
+```
+
+### useAddItem
+
+Returns a function that adds a new item to the cart when called, if this is the first item it will create the cart:
+
+```jsx
+import { useAddItem } from '@framework/cart'
+
+const AddToCartButton = ({ productId, variantId }) => {
+ const addItem = useAddItem()
+
+ const addToCart = async () => {
+ await addItem({
+ productId,
+ variantId,
+ })
+ }
+
+ return
+}
+```
+
+### useUpdateItem
+
+Returns a function that updates a current item in the cart when called, usually the quantity.
+
+```jsx
+import { useUpdateItem } from '@framework/cart'
+
+const CartItemQuantity = ({ item }) => {
+ const [quantity, setQuantity] = useState(item.quantity)
+ const updateItem = useUpdateItem({ item })
+
+ const updateQuantity = async (e) => {
+ const val = e.target.value
+
+ setQuantity(val)
+ await updateItem({ quantity: val })
+ }
+
+ return (
+
+ )
+}
+```
+
+If the `quantity` is lower than 1 the item will be removed from the cart.
+
+### useRemoveItem
+
+Returns a function that removes an item in the cart when called:
+
+```jsx
+import { useRemoveItem } from '@framework/cart'
+
+const RemoveButton = ({ item }) => {
+ const removeItem = useRemoveItem()
+ const handleRemove = async () => {
+ await removeItem(item)
+ }
+
+ return
+}
+```
+
+## Wishlist Hooks
+
+Wishlist hooks work just like [cart hooks](#cart-hooks). Feel free to check how those work first.
+
+The example below shows how to use the `useWishlist`, `useAddItem` and `useRemoveItem` hooks:
+
+```jsx
+import { useWishlist, useAddItem, useRemoveItem } from '@framework/wishlist'
+
+const WishlistButton = ({ productId, variant }) => {
+ const addItem = useAddItem()
+ const removeItem = useRemoveItem()
+ const { data, isLoading, isEmpty, error } = useWishlist()
+
+ if (isLoading) return
Loading...
+ if (error) return
{error.message}
+ if (isEmpty) return
The wihslist is empty
+
+ const { data: customer } = useCustomer()
+ const itemInWishlist = data?.items?.find(
+ (item) => item.product_id === productId && item.variant_id === variant.id
+ )
+
+ const handleWishlistChange = async (e) => {
+ e.preventDefault()
+ if (!customer) return
+
+ if (itemInWishlist) {
+ await removeItem({ id: itemInWishlist.id })
+ } else {
+ await addItem({
+ productId,
+ variantId: variant.id,
+ })
+ }
+ }
+
+ return (
+
+ )
+}
+```
+
+## Commerce API
+
+While commerce hooks focus on client side data fetching and interactions, the commerce API focuses on static content generation for pages and API endpoints in a Node.js context.
+
+> The commerce API is currently going through a refactor in https://github.com/vercel/commerce/pull/252 - We'll update the docs once the API is released.
+
+## More
+
+Feel free to read through the source for more usage, and check the commerce vercel demo and commerce repo for usage examples: ([demo.vercel.store](https://demo.vercel.store/)) ([repo](https://github.com/vercel/commerce))
diff --git a/framework/commerce/new-provider.md b/framework/commerce/new-provider.md
new file mode 100644
index 000000000..4051c0f01
--- /dev/null
+++ b/framework/commerce/new-provider.md
@@ -0,0 +1,239 @@
+# Adding a new Commerce Provider
+
+A commerce provider is a headless e-commerce platform that integrates with the [Commerce Framework](./README.md). Right now we have the following providers:
+
+- BigCommerce ([framework/bigcommerce](../bigcommerce))
+- Shopify ([framework/shopify](../shopify))
+
+Adding a commerce provider means adding a new folder in `framework` with a folder structure like the next one:
+
+- `api`
+ - index.ts
+- `product`
+ - usePrice
+ - useSearch
+ - getProduct
+ - getAllProducts
+- `wishlist`
+ - useWishlist
+ - useAddItem
+ - useRemoveItem
+- `auth`
+ - useLogin
+ - useLogout
+ - useSignup
+- `customer`
+ - useCustomer
+ - getCustomerId
+ - getCustomerWistlist
+- `cart`
+ - useCart
+ - useAddItem
+ - useRemoveItem
+ - useUpdateItem
+- `env.template`
+- `index.ts`
+- `provider.ts`
+- `commerce.config.json`
+- `next.config.js`
+- `README.md`
+
+`provider.ts` exports a provider object with handlers for the [Commerce Hooks](./README.md#commerce-hooks) and `api/index.ts` exports a Node.js provider for the [Commerce API](./README.md#commerce-api)
+
+> **Important:** We use TypeScript for every provider and expect its usage for every new one.
+
+The app imports from the provider directly instead of the core commerce folder (`framework/commerce`), but all providers are interchangeable and to achieve it every provider always has to implement the core types and helpers.
+
+The provider folder should only depend on `framework/commerce` and dependencies in the main `package.json`. In the future we'll move the `framework` folder to a package that can be shared easily for multiple apps.
+
+## Adding the provider hooks
+
+Using BigCommerce as an example. The first thing to do is export a `CommerceProvider` component that includes a `provider` object with all the handlers that can be used for hooks:
+
+```tsx
+import type { ReactNode } from 'react'
+import {
+ CommerceConfig,
+ CommerceProvider as CoreCommerceProvider,
+ useCommerce as useCoreCommerce,
+} from '@commerce'
+import { bigcommerceProvider, BigcommerceProvider } from './provider'
+
+export { bigcommerceProvider }
+export type { BigcommerceProvider }
+
+export const bigcommerceConfig: CommerceConfig = {
+ locale: 'en-us',
+ cartCookie: 'bc_cartId',
+}
+
+export type BigcommerceConfig = Partial
+
+export type BigcommerceProps = {
+ children?: ReactNode
+ locale: string
+} & BigcommerceConfig
+
+export function CommerceProvider({ children, ...config }: BigcommerceProps) {
+ return (
+
+ {children}
+
+ )
+}
+
+export const useCommerce = () => useCoreCommerce()
+```
+
+The exported types and components extend from the core ones exported by `@commerce`, which refers to `framework/commerce`.
+
+The `bigcommerceProvider` object looks like this:
+
+```tsx
+import { handler as useCart } from './cart/use-cart'
+import { handler as useAddItem } from './cart/use-add-item'
+import { handler as useUpdateItem } from './cart/use-update-item'
+import { handler as useRemoveItem } from './cart/use-remove-item'
+
+import { handler as useWishlist } from './wishlist/use-wishlist'
+import { handler as useWishlistAddItem } from './wishlist/use-add-item'
+import { handler as useWishlistRemoveItem } from './wishlist/use-remove-item'
+
+import { handler as useCustomer } from './customer/use-customer'
+import { handler as useSearch } from './product/use-search'
+
+import { handler as useLogin } from './auth/use-login'
+import { handler as useLogout } from './auth/use-logout'
+import { handler as useSignup } from './auth/use-signup'
+
+import fetcher from './fetcher'
+
+export const bigcommerceProvider = {
+ locale: 'en-us',
+ cartCookie: 'bc_cartId',
+ fetcher,
+ cart: { useCart, useAddItem, useUpdateItem, useRemoveItem },
+ wishlist: {
+ useWishlist,
+ useAddItem: useWishlistAddItem,
+ useRemoveItem: useWishlistRemoveItem,
+ },
+ customer: { useCustomer },
+ products: { useSearch },
+ auth: { useLogin, useLogout, useSignup },
+}
+
+export type BigcommerceProvider = typeof bigcommerceProvider
+```
+
+The provider object, in this case `bigcommerceProvider`, has to match the `Provider` type defined in [framework/commerce](./index.ts).
+
+A hook handler, like `useCart`, looks like this:
+
+```tsx
+import { useMemo } from 'react'
+import { SWRHook } from '@commerce/utils/types'
+import useCart, { UseCart, FetchCartInput } from '@commerce/cart/use-cart'
+import { normalizeCart } from '../lib/normalize'
+import type { Cart } from '../types'
+
+export default useCart as UseCart
+
+export const handler: SWRHook<
+ Cart | null,
+ {},
+ FetchCartInput,
+ { isEmpty?: boolean }
+> = {
+ fetchOptions: {
+ url: '/api/bigcommerce/cart',
+ method: 'GET',
+ },
+ async fetcher({ input: { cartId }, options, fetch }) {
+ const data = cartId ? await fetch(options) : null
+ return data && normalizeCart(data)
+ },
+ useHook: ({ useData }) => (input) => {
+ const response = useData({
+ swrOptions: { revalidateOnFocus: false, ...input?.swrOptions },
+ })
+
+ return useMemo(
+ () =>
+ Object.create(response, {
+ isEmpty: {
+ get() {
+ return (response.data?.lineItems.length ?? 0) <= 0
+ },
+ enumerable: true,
+ },
+ }),
+ [response]
+ )
+ },
+}
+```
+
+In the case of data fetching hooks like `useCart` each handler has to implement the `SWRHook` type that's defined in the core types. For mutations it's the `MutationHook`, e.g for `useAddItem`:
+
+```tsx
+import { useCallback } from 'react'
+import type { MutationHook } from '@commerce/utils/types'
+import { CommerceError } from '@commerce/utils/errors'
+import useAddItem, { UseAddItem } from '@commerce/cart/use-add-item'
+import { normalizeCart } from '../lib/normalize'
+import type {
+ Cart,
+ BigcommerceCart,
+ CartItemBody,
+ AddCartItemBody,
+} from '../types'
+import useCart from './use-cart'
+
+export default useAddItem as UseAddItem
+
+export const handler: MutationHook = {
+ fetchOptions: {
+ url: '/api/bigcommerce/cart',
+ method: 'POST',
+ },
+ async fetcher({ input: item, options, fetch }) {
+ if (
+ item.quantity &&
+ (!Number.isInteger(item.quantity) || item.quantity! < 1)
+ ) {
+ throw new CommerceError({
+ message: 'The item quantity has to be a valid integer greater than 0',
+ })
+ }
+
+ const data = await fetch({
+ ...options,
+ body: { item },
+ })
+
+ return normalizeCart(data)
+ },
+ useHook: ({ fetch }) => () => {
+ const { mutate } = useCart()
+
+ return useCallback(
+ async function addItem(input) {
+ const data = await fetch({ input })
+ await mutate(data, false)
+ return data
+ },
+ [fetch, mutate]
+ )
+ },
+}
+```
+
+## Adding the Node.js provider API
+
+TODO
+
+> The commerce API is currently going through a refactor in https://github.com/vercel/commerce/pull/252 - We'll update the docs once the API is released.
diff --git a/framework/shopify/.env.template b/framework/shopify/.env.template
index 9dc3674b6..74f446835 100644
--- a/framework/shopify/.env.template
+++ b/framework/shopify/.env.template
@@ -1,2 +1,4 @@
+COMMERCE_PROVIDER=shopify
+
NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN=
NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN=
diff --git a/framework/shopify/README.md b/framework/shopify/README.md
index eeae73afc..d67111a41 100644
--- a/framework/shopify/README.md
+++ b/framework/shopify/README.md
@@ -1,57 +1,28 @@
-## Table of Contents
+## Shopify Provider
-- [Getting Started](#getting-started)
- - [Modifications](#modifications)
- - [Adding item to Cart](#adding-item-to-cart)
- - [Proceed to Checkout](#proceed-to-checkout)
-- [General Usage](#general-usage)
- - [CommerceProvider](#commerceprovider)
- - [useCommerce](#usecommerce)
-- [Hooks](#hooks)
- - [usePrice](#useprice)
- - [useAddItem](#useadditem)
- - [useRemoveItem](#useremoveitem)
- - [useUpdateItem](#useupdateitem)
-- [APIs](#apis)
- - [getProduct](#getproduct)
- - [getAllProducts](#getallproducts)
- - [getAllCollections](#getallcollections)
- - [getAllPages](#getallpages)
+**Demo:** https://shopify.demo.vercel.store/
-# Shopify Storefront Data Hooks
+Before getting starter, a [Shopify](https://www.shopify.com/) account and store is required before using the provider.
-Collection of hooks and data fetching functions to integrate Shopify in a React application. Designed to work with [Next.js Commerce](https://demo.vercel.store/).
+Next, copy the `.env.template` file in this directory to `.env.local` in the main directory (which will be ignored by Git):
-## Getting Started
-
-1. Install dependencies:
-
-```
-yarn add shopify-buy
-yarn add @types/shopify-buy
+```bash
+cp framework/shopify/.env.template .env.local
```
-3. Environment variables need to be set:
+Then, set the environment variables in `.env.local` to match the ones from your store.
-```
-SHOPIFY_STORE_DOMAIN=
-SHOPIFY_STOREFRONT_ACCESS_TOKEN=
-NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN=
-NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN=
-```
+## Contribute
-4. Point the framework to `shopify` by updating `tsconfig.json`:
+Our commitment to Open Source can be found [here](https://vercel.com/oss).
-```
-"@framework/*": ["framework/shopify/*"],
-"@framework": ["framework/shopify"]
-```
+If you find an issue with the provider or want a new feature, feel free to open a PR or [create a new issue](https://github.com/vercel/commerce/issues).
-### Modifications
+## Modifications
These modifications are temporarily until contributions are made to remove them.
-#### Adding item to Cart
+### Adding item to Cart
```js
// components/product/ProductView/ProductView.tsx
@@ -72,7 +43,7 @@ const ProductView: FC = ({ product }) => {
}
```
-#### Proceed to Checkout
+### Proceed to Checkout
```js
// components/cart/CartSidebarView/CartSidebarView.tsx
@@ -88,114 +59,6 @@ const CartSidebarView: FC = () => {
}
```
-## General Usage
-
-### CommerceProvider
-
-Provider component that creates the commerce context for children.
-
-```js
-import { CommerceProvider } from '@framework'
-
-const App = ({ children }) => {
- return {children}
-}
-
-export default App
-```
-
-### useCommerce
-
-Returns the configs that are defined in the nearest `CommerceProvider`. Also provides access to Shopify's `checkout` and `shop`.
-
-```js
-import { useCommerce } from 'nextjs-commerce-shopify'
-
-const { checkout, shop } = useCommerce()
-```
-
-- `checkout`: The information required to checkout items and pay ([Documentation](https://shopify.dev/docs/storefront-api/reference/checkouts/checkout)).
-- `shop`: Represents a collection of the general settings and information about the shop ([Documentation](https://shopify.dev/docs/storefront-api/reference/online-store/shop/index)).
-
-## Hooks
-
-### usePrice
-
-Display the product variant price according to currency and locale.
-
-```js
-import usePrice from '@framework/product/use-price'
-
-const { price } = usePrice({
- amount,
-})
-```
-
-Takes in either `amount` or `variant`:
-
-- `amount`: A price value for a particular item if the amount is known.
-- `variant`: A shopify product variant. Price will be extracted from the variant.
-
-### useAddItem
-
-```js
-import { useAddItem } from '@framework/cart'
-
-const AddToCartButton = ({ variantId, quantity }) => {
- const addItem = useAddItem()
-
- const addToCart = async () => {
- await addItem({
- variantId,
- })
- }
-
- return
-}
-```
-
-### useRemoveItem
-
-```js
-import { useRemoveItem } from '@framework/cart'
-
-const RemoveButton = ({ item }) => {
- const removeItem = useRemoveItem()
-
- const handleRemove = async () => {
- await removeItem({ id: item.id })
- }
-
- return
-}
-```
-
-### useUpdateItem
-
-```js
-import { useUpdateItem } from '@framework/cart'
-
-const CartItem = ({ item }) => {
- const [quantity, setQuantity] = useState(item.quantity)
- const updateItem = useUpdateItem(item)
-
- const updateQuantity = async (e) => {
- const val = e.target.value
- await updateItem({ quantity: val })
- }
-
- return (
-
- )
-}
-```
-
## APIs
Collections of APIs to fetch data from a Shopify store.