4
0
forked from crowetic/commerce

Merge branch 'agnostic' of https://github.com/vercel/commerce into agnostic

This commit is contained in:
Luis Alvarez 2021-02-18 23:50:11 -05:00
commit 7005e45b09
26 changed files with 258 additions and 104 deletions

118
README.md
View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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 />

View File

@ -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 && (

View File

@ -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 (

View File

@ -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>
) )

View File

@ -0,0 +1 @@
export { default } from './WishlistButton'

View File

@ -1 +1,2 @@
export { default as WishlistCard } from './WishlistCard' export { default as WishlistCard } from './WishlistCard'
export { default as WishlistButton } from './WishlistButton'

View File

@ -0,0 +1,5 @@
{
"features": {
"wishlist": false
}
}

View File

@ -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 '..'

View File

@ -0,0 +1,5 @@
{
"features": {
"wishlist": true
}
}

View File

@ -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

View 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()

View File

@ -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",

View File

@ -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}</>

View File

@ -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>

View File

@ -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,

View File

@ -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}
/>
) )
} }

View File

@ -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>

View File

@ -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>

View File

@ -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"]
} }

View File

@ -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"