forked from crowetic/commerce
Improved Categories (#339)
* Improved Categories * Improved Categories * Improved Categories * Improved Categories * Improved Categories * Improved Categories
This commit is contained in:
parent
84a72718d2
commit
1bc721de83
@ -8,10 +8,9 @@ import { Navbar, Footer } from '@components/common'
|
||||
import { useAcceptCookies } from '@lib/hooks/useAcceptCookies'
|
||||
import { Sidebar, Button, Modal, LoadingDots } from '@components/ui'
|
||||
import CartSidebarView from '@components/cart/CartSidebarView'
|
||||
|
||||
import type { Page, Category } from '@commerce/types'
|
||||
import LoginView from '@components/auth/LoginView'
|
||||
import { CommerceProvider } from '@framework'
|
||||
import type { Page } from '@framework/common/get-all-pages'
|
||||
|
||||
const Loading = () => (
|
||||
<div className="w-80 h-80 flex items-center text-center justify-center p-3">
|
||||
@ -41,13 +40,13 @@ const FeatureBar = dynamic(
|
||||
interface Props {
|
||||
pageProps: {
|
||||
pages?: Page[]
|
||||
commerceFeatures: Record<string, boolean>
|
||||
categories: Category[]
|
||||
}
|
||||
}
|
||||
|
||||
const Layout: FC<Props> = ({
|
||||
children,
|
||||
pageProps: { commerceFeatures, ...pageProps },
|
||||
pageProps: { categories = [], ...pageProps },
|
||||
}) => {
|
||||
const {
|
||||
displaySidebar,
|
||||
@ -58,10 +57,16 @@ const Layout: FC<Props> = ({
|
||||
} = useUI()
|
||||
const { acceptedCookies, onAcceptCookies } = useAcceptCookies()
|
||||
const { locale = 'en-US' } = useRouter()
|
||||
|
||||
const navBarlinks = categories.slice(0, 2).map((c) => ({
|
||||
label: c.name,
|
||||
href: `/search/${c.slug}`,
|
||||
}))
|
||||
|
||||
return (
|
||||
<CommerceProvider locale={locale}>
|
||||
<div className={cn(s.root)}>
|
||||
<Navbar />
|
||||
<Navbar links={navBarlinks} />
|
||||
<main className="fit">{children}</main>
|
||||
<Footer pages={pageProps.pages} />
|
||||
|
||||
|
@ -5,7 +5,15 @@ import { Searchbar, UserNav } from '@components/common'
|
||||
import NavbarRoot from './NavbarRoot'
|
||||
import s from './Navbar.module.css'
|
||||
|
||||
const Navbar: FC = () => (
|
||||
interface Link {
|
||||
href: string
|
||||
label: string
|
||||
}
|
||||
interface NavbarProps {
|
||||
links?: Link[]
|
||||
}
|
||||
|
||||
const Navbar: FC<NavbarProps> = ({ links }) => (
|
||||
<NavbarRoot>
|
||||
<Container>
|
||||
<div className="relative flex flex-row justify-between py-4 align-center md:py-6">
|
||||
@ -19,15 +27,13 @@ const Navbar: FC = () => (
|
||||
<Link href="/search">
|
||||
<a className={s.link}>All</a>
|
||||
</Link>
|
||||
<Link href="/search?q=clothes">
|
||||
<a className={s.link}>Clothes</a>
|
||||
</Link>
|
||||
<Link href="/search?q=accessories">
|
||||
<a className={s.link}>Accessories</a>
|
||||
</Link>
|
||||
<Link href="/search?q=shoes">
|
||||
<a className={s.link}>Shoes</a>
|
||||
</Link>
|
||||
{links
|
||||
? links.map((l) => (
|
||||
<Link href={l.href}>
|
||||
<a className={s.link}>{l.label}</a>
|
||||
</Link>
|
||||
))
|
||||
: null}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
@ -3,6 +3,8 @@ import type { RecursivePartial, RecursiveRequired } from '../api/utils/types'
|
||||
import filterEdges from '../api/utils/filter-edges'
|
||||
import { BigcommerceConfig, getConfig } from '../api'
|
||||
import { categoryTreeItemFragment } from '../api/fragments/category-tree'
|
||||
import { Category } from '@commerce/types'
|
||||
import getSlug from '@lib/get-slug'
|
||||
|
||||
// Get 3 levels of categories
|
||||
export const getSiteInfoQuery = /* GraphQL */ `
|
||||
@ -56,7 +58,7 @@ export type Brands = BrandEdge[]
|
||||
|
||||
export type GetSiteInfoResult<
|
||||
T extends { categories: any[]; brands: any[] } = {
|
||||
categories: CategoriesTree
|
||||
categories: Category[]
|
||||
brands: Brands
|
||||
}
|
||||
> = T
|
||||
@ -68,7 +70,7 @@ async function getSiteInfo(opts?: {
|
||||
}): Promise<GetSiteInfoResult>
|
||||
|
||||
async function getSiteInfo<
|
||||
T extends { categories: any[]; brands: any[] },
|
||||
T extends { categories: Category[]; brands: any[] },
|
||||
V = any
|
||||
>(opts: {
|
||||
query: string
|
||||
@ -94,11 +96,20 @@ async function getSiteInfo({
|
||||
query,
|
||||
{ variables }
|
||||
)
|
||||
const categories = data.site?.categoryTree
|
||||
|
||||
let categories = data!.site!.categoryTree?.map(
|
||||
({ entityId, name, path }: any) => ({
|
||||
id: `${entityId}`,
|
||||
name,
|
||||
slug: getSlug(path),
|
||||
path,
|
||||
})
|
||||
)
|
||||
|
||||
const brands = data.site?.brands?.edges
|
||||
|
||||
return {
|
||||
categories: (categories as RecursiveRequired<typeof categories>) ?? [],
|
||||
categories: categories ?? [],
|
||||
brands: filterEdges(brands as RecursiveRequired<typeof brands>),
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ export default useSearch as UseSearch<typeof handler>
|
||||
|
||||
export type SearchProductsInput = {
|
||||
search?: string
|
||||
categoryId?: number
|
||||
categoryId?: number | string
|
||||
brandId?: number
|
||||
sort?: string
|
||||
}
|
||||
|
@ -151,6 +151,15 @@ export type RemoveCartItemHandlerBody = Partial<RemoveCartItemBody> & {
|
||||
cartId?: string
|
||||
}
|
||||
|
||||
export type Category = {
|
||||
id: string
|
||||
name: string
|
||||
slug: string
|
||||
path: string
|
||||
}
|
||||
|
||||
export type Page = any
|
||||
|
||||
/**
|
||||
* Temporal types
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
import getCategories, { Category } from '../utils/get-categories'
|
||||
import getVendors, { Brands } from '../utils/get-vendors'
|
||||
|
||||
import { Category } from '@commerce/types'
|
||||
import { getConfig, ShopifyConfig } from '../api'
|
||||
import getCategories from '../utils/get-categories'
|
||||
import getVendors, { Brands } from '../utils/get-vendors'
|
||||
|
||||
export type GetSiteInfoResult<
|
||||
T extends { categories: any[]; brands: any[] } = {
|
||||
|
@ -1,12 +1,7 @@
|
||||
import { ShopifyConfig } from '../api'
|
||||
import { CollectionEdge } from '../schema'
|
||||
import getSiteCollectionsQuery from './queries/get-all-collections-query'
|
||||
|
||||
export type Category = {
|
||||
entityId: string
|
||||
name: string
|
||||
path: string
|
||||
}
|
||||
import { Category } from '@commerce/types'
|
||||
|
||||
const getCategories = async (config: ShopifyConfig): Promise<Category[]> => {
|
||||
const { data } = await config.fetch(getSiteCollectionsQuery, {
|
||||
@ -17,9 +12,10 @@ const getCategories = async (config: ShopifyConfig): Promise<Category[]> => {
|
||||
|
||||
return (
|
||||
data.collections?.edges?.map(
|
||||
({ node: { id: entityId, title: name, handle } }: CollectionEdge) => ({
|
||||
entityId,
|
||||
({ node: { id, title: name, handle } }: CollectionEdge) => ({
|
||||
id,
|
||||
name,
|
||||
slug: handle,
|
||||
path: `/${handle}`,
|
||||
})
|
||||
) ?? []
|
||||
|
@ -1,6 +1,6 @@
|
||||
import getCategories, { Category } from '../utils/get-categories'
|
||||
import getCategories from '../utils/get-categories'
|
||||
import getVendors, { Brands } from '../utils/get-vendors'
|
||||
|
||||
import { Category } from '@commerce/types'
|
||||
import { getConfig, SwellConfig } from '../api'
|
||||
|
||||
export type GetSiteInfoResult<
|
||||
|
@ -1,17 +1,13 @@
|
||||
import { SwellConfig } from '../api'
|
||||
|
||||
export type Category = {
|
||||
entityId: string
|
||||
name: string
|
||||
path: string
|
||||
}
|
||||
import { Category } from '@commerce/types'
|
||||
|
||||
const getCategories = async (config: SwellConfig): Promise<Category[]> => {
|
||||
const data = await config.fetch('categories', 'get')
|
||||
return (
|
||||
data.results.map(({ id: entityId, name, slug }: any) => ({
|
||||
entityId,
|
||||
data.results.map(({ id, name, slug }: any) => ({
|
||||
id,
|
||||
name,
|
||||
slug,
|
||||
path: `/${slug}`,
|
||||
})) ?? []
|
||||
)
|
||||
|
@ -2,13 +2,7 @@ import { getConfig, VendureConfig } from '../api'
|
||||
import { GetCollectionsQuery } from '../schema'
|
||||
import { arrayToTree } from '../lib/array-to-tree'
|
||||
import { getCollectionsQuery } from '../lib/queries/get-collections-query'
|
||||
|
||||
export type Category = {
|
||||
entityId: string
|
||||
name: string
|
||||
path: string
|
||||
productCount: number
|
||||
}
|
||||
import { Category } from '@commerce/types'
|
||||
|
||||
export type GetSiteInfoResult<
|
||||
T extends { categories: any[]; brands: any[] } = {
|
||||
|
@ -1,14 +0,0 @@
|
||||
// Fallback to CMS Data
|
||||
|
||||
export const defaultPageProps = {
|
||||
header: {
|
||||
links: [
|
||||
{
|
||||
link: {
|
||||
title: 'New Arrivals',
|
||||
url: '/',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
@ -10,7 +10,7 @@ import { missingLocaleInPages } from '@lib/usage-warns'
|
||||
import { getConfig } from '@framework/api'
|
||||
import getPage from '@framework/common/get-page'
|
||||
import getAllPages from '@framework/common/get-all-pages'
|
||||
import { defaultPageProps } from '@lib/defaults'
|
||||
import getSiteInfo from '@framework/common/get-site-info'
|
||||
|
||||
export async function getStaticProps({
|
||||
preview,
|
||||
@ -19,9 +19,9 @@ export async function getStaticProps({
|
||||
}: GetStaticPropsContext<{ pages: string[] }>) {
|
||||
const config = getConfig({ locale })
|
||||
const { pages } = await getAllPages({ preview, config })
|
||||
const { categories } = await getSiteInfo({ config, preview })
|
||||
const path = params?.pages.join('/')
|
||||
const slug = locale ? `${locale}/${path}` : path
|
||||
|
||||
const pageItem = pages.find((p) => (p.url ? getSlug(p.url) === slug : false))
|
||||
const data =
|
||||
pageItem &&
|
||||
@ -34,7 +34,7 @@ export async function getStaticProps({
|
||||
}
|
||||
|
||||
return {
|
||||
props: { ...defaultPageProps, pages, page },
|
||||
props: { pages, page, categories },
|
||||
revalidate: 60 * 60, // Every hour
|
||||
}
|
||||
}
|
||||
|
@ -7,15 +7,17 @@ import { Layout } from '@components/common'
|
||||
import { Button, Text } from '@components/ui'
|
||||
import { Bag, Cross, Check, MapPin, CreditCard } from '@components/icons'
|
||||
import { CartItem } from '@components/cart'
|
||||
import getSiteInfo from '@framework/common/get-site-info'
|
||||
|
||||
export async function getStaticProps({
|
||||
preview,
|
||||
locale,
|
||||
}: GetStaticPropsContext) {
|
||||
const config = getConfig({ locale })
|
||||
const { categories } = await getSiteInfo({ config, preview })
|
||||
const { pages } = await getAllPages({ config, preview })
|
||||
return {
|
||||
props: { pages },
|
||||
props: { pages, categories },
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Layout } from '@components/common'
|
||||
import { Grid, Marquee, Hero } from '@components/ui'
|
||||
import { ProductCard } from '@components/product'
|
||||
import { Grid, Marquee, Hero } from '@components/ui'
|
||||
// import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid'
|
||||
import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
|
||||
|
||||
import { getConfig } from '@framework/api'
|
||||
import getAllProducts from '@framework/product/get-all-products'
|
||||
import getSiteInfo from '@framework/common/get-site-info'
|
||||
@ -14,6 +13,8 @@ export async function getStaticProps({
|
||||
locale,
|
||||
}: GetStaticPropsContext) {
|
||||
const config = getConfig({ locale })
|
||||
const { pages } = await getAllPages({ config, preview })
|
||||
const { categories } = await getSiteInfo({ config, preview })
|
||||
|
||||
const { products } = await getAllProducts({
|
||||
variables: { first: 12 },
|
||||
@ -21,15 +22,12 @@ export async function getStaticProps({
|
||||
preview,
|
||||
})
|
||||
|
||||
// const { categories, brands } = await getSiteInfo({ config, preview })
|
||||
// const { pages } = await getAllPages({ config, preview })
|
||||
|
||||
return {
|
||||
props: {
|
||||
products,
|
||||
categories: [],
|
||||
categories,
|
||||
brands: [],
|
||||
pages: [],
|
||||
pages,
|
||||
},
|
||||
revalidate: 14400,
|
||||
}
|
||||
@ -37,8 +35,6 @@ export async function getStaticProps({
|
||||
|
||||
export default function Home({
|
||||
products,
|
||||
brands,
|
||||
categories,
|
||||
}: InferGetStaticPropsType<typeof getStaticProps>) {
|
||||
return (
|
||||
<>
|
||||
|
@ -1,18 +1,21 @@
|
||||
import type { GetStaticPropsContext } from 'next'
|
||||
import { Bag } from '@components/icons'
|
||||
import { getConfig } from '@framework/api'
|
||||
import { Layout } from '@components/common'
|
||||
import { Container, Text } from '@components/ui'
|
||||
import { getConfig } from '@framework/api'
|
||||
import getAllPages from '@framework/common/get-all-pages'
|
||||
import getSiteInfo from '@framework/common/get-site-info'
|
||||
|
||||
export async function getStaticProps({
|
||||
preview,
|
||||
locale,
|
||||
}: GetStaticPropsContext) {
|
||||
const config = getConfig({ locale })
|
||||
const { categories } = await getSiteInfo({ config, preview })
|
||||
const { pages } = await getAllPages({ config, preview })
|
||||
|
||||
return {
|
||||
props: { pages },
|
||||
props: { pages, categories },
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ 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 getSiteInfo from '@framework/common/get-site-info'
|
||||
|
||||
export async function getStaticProps({
|
||||
params,
|
||||
@ -24,6 +25,7 @@ export async function getStaticProps({
|
||||
config,
|
||||
preview,
|
||||
})
|
||||
const { categories } = await getSiteInfo({ config, preview })
|
||||
|
||||
if (!product) {
|
||||
throw new Error(`Product with slug '${params!.slug}' not found`)
|
||||
@ -33,6 +35,7 @@ export async function getStaticProps({
|
||||
props: {
|
||||
pages,
|
||||
product,
|
||||
categories,
|
||||
},
|
||||
revalidate: 200,
|
||||
}
|
||||
|
@ -4,15 +4,17 @@ import getAllPages from '@framework/common/get-all-pages'
|
||||
import useCustomer from '@framework/customer/use-customer'
|
||||
import { Layout } from '@components/common'
|
||||
import { Container, Text } from '@components/ui'
|
||||
import getSiteInfo from '@framework/common/get-site-info'
|
||||
|
||||
export async function getStaticProps({
|
||||
preview,
|
||||
locale,
|
||||
}: GetStaticPropsContext) {
|
||||
const config = getConfig({ locale })
|
||||
const { categories } = await getSiteInfo({ config, preview })
|
||||
const { pages } = await getAllPages({ config, preview })
|
||||
return {
|
||||
props: { pages },
|
||||
props: { pages, categories },
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,9 @@ import useSearch from '@framework/product/use-search'
|
||||
import getAllPages from '@framework/common/get-all-pages'
|
||||
import getSiteInfo from '@framework/common/get-site-info'
|
||||
|
||||
import getSlug from '@lib/get-slug'
|
||||
import rangeMap from '@lib/range-map'
|
||||
|
||||
// TODO(bc) Remove this. This should come from the API
|
||||
import getSlug from '@lib/get-slug'
|
||||
|
||||
// TODO (bc) : Remove or standarize this.
|
||||
const SORT = Object.entries({
|
||||
'latest-desc': 'Latest arrivals',
|
||||
'trending-desc': 'Trending',
|
||||
@ -75,7 +72,7 @@ export default function Search({
|
||||
|
||||
const { data } = useSearch({
|
||||
search: typeof q === 'string' ? q : '',
|
||||
categoryId: activeCategory?.entityId,
|
||||
categoryId: activeCategory?.id,
|
||||
brandId: (activeBrand as any)?.entityId,
|
||||
sort: typeof sort === 'string' ? sort : '',
|
||||
})
|
||||
@ -164,8 +161,7 @@ export default function Search({
|
||||
className={cn(
|
||||
'block text-sm leading-5 text-gray-700 hover:bg-gray-100 lg:hover:bg-transparent hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900',
|
||||
{
|
||||
underline:
|
||||
activeCategory?.entityId === cat.entityId,
|
||||
underline: activeCategory?.id === cat.id,
|
||||
}
|
||||
)}
|
||||
>
|
||||
|
@ -1,13 +1,13 @@
|
||||
import type { GetStaticPropsContext } from 'next'
|
||||
import { Heart } from '@components/icons'
|
||||
import { getConfig } from '@framework/api'
|
||||
import { Layout } from '@components/common'
|
||||
import { Text, Container } from '@components/ui'
|
||||
import { defaultPageProps } from '@lib/defaults'
|
||||
import { getConfig } from '@framework/api'
|
||||
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 getSiteInfo from '@framework/common/get-site-info'
|
||||
|
||||
export async function getStaticProps({
|
||||
preview,
|
||||
@ -21,11 +21,12 @@ export async function getStaticProps({
|
||||
}
|
||||
|
||||
const config = getConfig({ locale })
|
||||
const { categories } = await getSiteInfo({ config, preview })
|
||||
const { pages } = await getAllPages({ config, preview })
|
||||
return {
|
||||
props: {
|
||||
pages,
|
||||
...defaultPageProps,
|
||||
categories,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user