mirror of
https://github.com/vercel/commerce.git
synced 2025-05-19 07:56:59 +00:00
merged
This commit is contained in:
parent
d48aec2c2d
commit
d9fe7d8e6b
@ -5,7 +5,7 @@ import { Grid, Marquee, Hero } from '@components/ui'
|
|||||||
import { ModuleWithInit } from '@agility/nextjs'
|
import { ModuleWithInit } from '@agility/nextjs'
|
||||||
|
|
||||||
interface ICustomData {
|
interface ICustomData {
|
||||||
bestSelling: any
|
products: any
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IModule {
|
interface IModule {
|
||||||
@ -14,19 +14,12 @@ interface IModule {
|
|||||||
|
|
||||||
const BestsellingProducts: ModuleWithInit<IModule, ICustomData> = ({ customData }) => {
|
const BestsellingProducts: ModuleWithInit<IModule, ICustomData> = ({ customData }) => {
|
||||||
|
|
||||||
const bestSelling = customData.bestSelling
|
const products = customData.products
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Marquee variant="secondary">
|
<Marquee variant="secondary">
|
||||||
{bestSelling.slice(0, 12).map(({ node }: any) => (
|
{products.slice(0, 3).map((product: any, i: number) => (
|
||||||
<ProductCard
|
<ProductCard key={product.id} product={product} variant="slim" />
|
||||||
key={node.path}
|
|
||||||
product={node}
|
|
||||||
variant="slim"
|
|
||||||
imgWidth={320}
|
|
||||||
imgHeight={320}
|
|
||||||
imgLayout="fixed"
|
|
||||||
/>
|
|
||||||
))}
|
))}
|
||||||
</Marquee>
|
</Marquee>
|
||||||
)
|
)
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
import React, { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
|
|
||||||
import { ProductCard } from '@components/product'
|
|
||||||
import { Grid, Marquee, Hero } from '@components/ui'
|
|
||||||
import useCart from '@framework/cart/use-cart'
|
import useCart from '@framework/cart/use-cart'
|
||||||
import usePrice from '@framework/use-price'
|
import usePrice from '@framework/product/use-price'
|
||||||
import { Button } from '@components/ui'
|
import commerce from '@lib/api/commerce'
|
||||||
import { Bag, Cross, Check } from '@components/icons'
|
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 { CartItem } from '@components/cart'
|
||||||
import { Text } from '@components/ui'
|
|
||||||
|
|
||||||
interface Fields {
|
interface Fields {
|
||||||
}
|
}
|
||||||
@ -18,29 +17,27 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Cart: FC<Props> = ({ fields, customData }) => {
|
const Cart: FC<Props> = ({ fields, customData }) => {
|
||||||
const { data, isEmpty } = useCart()
|
const error = null
|
||||||
|
const success = null
|
||||||
|
const { data, isLoading, isEmpty } = useCart()
|
||||||
|
|
||||||
const { price: subTotal } = usePrice(
|
const { price: subTotal } = usePrice(
|
||||||
data && {
|
data && {
|
||||||
amount: data.base_amount,
|
amount: Number(data.subtotalPrice),
|
||||||
currencyCode: data.currency.code,
|
currencyCode: data.currency.code,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const { price: total } = usePrice(
|
const { price: total } = usePrice(
|
||||||
data && {
|
data && {
|
||||||
amount: data.cart_amount,
|
amount: Number(data.totalPrice),
|
||||||
currencyCode: data.currency.code,
|
currencyCode: data.currency.code,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const items = data?.line_items.physical_items ?? []
|
|
||||||
|
|
||||||
const error = null
|
|
||||||
const success = null
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid lg:grid-cols-12">
|
<div className="grid lg:grid-cols-12 w-full max-w-7xl mx-auto">
|
||||||
<div className="lg:col-span-8">
|
<div className="lg:col-span-8">
|
||||||
{isEmpty ? (
|
{isLoading || isEmpty ? (
|
||||||
<div className="flex-1 px-12 py-24 flex flex-col justify-center items-center ">
|
<div className="flex-1 px-12 py-24 flex flex-col justify-center items-center ">
|
||||||
<span className="border border-dashed border-secondary flex items-center justify-center w-16 h-16 bg-primary p-12 rounded-lg text-primary">
|
<span className="border border-dashed border-secondary flex items-center justify-center w-16 h-16 bg-primary p-12 rounded-lg text-primary">
|
||||||
<Bag className="absolute" />
|
<Bag className="absolute" />
|
||||||
@ -48,7 +45,7 @@ const Cart: FC<Props> = ({ fields, customData }) => {
|
|||||||
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
||||||
Your cart is empty
|
Your cart is empty
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-accents-6 px-10 text-center pt-2">
|
<p className="text-accent-6 px-10 text-center pt-2">
|
||||||
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@ -75,8 +72,8 @@ const Cart: FC<Props> = ({ fields, customData }) => {
|
|||||||
<div className="px-4 sm:px-6 flex-1">
|
<div className="px-4 sm:px-6 flex-1">
|
||||||
<Text variant="pageHeading">My Cart</Text>
|
<Text variant="pageHeading">My Cart</Text>
|
||||||
<Text variant="sectionHeading">Review your Order</Text>
|
<Text variant="sectionHeading">Review your Order</Text>
|
||||||
<ul className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accents-2 border-b border-accents-2">
|
<ul className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accent-2 border-b border-accent-2">
|
||||||
{items.map((item) => (
|
{data!.lineItems.map((item: any) => (
|
||||||
<CartItem
|
<CartItem
|
||||||
key={item.id}
|
key={item.id}
|
||||||
item={item}
|
item={item}
|
||||||
@ -91,7 +88,10 @@ const Cart: FC<Props> = ({ fields, customData }) => {
|
|||||||
</Text>
|
</Text>
|
||||||
<div className="flex py-6 space-x-6">
|
<div className="flex py-6 space-x-6">
|
||||||
{[1, 2, 3, 4, 5, 6].map((x) => (
|
{[1, 2, 3, 4, 5, 6].map((x) => (
|
||||||
<div className="border border-accents-3 w-full h-24 bg-accents-2 bg-opacity-50 transform cursor-pointer hover:scale-110 duration-75" />
|
<div
|
||||||
|
key={x}
|
||||||
|
className="border border-accent-3 w-full h-24 bg-accent-2 bg-opacity-50 transform cursor-pointer hover:scale-110 duration-75"
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -100,7 +100,36 @@ const Cart: FC<Props> = ({ fields, customData }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="lg:col-span-4">
|
<div className="lg:col-span-4">
|
||||||
<div className="flex-shrink-0 px-4 py-24 sm:px-6">
|
<div className="flex-shrink-0 px-4 py-24 sm:px-6">
|
||||||
<div className="border-t border-accents-2">
|
{process.env.COMMERCE_CUSTOMCHECKOUT_ENABLED && (
|
||||||
|
<>
|
||||||
|
{/* Shipping Address */}
|
||||||
|
{/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */}
|
||||||
|
<div className="rounded-md border border-accent-2 px-6 py-6 mb-4 text-center flex items-center justify-center cursor-pointer hover:border-accent-4">
|
||||||
|
<div className="mr-5">
|
||||||
|
<MapPin />
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-center font-medium">
|
||||||
|
<span className="uppercase">+ Add Shipping Address</span>
|
||||||
|
{/* <span>
|
||||||
|
1046 Kearny Street.<br/>
|
||||||
|
San Franssisco, California
|
||||||
|
</span> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Payment Method */}
|
||||||
|
{/* Only available with customCheckout set to true - Meaning that the provider does offer checkout functionality. */}
|
||||||
|
<div className="rounded-md border border-accent-2 px-6 py-6 mb-4 text-center flex items-center justify-center cursor-pointer hover:border-accent-4">
|
||||||
|
<div className="mr-5">
|
||||||
|
<CreditCard />
|
||||||
|
</div>
|
||||||
|
<div className="text-sm text-center font-medium">
|
||||||
|
<span className="uppercase">+ Add Payment Method</span>
|
||||||
|
{/* <span>VISA #### #### #### 2345</span> */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<div className="border-t border-accent-2">
|
||||||
<ul className="py-3">
|
<ul className="py-3">
|
||||||
<li className="flex justify-between py-1">
|
<li className="flex justify-between py-1">
|
||||||
<span>Subtotal</span>
|
<span>Subtotal</span>
|
||||||
@ -115,7 +144,7 @@ const Cart: FC<Props> = ({ fields, customData }) => {
|
|||||||
<span className="font-bold tracking-wide">FREE</span>
|
<span className="font-bold tracking-wide">FREE</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="flex justify-between border-t border-accents-2 py-3 font-bold mb-10">
|
<div className="flex justify-between border-t border-accent-2 py-3 font-bold mb-10">
|
||||||
<span>Total</span>
|
<span>Total</span>
|
||||||
<span>{total}</span>
|
<span>{total}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -4,7 +4,7 @@ import { ProductCard } from '@components/product'
|
|||||||
import { ModuleWithInit } from "@agility/nextjs"
|
import { ModuleWithInit } from "@agility/nextjs"
|
||||||
|
|
||||||
interface ICustomData {
|
interface ICustomData {
|
||||||
featured: any
|
products: any
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IModule {
|
interface IModule {
|
||||||
@ -17,16 +17,18 @@ const FeaturedProducts: ModuleWithInit<IModule, ICustomData> = ({ customData })
|
|||||||
return <div>No featured products returned.</div>
|
return <div>No featured products returned.</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
const featured:any = customData.featured
|
const products:any = customData.products
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid layout="B">
|
<Grid variant="filled">
|
||||||
{featured.map(({ node }:any, i:number) => (
|
{products.slice(0, 3).map((product: any, i: number) => (
|
||||||
<ProductCard
|
<ProductCard
|
||||||
key={node.path}
|
key={product.id}
|
||||||
product={node}
|
product={product}
|
||||||
imgWidth={i === 1 ? 1080 : 540}
|
imgProps={{
|
||||||
imgHeight={i === 1 ? 1080 : 540}
|
width: i === 0 ? 1080 : 540,
|
||||||
|
height: i === 0 ? 1080 : 540,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import React, { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
import { Hero } from '@components/ui'
|
import { Hero } from '@components/ui'
|
||||||
import * as AgilityTypes from "@agility/types"
|
import { URLField } from "@agility/nextjs"
|
||||||
import { Module } from '@agility/nextjs'
|
import { Module } from '@agility/nextjs'
|
||||||
|
|
||||||
|
|
||||||
interface Fields {
|
interface Fields {
|
||||||
title:string,
|
title:string,
|
||||||
description:string
|
description:string
|
||||||
cTA?:AgilityTypes.URLField
|
cTA?:URLField
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeroModule:Module<Fields> = ({ module: {fields }}) => {
|
const HeroModule:Module<Fields> = ({ module: {fields }}) => {
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
import React, { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid'
|
import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid'
|
||||||
import { ModuleWithInit } from '@agility/nextjs'
|
import { ModuleWithInit } from '@agility/nextjs'
|
||||||
|
import { ProductCard } from '@components/product'
|
||||||
|
import { Grid, Marquee, Hero } from '@components/ui'
|
||||||
|
|
||||||
|
|
||||||
interface ICustomData {
|
interface ICustomData {
|
||||||
categories: any
|
|
||||||
newestProducts: any
|
products: any
|
||||||
brands: any
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IModule {
|
interface IModule {
|
||||||
@ -16,19 +17,25 @@ interface IModule {
|
|||||||
|
|
||||||
const HomeAllProductsGridModule: ModuleWithInit<IModule, ICustomData> = ({ customData }) => {
|
const HomeAllProductsGridModule: ModuleWithInit<IModule, ICustomData> = ({ customData }) => {
|
||||||
|
|
||||||
const categories = customData.categories
|
|
||||||
const newestProducts = customData.newestProducts
|
|
||||||
const brands = customData.brands
|
|
||||||
|
|
||||||
if (!categories) return <div>No data</div>
|
const products = customData.products
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HomeAllProductsGrid
|
<Grid layout="B" variant="filled">
|
||||||
categories={categories}
|
{products.slice(0, 3).map((product: any, i: number) => (
|
||||||
brands={brands}
|
<ProductCard
|
||||||
newestProducts={newestProducts}
|
key={product.id}
|
||||||
|
product={product}
|
||||||
|
imgProps={{
|
||||||
|
width: i === 0 ? 1080 : 540,
|
||||||
|
height: i === 0 ? 1080 : 540,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
))}
|
||||||
|
</Grid>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HomeAllProductsGridModule
|
export default HomeAllProductsGridModule
|
||||||
|
@ -19,8 +19,8 @@ const Orders: Module<Fields> = ({ }) => {
|
|||||||
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
<h2 className="pt-6 text-2xl font-bold tracking-wide text-center">
|
||||||
No orders found
|
No orders found
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-accents-6 px-10 text-center pt-2">
|
<p className="text-accent-6 px-10 text-center pt-2">
|
||||||
Orders coming soon!
|
Orders coming soon.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -1,20 +1,25 @@
|
|||||||
import React, { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
import { Hero } from '@components/ui'
|
|
||||||
import * as AgilityTypes from "@agility/types"
|
|
||||||
import { GetProductResult } from '@framework/api/operations/get-product'
|
|
||||||
import { ProductView } from '@components/product'
|
|
||||||
import { Module } from '@agility/nextjs'
|
|
||||||
|
|
||||||
interface Fields {
|
import { ProductView } from '@components/product'
|
||||||
|
import { Module, ModuleWithInit } from '@agility/nextjs'
|
||||||
|
|
||||||
|
interface IFields {
|
||||||
|
}
|
||||||
|
interface ICustomData {
|
||||||
|
products: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const HeroModule:Module<Fields> = ({ dynamicPageItem }) => {
|
const ProductDetails:ModuleWithInit<IFields, ICustomData> = ({ dynamicPageItem, customData }) => {
|
||||||
const product:any = dynamicPageItem
|
const product:any = dynamicPageItem
|
||||||
|
|
||||||
|
const relatedProducts:[] = customData.products
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProductView product={product} />
|
<ProductView product={product} relatedProducts={relatedProducts} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HeroModule
|
export default ProductDetails
|
||||||
|
|
||||||
|
@ -1,31 +1,7 @@
|
|||||||
import React, { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
import cn from 'classnames'
|
import Search from '@components/search'
|
||||||
import Link from 'next/link'
|
|
||||||
import { useState } from 'react'
|
|
||||||
import { useRouter } from 'next/router'
|
|
||||||
import useSearch from '@framework/products/use-search'
|
|
||||||
import { ProductCard } from '@components/product'
|
|
||||||
import { Container, Grid, Skeleton } from '@components/ui'
|
|
||||||
|
|
||||||
import rangeMap from '@lib/range-map'
|
|
||||||
import getSlug from '@lib/get-slug'
|
|
||||||
import {
|
|
||||||
filterQuery,
|
|
||||||
getCategoryPath,
|
|
||||||
getDesignerPath,
|
|
||||||
useSearchMeta,
|
|
||||||
} from '@lib/search'
|
|
||||||
import { ModuleWithInit } from '@agility/nextjs'
|
import { ModuleWithInit } from '@agility/nextjs'
|
||||||
|
|
||||||
|
|
||||||
const SORT = Object.entries({
|
|
||||||
'latest-desc': 'Latest arrivals',
|
|
||||||
'trending-desc': 'Trending',
|
|
||||||
'price-asc': 'Price: Low to high',
|
|
||||||
'price-desc': 'Price: High to low',
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
interface ICustomData {
|
interface ICustomData {
|
||||||
categories: any
|
categories: any
|
||||||
brands: any
|
brands: any
|
||||||
@ -40,416 +16,8 @@ const ProductSearch: ModuleWithInit<IModule, ICustomData> = ({ customData }) =>
|
|||||||
const categories:[any] = customData.categories
|
const categories:[any] = customData.categories
|
||||||
const brands:[any] = customData.brands
|
const brands:[any] = customData.brands
|
||||||
|
|
||||||
const [activeFilter, setActiveFilter] = useState('')
|
return <Search brands={brands} categories={categories} pages={[]} />
|
||||||
const [toggleFilter, setToggleFilter] = useState(false)
|
|
||||||
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const { asPath } = router
|
|
||||||
const { q, sort } = router.query
|
|
||||||
// `q` can be included but because categories and designers can't be searched
|
|
||||||
// in the same way of products, it's better to ignore the search input if one
|
|
||||||
// of those is selected
|
|
||||||
const query = filterQuery({ sort })
|
|
||||||
|
|
||||||
const { pathname, category, brand } = useSearchMeta(asPath)
|
|
||||||
const activeCategory = categories.find(
|
|
||||||
(cat) => getSlug(cat.path) === category
|
|
||||||
)
|
|
||||||
const activeBrand = brands.find(
|
|
||||||
(b) => getSlug(b.node.path) === `brands/${brand}`
|
|
||||||
)?.node
|
|
||||||
|
|
||||||
const { data } = useSearch({
|
|
||||||
search: typeof q === 'string' ? q : '',
|
|
||||||
categoryId: activeCategory?.entityId,
|
|
||||||
brandId: activeBrand?.entityId,
|
|
||||||
sort: typeof sort === 'string' ? sort : '',
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleClick = (event: any, filter: string) => {
|
|
||||||
if (filter !== activeFilter) {
|
|
||||||
setToggleFilter(true)
|
|
||||||
} else {
|
|
||||||
setToggleFilter(!toggleFilter)
|
|
||||||
}
|
|
||||||
|
|
||||||
setActiveFilter(filter)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Container>
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-12 gap-4 mt-3 mb-20">
|
|
||||||
<div className="col-span-8 lg:col-span-2 order-1 lg:order-none">
|
|
||||||
{/* Categories */}
|
|
||||||
<div className="relative inline-block w-full">
|
|
||||||
<div className="lg:hidden">
|
|
||||||
<span className="rounded-md shadow-sm">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={(e) => handleClick(e, 'categories')}
|
|
||||||
className="flex justify-between w-full rounded-sm border border-gray-300 px-4 py-3 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150"
|
|
||||||
id="options-menu"
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="true"
|
|
||||||
>
|
|
||||||
{activeCategory?.name
|
|
||||||
? `Category: ${activeCategory?.name}`
|
|
||||||
: 'All Categories'}
|
|
||||||
<svg
|
|
||||||
className="-mr-1 ml-2 h-5 w-5"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`origin-top-left absolute lg:relative left-0 mt-2 w-full rounded-md shadow-lg lg:shadow-none z-10 mb-10 lg:block ${
|
|
||||||
activeFilter !== 'categories' || toggleFilter !== true
|
|
||||||
? 'hidden'
|
|
||||||
: ''
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="rounded-sm bg-white shadow-xs lg:bg-none lg:shadow-none">
|
|
||||||
<div
|
|
||||||
role="menu"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
aria-labelledby="options-menu"
|
|
||||||
>
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
className={cn(
|
|
||||||
'block text-sm leading-5 text-gray-700 lg:text-base lg:no-underline lg:font-bold lg:tracking-wide 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?.name,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={{ pathname: getCategoryPath('', brand), query }}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
onClick={(e) => handleClick(e, 'categories')}
|
|
||||||
className={
|
|
||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
All Categories
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
{categories.map((cat) => (
|
|
||||||
<li
|
|
||||||
key={cat.path}
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname: getCategoryPath(cat.path, brand),
|
|
||||||
query,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
onClick={(e) => handleClick(e, 'categories')}
|
|
||||||
className={
|
|
||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{cat.name}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Designs */}
|
|
||||||
<div className="relative inline-block w-full">
|
|
||||||
<div className="lg:hidden mt-3">
|
|
||||||
<span className="rounded-md shadow-sm">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={(e) => handleClick(e, 'brands')}
|
|
||||||
className="flex justify-between w-full rounded-sm border border-gray-300 px-4 py-3 bg-white text-sm leading-5 font-medium text-gray-900 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150"
|
|
||||||
id="options-menu"
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="true"
|
|
||||||
>
|
|
||||||
{activeBrand?.name
|
|
||||||
? `Design: ${activeBrand?.name}`
|
|
||||||
: 'All Designs'}
|
|
||||||
<svg
|
|
||||||
className="-mr-1 ml-2 h-5 w-5"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`origin-top-left absolute lg:relative left-0 mt-2 w-full rounded-md shadow-lg lg:shadow-none z-10 mb-10 lg:block ${
|
|
||||||
activeFilter !== 'brands' || toggleFilter !== true
|
|
||||||
? 'hidden'
|
|
||||||
: ''
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="rounded-sm bg-white shadow-xs lg:bg-none lg:shadow-none">
|
|
||||||
<div
|
|
||||||
role="menu"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
aria-labelledby="options-menu"
|
|
||||||
>
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
className={cn(
|
|
||||||
'block text-sm leading-5 text-gray-700 lg:text-base lg:no-underline lg:font-bold lg:tracking-wide hover:bg-gray-100 lg:hover:bg-transparent hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900',
|
|
||||||
{
|
|
||||||
underline: !activeBrand?.name,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname: getDesignerPath('', category),
|
|
||||||
query,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
onClick={(e) => handleClick(e, 'brands')}
|
|
||||||
className={
|
|
||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
All Designers
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
{brands.flatMap(({ node }) => (
|
|
||||||
<li
|
|
||||||
key={node.path}
|
|
||||||
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: activeBrand?.entityId === node.entityId,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname: getDesignerPath(node.path, category),
|
|
||||||
query,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
onClick={(e) => handleClick(e, 'brands')}
|
|
||||||
className={
|
|
||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{node.name}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* Products */}
|
|
||||||
<div className="col-span-8 order-3 lg:order-none">
|
|
||||||
{(q || activeCategory || activeBrand) && (
|
|
||||||
<div className="mb-12 transition ease-in duration-75">
|
|
||||||
{data ? (
|
|
||||||
<>
|
|
||||||
<span
|
|
||||||
className={cn('animated', {
|
|
||||||
fadeIn: data.found,
|
|
||||||
hidden: !data.found,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
Showing {data.products.length} results{' '}
|
|
||||||
{q && (
|
|
||||||
<>
|
|
||||||
for "<strong>{q}</strong>"
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<span
|
|
||||||
className={cn('animated', {
|
|
||||||
fadeIn: !data.found,
|
|
||||||
hidden: data.found,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{q ? (
|
|
||||||
<>
|
|
||||||
There are no products that match "<strong>{q}</strong>"
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
There are no products that match the selected category &
|
|
||||||
designer
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</>
|
|
||||||
) : q ? (
|
|
||||||
<>
|
|
||||||
Searching for: "<strong>{q}</strong>"
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<>Searching...</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{data ? (
|
|
||||||
<Grid layout="normal">
|
|
||||||
{data.products.map(({ node }) => (
|
|
||||||
<ProductCard
|
|
||||||
variant="simple"
|
|
||||||
key={node.path}
|
|
||||||
className="animated fadeIn"
|
|
||||||
product={node}
|
|
||||||
imgWidth={480}
|
|
||||||
imgHeight={480}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
) : (
|
|
||||||
<Grid layout="normal">
|
|
||||||
{rangeMap(12, (i) => (
|
|
||||||
<Skeleton
|
|
||||||
key={i}
|
|
||||||
className="w-full animated fadeIn"
|
|
||||||
height={325}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Grid>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sort */}
|
|
||||||
<div className="col-span-8 lg:col-span-2 order-2 lg:order-none">
|
|
||||||
<div className="relative inline-block w-full">
|
|
||||||
<div className="lg:hidden">
|
|
||||||
<span className="rounded-md shadow-sm">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={(e) => handleClick(e, 'sort')}
|
|
||||||
className="flex justify-between w-full rounded-sm border border-gray-300 px-4 py-3 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition ease-in-out duration-150"
|
|
||||||
id="options-menu"
|
|
||||||
aria-haspopup="true"
|
|
||||||
aria-expanded="true"
|
|
||||||
>
|
|
||||||
{sort ? `Sort: ${sort}` : 'Relevance'}
|
|
||||||
<svg
|
|
||||||
className="-mr-1 ml-2 h-5 w-5"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fillRule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clipRule="evenodd"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={`origin-top-left absolute lg:relative left-0 mt-2 w-full rounded-md shadow-lg lg:shadow-none z-10 mb-10 lg:block ${
|
|
||||||
activeFilter !== 'sort' || toggleFilter !== true ? 'hidden' : ''
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<div className="rounded-sm bg-white shadow-xs lg:bg-none lg:shadow-none">
|
|
||||||
<div
|
|
||||||
role="menu"
|
|
||||||
aria-orientation="vertical"
|
|
||||||
aria-labelledby="options-menu"
|
|
||||||
>
|
|
||||||
<ul>
|
|
||||||
<li
|
|
||||||
className={cn(
|
|
||||||
'block text-sm leading-5 text-gray-700 lg:text-base lg:no-underline lg:font-bold lg:tracking-wide hover:bg-gray-100 lg:hover:bg-transparent hover:text-gray-900 focus:outline-none focus:bg-gray-100 focus:text-gray-900',
|
|
||||||
{
|
|
||||||
underline: !sort,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link href={{ pathname, query: filterQuery({ q }) }}>
|
|
||||||
<a
|
|
||||||
onClick={(e) => handleClick(e, 'sort')}
|
|
||||||
className={
|
|
||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Relevance
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
{SORT.map(([key, text]) => (
|
|
||||||
<li
|
|
||||||
key={key}
|
|
||||||
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: sort === key,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Link
|
|
||||||
href={{
|
|
||||||
pathname,
|
|
||||||
query: filterQuery({ q, sort: key }),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
onClick={(e) => handleClick(e, 'sort')}
|
|
||||||
className={
|
|
||||||
'block lg:inline-block px-4 py-2 lg:p-0 lg:my-2 lg:mx-4'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{text}
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Container>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
|
|
||||||
import useCustomer from '@framework/use-customer'
|
import useCustomer from '@framework/customer/use-customer'
|
||||||
import { Container, Text } from '@components/ui'
|
import { Container, Text } from '@components/ui'
|
||||||
import { Module } from '@agility/nextjs'
|
import { Module } from '@agility/nextjs'
|
||||||
|
|
||||||
@ -17,27 +17,23 @@ const ProfileModule:Module<Fields> = ({ module: {fields}}) => {
|
|||||||
const { data } = useCustomer()
|
const { data } = useCustomer()
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Text variant="pageHeading">{fields.heading}</Text>
|
<Text variant="pageHeading">My Profile</Text>
|
||||||
{data && (
|
{data && (
|
||||||
<div className="grid lg:grid-cols-12">
|
<div className="grid lg:grid-cols-12">
|
||||||
<div className="lg:col-span-8 pr-4">
|
<div className="lg:col-span-8 pr-4">
|
||||||
<div>
|
<div>
|
||||||
<Text variant="sectionHeading">{fields.fullNameLabel}</Text>
|
<Text variant="sectionHeading">Full Name</Text>
|
||||||
<span>
|
<span>
|
||||||
{data.firstName} {data.lastName}
|
{data.firstName} {data.lastName}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-5">
|
<div className="mt-5">
|
||||||
<Text variant="sectionHeading">{fields.emailLabel}</Text>
|
<Text variant="sectionHeading">Email</Text>
|
||||||
<span>{data.email}</span>
|
<span>{data.email}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{ !data &&
|
|
||||||
<Text variant="body">{fields.notLoggedInMessage}</Text>
|
|
||||||
}
|
|
||||||
</Container>
|
</Container>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ const LOCALES_MAP: Record<string, LOCALE_DATA> = {
|
|||||||
alt: 'Bandera Colombiana',
|
alt: 'Bandera Colombiana',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-us': {
|
||||||
name: 'English',
|
name: 'English',
|
||||||
img: {
|
img: {
|
||||||
filename: 'flag-en-us.svg',
|
filename: 'flag-en-us.svg',
|
||||||
|
@ -6,32 +6,23 @@ import Link from 'next/link'
|
|||||||
interface HeroProps {
|
interface HeroProps {
|
||||||
className?: string
|
className?: string
|
||||||
headline: string
|
headline: string
|
||||||
description: string,
|
description: string
|
||||||
linkText?: string,
|
|
||||||
linkUrl?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Hero: FC<Props> = ({ headline, description, linkText, linkUrl }) => {
|
const Hero: FC<HeroProps> = ({ headline, description }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-accent-9 border-b border-t border-accent-2">
|
<div className="bg-accent-9 border-b border-t border-accent-2">
|
||||||
<Container>
|
<Container>
|
||||||
<div className={s.root}>
|
<div className={s.root}>
|
||||||
<h2 className="text-4xl leading-10 font-extrabold text-white sm:text-5xl sm:leading-none sm:tracking-tight lg:text-6xl">
|
<h2 className={s.title}>{headline}</h2>
|
||||||
{headline}
|
<div className={s.description}>
|
||||||
</h2>
|
<p>{description}</p>
|
||||||
<div className="flex flex-col justify-between">
|
<Link href="/">
|
||||||
<p className="mt-5 text-xl leading-7 text-accent-2 text-white">
|
<a className="flex items-center text-accent-0 pt-3 font-bold hover:underline cursor-pointer w-max-content">
|
||||||
{description}
|
Read it here
|
||||||
</p>
|
<ArrowRight width="20" heigh="20" className="ml-1" />
|
||||||
{ linkText && linkUrl &&
|
|
||||||
<Link href={linkUrl}>
|
|
||||||
<a className="text-white pt-3 font-bold hover:underline flex flex-row cursor-pointer w-max-content">
|
|
||||||
{linkText}
|
|
||||||
<RightArrow width="20" heigh="20" className="ml-1" />
|
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -1,55 +1,27 @@
|
|||||||
import { getConfig } from '@framework/api'
|
import commerce from '@lib/api/commerce'
|
||||||
import getAllProducts from '@framework/api/operations/get-all-products'
|
|
||||||
|
|
||||||
import rangeMap from '@lib/range-map'
|
const getCustomInitialProps = async function ({ item, agility, languageCode, channelName, pageInSitemap, dynamicPageItem }: any) {
|
||||||
|
|
||||||
const nonNullable = (v: any) => v
|
|
||||||
|
|
||||||
const getCustomInitialProps = async function ({ }):Promise<{bestSelling:any}> {
|
|
||||||
//TODO: pass the locale and preview mode as props...
|
//TODO: pass the locale and preview mode as props...
|
||||||
|
|
||||||
|
|
||||||
const locale = "en-US"
|
const locale = "en-US"
|
||||||
const preview = false
|
const preview = false
|
||||||
|
|
||||||
const config = getConfig({ locale })
|
const config = { locale, locales: [locale] }
|
||||||
|
const productsPromise = commerce.getAllProducts({
|
||||||
// Get Best Selling Products
|
variables: { first: 6 },
|
||||||
const { products: bestSellingProducts } = await getAllProducts({
|
|
||||||
variables: { field: 'bestSellingProducts', first: 6 },
|
|
||||||
config,
|
config,
|
||||||
preview,
|
preview,
|
||||||
|
// Saleor provider only
|
||||||
|
...({ featured: true } as any),
|
||||||
})
|
})
|
||||||
|
|
||||||
// Get Best Newest Products
|
const { products } = await productsPromise
|
||||||
const { products: newestProducts } = await getAllProducts({
|
|
||||||
variables: { field: 'newestProducts', first: 12 },
|
|
||||||
config,
|
|
||||||
preview,
|
|
||||||
})
|
|
||||||
|
|
||||||
// These are the products that are going to be displayed in the landing.
|
|
||||||
// We prefer to do the computation at buildtime/servertime
|
|
||||||
const { bestSelling } = (() => {
|
|
||||||
|
|
||||||
// Create a copy of products that we can mutate
|
|
||||||
const products = [...newestProducts]
|
|
||||||
// If the lists of featured and best selling products don't have enough
|
|
||||||
// products, then fill them with products from the products list, this
|
|
||||||
// is useful for new commerce sites that don't have a lot of products
|
|
||||||
return {
|
|
||||||
bestSelling: rangeMap(
|
|
||||||
6,
|
|
||||||
(i) => bestSellingProducts[i] ?? products.shift()
|
|
||||||
).filter(nonNullable),
|
|
||||||
}
|
|
||||||
})()
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
bestSelling
|
products
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { getCustomInitialProps }
|
export default { getCustomInitialProps }
|
17
framework/module-data/CartData.ts
Normal file
17
framework/module-data/CartData.ts
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import commerce from '@lib/api/commerce'
|
||||||
|
|
||||||
|
const getCustomInitialProps = async function ({ }):Promise<{pages:any, categories: any}> {
|
||||||
|
const languageCode = "en-us"
|
||||||
|
const preview = false
|
||||||
|
const config = { locale: languageCode, locales: [languageCode] }
|
||||||
|
const pagesPromise = commerce.getAllPages({ config, preview })
|
||||||
|
const siteInfoPromise = commerce.getSiteInfo({ config, preview })
|
||||||
|
const { pages } = await pagesPromise
|
||||||
|
const { categories } = await siteInfoPromise
|
||||||
|
return {
|
||||||
|
pages, categories
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {getCustomInitialProps}
|
@ -1,11 +1,4 @@
|
|||||||
import { getConfig } from '@framework/api'
|
import commerce from '@lib/api/commerce'
|
||||||
import getAllProducts from '@framework/api/operations/get-all-products'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import rangeMap from '@lib/range-map'
|
|
||||||
|
|
||||||
const nonNullable = (v: any) => v
|
|
||||||
|
|
||||||
const getCustomInitialProps = async function ({ item, agility, languageCode, channelName, pageInSitemap, dynamicPageItem }: any) {
|
const getCustomInitialProps = async function ({ item, agility, languageCode, channelName, pageInSitemap, dynamicPageItem }: any) {
|
||||||
//TODO: pass the locale and preview mode as props...
|
//TODO: pass the locale and preview mode as props...
|
||||||
@ -14,21 +7,21 @@ const getCustomInitialProps = async function ({ item, agility, languageCode, cha
|
|||||||
const locale = "en-US"
|
const locale = "en-US"
|
||||||
const preview = false
|
const preview = false
|
||||||
|
|
||||||
const config = getConfig({ locale })
|
const config = { locale, locales: [locale] }
|
||||||
|
const productsPromise = commerce.getAllProducts({
|
||||||
// Get Featured Products
|
variables: { first: 6 },
|
||||||
const { products: featuredProducts } = await getAllProducts({
|
|
||||||
variables: { field: 'featuredProducts', first: 6 },
|
|
||||||
config,
|
config,
|
||||||
preview,
|
preview,
|
||||||
|
// Saleor provider only
|
||||||
|
...({ featured: true } as any),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { products } = await productsPromise
|
||||||
|
|
||||||
return {
|
return {
|
||||||
featured: featuredProducts
|
products
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { getCustomInitialProps }
|
export default { getCustomInitialProps }
|
@ -1,38 +1,27 @@
|
|||||||
import { getConfig } from '@framework/api'
|
import commerce from '@lib/api/commerce'
|
||||||
import getSiteInfo from '@framework/api/operations/get-site-info'
|
|
||||||
import getAllProducts from '@framework/api/operations/get-all-products'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import rangeMap from '@lib/range-map'
|
|
||||||
|
|
||||||
const nonNullable = (v: any) => v
|
|
||||||
|
|
||||||
const getCustomInitialProps = async function ({ item, agility, languageCode, channelName, pageInSitemap, dynamicPageItem }: any) {
|
const getCustomInitialProps = async function ({ item, agility, languageCode, channelName, pageInSitemap, dynamicPageItem }: any) {
|
||||||
//TODO: pass the locale and preview mode as props...
|
//TODO: pass the locale and preview mode as props...
|
||||||
|
|
||||||
|
|
||||||
const locale = "en-US"
|
const locale = "en-US"
|
||||||
const preview = false
|
const preview = false
|
||||||
|
|
||||||
|
const config = { locale, locales: [locale] }
|
||||||
const config = getConfig({ locale })
|
const productsPromise = commerce.getAllProducts({
|
||||||
const { categories, brands } = await getSiteInfo({ config, preview })
|
variables: { first: 6 },
|
||||||
|
|
||||||
// Get Best Newest Products
|
|
||||||
const { products: newestProducts } = await getAllProducts({
|
|
||||||
variables: { field: 'newestProducts', first: 12 },
|
|
||||||
config,
|
config,
|
||||||
preview,
|
preview,
|
||||||
|
// Saleor provider only
|
||||||
|
...({ featured: true } as any),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { products } = await productsPromise
|
||||||
|
|
||||||
return {
|
return {
|
||||||
newestProducts: newestProducts,
|
products
|
||||||
categories,
|
|
||||||
brands
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default { getCustomInitialProps }
|
export default { getCustomInitialProps }
|
26
framework/module-data/ProductDetailsData.ts
Normal file
26
framework/module-data/ProductDetailsData.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import commerce from '@lib/api/commerce'
|
||||||
|
|
||||||
|
const getCustomInitialProps = async function ({ item, agility, languageCode, channelName, pageInSitemap, dynamicPageItem }: any) {
|
||||||
|
//TODO: pass the locale and preview mode as props...
|
||||||
|
|
||||||
|
|
||||||
|
const locale = "en-us"
|
||||||
|
const preview = false
|
||||||
|
|
||||||
|
const config = { locale, locales: [locale] }
|
||||||
|
const productsPromise = commerce.getAllProducts({
|
||||||
|
variables: { first: 4 },
|
||||||
|
config,
|
||||||
|
preview,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const { products } = await productsPromise
|
||||||
|
|
||||||
|
return {
|
||||||
|
products
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default { getCustomInitialProps }
|
@ -1,5 +1,4 @@
|
|||||||
import { getConfig } from '@framework/api'
|
import commerce from '@lib/api/commerce'
|
||||||
import getSiteInfo from '@framework/api/operations/get-site-info'
|
|
||||||
|
|
||||||
const getCustomInitialProps = async ({ agility, channelName, languageCode }:any) => {
|
const getCustomInitialProps = async ({ agility, channelName, languageCode }:any) => {
|
||||||
|
|
||||||
@ -7,16 +6,18 @@ const getCustomInitialProps = async ({ agility, channelName, languageCode }:any)
|
|||||||
|
|
||||||
const locale = "en-US"
|
const locale = "en-US"
|
||||||
const preview = false
|
const preview = false
|
||||||
|
const config = { locale, locales: [locale] }
|
||||||
|
const pagesPromise = commerce.getAllPages({ config, preview })
|
||||||
|
const siteInfoPromise = commerce.getSiteInfo({ config, preview })
|
||||||
|
|
||||||
const config = getConfig({ locale })
|
const { categories, brands } = await siteInfoPromise
|
||||||
const { categories, brands } = await getSiteInfo({ config, preview })
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
categories,
|
categories,
|
||||||
brands
|
brands,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import BestsellingProductsData from "./BestsellingProductsData"
|
import BestsellingProductsData from "./BestsellingProductsData"
|
||||||
|
import CartData from "./CartData"
|
||||||
import FeaturedProductsData from "./FeaturedProductsData"
|
import FeaturedProductsData from "./FeaturedProductsData"
|
||||||
import HomeAllProductsGridData from "./HomeAllProductsGridData"
|
import HomeAllProductsGridData from "./HomeAllProductsGridData"
|
||||||
import ProductSearchData from "./ProductSearchData"
|
import ProductSearchData from "./ProductSearchData"
|
||||||
|
import ProductDetailsData from "./ProductDetailsData"
|
||||||
|
|
||||||
const allModules:any =[
|
const allModules:any =[
|
||||||
{ name: "BestsellingProducts", init: BestsellingProductsData },
|
{ name: "BestsellingProducts", init: BestsellingProductsData },
|
||||||
{ name: "FeaturedProducts", init: FeaturedProductsData},
|
{ name: "FeaturedProducts", init: FeaturedProductsData},
|
||||||
{ name: "HomeAllProductsGrid", init: HomeAllProductsGridData},
|
{ name: "HomeAllProductsGrid", init: HomeAllProductsGridData},
|
||||||
{ name: "ProductSearch", init: ProductSearchData}
|
{ name: "ProductSearch", init: ProductSearchData},
|
||||||
|
{ name: "Cart", init: CartData},
|
||||||
|
{ name: "ProductDetails", init: ProductDetailsData}
|
||||||
]
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,8 +17,8 @@ module.exports = withCommerceConfig({
|
|||||||
},
|
},
|
||||||
commerce,
|
commerce,
|
||||||
i18n: {
|
i18n: {
|
||||||
locales: ['en-US', 'es'],
|
locales: ['en-us'],
|
||||||
defaultLocale: 'en-US',
|
defaultLocale: 'en-us',
|
||||||
},
|
},
|
||||||
rewrites() {
|
rewrites() {
|
||||||
return [
|
return [
|
||||||
|
11033
package-lock.json
generated
11033
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -5,21 +5,15 @@ import type {
|
|||||||
|
|
||||||
} from 'next'
|
} from 'next'
|
||||||
|
|
||||||
|
import commerce from '@lib/api/commerce'
|
||||||
import { Layout } from '@components/common'
|
import { Layout } from '@components/common'
|
||||||
import { missingLocaleInPages } from '@lib/usage-warns'
|
|
||||||
|
|
||||||
import { getAgilityPageProps, getAgilityPaths } from "@agility/nextjs/node"
|
import { getAgilityPageProps, getAgilityPaths } from "@agility/nextjs/node"
|
||||||
import { handlePreview } from "@agility/nextjs"
|
import { handlePreview } from "@agility/nextjs"
|
||||||
|
|
||||||
import { defaultPageProps } from '@lib/defaults'
|
|
||||||
import AgilityPage from "components/agility-global/AgilityPage"
|
import AgilityPage from "components/agility-global/AgilityPage"
|
||||||
import { getConfig } from '@framework/api'
|
|
||||||
import getProduct from '@framework/api/operations/get-product'
|
|
||||||
import getModuleData from "framework/module-data"
|
import getModuleData from "framework/module-data"
|
||||||
|
|
||||||
import getAllProductPaths from '@framework/api/operations/get-all-product-paths'
|
|
||||||
|
|
||||||
|
|
||||||
export async function getStaticProps({ preview, params, locale, locales, defaultLocale }: GetStaticPropsContext<{ slug: string[] }>) {
|
export async function getStaticProps({ preview, params, locale, locales, defaultLocale }: GetStaticPropsContext<{ slug: string[] }>) {
|
||||||
try {
|
try {
|
||||||
@ -46,8 +40,10 @@ export async function getStaticProps({ preview, params, locale, locales, default
|
|||||||
let productDetail: any = null
|
let productDetail: any = null
|
||||||
|
|
||||||
if (productCode) {
|
if (productCode) {
|
||||||
const config = getConfig({ locale })
|
|
||||||
const { product } = await getProduct({
|
const config = { locale, locales }
|
||||||
|
|
||||||
|
const { product } = await commerce.getProduct({
|
||||||
variables: { slug: productCode },
|
variables: { slug: productCode },
|
||||||
config,
|
config,
|
||||||
preview,
|
preview,
|
||||||
@ -69,7 +65,7 @@ export async function getStaticProps({ preview, params, locale, locales, default
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
props: { ...defaultPageProps, agilityProps },
|
props: { agilityProps },
|
||||||
revalidate: rebuildFrequency
|
revalidate: rebuildFrequency
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -81,7 +77,6 @@ export async function getStaticProps({ preview, params, locale, locales, default
|
|||||||
return {
|
return {
|
||||||
props: {
|
props: {
|
||||||
error: `Params: ${params}, Error: ${err}, Stack: ${st}`,
|
error: `Params: ${params}, Error: ${err}, Stack: ${st}`,
|
||||||
header: null,
|
|
||||||
agilityProps: null
|
agilityProps: null
|
||||||
},
|
},
|
||||||
revalidate: 60000
|
revalidate: 60000
|
||||||
@ -98,14 +93,26 @@ export async function getStaticPaths({ defaultLocale, locales }: GetStaticPathsC
|
|||||||
agilityPaths = agilityPaths.filter(p => p !== "/product/product-details")
|
agilityPaths = agilityPaths.filter(p => p !== "/product/product-details")
|
||||||
|
|
||||||
//get the product paths from the commerce api
|
//get the product paths from the commerce api
|
||||||
const { products } = await getAllProductPaths()
|
const { products } = await commerce.getAllProductPaths()
|
||||||
const productPaths = products.map(p => `/product${p.node.path}`)
|
|
||||||
|
let productPaths = []
|
||||||
|
if (locales) {
|
||||||
|
productPaths = locales.reduce<string[]>((arr, locale) => {
|
||||||
|
// Add a product path for every locale
|
||||||
|
products.forEach((product: any) => {
|
||||||
|
arr.push(`/${locale}/product${product.path}`)
|
||||||
|
})
|
||||||
|
return arr
|
||||||
|
}, [])
|
||||||
|
} else {
|
||||||
|
productPaths = products.map((product: any) => `/product${product.path}`)
|
||||||
|
}
|
||||||
|
|
||||||
const paths = [...agilityPaths, ...productPaths]
|
const paths = [...agilityPaths, ...productPaths]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths,
|
paths,
|
||||||
fallback: true,
|
fallback: 'blocking',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,94 +1,2 @@
|
|||||||
|
|
||||||
//this is just a pointer to the catch-all route and logic for all CMS driven pages (i.e. even rootpage is dynamic from the CMS)
|
//this is just a pointer to the catch-all route and logic for all CMS driven pages (i.e. even rootpage is dynamic from the CMS)
|
||||||
export { default, getStaticProps } from './[...slug]';
|
export { default, getStaticProps } from './[...slug]';
|
||||||
|
|
||||||
// import commerce from '@lib/api/commerce'
|
|
||||||
// import { Layout } from '@components/common'
|
|
||||||
// import { ProductCard } from '@components/product'
|
|
||||||
// import { Grid, Marquee, Hero } from '@components/ui'
|
|
||||||
// // import HomeAllProductsGrid from '@components/common/HomeAllProductsGrid'
|
|
||||||
// import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
|
|
||||||
|
|
||||||
// export async function getStaticProps({
|
|
||||||
// preview,
|
|
||||||
// locale,
|
|
||||||
// locales,
|
|
||||||
// }: GetStaticPropsContext) {
|
|
||||||
// const config = { locale, locales }
|
|
||||||
// const productsPromise = commerce.getAllProducts({
|
|
||||||
// variables: { first: 6 },
|
|
||||||
// config,
|
|
||||||
// preview,
|
|
||||||
// // Saleor provider only
|
|
||||||
// ...({ featured: true } as any),
|
|
||||||
// })
|
|
||||||
// const pagesPromise = commerce.getAllPages({ config, preview })
|
|
||||||
// const siteInfoPromise = commerce.getSiteInfo({ config, preview })
|
|
||||||
// const { products } = await productsPromise
|
|
||||||
// const { pages } = await pagesPromise
|
|
||||||
// const { categories, brands } = await siteInfoPromise
|
|
||||||
|
|
||||||
// return {
|
|
||||||
// props: {
|
|
||||||
// products,
|
|
||||||
// categories,
|
|
||||||
// brands,
|
|
||||||
// pages,
|
|
||||||
// },
|
|
||||||
// revalidate: 60,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export default function Home({
|
|
||||||
// products,
|
|
||||||
// }: InferGetStaticPropsType<typeof getStaticProps>) {
|
|
||||||
// return (
|
|
||||||
// <>
|
|
||||||
// <Grid variant="filled">
|
|
||||||
// {products.slice(0, 3).map((product: any, i: number) => (
|
|
||||||
// <ProductCard
|
|
||||||
// key={product.id}
|
|
||||||
// product={product}
|
|
||||||
// imgProps={{
|
|
||||||
// width: i === 0 ? 1080 : 540,
|
|
||||||
// height: i === 0 ? 1080 : 540,
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// ))}
|
|
||||||
// </Grid>
|
|
||||||
// <Marquee variant="secondary">
|
|
||||||
// {products.slice(0, 3).map((product: any, i: number) => (
|
|
||||||
// <ProductCard key={product.id} product={product} variant="slim" />
|
|
||||||
// ))}
|
|
||||||
// </Marquee>
|
|
||||||
// <Hero
|
|
||||||
// headline=" Dessert dragée halvah croissant."
|
|
||||||
// description="Cupcake ipsum dolor sit amet lemon drops pastry cotton candy. Sweet carrot cake macaroon bonbon croissant fruitcake jujubes macaroon oat cake. Soufflé bonbon caramels jelly beans. Tiramisu sweet roll cheesecake pie carrot cake. "
|
|
||||||
// />
|
|
||||||
// <Grid layout="B" variant="filled">
|
|
||||||
// {products.slice(0, 3).map((product: any, i: number) => (
|
|
||||||
// <ProductCard
|
|
||||||
// key={product.id}
|
|
||||||
// product={product}
|
|
||||||
// imgProps={{
|
|
||||||
// width: i === 0 ? 1080 : 540,
|
|
||||||
// height: i === 0 ? 1080 : 540,
|
|
||||||
// }}
|
|
||||||
// />
|
|
||||||
// ))}
|
|
||||||
// </Grid>
|
|
||||||
// <Marquee>
|
|
||||||
// {products.slice(3).map((product: any, i: number) => (
|
|
||||||
// <ProductCard key={product.id} product={product} variant="slim" />
|
|
||||||
// ))}
|
|
||||||
// </Marquee>
|
|
||||||
// {/* <HomeAllProductsGrid
|
|
||||||
// newestProducts={products}
|
|
||||||
// categories={categories}
|
|
||||||
// brands={brands}
|
|
||||||
// /> */}
|
|
||||||
// </>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Home.Layout = Layout
|
|
||||||
|
@ -22,14 +22,13 @@
|
|||||||
"@components/*": ["components/*"],
|
"@components/*": ["components/*"],
|
||||||
"@commerce": ["framework/commerce"],
|
"@commerce": ["framework/commerce"],
|
||||||
"@commerce/*": ["framework/commerce/*"],
|
"@commerce/*": ["framework/commerce/*"],
|
||||||
"@framework": ["framework/local"],
|
"@framework": ["framework/bigcommerce"],
|
||||||
"@framework/*": ["framework/local/*"]
|
"@framework/*": ["framework/bigcommerce/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
"include": ["next-env.d.ts", "**/*.d.ts", "**/*.ts", "**/*.tsx", "**/*.js"],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"node_modules",
|
"node_modules",
|
||||||
"./framework/bigcommerce",
|
|
||||||
"./framework/shopify",
|
"./framework/shopify",
|
||||||
"./framework/swell",
|
"./framework/swell",
|
||||||
"./framework/vendure",
|
"./framework/vendure",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user