From b8a0bb5a21029cc037a8af228d1406226ee311b6 Mon Sep 17 00:00:00 2001
From: okbel <curciobel@gmail.com>
Date: Fri, 29 Jan 2021 11:22:41 -0300
Subject: [PATCH 01/11] Progress

---
 CHANGELOG.md                                         |  5 +++--
 components/product/ProductView/ProductView.tsx       |  5 ++---
 .../wishlist/WishlistButton/WishlistButton.tsx       |  6 +++---
 tsconfig.json                                        | 12 ++++++------
 4 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7d1d95638..b21b673f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,5 @@
 ## Changelog
 
-- Select Variants Working
-- Click on cart item title, closes the sidebar
+- Select Variants Fully Working
+- Click on the Cart Item Title, closes the sidebar.
+
diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx
index d3d11ea16..448dfb10a 100644
--- a/components/product/ProductView/ProductView.tsx
+++ b/components/product/ProductView/ProductView.tsx
@@ -4,9 +4,8 @@ import { NextSeo } from 'next-seo'
 import { FC, useState } from 'react'
 import s from './ProductView.module.css'
 
-import { useUI } from '@components/ui'
 import { Swatch, ProductSlider } from '@components/product'
-import { Button, Container, Text } from '@components/ui'
+import { Button, Container, Text, useUI} from '@components/ui'
 
 import usePrice from '@framework/product/use-price'
 import { useAddItem } from '@framework/cart'
@@ -100,8 +99,8 @@ const ProductView: FC<Props> = ({ product }) => {
               ))}
             </ProductSlider>
           </div>
-        </div>
 
+        </div>
         <div className={s.sidebar}>
           <section>
             {product.options?.map((opt) => (
diff --git a/components/wishlist/WishlistButton/WishlistButton.tsx b/components/wishlist/WishlistButton/WishlistButton.tsx
index dced18a89..19ae3ec1a 100644
--- a/components/wishlist/WishlistButton/WishlistButton.tsx
+++ b/components/wishlist/WishlistButton/WishlistButton.tsx
@@ -1,12 +1,12 @@
 import React, { FC, useState } from 'react'
 import cn from 'classnames'
-import { Heart } from '@components/icons'
 
 import { useUI } from '@components/ui'
-import useCustomer from '@framework/customer/use-customer'
+import { Heart } from '@components/icons'
 import useAddItem from '@framework/wishlist/use-add-item'
+import useWishlist from '@framework/wishlist/use-wishlist'
+import useCustomer from '@framework/customer/use-customer'
 import useRemoveItem from '@framework/wishlist/use-remove-item'
-import useWishlist from '@framework/wishlist/use-add-item'
 
 type Props = {
   productId: Product['id']
diff --git a/tsconfig.json b/tsconfig.json
index 67de1ee36..480622bb4 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -16,16 +16,16 @@
     "jsx": "preserve",
     "paths": {
       "@lib/*": ["lib/*"],
-      "@assets/*": ["assets/*"],
-      "@config/*": ["config/*"],
-      "@components/*": ["components/*"],
       "@utils/*": ["utils/*"],
-      "@commerce/*": ["framework/commerce/*"],
+      "@config/*": ["config/*"],
+      "@assets/*": ["assets/*"],
+      "@components/*": ["components/*"],
       "@commerce": ["framework/commerce"],
-      "@framework/*": ["framework/bigcommerce/*"],
+      "@commerce/*": ["framework/commerce/*"],
       "@framework": ["framework/bigcommerce"]
+      "@framework/*": ["framework/bigcommerce/*"],
     }
   },
   "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
-  "exclude": ["node_modules", "components/wishlist"]
+  "exclude": ["node_modules"]
 }

From 3f30344619730ce20eac92c0c8b0d66b3d18955a Mon Sep 17 00:00:00 2001
From: okbel <curciobel@gmail.com>
Date: Thu, 4 Feb 2021 12:29:20 -0300
Subject: [PATCH 02/11] userAvatar

---
 components/common/Avatar/Avatar.tsx   | 14 +++++---------
 components/common/UserNav/UserNav.tsx |  2 +-
 components/ui/context.tsx             | 16 ++++++++++++++++
 lib/hooks/useUserAvatar.ts            | 26 ++++++++++++++++++++++++++
 tsconfig.json                         |  4 ++--
 5 files changed, 50 insertions(+), 12 deletions(-)
 create mode 100644 lib/hooks/useUserAvatar.ts

diff --git a/components/common/Avatar/Avatar.tsx b/components/common/Avatar/Avatar.tsx
index 351a117ec..ab91d7089 100644
--- a/components/common/Avatar/Avatar.tsx
+++ b/components/common/Avatar/Avatar.tsx
@@ -1,5 +1,5 @@
-import { FC, useState, useMemo, useRef, useEffect } from 'react'
-import { getRandomPairOfColors } from '@lib/colors'
+import { FC, useRef, useEffect } from 'react'
+import { useUserAvatar } from '@lib/hooks/useUserAvatar'
 
 interface Props {
   className?: string
@@ -7,18 +7,14 @@ interface Props {
 }
 
 const Avatar: FC<Props> = ({}) => {
-  const [bg] = useState(useMemo(() => getRandomPairOfColors, []))
   let ref = useRef() as React.MutableRefObject<HTMLInputElement>
-
-  useEffect(() => {
-    if (ref && ref.current) {
-      ref.current.style.backgroundImage = `linear-gradient(140deg, ${bg[0]}, ${bg[1]} 100%)`
-    }
-  }, [bg])
+  let { userAvatar } = useUserAvatar()
+  console.log(userAvatar)
 
   return (
     <div
       ref={ref}
+      style={{ backgroundImage: userAvatar }}
       className="inline-block h-8 w-8 rounded-full border-2 border-primary hover:border-secondary focus:border-secondary transition linear-out duration-150"
     >
       {/* Add an image - We're generating a gradient as placeholder  <img></img> */}
diff --git a/components/common/UserNav/UserNav.tsx b/components/common/UserNav/UserNav.tsx
index f8e6373d9..e33796927 100644
--- a/components/common/UserNav/UserNav.tsx
+++ b/components/common/UserNav/UserNav.tsx
@@ -3,11 +3,11 @@ import Link from 'next/link'
 import cn from 'classnames'
 import useCart from '@framework/cart/use-cart'
 import useCustomer from '@framework/customer/use-customer'
+import { Avatar } from '@components/common'
 import { Heart, Bag } from '@components/icons'
 import { useUI } from '@components/ui/context'
 import DropdownMenu from './DropdownMenu'
 import s from './UserNav.module.css'
-import { Avatar } from '@components/common'
 
 interface Props {
   className?: string
diff --git a/components/ui/context.tsx b/components/ui/context.tsx
index 206573858..13992a736 100644
--- a/components/ui/context.tsx
+++ b/components/ui/context.tsx
@@ -8,6 +8,7 @@ export interface State {
   displayToast: boolean
   modalView: string
   toastText: string
+  userAvatar: string
 }
 
 const initialState = {
@@ -17,6 +18,7 @@ const initialState = {
   modalView: 'LOGIN_VIEW',
   displayToast: false,
   toastText: '',
+  userAvatar: '',
 }
 
 type Action =
@@ -52,6 +54,10 @@ type Action =
       type: 'SET_MODAL_VIEW'
       view: MODAL_VIEWS
     }
+  | {
+      type: 'SET_USER_AVATAR'
+      value: string
+    }
 
 type MODAL_VIEWS = 'SIGNUP_VIEW' | 'LOGIN_VIEW' | 'FORGOT_VIEW'
 type ToastText = string
@@ -123,6 +129,12 @@ function uiReducer(state: State, action: Action) {
         toastText: action.text,
       }
     }
+    case 'SET_USER_AVATAR': {
+      return {
+        ...state,
+        userAvatar: action.value,
+      }
+    }
   }
 }
 
@@ -147,6 +159,9 @@ export const UIProvider: FC = (props) => {
   const openToast = () => dispatch({ type: 'OPEN_TOAST' })
   const closeToast = () => dispatch({ type: 'CLOSE_TOAST' })
 
+  const setUserAvatar = (value: string) =>
+    dispatch({ type: 'SET_USER_AVATAR', value })
+
   const setModalView = (view: MODAL_VIEWS) =>
     dispatch({ type: 'SET_MODAL_VIEW', view })
 
@@ -164,6 +179,7 @@ export const UIProvider: FC = (props) => {
       setModalView,
       openToast,
       closeToast,
+      setUserAvatar,
     }),
     [state]
   )
diff --git a/lib/hooks/useUserAvatar.ts b/lib/hooks/useUserAvatar.ts
new file mode 100644
index 000000000..bc9020931
--- /dev/null
+++ b/lib/hooks/useUserAvatar.ts
@@ -0,0 +1,26 @@
+import { useEffect } from 'react'
+import { getRandomPairOfColors } from '@lib/colors'
+import { useUI } from '@components/ui/context'
+
+export const useUserAvatar = (name = 'userAvatar') => {
+  const { userAvatar, setUserAvatar } = useUI()
+
+  useEffect(() => {
+    if (!userAvatar && localStorage.getItem(name)) {
+      // get bg value locally.
+      setUserAvatar(localStorage.getItem(name))
+    }
+    if (!localStorage.getItem(name)) {
+      // local not set, set.
+      const bg = getRandomPairOfColors()
+      const value = `linear-gradient(140deg, ${bg[0]}, ${bg[1]} 100%)`
+      localStorage.setItem(name, value)
+      setUserAvatar(value)
+    }
+  }, [])
+
+  return {
+    userAvatar,
+    setUserAvatar,
+  }
+}
diff --git a/tsconfig.json b/tsconfig.json
index 480622bb4..f8161ccf2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -22,8 +22,8 @@
       "@components/*": ["components/*"],
       "@commerce": ["framework/commerce"],
       "@commerce/*": ["framework/commerce/*"],
-      "@framework": ["framework/bigcommerce"]
-      "@framework/*": ["framework/bigcommerce/*"],
+      "@framework": ["framework/bigcommerce"],
+      "@framework/*": ["framework/bigcommerce/*"]
     }
   },
   "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],

