forked from crowetic/commerce
Merge branch 'agnostic' of https://github.com/vercel/commerce into agnostic
This commit is contained in:
commit
7005e45b09
118
README.md
118
README.md
@ -42,57 +42,6 @@ Additionally, we need to ensure feature parity (not all providers have e.g. wish
|
|||||||
|
|
||||||
People actively working on this project: @okbel & @lfades.
|
People actively working on this project: @okbel & @lfades.
|
||||||
|
|
||||||
## Troubleshoot
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>I already own a BigCommerce store. What should I do?</summary>
|
|
||||||
<br>
|
|
||||||
First thing you do is: <b>set your environment variables</b>
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
```sh
|
|
||||||
BIGCOMMERCE_STOREFRONT_API_URL=<>
|
|
||||||
BIGCOMMERCE_STOREFRONT_API_TOKEN=<>
|
|
||||||
BIGCOMMERCE_STORE_API_URL=<>
|
|
||||||
BIGCOMMERCE_STORE_API_TOKEN=<>
|
|
||||||
BIGCOMMERCE_STORE_API_CLIENT_ID=<>
|
|
||||||
```
|
|
||||||
|
|
||||||
If your project was started with a "Deploy with Vercel" button, you can use Vercel's CLI to retrieve these credentials.
|
|
||||||
|
|
||||||
1. Install Vercel CLI: `npm i -g vercel`
|
|
||||||
2. Link local instance with Vercel and Github accounts (creates .vercel file): `vercel link`
|
|
||||||
3. Download your environment variables: `vercel env pull .env.local`
|
|
||||||
|
|
||||||
Next, you're free to customize the starter. More updates coming soon. Stay tuned.
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>BigCommerce shows a Coming Soon page and requests a Preview Code</summary>
|
|
||||||
<br>
|
|
||||||
After Email confirmation, Checkout should be manually enabled through BigCommerce platform. Look for "Review & test your store" section through BigCommerce's dashboard.
|
|
||||||
<br>
|
|
||||||
<br>
|
|
||||||
BigCommerce team has been notified and they plan to add more detailed about this subject.
|
|
||||||
</details>
|
|
||||||
|
|
||||||
## 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`.
|
|
||||||
|
|
||||||
## Framework
|
## Framework
|
||||||
|
|
||||||
Framework is where the data comes from. It contains mostly hooks and functions.
|
Framework is where the data comes from. It contains mostly hooks and functions.
|
||||||
@ -132,3 +81,70 @@ import { useUI } from '@components/ui'
|
|||||||
import { useCustomer } from '@framework/customer'
|
import { useCustomer } from '@framework/customer'
|
||||||
import { useAddItem, useWishlist, useRemoveItem } from '@framework/wishlist'
|
import { useAddItem, useWishlist, useRemoveItem } from '@framework/wishlist'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Config
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
In order to make the UI entirely functional, we need to specify which features certain providers do not **provide**.
|
||||||
|
|
||||||
|
**Disabling wishlist:**
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"wishlist": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>I already own a BigCommerce store. What should I do?</summary>
|
||||||
|
<br>
|
||||||
|
First thing you do is: <b>set your environment variables</b>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
```sh
|
||||||
|
BIGCOMMERCE_STOREFRONT_API_URL=<>
|
||||||
|
BIGCOMMERCE_STOREFRONT_API_TOKEN=<>
|
||||||
|
BIGCOMMERCE_STORE_API_URL=<>
|
||||||
|
BIGCOMMERCE_STORE_API_TOKEN=<>
|
||||||
|
BIGCOMMERCE_STORE_API_CLIENT_ID=<>
|
||||||
|
```
|
||||||
|
|
||||||
|
If your project was started with a "Deploy with Vercel" button, you can use Vercel's CLI to retrieve these credentials.
|
||||||
|
|
||||||
|
1. Install Vercel CLI: `npm i -g vercel`
|
||||||
|
2. Link local instance with Vercel and Github accounts (creates .vercel file): `vercel link`
|
||||||
|
3. Download your environment variables: `vercel env pull .env.local`
|
||||||
|
|
||||||
|
Next, you're free to customize the starter. More updates coming soon. Stay tuned.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>BigCommerce shows a Coming Soon page and requests a Preview Code</summary>
|
||||||
|
<br>
|
||||||
|
After Email confirmation, Checkout should be manually enabled through BigCommerce platform. Look for "Review & test your store" section through BigCommerce's dashboard.
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
BigCommerce team has been notified and they plan to add more detailed about this subject.
|
||||||
|
</details>
|
||||||
|
@ -9,7 +9,7 @@ import usePrice from '@framework/product/use-price'
|
|||||||
import CartItem from '../CartItem'
|
import CartItem from '../CartItem'
|
||||||
import s from './CartSidebarView.module.css'
|
import s from './CartSidebarView.module.css'
|
||||||
|
|
||||||
const CartSidebarView: FC = () => {
|
const CartSidebarView: FC<{ wishlist?: boolean }> = ({ wishlist }) => {
|
||||||
const { closeSidebar } = useUI()
|
const { closeSidebar } = useUI()
|
||||||
const { data, isLoading, isEmpty } = useCart()
|
const { data, isLoading, isEmpty } = useCart()
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ const CartSidebarView: FC = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<UserNav className="" />
|
<UserNav wishlist={wishlist} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
@ -5,14 +5,21 @@ import { Grid } from '@components/ui'
|
|||||||
import { ProductCard } from '@components/product'
|
import { ProductCard } from '@components/product'
|
||||||
import s from './HomeAllProductsGrid.module.css'
|
import s from './HomeAllProductsGrid.module.css'
|
||||||
import { getCategoryPath, getDesignerPath } from '@lib/search'
|
import { getCategoryPath, getDesignerPath } from '@lib/search'
|
||||||
|
import wishlist from '@framework/api/wishlist'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
categories?: any
|
categories?: any
|
||||||
brands?: any
|
brands?: any
|
||||||
products?: Product[]
|
products?: Product[]
|
||||||
|
wishlist?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const Head: FC<Props> = ({ categories, brands, products = [] }) => {
|
const HomeAllProductsGrid: FC<Props> = ({
|
||||||
|
categories,
|
||||||
|
brands,
|
||||||
|
products = [],
|
||||||
|
wishlist = false,
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={s.root}>
|
<div className={s.root}>
|
||||||
<div className={s.asideWrapper}>
|
<div className={s.asideWrapper}>
|
||||||
@ -58,6 +65,7 @@ const Head: FC<Props> = ({ categories, brands, products = [] }) => {
|
|||||||
width: 480,
|
width: 480,
|
||||||
height: 480,
|
height: 480,
|
||||||
}}
|
}}
|
||||||
|
wishlist={wishlist}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -66,4 +74,4 @@ const Head: FC<Props> = ({ categories, brands, products = [] }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Head
|
export default HomeAllProductsGrid
|
||||||
|
@ -41,10 +41,14 @@ const FeatureBar = dynamic(
|
|||||||
interface Props {
|
interface Props {
|
||||||
pageProps: {
|
pageProps: {
|
||||||
pages?: Page[]
|
pages?: Page[]
|
||||||
|
commerceFeatures: Record<string, boolean>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Layout: FC<Props> = ({ children, pageProps }) => {
|
const Layout: FC<Props> = ({
|
||||||
|
children,
|
||||||
|
pageProps: { commerceFeatures, ...pageProps },
|
||||||
|
}) => {
|
||||||
const {
|
const {
|
||||||
displaySidebar,
|
displaySidebar,
|
||||||
displayModal,
|
displayModal,
|
||||||
@ -54,11 +58,11 @@ const Layout: FC<Props> = ({ children, pageProps }) => {
|
|||||||
} = useUI()
|
} = useUI()
|
||||||
const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
|
const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
|
||||||
const { locale = 'en-US' } = useRouter()
|
const { locale = 'en-US' } = useRouter()
|
||||||
|
const isWishlistEnabled = commerceFeatures.wishlist
|
||||||
return (
|
return (
|
||||||
<CommerceProvider locale={locale}>
|
<CommerceProvider locale={locale}>
|
||||||
<div className={cn(s.root)}>
|
<div className={cn(s.root)}>
|
||||||
<Navbar />
|
<Navbar wishlist={isWishlistEnabled} />
|
||||||
<main className="fit">{children}</main>
|
<main className="fit">{children}</main>
|
||||||
<Footer pages={pageProps.pages} />
|
<Footer pages={pageProps.pages} />
|
||||||
|
|
||||||
@ -69,7 +73,7 @@ const Layout: FC<Props> = ({ children, pageProps }) => {
|
|||||||
</Modal>
|
</Modal>
|
||||||
|
|
||||||
<Sidebar open={displaySidebar} onClose={closeSidebar}>
|
<Sidebar open={displaySidebar} onClose={closeSidebar}>
|
||||||
<CartSidebarView />
|
<CartSidebarView wishlist={isWishlistEnabled} />
|
||||||
</Sidebar>
|
</Sidebar>
|
||||||
|
|
||||||
<FeatureBar
|
<FeatureBar
|
||||||
|
@ -5,7 +5,7 @@ import { Searchbar, UserNav } from '@components/common'
|
|||||||
import NavbarRoot from './NavbarRoot'
|
import NavbarRoot from './NavbarRoot'
|
||||||
import s from './Navbar.module.css'
|
import s from './Navbar.module.css'
|
||||||
|
|
||||||
const Navbar: FC = () => (
|
const Navbar: FC<{ wishlist?: boolean }> = ({ wishlist }) => (
|
||||||
<NavbarRoot>
|
<NavbarRoot>
|
||||||
<Container>
|
<Container>
|
||||||
<div className="relative flex flex-row justify-between py-4 align-center md:py-6">
|
<div className="relative flex flex-row justify-between py-4 align-center md:py-6">
|
||||||
@ -33,7 +33,7 @@ const Navbar: FC = () => (
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex justify-end flex-1 space-x-8">
|
<div className="flex justify-end flex-1 space-x-8">
|
||||||
<UserNav />
|
<UserNav wishlist={wishlist} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -12,11 +12,12 @@ import { Avatar } from '@components/common'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
|
wishlist?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const countItem = (count: number, item: LineItem) => count + item.quantity
|
const countItem = (count: number, item: LineItem) => count + item.quantity
|
||||||
|
|
||||||
const UserNav: FC<Props> = ({ className }) => {
|
const UserNav: FC<Props> = ({ className, wishlist = false }) => {
|
||||||
const { data } = useCart()
|
const { data } = useCart()
|
||||||
const { data: customer } = useCustomer()
|
const { data: customer } = useCustomer()
|
||||||
const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI()
|
const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI()
|
||||||
@ -30,6 +31,7 @@ const UserNav: FC<Props> = ({ className }) => {
|
|||||||
<Bag />
|
<Bag />
|
||||||
{itemsCount > 0 && <span className={s.bagCount}>{itemsCount}</span>}
|
{itemsCount > 0 && <span className={s.bagCount}>{itemsCount}</span>}
|
||||||
</li>
|
</li>
|
||||||
|
{wishlist && (
|
||||||
<li className={s.item}>
|
<li className={s.item}>
|
||||||
<Link href="/wishlist">
|
<Link href="/wishlist">
|
||||||
<a onClick={closeSidebarIfPresent} aria-label="Wishlist">
|
<a onClick={closeSidebarIfPresent} aria-label="Wishlist">
|
||||||
@ -37,6 +39,7 @@ const UserNav: FC<Props> = ({ className }) => {
|
|||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
)}
|
||||||
<li className={s.item}>
|
<li className={s.item}>
|
||||||
{customer ? (
|
{customer ? (
|
||||||
<DropdownMenu />
|
<DropdownMenu />
|
||||||
|
@ -4,13 +4,14 @@ import Link from 'next/link'
|
|||||||
import type { Product } from '@commerce/types'
|
import type { Product } from '@commerce/types'
|
||||||
import s from './ProductCard.module.css'
|
import s from './ProductCard.module.css'
|
||||||
import Image, { ImageProps } from 'next/image'
|
import Image, { ImageProps } from 'next/image'
|
||||||
// import WishlistButton from '@components/wishlist/WishlistButton'
|
import WishlistButton from '@components/wishlist/WishlistButton'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
product: Product
|
product: Product
|
||||||
variant?: 'slim' | 'simple'
|
variant?: 'slim' | 'simple'
|
||||||
imgProps?: Omit<ImageProps, 'src'>
|
imgProps?: Omit<ImageProps, 'src'>
|
||||||
|
wishlist?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const placeholderImg = '/product-img-placeholder.svg'
|
const placeholderImg = '/product-img-placeholder.svg'
|
||||||
@ -20,6 +21,7 @@ const ProductCard: FC<Props> = ({
|
|||||||
product,
|
product,
|
||||||
variant,
|
variant,
|
||||||
imgProps,
|
imgProps,
|
||||||
|
wishlist = false,
|
||||||
...props
|
...props
|
||||||
}) => (
|
}) => (
|
||||||
<Link href={`/product/${product.slug}`} {...props}>
|
<Link href={`/product/${product.slug}`} {...props}>
|
||||||
@ -57,11 +59,13 @@ const ProductCard: FC<Props> = ({
|
|||||||
{product.price.currencyCode}
|
{product.price.currencyCode}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
{/* <WishlistButton
|
{wishlist && (
|
||||||
|
<WishlistButton
|
||||||
className={s.wishlistButton}
|
className={s.wishlistButton}
|
||||||
productId={product.id}
|
productId={product.id}
|
||||||
variant={product.variants[0]}
|
variant={product.variants[0]}
|
||||||
/> */}
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={s.imageContainer}>
|
<div className={s.imageContainer}>
|
||||||
{product?.images && (
|
{product?.images && (
|
||||||
|
@ -50,11 +50,13 @@ const ProductSlider: FC = ({ children }) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
if (sliderContainerRef.current) {
|
||||||
sliderContainerRef.current!.removeEventListener(
|
sliderContainerRef.current!.removeEventListener(
|
||||||
'touchstart',
|
'touchstart',
|
||||||
preventNavigation
|
preventNavigation
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -13,15 +13,16 @@ import usePrice from '@framework/product/use-price'
|
|||||||
import { useAddItem } from '@framework/cart'
|
import { useAddItem } from '@framework/cart'
|
||||||
|
|
||||||
import { getVariant, SelectedOptions } from '../helpers'
|
import { getVariant, SelectedOptions } from '../helpers'
|
||||||
// import WishlistButton from '@components/wishlist/WishlistButton'
|
import WishlistButton from '@components/wishlist/WishlistButton'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
children?: any
|
children?: any
|
||||||
product: Product
|
product: Product
|
||||||
|
wishlist?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductView: FC<Props> = ({ product }) => {
|
const ProductView: FC<Props> = ({ product, wishlist = false }) => {
|
||||||
const addItem = useAddItem()
|
const addItem = useAddItem()
|
||||||
const { price } = usePrice({
|
const { price } = usePrice({
|
||||||
amount: product.price.value,
|
amount: product.price.value,
|
||||||
@ -151,11 +152,13 @@ const ProductView: FC<Props> = ({ product }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* <WishlistButton
|
{wishlist && (
|
||||||
|
<WishlistButton
|
||||||
className={s.wishlistButton}
|
className={s.wishlistButton}
|
||||||
productId={product.id}
|
productId={product.id}
|
||||||
variant={product.variants[0]!}
|
variant={product.variants[0]!}
|
||||||
/> */}
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
|
1
components/wishlist/WishlistButton/index.ts
Normal file
1
components/wishlist/WishlistButton/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { default } from './WishlistButton'
|
@ -1 +1,2 @@
|
|||||||
export { default as WishlistCard } from './WishlistCard'
|
export { default as WishlistCard } from './WishlistCard'
|
||||||
|
export { default as WishlistButton } from './WishlistButton'
|
||||||
|
5
framework/bigcommerce/config.json
Normal file
5
framework/bigcommerce/config.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"wishlist": false
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { HookHandler } from '@commerce/utils/types'
|
import { HookHandler } from '@commerce/utils/types'
|
||||||
import useSearch, { UseSearch } from '@commerce/products/use-search'
|
import useSearch, { UseSearch } from '@commerce/product/use-search'
|
||||||
import type { SearchProductsData } from '../api/catalog/products'
|
import type { SearchProductsData } from '../api/catalog/products'
|
||||||
import type { BigcommerceProvider } from '..'
|
import type { BigcommerceProvider } from '..'
|
||||||
|
|
||||||
|
5
framework/commerce/config.json
Normal file
5
framework/commerce/config.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"features": {
|
||||||
|
"wishlist": true
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,10 @@ import type { Wishlist as BCWishlist } from '@framework/api/wishlist'
|
|||||||
import type { Customer as BCCustomer } from '@framework/api/customers'
|
import type { Customer as BCCustomer } from '@framework/api/customers'
|
||||||
import type { SearchProductsData as BCSearchProductsData } from '@framework/api/catalog/products'
|
import type { SearchProductsData as BCSearchProductsData } from '@framework/api/catalog/products'
|
||||||
|
|
||||||
|
export type CommerceProviderConfig = {
|
||||||
|
features: Record<string, boolean>
|
||||||
|
}
|
||||||
|
|
||||||
export type Discount = {
|
export type Discount = {
|
||||||
// The value of the discount, can be an amount or percentage
|
// The value of the discount, can be an amount or percentage
|
||||||
value: number
|
value: number
|
||||||
|
37
framework/commerce/utils/features.ts
Normal file
37
framework/commerce/utils/features.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import commerceProviderConfig from '@framework/config.json'
|
||||||
|
import type { CommerceProviderConfig } from '../types'
|
||||||
|
import memo from 'lodash.memoize'
|
||||||
|
|
||||||
|
type FeaturesAPI = {
|
||||||
|
isEnabled: (desideredFeature: string) => boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFeatureEnabled(config: CommerceProviderConfig) {
|
||||||
|
const features = config.features
|
||||||
|
return (desideredFeature: string) =>
|
||||||
|
Object.keys(features)
|
||||||
|
.filter((k) => features[k])
|
||||||
|
.includes(desideredFeature)
|
||||||
|
}
|
||||||
|
|
||||||
|
function boostrap(): FeaturesAPI {
|
||||||
|
const basis = {
|
||||||
|
isEnabled: () => false,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!commerceProviderConfig) {
|
||||||
|
console.log('No config.json found - Please add a config.json')
|
||||||
|
return basis
|
||||||
|
}
|
||||||
|
|
||||||
|
if (commerceProviderConfig.features) {
|
||||||
|
return {
|
||||||
|
...basis,
|
||||||
|
isEnabled: memo(isFeatureEnabled(commerceProviderConfig)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return basis
|
||||||
|
}
|
||||||
|
|
||||||
|
export default boostrap()
|
@ -21,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reach/portal": "^0.11.2",
|
"@reach/portal": "^0.11.2",
|
||||||
|
"@types/lodash.memoize": "^4.1.6",
|
||||||
"@vercel/fetch": "^6.1.0",
|
"@vercel/fetch": "^6.1.0",
|
||||||
"body-scroll-lock": "^3.1.5",
|
"body-scroll-lock": "^3.1.5",
|
||||||
"bowser": "^2.11.0",
|
"bowser": "^2.11.0",
|
||||||
@ -32,6 +33,7 @@
|
|||||||
"js-cookie": "^2.2.1",
|
"js-cookie": "^2.2.1",
|
||||||
"keen-slider": "^5.2.4",
|
"keen-slider": "^5.2.4",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
|
"lodash.memoize": "^4.1.2",
|
||||||
"lodash.random": "^3.2.0",
|
"lodash.random": "^3.2.0",
|
||||||
"lodash.throttle": "^4.1.1",
|
"lodash.throttle": "^4.1.1",
|
||||||
"next": "^10.0.7-canary.3",
|
"next": "^10.0.7-canary.3",
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import '@assets/main.css'
|
import '@assets/main.css'
|
||||||
import 'keen-slider/keen-slider.min.css'
|
|
||||||
import '@assets/chrome-bug.css'
|
import '@assets/chrome-bug.css'
|
||||||
|
import 'keen-slider/keen-slider.min.css'
|
||||||
|
|
||||||
import { FC, useEffect } from 'react'
|
import { FC, useEffect } from 'react'
|
||||||
import type { AppProps } from 'next/app'
|
import type { AppProps } from 'next/app'
|
||||||
|
|
||||||
import { ManagedUIContext } from '@components/ui/context'
|
|
||||||
import { Head } from '@components/common'
|
import { Head } from '@components/common'
|
||||||
|
import { ManagedUIContext } from '@components/ui/context'
|
||||||
|
|
||||||
const Noop: FC = ({ children }) => <>{children}</>
|
const Noop: FC = ({ children }) => <>{children}</>
|
||||||
|
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import { Layout } from '@components/common'
|
import { Layout } from '@components/common'
|
||||||
import { Grid, Marquee, Hero } from '@components/ui'
|
import { Grid, Marquee, Hero } from '@components/ui'
|
||||||
import { ProductCard } from '@components/product'
|
import { ProductCard } from '@components/product'
|
||||||
import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid'
|
// import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid'
|
||||||
import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
|
import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
|
||||||
|
|
||||||
import { getConfig } from '@framework/api'
|
import { getConfig } from '@framework/api'
|
||||||
import getAllProducts from '@framework/product/get-all-products'
|
import getAllProducts from '@framework/product/get-all-products'
|
||||||
import getSiteInfo from '@framework/common/get-site-info'
|
import getSiteInfo from '@framework/common/get-site-info'
|
||||||
import getAllPages from '@framework/common/get-all-pages'
|
import getAllPages from '@framework/common/get-all-pages'
|
||||||
|
import Features from '@commerce/utils/features'
|
||||||
|
|
||||||
export async function getStaticProps({
|
export async function getStaticProps({
|
||||||
preview,
|
preview,
|
||||||
@ -23,6 +24,7 @@ export async function getStaticProps({
|
|||||||
|
|
||||||
const { categories, brands } = await getSiteInfo({ config, preview })
|
const { categories, brands } = await getSiteInfo({ config, preview })
|
||||||
const { pages } = await getAllPages({ config, preview })
|
const { pages } = await getAllPages({ config, preview })
|
||||||
|
const isWishlistEnabled = Features.isEnabled('wishlist')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
@ -30,6 +32,9 @@ export async function getStaticProps({
|
|||||||
categories,
|
categories,
|
||||||
brands,
|
brands,
|
||||||
pages,
|
pages,
|
||||||
|
commerceFeatures: {
|
||||||
|
wishlist: isWishlistEnabled,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
revalidate: 14400,
|
revalidate: 14400,
|
||||||
}
|
}
|
||||||
@ -39,6 +44,7 @@ export default function Home({
|
|||||||
products,
|
products,
|
||||||
brands,
|
brands,
|
||||||
categories,
|
categories,
|
||||||
|
commerceFeatures,
|
||||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -51,6 +57,7 @@ export default function Home({
|
|||||||
width: i === 0 ? 1080 : 540,
|
width: i === 0 ? 1080 : 540,
|
||||||
height: i === 0 ? 1080 : 540,
|
height: i === 0 ? 1080 : 540,
|
||||||
}}
|
}}
|
||||||
|
wishlist={commerceFeatures.wishlist}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -64,6 +71,7 @@ export default function Home({
|
|||||||
width: 320,
|
width: 320,
|
||||||
height: 320,
|
height: 320,
|
||||||
}}
|
}}
|
||||||
|
wishlist={commerceFeatures.wishlist}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Marquee>
|
</Marquee>
|
||||||
@ -86,6 +94,7 @@ export default function Home({
|
|||||||
width: i === 0 ? 1080 : 540,
|
width: i === 0 ? 1080 : 540,
|
||||||
height: i === 0 ? 1080 : 540,
|
height: i === 0 ? 1080 : 540,
|
||||||
}}
|
}}
|
||||||
|
wishlist={commerceFeatures.wishlist}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -99,6 +108,7 @@ export default function Home({
|
|||||||
width: 320,
|
width: 320,
|
||||||
height: 320,
|
height: 320,
|
||||||
}}
|
}}
|
||||||
|
wishlist={commerceFeatures.wishlist}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Marquee>
|
</Marquee>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import type { GetStaticPropsContext } from 'next'
|
import type { GetStaticPropsContext } from 'next'
|
||||||
import { getConfig } from '@framework/api'
|
import { Bag } from '@components/icons'
|
||||||
import getAllPages from '@framework/common/get-all-pages'
|
|
||||||
import { Layout } from '@components/common'
|
import { Layout } from '@components/common'
|
||||||
import { Container, Text } from '@components/ui'
|
import { Container, Text } from '@components/ui'
|
||||||
import { Bag } from '@components/icons'
|
import { getConfig } from '@framework/api'
|
||||||
|
import getAllPages from '@framework/common/get-all-pages'
|
||||||
|
|
||||||
export async function getStaticProps({
|
export async function getStaticProps({
|
||||||
preview,
|
preview,
|
||||||
|
@ -11,14 +11,15 @@ import { getConfig } from '@framework/api'
|
|||||||
import getProduct from '@framework/product/get-product'
|
import getProduct from '@framework/product/get-product'
|
||||||
import getAllPages from '@framework/common/get-all-pages'
|
import getAllPages from '@framework/common/get-all-pages'
|
||||||
import getAllProductPaths from '@framework/product/get-all-product-paths'
|
import getAllProductPaths from '@framework/product/get-all-product-paths'
|
||||||
|
import Features from '@commerce/utils/features'
|
||||||
|
|
||||||
export async function getStaticProps({
|
export async function getStaticProps({
|
||||||
params,
|
params,
|
||||||
locale,
|
locale,
|
||||||
preview,
|
preview,
|
||||||
}: GetStaticPropsContext<{ slug: string }>) {
|
}: GetStaticPropsContext<{ slug: string }>) {
|
||||||
|
const isWishlistEnabled = Features.isEnabled('wishlist')
|
||||||
const config = getConfig({ locale })
|
const config = getConfig({ locale })
|
||||||
|
|
||||||
const { pages } = await getAllPages({ config, preview })
|
const { pages } = await getAllPages({ config, preview })
|
||||||
const { product } = await getProduct({
|
const { product } = await getProduct({
|
||||||
variables: { slug: params!.slug },
|
variables: { slug: params!.slug },
|
||||||
@ -31,7 +32,13 @@ export async function getStaticProps({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: { pages, product },
|
props: {
|
||||||
|
pages,
|
||||||
|
product,
|
||||||
|
commerceFeatures: {
|
||||||
|
wishlist: isWishlistEnabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
revalidate: 200,
|
revalidate: 200,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,13 +62,17 @@ export async function getStaticPaths({ locales }: GetStaticPathsContext) {
|
|||||||
|
|
||||||
export default function Slug({
|
export default function Slug({
|
||||||
product,
|
product,
|
||||||
|
commerceFeatures,
|
||||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
return router.isFallback ? (
|
return router.isFallback ? (
|
||||||
<h1>Loading...</h1> // TODO (BC) Add Skeleton Views
|
<h1>Loading...</h1> // TODO (BC) Add Skeleton Views
|
||||||
) : (
|
) : (
|
||||||
<ProductView product={product as any} />
|
<ProductView
|
||||||
|
product={product as any}
|
||||||
|
wishlist={commerceFeatures.wishlist}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,8 @@ const SORT = Object.entries({
|
|||||||
'price-desc': 'Price: High to low',
|
'price-desc': 'Price: High to low',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
import Features from '@commerce/utils/features'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
filterQuery,
|
filterQuery,
|
||||||
getCategoryPath,
|
getCategoryPath,
|
||||||
@ -40,14 +42,23 @@ export async function getStaticProps({
|
|||||||
const config = getConfig({ locale })
|
const config = getConfig({ locale })
|
||||||
const { pages } = await getAllPages({ config, preview })
|
const { pages } = await getAllPages({ config, preview })
|
||||||
const { categories, brands } = await getSiteInfo({ config, preview })
|
const { categories, brands } = await getSiteInfo({ config, preview })
|
||||||
|
const isWishlistEnabled = Features.isEnabled('wishlist')
|
||||||
return {
|
return {
|
||||||
props: { pages, categories, brands },
|
props: {
|
||||||
|
pages,
|
||||||
|
categories,
|
||||||
|
brands,
|
||||||
|
commerceFeatures: {
|
||||||
|
wishlist: isWishlistEnabled,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Search({
|
export default function Search({
|
||||||
categories,
|
categories,
|
||||||
brands,
|
brands,
|
||||||
|
commerceFeatures: { wishlist },
|
||||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||||
const [activeFilter, setActiveFilter] = useState('')
|
const [activeFilter, setActiveFilter] = useState('')
|
||||||
const [toggleFilter, setToggleFilter] = useState(false)
|
const [toggleFilter, setToggleFilter] = useState(false)
|
||||||
@ -337,7 +348,7 @@ export default function Search({
|
|||||||
|
|
||||||
{data ? (
|
{data ? (
|
||||||
<Grid layout="normal">
|
<Grid layout="normal">
|
||||||
{data.products.map((product) => (
|
{data.products.map((product: Product) => (
|
||||||
<ProductCard
|
<ProductCard
|
||||||
variant="simple"
|
variant="simple"
|
||||||
key={product.path}
|
key={product.path}
|
||||||
@ -347,6 +358,7 @@ export default function Search({
|
|||||||
width: 480,
|
width: 480,
|
||||||
height: 480,
|
height: 480,
|
||||||
}}
|
}}
|
||||||
|
wishlist={wishlist}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -1,28 +1,43 @@
|
|||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
import type { GetStaticPropsContext } from 'next'
|
import type { GetStaticPropsContext } from 'next'
|
||||||
import { getConfig } from '@framework/api'
|
|
||||||
import getAllPages from '@framework/common/get-all-pages'
|
|
||||||
import useWishlist from '@framework/wishlist/use-wishlist'
|
|
||||||
import { Layout } from '@components/common'
|
|
||||||
import { Heart } from '@components/icons'
|
import { Heart } from '@components/icons'
|
||||||
|
import { Layout } from '@components/common'
|
||||||
import { Text, Container } from '@components/ui'
|
import { Text, Container } from '@components/ui'
|
||||||
import { WishlistCard } from '@components/wishlist'
|
|
||||||
import { defaultPageProps } from '@lib/defaults'
|
import { defaultPageProps } from '@lib/defaults'
|
||||||
|
import { getConfig } from '@framework/api'
|
||||||
import { useCustomer } from '@framework/customer'
|
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({
|
export async function getStaticProps({
|
||||||
preview,
|
preview,
|
||||||
locale,
|
locale,
|
||||||
}: GetStaticPropsContext) {
|
}: GetStaticPropsContext) {
|
||||||
|
// Disabling page if Feature is not available
|
||||||
|
if (Features.isEnabled('wishlist')) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const config = getConfig({ locale })
|
const config = getConfig({ locale })
|
||||||
const { pages } = await getAllPages({ config, preview })
|
const { pages } = await getAllPages({ config, preview })
|
||||||
return {
|
return {
|
||||||
props: { ...defaultPageProps, pages },
|
props: {
|
||||||
|
pages,
|
||||||
|
...defaultPageProps,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Wishlist() {
|
export default function Wishlist() {
|
||||||
const { data: customer } = useCustomer()
|
const { data: customer } = useCustomer()
|
||||||
const { data, isLoading, isEmpty } = useWishlist()
|
const { data, isLoading, isEmpty } = useWishlist()
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
|
@ -26,6 +26,6 @@
|
|||||||
"@framework": ["framework/bigcommerce"]
|
"@framework": ["framework/bigcommerce"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
||||||
"exclude": ["node_modules", "components/wishlist"]
|
"exclude": ["node_modules"]
|
||||||
}
|
}
|
||||||
|
12
yarn.lock
12
yarn.lock
@ -1060,6 +1060,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/lodash" "*"
|
"@types/lodash" "*"
|
||||||
|
|
||||||
|
"@types/lodash.memoize@^4.1.6":
|
||||||
|
version "4.1.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/lodash.memoize/-/lodash.memoize-4.1.6.tgz#3221f981790a415cab1a239f25c17efd8b604c23"
|
||||||
|
integrity sha512-mYxjKiKzRadRJVClLKxS4wb3Iy9kzwJ1CkbyKiadVxejnswnRByyofmPMscFKscmYpl36BEEhCMPuWhA1R/1ZQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/lodash" "*"
|
||||||
|
|
||||||
"@types/lodash.random@^3.2.6":
|
"@types/lodash.random@^3.2.6":
|
||||||
version "3.2.6"
|
version "3.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash.random/-/lodash.random-3.2.6.tgz#64b08abad168dca39c778ed40cce75b2f9e168eb"
|
resolved "https://registry.yarnpkg.com/@types/lodash.random/-/lodash.random-3.2.6.tgz#64b08abad168dca39c778ed40cce75b2f9e168eb"
|
||||||
@ -4232,6 +4239,11 @@ lodash.isstring@^4.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
|
resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451"
|
||||||
integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
|
integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=
|
||||||
|
|
||||||
|
lodash.memoize@^4.1.2:
|
||||||
|
version "4.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
|
||||||
|
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
|
||||||
|
|
||||||
lodash.once@^4.0.0:
|
lodash.once@^4.0.0:
|
||||||
version "4.1.1"
|
version "4.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user