diff --git a/.env.template b/.env.template
index 73a8a6e3b..9b45afe4b 100644
--- a/.env.template
+++ b/.env.template
@@ -2,4 +2,8 @@ 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=
+BIGCOMMERCE_CHANNEL_ID=
+
+SHOPIFY_STORE_DOMAIN=
+SHOPIFY_STOREFRONT_ACCESS_TOKEN=
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 000000000..e1076edfa
--- /dev/null
+++ b/.prettierrc
@@ -0,0 +1,6 @@
+{
+ "semi": false,
+ "singleQuote": true,
+ "tabWidth": 2,
+ "useTabs": false
+}
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/README.md b/README.md
index 8eb69383c..885c95e85 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,8 @@ Start right now at [nextjs.org/commerce](https://nextjs.org/commerce)
Demo live at: [demo.vercel.store](https://demo.vercel.store/)
-This project is currently under development.
+- Shopify Demo: https://shopify.demo.vercel.store/
+- BigCommerce Demo: https://bigcommerce.demo.vercel.store/
## Features
@@ -21,26 +22,122 @@ This project is currently under development.
- Integrations - Integrate seamlessly with the most common ecommerce platforms.
- Dark Mode Support
+## Integrations
+
+Next.js Commerce integrates out-of-the-box with BigCommerce and Shopify. We plan to support all major ecommerce backends.
+
+## Considerations
+
+- `framework/commerce` contains all types, helpers and functions to be used as base to build a new **provider**.
+- **Providers** live under `framework`'s root folder and they will extend Next.js Commerce types and functionality.
+- **Features API** is to ensure feature parity between the UI and the Provider. The UI should update accordingly and no extra code should be bundled. All extra configuration for features will live under `features` in `commerce.config.json` and if needed it can also be accessed programatically.
+- Each **provider** should add its corresponding `next.config.js` and `commerce.config.json` adding specific data related to the provider. For example in case of BigCommerce, the images CDN and additional API routes.
+- **Providers don't depend on anything that's specific to the application they're used in**. They only depend on `framework/commerce`, on their own framework folder and on some dependencies included in `package.json`
+- We recommend that each **provider** ships with an `env.template` file and a `[readme.md](http://readme.md)` file.
+
+## Provider Structure
+
+Next.js Commerce provides a set of utilities and functions to create new providers. This is how a provider structure looks like.
+
+- `product`
+ - usePrice
+ - useSearch
+ - getProduct
+ - getAllProducts
+- `wishlist`
+ - useWishlist
+ - useAddItem
+ - useRemoveItem
+- `auth`
+ - useLogin
+ - useLogout
+ - useSignup
+- `customer`
+ - useCustomer
+ - getCustomerId
+ - getCustomerWistlist
+- `cart`
+ - useCart
+ - useAddItem
+ - useRemoveItem
+ - useUpdateItem
+- `env.template`
+- `provider.ts`
+- `commerce.config.json`
+- `next.config.js`
+- `README.md`
+
+## Configuration
+
+### How to change providers
+
+First, update the provider selected in `commerce.config.json`:
+
+```json
+{
+ "provider": "bigcommerce",
+ "features": {
+ "wishlist": true
+ }
+}
+```
+
+Then, change the paths defined in `tsconfig.json` and update the `@framework` paths to point to the right folder provider:
+
+```json
+"@framework": ["framework/bigcommerce"],
+"@framework/*": ["framework/bigcommerce/*"]
+```
+
+Make sure to add the environment variables required by the new provider.
+
+### Features
+
+Every provider defines the features that it supports under `framework/{provider}/commerce.config.json`
+
+#### How to turn Features on and off
+
+> NOTE: The selected provider should support the feature that you are toggling. (This means that you can't turn wishlist on if the provider doesn't support this functionality out the box)
+
+- Open `commerce.config.json`
+- You'll see a config file like this:
+ ```json
+ {
+ "provider": "bigcommerce",
+ "features": {
+ "wishlist": false
+ }
+ }
+ ```
+- Turn wishlist on by setting wishlist to true.
+- Run the app and the wishlist functionality should be back on.
+
+### How to create a new provider
+
+We'd recommend to duplicate a provider folder and push your providers SDK.
+
+If you succeeded building a provider, submit a PR so we can all enjoy it.
+
## Work in progress
+
We're using Github Projects to keep track of issues in progress and todo's. Here is our [Board](https://github.com/vercel/commerce/projects/1)
-## Integrations
-Next.js Commerce integrates out-of-the-box with BigCommerce. We plan to support all major ecommerce backends.
-
-
-## Goals
-
-* **Next.js Commerce** should have a completely data **agnostic** UI
-* **Aware of schema**: should ship with the right data schemas and types.
-* All providers should return the right data types and schemas to blend correctly with Next.js Commerce.
-* `@framework` will be the alias utilized in commerce and it will map to the ecommerce provider of preference- e.g BigCommerce, Shopify, Swell. All providers should expose the same standardized functions. _Note that the same applies for recipes using a CMS + an ecommerce provider._
-
-There is a `framework` folder in the root folder that will contain multiple ecommerce providers.
-
-Additionally, we need to ensure feature parity (not all providers have e.g. wishlist) we will also have to build a feature API to disable/enable features in the UI.
-
People actively working on this project: @okbel & @lfades.
+## Contribute
+
+Our commitment to Open Source can be found [here](https://vercel.com/oss).
+
+1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device.
+2. Create a new branch `git checkout -b MY_BRANCH_NAME`
+3. Install yarn: `npm install -g yarn`
+4. Install the dependencies: `yarn`
+5. Duplicate `.env.template` and rename it to `.env.local`.
+6. Add proper store values to `.env.local`.
+7. Run `yarn dev` to build and watch for code changes
+8. The development branch is `canary` (this is the branch pull requests should be made against).
+ On a release, `canary` branch is rebased into `master`.
+
## Troubleshoot
@@ -57,6 +154,7 @@ BIGCOMMERCE_STOREFRONT_API_TOKEN=<>
BIGCOMMERCE_STORE_API_URL=<>
BIGCOMMERCE_STORE_API_TOKEN=<>
BIGCOMMERCE_STORE_API_CLIENT_ID=<>
+BIGCOMMERCE_CHANNEL_ID=<>
```
If your project was started with a "Deploy with Vercel" button, you can use Vercel's CLI to retrieve these credentials.
@@ -77,22 +175,3 @@ After Email confirmation, Checkout should be manually enabled through BigCommerc
BigCommerce team has been notified and they plan to add more detailed about this subject.
-
-## Contribute
-
-Our commitment to Open Source can be found [here](https://vercel.com/oss).
-
-1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device.
-2. Create a new branch `git checkout -b MY_BRANCH_NAME`
-3. Install yarn: `npm install -g yarn`
-4. Install the dependencies: `yarn`
-5. Duplicate `.env.template` and rename it to `.env.local`.
-6. Add proper store values to `.env.local`.
-7. Run `yarn dev` to build and watch for code changes
-8. The development branch is `canary` (this is the branch pull requests should be made against).
- On a release, `canary` branch is rebased into `master`.
-
-
-
-
-
diff --git a/commerce.config.json b/commerce.config.json
new file mode 100644
index 000000000..bef7db222
--- /dev/null
+++ b/commerce.config.json
@@ -0,0 +1,7 @@
+{
+ "provider": "bigcommerce",
+ "features": {
+ "wishlist": true,
+ "customCheckout": false
+ }
+}
diff --git a/components/auth/LoginView.tsx b/components/auth/LoginView.tsx
index 9102a53c6..89d5bf893 100644
--- a/components/auth/LoginView.tsx
+++ b/components/auth/LoginView.tsx
@@ -1,6 +1,6 @@
import { FC, useEffect, useState, useCallback } from 'react'
import { Logo, Button, Input } from '@components/ui'
-import useLogin from '@framework/use-login'
+import useLogin from '@framework/auth/use-login'
import { useUI } from '@components/ui/context'
import { validate } from 'email-validator'
diff --git a/components/auth/SignUpView.tsx b/components/auth/SignUpView.tsx
index c49637d47..1b619828b 100644
--- a/components/auth/SignUpView.tsx
+++ b/components/auth/SignUpView.tsx
@@ -3,7 +3,7 @@ import { validate } from 'email-validator'
import { Info } from '@components/icons'
import { useUI } from '@components/ui/context'
import { Logo, Button, Input } from '@components/ui'
-import useSignup from '@framework/use-signup'
+import useSignup from '@framework/auth/use-signup'
interface Props {}
diff --git a/components/cart/CartItem/CartItem.tsx b/components/cart/CartItem/CartItem.tsx
index 2769ac715..cb7f8600e 100644
--- a/components/cart/CartItem/CartItem.tsx
+++ b/components/cart/CartItem/CartItem.tsx
@@ -2,43 +2,51 @@ import { ChangeEvent, useEffect, useState } from 'react'
import cn from 'classnames'
import Image from 'next/image'
import Link from 'next/link'
+import s from './CartItem.module.css'
import { Trash, Plus, Minus } from '@components/icons'
-import usePrice from '@framework/use-price'
+import { useUI } from '@components/ui/context'
+import type { LineItem } from '@framework/types'
+import usePrice from '@framework/product/use-price'
import useUpdateItem from '@framework/cart/use-update-item'
import useRemoveItem from '@framework/cart/use-remove-item'
-import s from './CartItem.module.css'
type ItemOption = {
- name: string,
- nameId: number,
- value: string,
+ name: string
+ nameId: number
+ value: string
valueId: number
}
const CartItem = ({
item,
currencyCode,
+ ...rest
}: {
- item: any
+ item: LineItem
currencyCode: string
}) => {
+ const { closeSidebarIfPresent } = useUI()
+
const { price } = usePrice({
- amount: item.extended_sale_price,
- baseAmount: item.extended_list_price,
+ amount: item.variant.price * item.quantity,
+ baseAmount: item.variant.listPrice * item.quantity,
currencyCode,
})
- const updateItem = useUpdateItem(item)
+
+ const updateItem = useUpdateItem({ item })
const removeItem = useRemoveItem()
const [quantity, setQuantity] = useState(item.quantity)
const [removing, setRemoving] = useState(false)
+
const updateQuantity = async (val: number) => {
await updateItem({ quantity: val })
}
+
const handleQuantity = (e: ChangeEvent) => {
const val = Number(e.target.value)
if (Number.isInteger(val) && val >= 0) {
- setQuantity(e.target.value)
+ setQuantity(Number(e.target.value))
}
}
const handleBlur = () => {
@@ -62,11 +70,13 @@ const CartItem = ({
try {
// If this action succeeds then there's no need to do `setRemoving(true)`
// because the component will be removed from the view
- await removeItem({ id: item.id })
+ await removeItem(item)
} catch (error) {
setRemoving(false)
}
}
+ // TODO: Add a type for this
+ const options = (item as any).options
useEffect(() => {
// Reset the quantity state if the item quantity changes
@@ -80,32 +90,38 @@ const CartItem = ({
className={cn('flex flex-row space-x-8 py-8', {
'opacity-75 pointer-events-none': removing,
})}
+ {...rest}
>