From 300d04c1acadcc4e162c7d9810b6e2730f64c2c4 Mon Sep 17 00:00:00 2001
From: Peter Mekhaeil <4616064+petermekhaeil@users.noreply.github.com>
Date: Fri, 12 Feb 2021 22:14:16 +0800
Subject: [PATCH 03/11] Shopify Provider (#186)

* Start of Shopify provider

* add missing comment to documentation

* add missing env vars to documentation

* update reference to types file
---
 .env.template                                 |   4 +-
 framework/shopify/README.md                   | 260 ++++++++++++++++++
 framework/shopify/api/cart/index.ts           |   1 +
 framework/shopify/api/catalog/index.ts        |   1 +
 framework/shopify/api/catalog/products.ts     |   1 +
 framework/shopify/api/checkout/index.ts       |   1 +
 framework/shopify/api/customers/index.ts      |   1 +
 framework/shopify/api/customers/login.ts      |   1 +
 framework/shopify/api/customers/logout.ts     |   1 +
 framework/shopify/api/customers/signup.ts     |   1 +
 framework/shopify/api/index.ts                |  60 ++++
 .../api/operations/get-all-collections.ts     |  21 ++
 framework/shopify/api/operations/get-page.ts  |  27 ++
 .../shopify/api/utils/fetch-graphql-api.ts    |  51 ++++
 framework/shopify/api/wishlist/index.tsx      |   2 +
 framework/shopify/auth/use-login.tsx          |  13 +
 framework/shopify/auth/use-logout.tsx         |  13 +
 framework/shopify/auth/use-signup.tsx         |  13 +
 framework/shopify/cart/index.ts               |   5 +
 framework/shopify/cart/use-add-item.tsx       |  30 ++
 framework/shopify/cart/use-cart.tsx           |  42 +++
 framework/shopify/cart/use-remove-item.tsx    |  17 ++
 framework/shopify/cart/use-update-item.tsx    |  24 ++
 framework/shopify/common/get-all-pages.ts     |  55 ++++
 framework/shopify/common/get-site-info.ts     |  30 ++
 framework/shopify/customer/use-customer.tsx   |  32 +++
 framework/shopify/index.tsx                   | 109 ++++++++
 .../shopify/product/get-all-product-paths.ts  |  31 +++
 framework/shopify/product/get-all-products.ts |  40 +++
 framework/shopify/product/get-product.ts      |  37 +++
 framework/shopify/product/use-price.tsx       |   2 +
 framework/shopify/product/use-search.tsx      |  41 +++
 framework/shopify/types.ts                    | 130 +++++++++
 framework/shopify/utils/storage.ts            |  13 +
 .../shopify/utils/to-commerce-products.ts     |  60 ++++
 framework/shopify/wishlist/use-add-item.tsx   |  13 +
 .../shopify/wishlist/use-remove-item.tsx      |  17 ++
 framework/shopify/wishlist/use-wishlist.tsx   |  45 +++
 next.config.js                                |   2 +-
 39 files changed, 1245 insertions(+), 2 deletions(-)
 create mode 100644 framework/shopify/README.md
 create mode 100644 framework/shopify/api/cart/index.ts
 create mode 100644 framework/shopify/api/catalog/index.ts
 create mode 100644 framework/shopify/api/catalog/products.ts
 create mode 100644 framework/shopify/api/checkout/index.ts
 create mode 100644 framework/shopify/api/customers/index.ts
 create mode 100644 framework/shopify/api/customers/login.ts
 create mode 100644 framework/shopify/api/customers/logout.ts
 create mode 100644 framework/shopify/api/customers/signup.ts
 create mode 100644 framework/shopify/api/index.ts
 create mode 100644 framework/shopify/api/operations/get-all-collections.ts
 create mode 100644 framework/shopify/api/operations/get-page.ts
 create mode 100644 framework/shopify/api/utils/fetch-graphql-api.ts
 create mode 100644 framework/shopify/api/wishlist/index.tsx
 create mode 100644 framework/shopify/auth/use-login.tsx
 create mode 100644 framework/shopify/auth/use-logout.tsx
 create mode 100644 framework/shopify/auth/use-signup.tsx
 create mode 100644 framework/shopify/cart/index.ts
 create mode 100644 framework/shopify/cart/use-add-item.tsx
 create mode 100644 framework/shopify/cart/use-cart.tsx
 create mode 100644 framework/shopify/cart/use-remove-item.tsx
 create mode 100644 framework/shopify/cart/use-update-item.tsx
 create mode 100644 framework/shopify/common/get-all-pages.ts
 create mode 100644 framework/shopify/common/get-site-info.ts
 create mode 100644 framework/shopify/customer/use-customer.tsx
 create mode 100644 framework/shopify/index.tsx
 create mode 100644 framework/shopify/product/get-all-product-paths.ts
 create mode 100644 framework/shopify/product/get-all-products.ts
 create mode 100644 framework/shopify/product/get-product.ts
 create mode 100644 framework/shopify/product/use-price.tsx
 create mode 100644 framework/shopify/product/use-search.tsx
 create mode 100644 framework/shopify/types.ts
 create mode 100644 framework/shopify/utils/storage.ts
 create mode 100644 framework/shopify/utils/to-commerce-products.ts
 create mode 100644 framework/shopify/wishlist/use-add-item.tsx
 create mode 100644 framework/shopify/wishlist/use-remove-item.tsx
 create mode 100644 framework/shopify/wishlist/use-wishlist.tsx

diff --git a/.env.template b/.env.template
index 73a8a6e3b..7d8400baf 100644
--- a/.env.template
+++ b/.env.template
@@ -2,4 +2,6 @@ BIGCOMMERCE_STOREFRONT_API_URL=
 BIGCOMMERCE_STOREFRONT_API_TOKEN=
 BIGCOMMERCE_STORE_API_URL=
 BIGCOMMERCE_STORE_API_TOKEN=
-BIGCOMMERCE_STORE_API_CLIENT_ID=
\ No newline at end of file
+BIGCOMMERCE_STORE_API_CLIENT_ID=
+SHOPIFY_STORE_DOMAIN=
+SHOPIFY_STOREFRONT_ACCESS_TOKEN=
\ No newline at end of file
diff --git a/framework/shopify/README.md b/framework/shopify/README.md
new file mode 100644
index 000000000..fc6a70ce3
--- /dev/null
+++ b/framework/shopify/README.md
@@ -0,0 +1,260 @@
+## Table of Contents
+
+- [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)
+
+# Shopify Storefront Data Hooks
+
+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/).
+
+## Getting Started
+
+1. Install dependencies:
+
+```
+yarn install shopify-buy
+yarn install -D @types/shopify-buy
+```
+
+3. Environment variables need to be set:
+
+```
+SHOPIFY_STORE_DOMAIN=
+SHOPIFY_STOREFRONT_ACCESS_TOKEN=
+NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN=
+NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN=
+```
+
+4. Point the framework to `shopify` by updating `tsconfig.json`:
+
+```
+"@framework/*": ["framework/shopify/*"],
+"@framework": ["framework/shopify"]
+```
+
+### Modifications
+
+These modifications are temporarily until contributions are made to remove them.
+
+#### Adding item to Cart
+
+```js
+// components/product/ProductView/ProductView.tsx
+const ProductView: FC<Props> = ({ product }) => {
+  const addToCart = async () => {
+    setLoading(true)
+    try {
+      await addItem({
+        productId: product.id,
+        variantId: variant ? variant.id : product.variants[0].id,
+      })
+      openSidebar()
+      setLoading(false)
+    } catch (err) {
+      setLoading(false)
+    }
+  }
+}
+```
+
+#### Proceed to Checkout
+
+```js
+// components/cart/CartSidebarView/CartSidebarView.tsx
+import { useCommerce } from '@framework'
+
+const CartSidebarView: FC = () => {
+  const { checkout } = useCommerce()
+  return (
+    <Button href={checkout.webUrl} Component="a" width="100%">
+      Proceed to Checkout
+    </Button>
+  )
+}
+```
+
+## General Usage
+
+### CommerceProvider
+
+Provider component that creates the commerce context for children.
+
+```js
+import { CommerceProvider } from '@framework'
+
+const App = ({ children }) => {
+  return <CommerceProvider locale={locale}>{children}</CommerceProvider>
+}
+
+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 <button onClick={addToCart}>Add To Cart</button>
+}
+```
+
+### useRemoveItem
+
+```js
+import { useRemoveItem } from '@framework/cart'
+
+const RemoveButton = ({ item }) => {
+  const removeItem = useRemoveItem()
+
+  const handleRemove = async () => {
+    await removeItem({ id: item.id })
+  }
+
+  return <button onClick={handleRemove}>Remove</button>
+}
+```
+
+### 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 (
+    <input
+      type="number"
+      max={99}
+      min={0}
+      value={quantity}
+      onChange={updateQuantity}
+    />
+  )
+}
+```
+
+## APIs
+
+Collections of APIs to fetch data from a Shopify store.
+
+The data is fetched using the [Shopify JavaScript Buy SDK](https://github.com/Shopify/js-buy-sdk#readme). Read the [Shopify Storefront API reference](https://shopify.dev/docs/storefront-api/reference) for more information.
+
+### getProduct
+
+Get a single product by its `handle`.
+
+```js
+import getProduct from '@framework/product/get-product'
+import { getConfig } from '@framework/api'
+
+const config = getConfig()
+
+const product = await getProduct({
+  variables: { slug },
+  config,
+})
+```
+
+### getAllProducts
+
+```js
+import getAllProducts from '@framework/product/get-all-products'
+import { getConfig } from '@framework/api'
+
+const config = getConfig()
+
+const { products } = await getAllProducts({
+  variables: { first: 12 },
+  config,
+})
+```
+
+### getAllCollections
+
+```js
+import getAllCollections from '@framework/product/get-all-collections'
+import { getConfig } from '@framework/api'
+
+const config = getConfig()
+
+const collections = await getAllCollections({
+  config,
+})
+```
+
+### getAllPages
+
+```js
+import getAllPages from '@framework/common/get-all-pages'
+import { getConfig } from '@framework/api'
+
+const config = getConfig()
+
+const pages = await getAllPages({
+  variables: { first: 12 },
+  config,
+})
+```
diff --git a/framework/shopify/api/cart/index.ts b/framework/shopify/api/cart/index.ts
new file mode 100644
index 000000000..ea9b101e1
--- /dev/null
+++ b/framework/shopify/api/cart/index.ts
@@ -0,0 +1 @@
+export default function () {}
diff --git a/framework/shopify/api/catalog/index.ts b/framework/shopify/api/catalog/index.ts
new file mode 100644
index 000000000..ea9b101e1
--- /dev/null
+++ b/framework/shopify/api/catalog/index.ts
@@ -0,0 +1 @@
+export default function () {}
diff --git a/framework/shopify/api/catalog/products.ts b/framework/shopify/api/catalog/products.ts
new file mode 100644
index 000000000..ea9b101e1
--- /dev/null
+++ b/framework/shopify/api/catalog/products.ts
@@ -0,0 +1 @@
+export default function () {}
diff --git a/framework/shopify/api/checkout/index.ts b/framework/shopify/api/checkout/index.ts
new file mode 100644
index 000000000..ea9b101e1
--- /dev/null
+++ b/framework/shopify/api/checkout/index.ts
@@ -0,0 +1 @@
+export default function () {}
diff --git a/framework/shopify/api/customers/index.ts b/framework/shopify/api/customers/index.ts
new file mode 100644
index 000000000..ea9b101e1
--- /dev/null
+++ b/framework/shopify/api/customers/index.ts
@@ -0,0 +1 @@
+export default function () {}
diff --git a/framework/shopify/api/customers/login.ts b/framework/shopify/api/customers/login.ts
new file mode 100644
index 000000000..ea9b101e1
--- /dev/null
+++ b/framework/shopify/api/customers/login.ts
@@ -0,0 +1 @@
+export default function () {}
diff --git a/framework/shopify/api/customers/logout.ts b/framework/shopify/api/customers/logout.ts
new file mode 100644
index 000000000..ea9b101e1
--- /dev/null
+++ b/framework/shopify/api/customers/logout.ts
@@ -0,0 +1 @@
+export default function () {}
diff --git a/framework/shopify/api/customers/signup.ts b/framework/shopify/api/customers/signup.ts
new file mode 100644
index 000000000..ea9b101e1
--- /dev/null
+++ b/framework/shopify/api/customers/signup.ts
@@ -0,0 +1 @@
+export default function () {}
diff --git a/framework/shopify/api/index.ts b/framework/shopify/api/index.ts
new file mode 100644
index 000000000..dcb0fc2ba
--- /dev/null
+++ b/framework/shopify/api/index.ts
@@ -0,0 +1,60 @@
+import type { CommerceAPIConfig } from '@commerce/api'
+import fetchGraphqlApi from './utils/fetch-graphql-api'
+
+export interface ShopifyConfig extends CommerceAPIConfig {}
+
+// No I don't like this - will fix it later
+const API_URL =
+  process.env.SHOPIFY_STORE_DOMAIN ||
+  process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN
+const API_TOKEN =
+  process.env.SHOPIFY_STOREFRONT_ACCESS_TOKEN ||
+  process.env.NEXT_PUBLIC_SHOPIFY_STOREFRONT_ACCESS_TOKEN
+
+if (!API_URL) {
+  throw new Error(
+    `The environment variable SHOPIFY_STORE_DOMAIN is missing and it's required to access your store`
+  )
+}
+
+if (!API_TOKEN) {
+  throw new Error(
+    `The environment variable SHOPIFY_STOREFRONT_ACCESS_TOKEN is missing and it's required to access your store`
+  )
+}
+
+export class Config {
+  private config: ShopifyConfig
+
+  constructor(config: ShopifyConfig) {
+    this.config = config
+  }
+
+  getConfig(userConfig: Partial<ShopifyConfig> = {}) {
+    return Object.entries(userConfig).reduce<ShopifyConfig>(
+      (cfg, [key, value]) => Object.assign(cfg, { [key]: value }),
+      { ...this.config }
+    )
+  }
+
+  setConfig(newConfig: Partial<ShopifyConfig>) {
+    Object.assign(this.config, newConfig)
+  }
+}
+
+const config = new Config({
+  commerceUrl: API_URL,
+  apiToken: API_TOKEN,
+  // TODO
+  // @ts-ignore
+  fetch: fetchGraphqlApi,
+  customerCookie: 'SHOP_TOKEN',
+})
+
+export function getConfig(userConfig?: Partial<ShopifyConfig>) {
+  return config.getConfig(userConfig)
+}
+
+export function setConfig(newConfig: Partial<ShopifyConfig>) {
+  return config.setConfig(newConfig)
+}
diff --git a/framework/shopify/api/operations/get-all-collections.ts b/framework/shopify/api/operations/get-all-collections.ts
new file mode 100644
index 000000000..9cf216a91
--- /dev/null
+++ b/framework/shopify/api/operations/get-all-collections.ts
@@ -0,0 +1,21 @@
+import Client from 'shopify-buy'
+import { ShopifyConfig } from '../index'
+
+type Options = {
+  config: ShopifyConfig
+}
+
+const getAllCollections = async (options: Options) => {
+  const { config } = options
+
+  const client = Client.buildClient({
+    storefrontAccessToken: config.apiToken,
+    domain: config.commerceUrl,
+  })
+
+  const res = await client.collection.fetchAllWithProducts()
+
+  return JSON.parse(JSON.stringify(res))
+}
+
+export default getAllCollections
diff --git a/framework/shopify/api/operations/get-page.ts b/framework/shopify/api/operations/get-page.ts
new file mode 100644
index 000000000..11651e335
--- /dev/null
+++ b/framework/shopify/api/operations/get-page.ts
@@ -0,0 +1,27 @@
+import { ShopifyConfig, getConfig } from '..'
+import type { Page } from '../../types'
+
+export type { Page }
+
+export type GetPageResult<T extends { page?: any } = { page?: Page }> = T
+
+export type PageVariables = {
+  id: string
+}
+
+async function getPage({
+  url,
+  variables,
+  config,
+  preview,
+}: {
+  url?: string
+  variables: PageVariables
+  config?: ShopifyConfig
+  preview?: boolean
+}): Promise<GetPageResult> {
+  config = getConfig(config)
+  return {}
+}
+
+export default getPage
diff --git a/framework/shopify/api/utils/fetch-graphql-api.ts b/framework/shopify/api/utils/fetch-graphql-api.ts
new file mode 100644
index 000000000..946242c93
--- /dev/null
+++ b/framework/shopify/api/utils/fetch-graphql-api.ts
@@ -0,0 +1,51 @@
+import { CommerceAPIFetchOptions } from '@commerce/api'
+import { FetcherError } from '@commerce/utils/errors'
+import { getConfig } from '../index'
+
+export interface GraphQLFetcherResult<Data = any> {
+  data: Data
+  res: Response
+}
+export type GraphQLFetcher<
+  Data extends GraphQLFetcherResult = GraphQLFetcherResult,
+  Variables = any
+> = (
+  query: string,
+  queryData?: CommerceAPIFetchOptions<Variables>,
+  fetchOptions?: RequestInit
+) => Promise<Data>
+
+const fetchGraphqlApi: GraphQLFetcher = async (
+  query: string,
+  { variables } = {},
+  fetchOptions
+) => {
+  const config = getConfig()
+  const url = `https://${config.commerceUrl}/api/2020-10/graphql.json`
+
+  const res = await fetch(url, {
+    ...fetchOptions,
+    method: 'POST',
+    headers: {
+      'X-Shopify-Storefront-Access-Token': config.apiToken,
+      ...fetchOptions?.headers,
+      'Content-Type': 'application/json',
+    },
+    body: JSON.stringify({
+      query,
+      variables,
+    }),
+  })
+
+  const json = await res.json()
+  if (json.errors) {
+    throw new FetcherError({
+      errors: json.errors ?? [{ message: 'Failed to fetch Shopify API' }],
+      status: res.status,
+    })
+  }
+
+  return { data: json.data, res }
+}
+
+export default fetchGraphqlApi
diff --git a/framework/shopify/api/wishlist/index.tsx b/framework/shopify/api/wishlist/index.tsx
new file mode 100644
index 000000000..a72856673
--- /dev/null
+++ b/framework/shopify/api/wishlist/index.tsx
@@ -0,0 +1,2 @@
+export type WishlistItem = { product: any; id: number }
+export default function () {}
diff --git a/framework/shopify/auth/use-login.tsx b/framework/shopify/auth/use-login.tsx
new file mode 100644
index 000000000..75f067c3a
--- /dev/null
+++ b/framework/shopify/auth/use-login.tsx
@@ -0,0 +1,13 @@
+import { useCallback } from 'react'
+
+export function emptyHook() {
+  const useEmptyHook = async (options = {}) => {
+    return useCallback(async function () {
+      return Promise.resolve()
+    }, [])
+  }
+
+  return useEmptyHook
+}
+
+export default emptyHook
diff --git a/framework/shopify/auth/use-logout.tsx b/framework/shopify/auth/use-logout.tsx
new file mode 100644
index 000000000..75f067c3a
--- /dev/null
+++ b/framework/shopify/auth/use-logout.tsx
@@ -0,0 +1,13 @@
+import { useCallback } from 'react'
+
+export function emptyHook() {
+  const useEmptyHook = async (options = {}) => {
+    return useCallback(async function () {
+      return Promise.resolve()
+    }, [])
+  }
+
+  return useEmptyHook
+}
+
+export default emptyHook
diff --git a/framework/shopify/auth/use-signup.tsx b/framework/shopify/auth/use-signup.tsx
new file mode 100644
index 000000000..75f067c3a
--- /dev/null
+++ b/framework/shopify/auth/use-signup.tsx
@@ -0,0 +1,13 @@
+import { useCallback } from 'react'
+
+export function emptyHook() {
+  const useEmptyHook = async (options = {}) => {
+    return useCallback(async function () {
+      return Promise.resolve()
+    }, [])
+  }
+
+  return useEmptyHook
+}
+
+export default emptyHook
diff --git a/framework/shopify/cart/index.ts b/framework/shopify/cart/index.ts
new file mode 100644
index 000000000..e1c6ef823
--- /dev/null
+++ b/framework/shopify/cart/index.ts
@@ -0,0 +1,5 @@
+export { default as useCart } from './use-cart'
+export { default as useAddItem } from './use-add-item'
+export { default as useRemoveItem } from './use-remove-item'
+// export { default as useWishlistActions } from './use-cart-actions'
+// export { default as useUpdateItem } from './use-cart-actions'
diff --git a/framework/shopify/cart/use-add-item.tsx b/framework/shopify/cart/use-add-item.tsx
new file mode 100644
index 000000000..276d66e30
--- /dev/null
+++ b/framework/shopify/cart/use-add-item.tsx
@@ -0,0 +1,30 @@
+import { useCallback } from 'react'
+import { LineItemToAdd } from 'shopify-buy'
+import { useCommerce } from '../index'
+
+type Options = {
+  productId: number
+  variantId: string | number
+}
+
+const useAddItem = () => {
+  const { checkout, client, updateCheckout } = useCommerce()
+
+  return useCallback(
+    async function addItem(options: Options) {
+      const lineItems: LineItemToAdd[] = [
+        {
+          variantId: `${options.variantId}`,
+          quantity: 1,
+        },
+      ]
+
+      const cart = await client?.checkout.addLineItems(checkout.id, lineItems)
+      updateCheckout(cart)
+      return cart
+    },
+    [checkout, client]
+  )
+}
+
+export default useAddItem
diff --git a/framework/shopify/cart/use-cart.tsx b/framework/shopify/cart/use-cart.tsx
new file mode 100644
index 000000000..f067b520d
--- /dev/null
+++ b/framework/shopify/cart/use-cart.tsx
@@ -0,0 +1,42 @@
+import { useCommerce } from '../index'
+
+export function emptyHook() {
+  const { checkout } = useCommerce()
+  const { lineItems, totalPriceV2 } = checkout || {}
+
+  return {
+    data: {
+      subTotal: totalPriceV2?.amount || 0,
+      total: totalPriceV2?.amount || 0,
+      currency: {
+        code: '',
+      },
+      line_items:
+        lineItems?.map((item) => {
+          return [
+            {
+              id: item.id,
+              name: item.title,
+              quantity: item.quantity,
+            },
+          ]
+        }) || [],
+      items:
+        lineItems?.map((item) => {
+          return {
+            id: item.id,
+            name: item.title,
+            images: [{ url: '/jacket.png' }],
+            url: '/',
+            quantity: item.quantity,
+            productId: item.id,
+            variantId: item.id,
+          }
+        }) || [],
+    },
+    isEmpty: false,
+    isLoading: false,
+  }
+}
+
+export default emptyHook
diff --git a/framework/shopify/cart/use-remove-item.tsx b/framework/shopify/cart/use-remove-item.tsx
new file mode 100644
index 000000000..c0ce93bd5
--- /dev/null
+++ b/framework/shopify/cart/use-remove-item.tsx
@@ -0,0 +1,17 @@
+import { useCallback } from 'react'
+import { useCommerce } from '../index'
+
+const useRemoveItem = () => {
+  const { checkout, client, updateCheckout } = useCommerce()
+
+  return useCallback(
+    async function removeItem({ id }: { id: string }) {
+      const cart = await client?.checkout.removeLineItems(checkout.id, [id])
+      updateCheckout(cart)
+      return cart
+    },
+    [checkout, client]
+  )
+}
+
+export default useRemoveItem
diff --git a/framework/shopify/cart/use-update-item.tsx b/framework/shopify/cart/use-update-item.tsx
new file mode 100644
index 000000000..05118a65b
--- /dev/null
+++ b/framework/shopify/cart/use-update-item.tsx
@@ -0,0 +1,24 @@
+import { useCallback } from 'react'
+import { useCommerce } from '../index'
+
+const useUpdateItem = (item: CartItem) => {
+  const { checkout, client, updateCheckout } = useCommerce()
+
+  return useCallback(
+    async function updateItem({ quantity }: { quantity: number }) {
+      const lineItemsToUpdate = [{ id: item.id, quantity }]
+
+      const cart = await client?.checkout.updateLineItems(
+        checkout.id,
+        lineItemsToUpdate
+      )
+
+      updateCheckout(cart)
+
+      return cart
+    },
+    [checkout, client]
+  )
+}
+
+export default useUpdateItem
diff --git a/framework/shopify/common/get-all-pages.ts b/framework/shopify/common/get-all-pages.ts
new file mode 100644
index 000000000..02db3fdc3
--- /dev/null
+++ b/framework/shopify/common/get-all-pages.ts
@@ -0,0 +1,55 @@
+import { getConfig, ShopifyConfig } from '../api'
+import { Page as PageType, PageEdge } from '../types'
+
+export type Page = PageType
+
+export const getAllPagesQuery = /* GraphQL */ `
+  query($first: Int!) {
+    pages(first: $first) {
+      edges {
+        node {
+          id
+          title
+          handle
+          body
+          bodySummary
+          url
+        }
+      }
+    }
+  }
+`
+
+type Variables = {
+  first?: number
+}
+
+type Options = {
+  variables?: Variables
+  config: ShopifyConfig
+  preview?: boolean
+}
+
+type ReturnType = {
+  pages: Page[]
+}
+
+const getAllPages = async (options?: Options): Promise<ReturnType> => {
+  let { config, variables = { first: 250 } } = options || {}
+
+  config = getConfig(config)
+
+  const { data } = await config.fetch(getAllPagesQuery, { variables })
+
+  const pages = data.pages.edges.map(({ node }: PageEdge) => {
+    return {
+      ...node,
+      name: node.handle,
+      url: `${config!.locale}/${node.handle}`,
+    }
+  })
+
+  return { pages }
+}
+
+export default getAllPages
diff --git a/framework/shopify/common/get-site-info.ts b/framework/shopify/common/get-site-info.ts
new file mode 100644
index 000000000..c08ae2b92
--- /dev/null
+++ b/framework/shopify/common/get-site-info.ts
@@ -0,0 +1,30 @@
+import { ShopifyConfig } from '../index'
+
+type Options = {
+  config: ShopifyConfig
+  preview?: boolean
+}
+
+const getSiteInfo = async (options: Options) => {
+  // TODO
+  return {
+    categories: [
+      {
+        path: '',
+        name: '',
+        entityId: 0,
+      },
+    ],
+    brands: [
+      {
+        node: {
+          path: '',
+          name: '',
+          entityId: 0,
+        },
+      },
+    ],
+  }
+}
+
+export default getSiteInfo
diff --git a/framework/shopify/customer/use-customer.tsx b/framework/shopify/customer/use-customer.tsx
new file mode 100644
index 000000000..a909443ff
--- /dev/null
+++ b/framework/shopify/customer/use-customer.tsx
@@ -0,0 +1,32 @@
+import type { HookFetcher } from '@commerce/utils/types'
+import type { SwrOptions } from '@commerce/utils/use-data'
+import useCommerceCustomer from '@commerce/use-customer'
+
+const defaultOpts = {}
+
+export type Customer = {
+  entityId: number
+  firstName: string
+  lastName: string
+  email: string
+}
+export type CustomerData = {}
+
+export const fetcher: HookFetcher<Customer | null> = async () => {
+  return null
+}
+
+export function extendHook(
+  customFetcher: typeof fetcher,
+  swrOptions?: SwrOptions<Customer | null>
+) {
+  const useCustomer = () => {
+    return { data: { firstName: null, lastName: null, email: null } }
+  }
+
+  useCustomer.extend = extendHook
+
+  return useCustomer
+}
+
+export default extendHook(fetcher)
diff --git a/framework/shopify/index.tsx b/framework/shopify/index.tsx
new file mode 100644
index 000000000..5fd08e0d9
--- /dev/null
+++ b/framework/shopify/index.tsx
@@ -0,0 +1,109 @@
+import React, {
+  ReactNode,
+  createContext,
+  useContext,
+  useMemo,
+  useState,
+  useEffect,
+} from 'react'
+import Client from 'shopify-buy'
+import { Shop, Cart, Client as ClientType } from './types'
+import {
+  getCheckoutIdFromStorage,
+  setCheckoutIdInStorage,
+} from './utils/storage'
+import { getConfig } from '@framework/api'
+
+const Commerce = createContext<CommerceContextValue | {}>({})
+
+type CommerceProps = {
+  children?: ReactNode
+  locale: string
+}
+
+type CommerceContextValue = {
+  client: ClientType
+  shop: Shop
+  checkout: Cart
+  updateCheckout: (cart: Cart | undefined) => void
+  currencyCode: string
+  locale: string
+  sessionToken: string
+}
+
+export function CommerceProvider({
+  children,
+  locale = 'en-US',
+}: CommerceProps) {
+  const sessionToken = 'nextjs-commerce-shopify-token'
+
+  const config = getConfig()
+
+  const client = Client.buildClient({
+    storefrontAccessToken: config.apiToken,
+    domain: config.commerceUrl,
+    language: locale,
+  }) as ClientType
+
+  const [shop, setShop] = useState<Shop>()
+  const [checkout, setCheckout] = useState<Cart>()
+
+  const fetchShopify = async () => {
+    const shopInfo: Shop = await client.shop.fetchInfo()
+    let checkoutResource: Cart
+
+    const checkoutOptions = {
+      presentmentCurrencyCode:
+        /*config.currencyCode ||*/ shopInfo?.currencyCode,
+    }
+
+    let checkoutId = getCheckoutIdFromStorage(sessionToken)
+
+    // we could have a cart id stored in session storage
+    // user could be refreshing or navigating back and forth
+    if (checkoutId) {
+      checkoutResource = await client.checkout.fetch(checkoutId)
+
+      // could be expired order - we will create a new order
+      if (checkoutResource.completedAt) {
+        checkoutResource = await client.checkout.create(checkoutOptions)
+      }
+    } else {
+      checkoutResource = await client.checkout.create(checkoutOptions)
+    }
+
+    setCheckoutIdInStorage(sessionToken, checkoutResource.id)
+
+    setShop(shopInfo)
+    setCheckout(checkoutResource)
+  }
+
+  useEffect(() => {
+    fetchShopify()
+  }, [])
+
+  const updateCheckout = (newCheckout: Cart) => {
+    setCheckout(newCheckout)
+  }
+
+  // Because the config is an object, if the parent re-renders this provider
+  // will re-render every consumer unless we memoize the config
+  const cfg = useMemo(
+    () => ({
+      client,
+      checkout,
+      shop,
+      updateCheckout: updateCheckout,
+      currencyCode: /*config.currencyCode ||*/ checkout?.currencyCode,
+      locale,
+      sessionToken,
+    }),
+    [client]
+  )
+
+  return <Commerce.Provider value={cfg}>{children}</Commerce.Provider>
+}
+
+export function useCommerce<T extends CommerceContextValue>() {
+  return useContext(Commerce) as T
+}
diff --git a/framework/shopify/product/get-all-product-paths.ts b/framework/shopify/product/get-all-product-paths.ts
new file mode 100644
index 000000000..3d4f0ef7a
--- /dev/null
+++ b/framework/shopify/product/get-all-product-paths.ts
@@ -0,0 +1,31 @@
+import Client from 'shopify-buy'
+import { getConfig } from '../api'
+import { Product } from '../types'
+import toCommerceProducts from '../utils/to-commerce-products'
+
+type ReturnType = {
+  products: any[]
+}
+
+const getAllProductPaths = async (): Promise<ReturnType> => {
+  const config = getConfig()
+
+  const client = Client.buildClient({
+    storefrontAccessToken: config.apiToken,
+    domain: config.commerceUrl,
+  })
+
+  const res = (await client.product.fetchAll()) as Product[]
+
+  const products = toCommerceProducts(res)
+
+  return {
+    products: products.map((product) => {
+      return {
+        node: { ...product },
+      }
+    }),
+  }
+}
+
+export default getAllProductPaths
diff --git a/framework/shopify/product/get-all-products.ts b/framework/shopify/product/get-all-products.ts
new file mode 100644
index 000000000..6e4881e99
--- /dev/null
+++ b/framework/shopify/product/get-all-products.ts
@@ -0,0 +1,40 @@
+import Client from 'shopify-buy'
+import { ShopifyConfig } from '../api'
+import { Product } from '../types'
+import toCommerceProducts from '../utils/to-commerce-products'
+
+export type ProductNode = Product
+
+type Variables = {
+  first?: number
+  field?: string
+}
+
+type Options = {
+  variables: Variables
+  config: ShopifyConfig
+  preview?: boolean
+}
+
+type ReturnType = {
+  products: any[]
+}
+
+const getAllProducts = async (options: Options): Promise<ReturnType> => {
+  const { config } = options
+
+  const client = Client.buildClient({
+    storefrontAccessToken: config.apiToken,
+    domain: config.commerceUrl,
+  })
+
+  const res = (await client.product.fetchAll()) as Product[]
+
+  const products = toCommerceProducts(res)
+
+  return {
+    products,
+  }
+}
+
+export default getAllProducts
diff --git a/framework/shopify/product/get-product.ts b/framework/shopify/product/get-product.ts
new file mode 100644
index 000000000..f71aa0213
--- /dev/null
+++ b/framework/shopify/product/get-product.ts
@@ -0,0 +1,37 @@
+import Client from 'shopify-buy'
+import { ShopifyConfig } from '../api'
+import { Product } from '../types'
+import toCommerceProducts from '../utils/to-commerce-products'
+
+export type ProductNode = Product
+
+type Variables = {
+  slug: string
+}
+
+type Options = {
+  variables: Variables
+  config: ShopifyConfig
+  preview?: boolean
+}
+
+type ReturnType = {
+  product: any
+}
+
+const getProduct = async (options: Options): Promise<ReturnType> => {
+  const { variables, config } = options
+
+  const client = Client.buildClient({
+    storefrontAccessToken: config.apiToken,
+    domain: config.commerceUrl,
+  })
+
+  const res = (await client.product.fetchByHandle(variables.slug)) as Product
+
+  return {
+    product: toCommerceProducts([res])[0],
+  }
+}
+
+export default getProduct
diff --git a/framework/shopify/product/use-price.tsx b/framework/shopify/product/use-price.tsx
new file mode 100644
index 000000000..a79940a76
--- /dev/null
+++ b/framework/shopify/product/use-price.tsx
@@ -0,0 +1,2 @@
+export * from '@commerce/use-price'
+export { default } from '@commerce/use-price'
diff --git a/framework/shopify/product/use-search.tsx b/framework/shopify/product/use-search.tsx
new file mode 100644
index 000000000..a2c32c896
--- /dev/null
+++ b/framework/shopify/product/use-search.tsx
@@ -0,0 +1,41 @@
+import type { HookFetcher } from '@commerce/utils/types'
+import type { SwrOptions } from '@commerce/utils/use-data'
+import useCommerceSearch from '@commerce/products/use-search'
+import { ProductEdge } from '../types'
+
+const defaultOpts = {}
+
+export type SearchProductsInput = {
+  search?: string
+  categoryId?: number
+  brandId?: number
+  sort?: string
+}
+
+export type SearchProductsData = {
+  products: ProductEdge[]
+  found: boolean
+}
+
+export const fetcher: HookFetcher<SearchProductsData, SearchProductsInput> = (
+  options,
+  { search, categoryId, brandId, sort },
+  fetch
+) => {
+  return { found: false, products: [] }
+}
+
+export function extendHook(
+  customFetcher: typeof fetcher,
+  swrOptions?: SwrOptions<SearchProductsData, SearchProductsInput>
+) {
+  const useSearch = (input: SearchProductsInput = {}) => {
+    return {}
+  }
+
+  useSearch.extend = extendHook
+
+  return useSearch
+}
+
+export default extendHook(fetcher)
diff --git a/framework/shopify/types.ts b/framework/shopify/types.ts
new file mode 100644
index 000000000..47bb94e62
--- /dev/null
+++ b/framework/shopify/types.ts
@@ -0,0 +1,130 @@
+import {
+  Product as BaseProduct,
+  ProductVariant as BaseProductVariant,
+  Cart as BaseCart,
+  CheckoutResource as BaseCheckoutResource,
+  AttributeInput,
+  Client as BaseClient,
+  Shop as BaseShop,
+  Image as BaseImage,
+} from 'shopify-buy'
+
+export type SelectedOptions = {
+  id: string
+  name: string
+  value: string
+}
+
+export type PresentmentPrice = {
+  price: PriceV2
+}
+
+export type ProductVariant = BaseProductVariant & {
+  selectedOptions: Array<SelectedOptions>
+  presentmentPrices: Array<PresentmentPrice>
+}
+
+// TODO
+export type ProductOptions = {
+  node: {
+    __typename: string
+    displayName: string
+    values: {
+      edges: [
+        {
+          node: {
+            label: string
+            id: string
+          }
+        }
+      ]
+    }
+  }
+}
+
+// TODO
+export type ProductEdge = {
+  node: Product
+}
+
+export type Product = BaseProduct & {
+  handle: string
+  name: string
+  path: string
+  entityId: number
+  descriptionHtml: string
+  prices: {
+    price: {
+      value: number
+      currencyCode: string
+    }
+    retailPrice: {
+      value: number
+      currencyCode: string
+    }
+  }
+  images: {
+    edges: [{ node: { urlOriginal: string; altText: string } }]
+  }
+  productOptions: ProductOptions
+  variants: Array<ProductVariant> & {
+    edges: [
+      {
+        node: {
+          productOptions: ProductOptions[]
+          entityId: number
+        }
+      }
+    ]
+  }
+}
+
+export type PriceV2 = {
+  amount: number
+  currencyCode: string
+}
+
+export type Cart = BaseCart & {
+  webUrl?: string
+  currencyCode?: string
+  lineItemsSubtotalPrice?: PriceV2
+  totalPriceV2?: PriceV2
+}
+
+export type Shop = BaseShop & {
+  currencyCode?: string
+}
+
+export type Create = {
+  presentmentCurrencyCode?: string
+}
+
+export type CheckoutResource = BaseCheckoutResource & {
+  updateLineItems(
+    checkoutId: string | number,
+    lineItems: AttributeInput[]
+  ): Promise<Cart>
+
+  create: (input: Create) => Promise<Cart>
+}
+
+export type Client = BaseClient & {
+  checkout: CheckoutResource
+}
+
+export type Page = {
+  id: string
+  title: string
+  name: string
+  handle: string
+  body: string
+  bodySummary: string
+  url: string
+  sort_order: number
+}
+
+export type PageEdge = {
+  node: Page
+}
+
+export type Image = BaseImage
diff --git a/framework/shopify/utils/storage.ts b/framework/shopify/utils/storage.ts
new file mode 100644
index 000000000..d46dadb21
--- /dev/null
+++ b/framework/shopify/utils/storage.ts
@@ -0,0 +1,13 @@
+export const getCheckoutIdFromStorage = (token: string) => {
+  if (window && window.sessionStorage) {
+    return window.sessionStorage.getItem(token)
+  }
+
+  return null
+}
+
+export const setCheckoutIdInStorage = (token: string, id: string | number) => {
+  if (window && window.sessionStorage) {
+    return window.sessionStorage.setItem(token, id + '')
+  }
+}
diff --git a/framework/shopify/utils/to-commerce-products.ts b/framework/shopify/utils/to-commerce-products.ts
new file mode 100644
index 000000000..c0b411eb6
--- /dev/null
+++ b/framework/shopify/utils/to-commerce-products.ts
@@ -0,0 +1,60 @@
+import { Product, Image } from '../types'
+
+export default function toCommerceProducts(products: Product[]) {
+  return products.map((product: Product) => {
+    return {
+      id: product.id,
+      entityId: product.id,
+      name: product.title,
+      slug: product.handle,
+      title: product.title,
+      vendor: product.vendor,
+      description: product.descriptionHtml,
+      path: `/${product.handle}`,
+      price: {
+        value: +product.variants[0].price,
+        currencyCode: 'USD', // TODO
+      },
+      images: product.images.map((image: Image) => {
+        return {
+          url: image.src,
+        }
+      }),
+      variants: product.variants.map((variant) => {
+        return {
+          id: variant.id,
+          options: variant.selectedOptions.map((selectedOption) => {
+            return {
+              __typename: 'MultipleChoiceOption',
+              displayName: selectedOption.name,
+              values: [
+                {
+                  node: {
+                    id: variant.id,
+                    label: selectedOption.value,
+                  },
+                },
+              ],
+            }
+          }),
+        }
+      }),
+      productOptions: product.options.map((option) => {
+        return {
+          __typename: 'MultipleChoiceOption',
+          displayName: option.name,
+          values: option.values.map((value) => {
+            return {
+              node: {
+                entityId: 1,
+                label: value.value,
+                hexColors: [value.value],
+              },
+            }
+          }),
+        }
+      }),
+      options: [],
+    }
+  })
+}
diff --git a/framework/shopify/wishlist/use-add-item.tsx b/framework/shopify/wishlist/use-add-item.tsx
new file mode 100644
index 000000000..75f067c3a
--- /dev/null
+++ b/framework/shopify/wishlist/use-add-item.tsx
@@ -0,0 +1,13 @@
+import { useCallback } from 'react'
+
+export function emptyHook() {
+  const useEmptyHook = async (options = {}) => {
+    return useCallback(async function () {
+      return Promise.resolve()
+    }, [])
+  }
+
+  return useEmptyHook
+}
+
+export default emptyHook
diff --git a/framework/shopify/wishlist/use-remove-item.tsx b/framework/shopify/wishlist/use-remove-item.tsx
new file mode 100644
index 000000000..a2d3a8a05
--- /dev/null
+++ b/framework/shopify/wishlist/use-remove-item.tsx
@@ -0,0 +1,17 @@
+import { useCallback } from 'react'
+
+type Options = {
+  includeProducts?: boolean
+}
+
+export function emptyHook(options?: Options) {
+  const useEmptyHook = async ({ id }: { id: string | number }) => {
+    return useCallback(async function () {
+      return Promise.resolve()
+    }, [])
+  }
+
+  return useEmptyHook
+}
+
+export default emptyHook
diff --git a/framework/shopify/wishlist/use-wishlist.tsx b/framework/shopify/wishlist/use-wishlist.tsx
new file mode 100644
index 000000000..2aac16810
--- /dev/null
+++ b/framework/shopify/wishlist/use-wishlist.tsx
@@ -0,0 +1,45 @@
+import { HookFetcher } from '@commerce/utils/types'
+import { SwrOptions } from '@commerce/utils/use-data'
+import useCommerceWishlist from '@commerce/wishlist/use-wishlist'
+import { Product } from '../types'
+import useCustomer from '../customer/use-customer'
+
+const defaultOpts = {}
+
+export type Wishlist = {
+  items: [
+    {
+      product_id: number
+      variant_id: number
+      id: number
+      product: Product
+    }
+  ]
+}
+
+export interface UseWishlistOptions {
+  includeProducts?: boolean
+}
+
+export interface UseWishlistInput extends UseWishlistOptions {
+  customerId?: number
+}
+
+export const fetcher: HookFetcher<Wishlist | null, UseWishlistInput> = () => {
+  return null
+}
+
+export function extendHook(
+  customFetcher: typeof fetcher,
+  swrOptions?: SwrOptions<Wishlist | null, UseWishlistInput>
+) {
+  const useWishlist = ({ includeProducts }: UseWishlistOptions = {}) => {
+    return { data: null }
+  }
+
+  useWishlist.extend = extendHook
+
+  return useWishlist
+}
+
+export default extendHook(fetcher)
diff --git a/next.config.js b/next.config.js
index e732ef78a..3c9e37210 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,6 +1,6 @@
 module.exports = {
   images: {
-    domains: ['cdn11.bigcommerce.com'],
+    domains: ['cdn11.bigcommerce.com', 'cdn.shopify.com'],
   },
   i18n: {
     locales: ['en-US', 'es'],

From a8607f24cd215129527418dc6b81748baa1faae4 Mon Sep 17 00:00:00 2001
From: Luis Alvarez <luis@vercel.com>
Date: Mon, 22 Feb 2021 19:06:03 -0500
Subject: [PATCH 04/11] Updates to wishlist feature

---
 components/common/Layout/Layout.tsx                   | 5 ++---
 components/product/ProductCard/ProductCard.tsx        | 4 ++--
 components/product/ProductView/ProductView.tsx        | 4 ++--
 components/wishlist/WishlistButton/WishlistButton.tsx | 5 +++--
 framework/commerce/utils/features.ts                  | 2 +-
 next.config.js                                        | 3 +++
 package.json                                          | 1 +
 pages/index.tsx                                       | 8 ++++----
 pages/product/[slug].tsx                              | 2 +-
 pages/search.tsx                                      | 1 +
 10 files changed, 20 insertions(+), 15 deletions(-)

diff --git a/components/common/Layout/Layout.tsx b/components/common/Layout/Layout.tsx
index f4376bbf3..82e045474 100644
--- a/components/common/Layout/Layout.tsx
+++ b/components/common/Layout/Layout.tsx
@@ -58,11 +58,10 @@ const Layout: FC<Props> = ({
   } = useUI()
   const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
   const { locale = 'en-US' } = useRouter()
-  const isWishlistEnabled = commerceFeatures.wishlist
   return (
     <CommerceProvider locale={locale}>
       <div className={cn(s.root)}>
-        <Navbar wishlist={isWishlistEnabled} />
+        <Navbar wishlist={!!process.env.WISHLIST_ENABLED} />
         <main className="fit">{children}</main>
         <Footer pages={pageProps.pages} />
 
@@ -73,7 +72,7 @@ const Layout: FC<Props> = ({
         </Modal>
 
         <Sidebar open={displaySidebar} onClose={closeSidebar}>
-          <CartSidebarView wishlist={isWishlistEnabled} />
+          <CartSidebarView wishlist={!!process.env.WISHLIST_ENABLED} />
         </Sidebar>
 
         <FeatureBar
diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx
index a9eaf8568..52ce129dd 100644
--- a/components/product/ProductCard/ProductCard.tsx
+++ b/components/product/ProductCard/ProductCard.tsx
@@ -59,11 +59,11 @@ const ProductCard: FC<Props> = ({
                 {product.price.currencyCode}
               </span>
             </div>
-            {wishlist && (
+            {process.env.WISHLIST_ENABLED && (
               <WishlistButton
                 className={s.wishlistButton}
                 productId={product.id}
-                variant={product.variants[0]}
+                variant={product.variants[0] as any}
               />
             )}
           </div>
diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx
index c502303c4..e666e1a08 100644
--- a/components/product/ProductView/ProductView.tsx
+++ b/components/product/ProductView/ProductView.tsx
@@ -152,11 +152,11 @@ const ProductView: FC<Props> = ({ product, wishlist = false }) => {
             </Button>
           </div>
         </div>
-        {wishlist && (
+        {process.env.WISHLIST_ENABLED && (
           <WishlistButton
             className={s.wishlistButton}
             productId={product.id}
-            variant={product.variants[0]!}
+            variant={product.variants[0]! as any}
           />
         )}
       </div>
diff --git a/components/wishlist/WishlistButton/WishlistButton.tsx b/components/wishlist/WishlistButton/WishlistButton.tsx
index 0c4c20194..e22215363 100644
--- a/components/wishlist/WishlistButton/WishlistButton.tsx
+++ b/components/wishlist/WishlistButton/WishlistButton.tsx
@@ -7,7 +7,7 @@ import type { Product, ProductVariant } from '@commerce/types'
 import useCustomer from '@framework/customer/use-customer'
 import useAddItem from '@framework/wishlist/use-add-item'
 import useRemoveItem from '@framework/wishlist/use-remove-item'
-import useWishlist from '@framework/wishlist/use-add-item'
+import useWishlist from '@framework/wishlist/use-wishlist'
 
 type Props = {
   productId: Product['id']
@@ -28,7 +28,8 @@ const WishlistButton: FC<Props> = ({
   const [loading, setLoading] = useState(false)
 
   const itemInWishlist = data?.items?.find(
-    (item) => item.product_id === productId && item.variant_id === variant.id
+    (item) =>
+      item.product_id === productId && (item.variant_id as any) === variant.id
   )
 
   const handleWishlistChange = async (e: any) => {
diff --git a/framework/commerce/utils/features.ts b/framework/commerce/utils/features.ts
index d84321967..98a53ed54 100644
--- a/framework/commerce/utils/features.ts
+++ b/framework/commerce/utils/features.ts
@@ -1,4 +1,4 @@
-import commerceProviderConfig from '@framework/config.json'
+import commerceProviderConfig from '../config.json'
 import type { CommerceProviderConfig } from '../types'
 import memo from 'lodash.memoize'
 
diff --git a/next.config.js b/next.config.js
index e732ef78a..939031884 100644
--- a/next.config.js
+++ b/next.config.js
@@ -6,6 +6,9 @@ module.exports = {
     locales: ['en-US', 'es'],
     defaultLocale: 'en-US',
   },
+  env: {
+    WISHLIST_ENABLED: false,
+  },
   rewrites() {
     return [
       {
diff --git a/package.json b/package.json
index 2d8e32772..d1bfbb574 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
     "generate": "graphql-codegen",
     "generate:definitions": "node framework/bigcommerce/scripts/generate-definitions.js"
   },
+  "sideEffects": false,
   "license": "MIT",
   "engines": {
     "node": "12.x"
diff --git a/pages/index.tsx b/pages/index.tsx
index acb1474be..c4fb68252 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -57,7 +57,7 @@ export default function Home({
               width: i === 0 ? 1080 : 540,
               height: i === 0 ? 1080 : 540,
             }}
-            wishlist={commerceFeatures.wishlist}
+            wishlist={!!process.env.WISHLIST_ENABLED}
           />
         ))}
       </Grid>
@@ -71,7 +71,7 @@ export default function Home({
               width: 320,
               height: 320,
             }}
-            wishlist={commerceFeatures.wishlist}
+            wishlist={!!process.env.WISHLIST_ENABLED}
           />
         ))}
       </Marquee>
@@ -94,7 +94,7 @@ export default function Home({
               width: i === 0 ? 1080 : 540,
               height: i === 0 ? 1080 : 540,
             }}
-            wishlist={commerceFeatures.wishlist}
+            wishlist={!!process.env.WISHLIST_ENABLED}
           />
         ))}
       </Grid>
@@ -108,7 +108,7 @@ export default function Home({
               width: 320,
               height: 320,
             }}
-            wishlist={commerceFeatures.wishlist}
+            wishlist={!!process.env.WISHLIST_ENABLED}
           />
         ))}
       </Marquee>
diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx
index a705c001b..90da202b2 100644
--- a/pages/product/[slug].tsx
+++ b/pages/product/[slug].tsx
@@ -71,7 +71,7 @@ export default function Slug({
   ) : (
     <ProductView
       product={product as any}
-      wishlist={commerceFeatures.wishlist}
+      wishlist={!!process.env.WISHLIST_ENABLED}
     />
   )
 }
diff --git a/pages/search.tsx b/pages/search.tsx
index c9958a9f8..d62ce22d4 100644
--- a/pages/search.tsx
+++ b/pages/search.tsx
@@ -34,6 +34,7 @@ import {
   getDesignerPath,
   useSearchMeta,
 } from '@lib/search'
+import { Product } from '@commerce/types'
 
 export async function getStaticProps({
   preview,

From 67d05ea165c22a8cedf98b38d73ca9593b73a70b Mon Sep 17 00:00:00 2001
From: Luis Alvarez <luis@vercel.com>
Date: Tue, 23 Feb 2021 11:32:54 -0500
Subject: [PATCH 05/11] Moved the features to be environment variable only

---
 components/product/ProductCard/ProductCard.tsx |  2 --
 components/product/ProductView/ProductView.tsx |  3 +--
 next.config.js                                 |  2 +-
 pages/index.tsx                                | 10 ----------
 pages/product/[slug].tsx                       | 11 +----------
 pages/search.tsx                               |  8 --------
 pages/wishlist.tsx                             |  3 +--
 7 files changed, 4 insertions(+), 35 deletions(-)

diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx
index 52ce129dd..3c28e6663 100644
--- a/components/product/ProductCard/ProductCard.tsx
+++ b/components/product/ProductCard/ProductCard.tsx
@@ -11,7 +11,6 @@ interface Props {
   product: Product
   variant?: 'slim' | 'simple'
   imgProps?: Omit<ImageProps, 'src'>
-  wishlist?: boolean
 }
 
 const placeholderImg = '/product-img-placeholder.svg'
@@ -21,7 +20,6 @@ const ProductCard: FC<Props> = ({
   product,
   variant,
   imgProps,
-  wishlist = false,
   ...props
 }) => (
   <Link href={`/product/${product.slug}`} {...props}>
diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx
index e666e1a08..51b9888b0 100644
--- a/components/product/ProductView/ProductView.tsx
+++ b/components/product/ProductView/ProductView.tsx
@@ -19,10 +19,9 @@ interface Props {
   className?: string
   children?: any
   product: Product
-  wishlist?: boolean
 }
 
-const ProductView: FC<Props> = ({ product, wishlist = false }) => {
+const ProductView: FC<Props> = ({ product }) => {
   const addItem = useAddItem()
   const { price } = usePrice({
     amount: product.price.value,
diff --git a/next.config.js b/next.config.js
index 939031884..fe4441dda 100644
--- a/next.config.js
+++ b/next.config.js
@@ -7,7 +7,7 @@ module.exports = {
     defaultLocale: 'en-US',
   },
   env: {
-    WISHLIST_ENABLED: false,
+    WISHLIST_ENABLED: true,
   },
   rewrites() {
     return [
diff --git a/pages/index.tsx b/pages/index.tsx
index c4fb68252..3a84112e5 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -8,7 +8,6 @@ import { getConfig } from '@framework/api'
 import getAllProducts from '@framework/product/get-all-products'
 import getSiteInfo from '@framework/common/get-site-info'
 import getAllPages from '@framework/common/get-all-pages'
-import Features from '@commerce/utils/features'
 
 export async function getStaticProps({
   preview,
@@ -24,7 +23,6 @@ export async function getStaticProps({
 
   const { categories, brands } = await getSiteInfo({ config, preview })
   const { pages } = await getAllPages({ config, preview })
-  const isWishlistEnabled = Features.isEnabled('wishlist')
 
   return {
     props: {
@@ -32,9 +30,6 @@ export async function getStaticProps({
       categories,
       brands,
       pages,
-      commerceFeatures: {
-        wishlist: isWishlistEnabled,
-      },
     },
     revalidate: 14400,
   }
@@ -44,7 +39,6 @@ export default function Home({
   products,
   brands,
   categories,
-  commerceFeatures,
 }: InferGetStaticPropsType<typeof getStaticProps>) {
   return (
     <>
@@ -57,7 +51,6 @@ export default function Home({
               width: i === 0 ? 1080 : 540,
               height: i === 0 ? 1080 : 540,
             }}
-            wishlist={!!process.env.WISHLIST_ENABLED}
           />
         ))}
       </Grid>
@@ -71,7 +64,6 @@ export default function Home({
               width: 320,
               height: 320,
             }}
-            wishlist={!!process.env.WISHLIST_ENABLED}
           />
         ))}
       </Marquee>
@@ -94,7 +86,6 @@ export default function Home({
               width: i === 0 ? 1080 : 540,
               height: i === 0 ? 1080 : 540,
             }}
-            wishlist={!!process.env.WISHLIST_ENABLED}
           />
         ))}
       </Grid>
@@ -108,7 +99,6 @@ export default function Home({
               width: 320,
               height: 320,
             }}
-            wishlist={!!process.env.WISHLIST_ENABLED}
           />
         ))}
       </Marquee>
diff --git a/pages/product/[slug].tsx b/pages/product/[slug].tsx
index 90da202b2..61420a8d9 100644
--- a/pages/product/[slug].tsx
+++ b/pages/product/[slug].tsx
@@ -11,14 +11,12 @@ import { getConfig } from '@framework/api'
 import getProduct from '@framework/product/get-product'
 import getAllPages from '@framework/common/get-all-pages'
 import getAllProductPaths from '@framework/product/get-all-product-paths'
-import Features from '@commerce/utils/features'
 
 export async function getStaticProps({
   params,
   locale,
   preview,
 }: GetStaticPropsContext<{ slug: string }>) {
-  const isWishlistEnabled = Features.isEnabled('wishlist')
   const config = getConfig({ locale })
   const { pages } = await getAllPages({ config, preview })
   const { product } = await getProduct({
@@ -35,9 +33,6 @@ export async function getStaticProps({
     props: {
       pages,
       product,
-      commerceFeatures: {
-        wishlist: isWishlistEnabled,
-      },
     },
     revalidate: 200,
   }
@@ -62,17 +57,13 @@ export async function getStaticPaths({ locales }: GetStaticPathsContext) {
 
 export default function Slug({
   product,
-  commerceFeatures,
 }: InferGetStaticPropsType<typeof getStaticProps>) {
   const router = useRouter()
 
   return router.isFallback ? (
     <h1>Loading...</h1> // TODO (BC) Add Skeleton Views
   ) : (
-    <ProductView
-      product={product as any}
-      wishlist={!!process.env.WISHLIST_ENABLED}
-    />
+    <ProductView product={product as any} />
   )
 }
 
diff --git a/pages/search.tsx b/pages/search.tsx
index d62ce22d4..a05203892 100644
--- a/pages/search.tsx
+++ b/pages/search.tsx
@@ -26,8 +26,6 @@ const SORT = Object.entries({
   'price-desc': 'Price: High to low',
 })
 
-import Features from '@commerce/utils/features'
-
 import {
   filterQuery,
   getCategoryPath,
@@ -43,15 +41,11 @@ export async function getStaticProps({
   const config = getConfig({ locale })
   const { pages } = await getAllPages({ config, preview })
   const { categories, brands } = await getSiteInfo({ config, preview })
-  const isWishlistEnabled = Features.isEnabled('wishlist')
   return {
     props: {
       pages,
       categories,
       brands,
-      commerceFeatures: {
-        wishlist: isWishlistEnabled,
-      },
     },
   }
 }
@@ -59,7 +53,6 @@ export async function getStaticProps({
 export default function Search({
   categories,
   brands,
-  commerceFeatures: { wishlist },
 }: InferGetStaticPropsType<typeof getStaticProps>) {
   const [activeFilter, setActiveFilter] = useState('')
   const [toggleFilter, setToggleFilter] = useState(false)
@@ -359,7 +352,6 @@ export default function Search({
                     width: 480,
                     height: 480,
                   }}
-                  wishlist={wishlist}
                 />
               ))}
             </Grid>
diff --git a/pages/wishlist.tsx b/pages/wishlist.tsx
index ca11152f4..dcda912c6 100644
--- a/pages/wishlist.tsx
+++ b/pages/wishlist.tsx
@@ -11,14 +11,13 @@ import { useCustomer } from '@framework/customer'
 import { WishlistCard } from '@components/wishlist'
 import useWishlist from '@framework/wishlist/use-wishlist'
 import getAllPages from '@framework/common/get-all-pages'
-import Features from '@commerce/utils/features'
 
 export async function getStaticProps({
   preview,
   locale,
 }: GetStaticPropsContext) {
   // Disabling page if Feature is not available
-  if (Features.isEnabled('wishlist')) {
+  if (!process.env.WISHLIST_ENABLED) {
     return {
       notFound: true,
     }

From 412f2681487dd46917197172221d442dd12cddcc Mon Sep 17 00:00:00 2001
From: Luis Alvarez <luis@vercel.com>
Date: Tue, 23 Feb 2021 13:21:25 -0500
Subject: [PATCH 06/11] More changes for wishlist config

---
 components/cart/CartSidebarView/CartSidebarView.tsx          | 4 ++--
 .../common/HomeAllProductsGrid/HomeAllProductsGrid.tsx       | 4 ----
 components/common/Layout/Layout.tsx                          | 4 ++--
 components/common/Navbar/Navbar.tsx                          | 4 ++--
 components/common/UserNav/UserNav.tsx                        | 5 ++---
 5 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/components/cart/CartSidebarView/CartSidebarView.tsx b/components/cart/CartSidebarView/CartSidebarView.tsx
index 5b28fde27..3ceda44fe 100644
--- a/components/cart/CartSidebarView/CartSidebarView.tsx
+++ b/components/cart/CartSidebarView/CartSidebarView.tsx
@@ -9,7 +9,7 @@ import usePrice from '@framework/product/use-price'
 import CartItem from '../CartItem'
 import s from './CartSidebarView.module.css'
 
-const CartSidebarView: FC<{ wishlist?: boolean }> = ({ wishlist }) => {
+const CartSidebarView: FC = () => {
   const { closeSidebar } = useUI()
   const { data, isLoading, isEmpty } = useCart()
 
@@ -48,7 +48,7 @@ const CartSidebarView: FC<{ wishlist?: boolean }> = ({ wishlist }) => {
             </button>
           </div>
           <div className="space-y-1">
-            <UserNav wishlist={wishlist} />
+            <UserNav />
           </div>
         </div>
       </header>
diff --git a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx
index 4b838e1a4..423048f75 100644
--- a/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx
+++ b/components/common/HomeAllProductsGrid/HomeAllProductsGrid.tsx
@@ -5,20 +5,17 @@ import { Grid } from '@components/ui'
 import { ProductCard } from '@components/product'
 import s from './HomeAllProductsGrid.module.css'
 import { getCategoryPath, getDesignerPath } from '@lib/search'
-import wishlist from '@framework/api/wishlist'
 
 interface Props {
   categories?: any
   brands?: any
   products?: Product[]
-  wishlist?: boolean
 }
 
 const HomeAllProductsGrid: FC<Props> = ({
   categories,
   brands,
   products = [],
-  wishlist = false,
 }) => {
   return (
     <div className={s.root}>
@@ -65,7 +62,6 @@ const HomeAllProductsGrid: FC<Props> = ({
                 width: 480,
                 height: 480,
               }}
-              wishlist={wishlist}
             />
           ))}
         </Grid>
diff --git a/components/common/Layout/Layout.tsx b/components/common/Layout/Layout.tsx
index 82e045474..54749c46b 100644
--- a/components/common/Layout/Layout.tsx
+++ b/components/common/Layout/Layout.tsx
@@ -61,7 +61,7 @@ const Layout: FC<Props> = ({
   return (
     <CommerceProvider locale={locale}>
       <div className={cn(s.root)}>
-        <Navbar wishlist={!!process.env.WISHLIST_ENABLED} />
+        <Navbar />
         <main className="fit">{children}</main>
         <Footer pages={pageProps.pages} />
 
@@ -72,7 +72,7 @@ const Layout: FC<Props> = ({
         </Modal>
 
         <Sidebar open={displaySidebar} onClose={closeSidebar}>
-          <CartSidebarView wishlist={!!process.env.WISHLIST_ENABLED} />
+          <CartSidebarView />
         </Sidebar>
 
         <FeatureBar
diff --git a/components/common/Navbar/Navbar.tsx b/components/common/Navbar/Navbar.tsx
index ce9d91b38..b2a372f66 100644
--- a/components/common/Navbar/Navbar.tsx
+++ b/components/common/Navbar/Navbar.tsx
@@ -5,7 +5,7 @@ import { Searchbar, UserNav } from '@components/common'
 import NavbarRoot from './NavbarRoot'
 import s from './Navbar.module.css'
 
-const Navbar: FC<{ wishlist?: boolean }> = ({ wishlist }) => (
+const Navbar: FC = () => (
   <NavbarRoot>
     <Container>
       <div className="relative flex flex-row justify-between py-4 align-center md:py-6">
@@ -33,7 +33,7 @@ const Navbar: FC<{ wishlist?: boolean }> = ({ wishlist }) => (
         </div>
 
         <div className="flex justify-end flex-1 space-x-8">
-          <UserNav wishlist={wishlist} />
+          <UserNav />
         </div>
       </div>
 
diff --git a/components/common/UserNav/UserNav.tsx b/components/common/UserNav/UserNav.tsx
index 5d9d58fff..d2dfc11dd 100644
--- a/components/common/UserNav/UserNav.tsx
+++ b/components/common/UserNav/UserNav.tsx
@@ -12,12 +12,11 @@ import { Avatar } from '@components/common'
 
 interface Props {
   className?: string
-  wishlist?: boolean
 }
 
 const countItem = (count: number, item: LineItem) => count + item.quantity
 
-const UserNav: FC<Props> = ({ className, wishlist = false }) => {
+const UserNav: FC<Props> = ({ className }) => {
   const { data } = useCart()
   const { data: customer } = useCustomer()
   const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI()
@@ -31,7 +30,7 @@ const UserNav: FC<Props> = ({ className, wishlist = false }) => {
             <Bag />
             {itemsCount > 0 && <span className={s.bagCount}>{itemsCount}</span>}
           </li>
-          {wishlist && (
+          {process.env.WISHLIST_ENABLED && (
             <li className={s.item}>
               <Link href="/wishlist">
                 <a onClick={closeSidebarIfPresent} aria-label="Wishlist">

From b931bc47afe20c923381316d36c6e3b4a4358bc7 Mon Sep 17 00:00:00 2001
From: Luis Alvarez <luis@vercel.com>
Date: Tue, 23 Feb 2021 13:59:11 -0500
Subject: [PATCH 07/11] Disable wishlist

---
 next.config.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/next.config.js b/next.config.js
index fe4441dda..939031884 100644
--- a/next.config.js
+++ b/next.config.js
@@ -7,7 +7,7 @@ module.exports = {
     defaultLocale: 'en-US',
   },
   env: {
-    WISHLIST_ENABLED: true,
+    WISHLIST_ENABLED: false,
   },
   rewrites() {
     return [

From 9b251a10c6b844af7c2078b08bddc66fd1019e34 Mon Sep 17 00:00:00 2001
From: Luis Alvarez <luis@vercel.com>
Date: Tue, 23 Feb 2021 23:03:23 -0500
Subject: [PATCH 08/11] Removed useWishlistActions

---
 framework/bigcommerce/wishlist/index.ts               |  1 -
 .../bigcommerce/wishlist/use-wishlist-actions.tsx     | 11 -----------
 2 files changed, 12 deletions(-)
 delete mode 100644 framework/bigcommerce/wishlist/use-wishlist-actions.tsx

diff --git a/framework/bigcommerce/wishlist/index.ts b/framework/bigcommerce/wishlist/index.ts
index 9ea28291c..241af3c7e 100644
--- a/framework/bigcommerce/wishlist/index.ts
+++ b/framework/bigcommerce/wishlist/index.ts
@@ -1,4 +1,3 @@
 export { default as useAddItem } from './use-add-item'
 export { default as useWishlist } from './use-wishlist'
 export { default as useRemoveItem } from './use-remove-item'
-export { default as useWishlistActions } from './use-wishlist-actions'
diff --git a/framework/bigcommerce/wishlist/use-wishlist-actions.tsx b/framework/bigcommerce/wishlist/use-wishlist-actions.tsx
deleted file mode 100644
index 711d00516..000000000
--- a/framework/bigcommerce/wishlist/use-wishlist-actions.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import useAddItem from './use-add-item'
-import useRemoveItem from './use-remove-item'
-
-// This hook is probably not going to be used, but it's here
-// to show how a commerce should be structuring it
-export default function useWishlistActions() {
-  const addItem = useAddItem()
-  const removeItem = useRemoveItem()
-
-  return { addItem, removeItem }
-}

From bbfca29217540df58ff34f604970e2bb16e856d4 Mon Sep 17 00:00:00 2001
From: Luis Alvarez <luis@vercel.com>
Date: Tue, 23 Feb 2021 23:07:49 -0500
Subject: [PATCH 09/11] Updated readme

---
 README.md | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/README.md b/README.md
index ea6248c51..9d2108cfe 100644
--- a/README.md
+++ b/README.md
@@ -57,18 +57,21 @@ Main folder and its exposed functions
   - getAllProducts
 - `wishlist`
   - useWishlist
-  - addWishlistItem
-  - removeWishlistItem
+  - useAddItem
+  - useRemoveItem
 - `auth`
   - useLogin
   - useLogout
   - useSignup
+- `customer`
+  - useCustomer
+  - getCustomerId
+  - getCustomerWistlist
 - `cart`
 
   - useCart
   - useAddItem
   - useRemoveItem
-  - useCartActions
   - useUpdateItem
 
 - `config.json`

From bcd1d46e30d0cfc7078544afcf82532d03b586d6 Mon Sep 17 00:00:00 2001
From: okbel <curciobel@gmail.com>
Date: Wed, 24 Feb 2021 14:37:25 -0300
Subject: [PATCH 10/11] updates

---
 .vscode/extensions.json                       |  3 ++
 components/common/UserNav/UserNav.tsx         |  2 +-
 .../product/ProductCard/ProductCard.tsx       |  2 +-
 .../product/ProductView/ProductView.tsx       |  2 +-
 framework/bigcommerce/auth/use-login.tsx      |  2 +-
 framework/bigcommerce/auth/use-logout.tsx     |  2 +-
 framework/bigcommerce/auth/use-signup.tsx     |  2 +-
 framework/bigcommerce/next.config.js          | 37 +++++++++++++++
 framework/bigcommerce/product/use-price.tsx   |  4 +-
 framework/commerce/{ => auth}/use-login.tsx   |  8 ++--
 framework/commerce/{ => auth}/use-logout.tsx  |  8 ++--
 framework/commerce/{ => auth}/use-signup.tsx  |  8 ++--
 framework/commerce/config.json                |  5 --
 .../commerce/{ => product}/use-price.tsx      |  2 +-
 framework/commerce/types.ts                   |  4 +-
 framework/commerce/utils/bootstrap.js         | 11 +++++
 framework/commerce/utils/features.ts          | 10 ++++
 next.config.js                                | 46 +++----------------
 package.json                                  |  1 +
 pages/wishlist.tsx                            |  2 +-
 yarn.lock                                     |  5 ++
 21 files changed, 98 insertions(+), 68 deletions(-)
 create mode 100644 .vscode/extensions.json
 create mode 100644 framework/bigcommerce/next.config.js
 rename framework/commerce/{ => auth}/use-login.tsx (64%)
 rename framework/commerce/{ => auth}/use-logout.tsx (64%)
 rename framework/commerce/{ => auth}/use-signup.tsx (64%)
 delete mode 100644 framework/commerce/config.json
 rename framework/commerce/{ => product}/use-price.tsx (97%)
 create mode 100644 framework/commerce/utils/bootstrap.js

diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 000000000..c83e26348
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+  "recommendations": ["esbenp.prettier-vscode"]
+}
diff --git a/components/common/UserNav/UserNav.tsx b/components/common/UserNav/UserNav.tsx
index d2dfc11dd..9d143a572 100644
--- a/components/common/UserNav/UserNav.tsx
+++ b/components/common/UserNav/UserNav.tsx
@@ -30,7 +30,7 @@ const UserNav: FC<Props> = ({ className }) => {
             <Bag />
             {itemsCount > 0 && <span className={s.bagCount}>{itemsCount}</span>}
           </li>
-          {process.env.WISHLIST_ENABLED && (
+          {process.env.COMMERCE_WISHLIST_ENABLED && (
             <li className={s.item}>
               <Link href="/wishlist">
                 <a onClick={closeSidebarIfPresent} aria-label="Wishlist">
diff --git a/components/product/ProductCard/ProductCard.tsx b/components/product/ProductCard/ProductCard.tsx
index 3c28e6663..ade53380c 100644
--- a/components/product/ProductCard/ProductCard.tsx
+++ b/components/product/ProductCard/ProductCard.tsx
@@ -57,7 +57,7 @@ const ProductCard: FC<Props> = ({
                 {product.price.currencyCode}
               </span>
             </div>
-            {process.env.WISHLIST_ENABLED && (
+            {process.env.COMMERCE_WISHLIST_ENABLED && (
               <WishlistButton
                 className={s.wishlistButton}
                 productId={product.id}
diff --git a/components/product/ProductView/ProductView.tsx b/components/product/ProductView/ProductView.tsx
index 51b9888b0..2d31aaafc 100644
--- a/components/product/ProductView/ProductView.tsx
+++ b/components/product/ProductView/ProductView.tsx
@@ -151,7 +151,7 @@ const ProductView: FC<Props> = ({ product }) => {
             </Button>
           </div>
         </div>
-        {process.env.WISHLIST_ENABLED && (
+        {process.env.COMMERCE_WISHLIST_ENABLED && (
           <WishlistButton
             className={s.wishlistButton}
             productId={product.id}
diff --git a/framework/bigcommerce/auth/use-login.tsx b/framework/bigcommerce/auth/use-login.tsx
index b66fca493..1be96a58c 100644
--- a/framework/bigcommerce/auth/use-login.tsx
+++ b/framework/bigcommerce/auth/use-login.tsx
@@ -1,7 +1,7 @@
 import { useCallback } from 'react'
 import type { MutationHook } from '@commerce/utils/types'
 import { CommerceError } from '@commerce/utils/errors'
-import useLogin, { UseLogin } from '@commerce/use-login'
+import useLogin, { UseLogin } from '@commerce/auth/use-login'
 import type { LoginBody } from '../api/customers/login'
 import useCustomer from '../customer/use-customer'
 
diff --git a/framework/bigcommerce/auth/use-logout.tsx b/framework/bigcommerce/auth/use-logout.tsx
index 6278a4dd1..71015a1c1 100644
--- a/framework/bigcommerce/auth/use-logout.tsx
+++ b/framework/bigcommerce/auth/use-logout.tsx
@@ -1,6 +1,6 @@
 import { useCallback } from 'react'
 import type { MutationHook } from '@commerce/utils/types'
-import useLogout, { UseLogout } from '@commerce/use-logout'
+import useLogout, { UseLogout } from '@commerce/auth/use-logout'
 import useCustomer from '../customer/use-customer'
 
 export default useLogout as UseLogout<typeof handler>
diff --git a/framework/bigcommerce/auth/use-signup.tsx b/framework/bigcommerce/auth/use-signup.tsx
index 23b7ce9c6..28f7024ef 100644
--- a/framework/bigcommerce/auth/use-signup.tsx
+++ b/framework/bigcommerce/auth/use-signup.tsx
@@ -1,7 +1,7 @@
 import { useCallback } from 'react'
 import type { MutationHook } from '@commerce/utils/types'
 import { CommerceError } from '@commerce/utils/errors'
-import useSignup, { UseSignup } from '@commerce/use-signup'
+import useSignup, { UseSignup } from '@commerce/auth/use-signup'
 import type { SignupBody } from '../api/customers/signup'
 import useCustomer from '../customer/use-customer'
 
diff --git a/framework/bigcommerce/next.config.js b/framework/bigcommerce/next.config.js
new file mode 100644
index 000000000..e732ef78a
--- /dev/null
+++ b/framework/bigcommerce/next.config.js
@@ -0,0 +1,37 @@
+module.exports = {
+  images: {
+    domains: ['cdn11.bigcommerce.com'],
+  },
+  i18n: {
+    locales: ['en-US', 'es'],
+    defaultLocale: 'en-US',
+  },
+  rewrites() {
+    return [
+      {
+        source: '/checkout',
+        destination: '/api/bigcommerce/checkout',
+      },
+      // The logout is also an action so this route is not required, but it's also another way
+      // you can allow a logout!
+      {
+        source: '/logout',
+        destination: '/api/bigcommerce/customers/logout?redirect_to=/',
+      },
+      // Rewrites for /search
+      {
+        source: '/search/designers/:name',
+        destination: '/search',
+      },
+      {
+        source: '/search/designers/:name/:category',
+        destination: '/search',
+      },
+      {
+        // This rewrite will also handle `/search/designers`
+        source: '/search/:category',
+        destination: '/search',
+      },
+    ]
+  },
+}
diff --git a/framework/bigcommerce/product/use-price.tsx b/framework/bigcommerce/product/use-price.tsx
index a79940a76..0174faf5e 100644
--- a/framework/bigcommerce/product/use-price.tsx
+++ b/framework/bigcommerce/product/use-price.tsx
@@ -1,2 +1,2 @@
-export * from '@commerce/use-price'
-export { default } from '@commerce/use-price'
+export * from '@commerce/product/use-price'
+export { default } from '@commerce/product/use-price'
diff --git a/framework/commerce/use-login.tsx b/framework/commerce/auth/use-login.tsx
similarity index 64%
rename from framework/commerce/use-login.tsx
rename to framework/commerce/auth/use-login.tsx
index 755e10fd9..cc4cf6a73 100644
--- a/framework/commerce/use-login.tsx
+++ b/framework/commerce/auth/use-login.tsx
@@ -1,7 +1,7 @@
-import { useHook, useMutationHook } from './utils/use-hook'
-import { mutationFetcher } from './utils/default-fetcher'
-import type { MutationHook, HookFetcherFn } from './utils/types'
-import type { Provider } from '.'
+import { useHook, useMutationHook } from '../utils/use-hook'
+import { mutationFetcher } from '../utils/default-fetcher'
+import type { MutationHook, HookFetcherFn } from '../utils/types'
+import type { Provider } from '..'
 
 export type UseLogin<
   H extends MutationHook<any, any, any> = MutationHook<null, {}, {}>
diff --git a/framework/commerce/use-logout.tsx b/framework/commerce/auth/use-logout.tsx
similarity index 64%
rename from framework/commerce/use-logout.tsx
rename to framework/commerce/auth/use-logout.tsx
index 0a80c318b..d0f7e3ae0 100644
--- a/framework/commerce/use-logout.tsx
+++ b/framework/commerce/auth/use-logout.tsx
@@ -1,7 +1,7 @@
-import { useHook, useMutationHook } from './utils/use-hook'
-import { mutationFetcher } from './utils/default-fetcher'
-import type { HookFetcherFn, MutationHook } from './utils/types'
-import type { Provider } from '.'
+import { useHook, useMutationHook } from '../utils/use-hook'
+import { mutationFetcher } from '../utils/default-fetcher'
+import type { HookFetcherFn, MutationHook } from '../utils/types'
+import type { Provider } from '..'
 
 export type UseLogout<
   H extends MutationHook<any, any, any> = MutationHook<null>
diff --git a/framework/commerce/use-signup.tsx b/framework/commerce/auth/use-signup.tsx
similarity index 64%
rename from framework/commerce/use-signup.tsx
rename to framework/commerce/auth/use-signup.tsx
index be3c32000..72e242209 100644
--- a/framework/commerce/use-signup.tsx
+++ b/framework/commerce/auth/use-signup.tsx
@@ -1,7 +1,7 @@
-import { useHook, useMutationHook } from './utils/use-hook'
-import { mutationFetcher } from './utils/default-fetcher'
-import type { HookFetcherFn, MutationHook } from './utils/types'
-import type { Provider } from '.'
+import { useHook, useMutationHook } from '../utils/use-hook'
+import { mutationFetcher } from '../utils/default-fetcher'
+import type { HookFetcherFn, MutationHook } from '../utils/types'
+import type { Provider } from '..'
 
 export type UseSignup<
   H extends MutationHook<any, any, any> = MutationHook<null>
diff --git a/framework/commerce/config.json b/framework/commerce/config.json
deleted file mode 100644
index a0e7afc5d..000000000
--- a/framework/commerce/config.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-  "features": {
-    "wishlist": true
-  }
-}
diff --git a/framework/commerce/use-price.tsx b/framework/commerce/product/use-price.tsx
similarity index 97%
rename from framework/commerce/use-price.tsx
rename to framework/commerce/product/use-price.tsx
index 9a3fc4b6e..9c09e3487 100644
--- a/framework/commerce/use-price.tsx
+++ b/framework/commerce/product/use-price.tsx
@@ -1,5 +1,5 @@
 import { useMemo } from 'react'
-import { useCommerce } from '.'
+import { useCommerce } from '..'
 
 export function formatPrice({
   amount,
diff --git a/framework/commerce/types.ts b/framework/commerce/types.ts
index 0ae766095..57e707f35 100644
--- a/framework/commerce/types.ts
+++ b/framework/commerce/types.ts
@@ -2,8 +2,10 @@ import type { Wishlist as BCWishlist } from '@framework/api/wishlist'
 import type { Customer as BCCustomer } from '@framework/api/customers'
 import type { SearchProductsData as BCSearchProductsData } from '@framework/api/catalog/products'
 
+export type Features = 'wishlist' | 'checkout' | string
+
 export type CommerceProviderConfig = {
-  features: Record<string, boolean>
+  features: Record<Features, boolean>
 }
 
 export type Discount = {
diff --git a/framework/commerce/utils/bootstrap.js b/framework/commerce/utils/bootstrap.js
new file mode 100644
index 000000000..6a604b7dd
--- /dev/null
+++ b/framework/commerce/utils/bootstrap.js
@@ -0,0 +1,11 @@
+module.exports = ({ features }) => {
+  let output = {
+    env: {},
+  }
+  if (!!Object.keys(features).length) {
+    Object.keys(features).map(
+      (r) => (output.env[`COMMERCE_${r.toUpperCase()}_ENABLED`] = features[r])
+    )
+  }
+  return output
+}
diff --git a/framework/commerce/utils/features.ts b/framework/commerce/utils/features.ts
index 98a53ed54..72ed0d7f5 100644
--- a/framework/commerce/utils/features.ts
+++ b/framework/commerce/utils/features.ts
@@ -14,6 +14,16 @@ function isFeatureEnabled(config: CommerceProviderConfig) {
       .includes(desideredFeature)
 }
 
+export function toEnvConfig(
+  configMap: CommerceProviderConfig['features']
+): Map<string, boolean> {
+  let toEnvConfigMap = new Map<string, boolean>()
+  Object.keys(configMap).map((r) =>
+    toEnvConfigMap.set(`${r.toUpperCase()}_ENABLED`, configMap[r])
+  )
+  return toEnvConfigMap
+}
+
 function boostrap(): FeaturesAPI {
   const basis = {
     isEnabled: () => false,
diff --git a/next.config.js b/next.config.js
index 939031884..749fd1b0a 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,40 +1,6 @@
-module.exports = {
-  images: {
-    domains: ['cdn11.bigcommerce.com'],
-  },
-  i18n: {
-    locales: ['en-US', 'es'],
-    defaultLocale: 'en-US',
-  },
-  env: {
-    WISHLIST_ENABLED: false,
-  },
-  rewrites() {
-    return [
-      {
-        source: '/checkout',
-        destination: '/api/bigcommerce/checkout',
-      },
-      // The logout is also an action so this route is not required, but it's also another way
-      // you can allow a logout!
-      {
-        source: '/logout',
-        destination: '/api/bigcommerce/customers/logout?redirect_to=/',
-      },
-      // Rewrites for /search
-      {
-        source: '/search/designers/:name',
-        destination: '/search',
-      },
-      {
-        source: '/search/designers/:name/:category',
-        destination: '/search',
-      },
-      {
-        // This rewrite will also handle `/search/designers`
-        source: '/search/:category',
-        destination: '/search',
-      },
-    ]
-  },
-}
+const providerConfig = require('./framework/bigcommerce/config.json')
+const providerNextConfig = require('./framework/bigcommerce/next.config')
+const bootstrap = require('./framework/commerce/utils/bootstrap')
+const d = require('deepmerge')
+
+module.exports = d(providerNextConfig, bootstrap(providerConfig))
diff --git a/package.json b/package.json
index d1bfbb574..8a7d64e6a 100644
--- a/package.json
+++ b/package.json
@@ -66,6 +66,7 @@
     "@types/lodash.throttle": "^4.1.6",
     "@types/node": "^14.14.16",
     "@types/react": "^17.0.0",
+    "deepmerge": "^4.2.2",
     "graphql": "^15.4.0",
     "husky": "^4.3.8",
     "lint-staged": "^10.5.3",
diff --git a/pages/wishlist.tsx b/pages/wishlist.tsx
index dcda912c6..ce97532b0 100644
--- a/pages/wishlist.tsx
+++ b/pages/wishlist.tsx
@@ -17,7 +17,7 @@ export async function getStaticProps({
   locale,
 }: GetStaticPropsContext) {
   // Disabling page if Feature is not available
-  if (!process.env.WISHLIST_ENABLED) {
+  if (!process.env.COMMERCE_WISHLIST_ENABLED) {
     return {
       notFound: true,
     }
diff --git a/yarn.lock b/yarn.lock
index e7cd08438..3497602b9 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2532,6 +2532,11 @@ deep-is@~0.1.3:
   resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
   integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
 
+deepmerge@^4.2.2:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955"
+  integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==
+
 defaults@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d"

From 4de9b906f4f15db74a792cd1fa743f56ea92767b Mon Sep 17 00:00:00 2001
From: okbel <curciobel@gmail.com>
Date: Wed, 24 Feb 2021 19:32:03 -0300
Subject: [PATCH 11/11] typos

---
 framework/bigcommerce/config.json           | 2 +-
 framework/shopify/api/index.ts              | 2 +-
 framework/shopify/customer/use-customer.tsx | 2 +-
 framework/shopify/product/use-search.tsx    | 2 +-
 package.json                                | 1 +
 yarn.lock                                   | 5 +++++
 6 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/framework/bigcommerce/config.json b/framework/bigcommerce/config.json
index 17ef37e25..a0e7afc5d 100644
--- a/framework/bigcommerce/config.json
+++ b/framework/bigcommerce/config.json
@@ -1,5 +1,5 @@
 {
   "features": {
-    "wishlist": false
+    "wishlist": true
   }
 }
diff --git a/framework/shopify/api/index.ts b/framework/shopify/api/index.ts
index dcb0fc2ba..0402cfccc 100644
--- a/framework/shopify/api/index.ts
+++ b/framework/shopify/api/index.ts
@@ -3,7 +3,7 @@ import fetchGraphqlApi from './utils/fetch-graphql-api'
 
 export interface ShopifyConfig extends CommerceAPIConfig {}
 
-// No I don't like this - will fix it later
+// TODO(bc)
 const API_URL =
   process.env.SHOPIFY_STORE_DOMAIN ||
   process.env.NEXT_PUBLIC_SHOPIFY_STORE_DOMAIN
diff --git a/framework/shopify/customer/use-customer.tsx b/framework/shopify/customer/use-customer.tsx
index a909443ff..7ea2ae679 100644
--- a/framework/shopify/customer/use-customer.tsx
+++ b/framework/shopify/customer/use-customer.tsx
@@ -1,6 +1,6 @@
 import type { HookFetcher } from '@commerce/utils/types'
 import type { SwrOptions } from '@commerce/utils/use-data'
-import useCommerceCustomer from '@commerce/use-customer'
+import useCommerceCustomer from '@commerce/customer/use-customer'
 
 const defaultOpts = {}
 
diff --git a/framework/shopify/product/use-search.tsx b/framework/shopify/product/use-search.tsx
index a2c32c896..04f6a3536 100644
--- a/framework/shopify/product/use-search.tsx
+++ b/framework/shopify/product/use-search.tsx
@@ -1,6 +1,6 @@
 import type { HookFetcher } from '@commerce/utils/types'
 import type { SwrOptions } from '@commerce/utils/use-data'
-import useCommerceSearch from '@commerce/products/use-search'
+import useCommerceSearch from '@commerce/product/use-search'
 import { ProductEdge } from '../types'
 
 const defaultOpts = {}
diff --git a/package.json b/package.json
index 8a7d64e6a..85bd9c063 100644
--- a/package.json
+++ b/package.json
@@ -46,6 +46,7 @@
     "react-dom": "^17.0.1",
     "react-merge-refs": "^1.1.0",
     "react-ticker": "^1.2.2",
+    "shopify-buy": "^2.11.0",
     "swr": "^0.4.0",
     "tabbable": "^5.1.5",
     "tailwindcss": "^2.0.2"
diff --git a/yarn.lock b/yarn.lock
index 3497602b9..1255b9d62 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6226,6 +6226,11 @@ shell-quote@1.7.2:
   resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
   integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==
 
+shopify-buy@^2.11.0:
+  version "2.11.0"
+  resolved "https://registry.yarnpkg.com/shopify-buy/-/shopify-buy-2.11.0.tgz#0f7cb52741395e4ae778c336f32ddf3fe67c2f35"
+  integrity sha512-bGjS1b/VCPvCjazSstlKwgLtK1WBotWom06/12loja8yfo/cWkLuJsakBbQe1uEIDiOLhKaR0M0CAXZFheYDug==
+
 signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.3"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"