This commit is contained in:
Joel Varty 2021-06-17 17:37:32 -04:00
parent d48aec2c2d
commit d9fe7d8e6b
23 changed files with 263 additions and 11789 deletions

View File

@ -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,21 +14,14 @@ 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} </Marquee>
variant="slim"
imgWidth={320}
imgHeight={320}
imgLayout="fixed"
/>
))}
</Marquee>
) )
} }

View File

@ -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,39 +17,37 @@ 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" />
</span> </span>
<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>
) : error ? ( ) : error ? (
<div className="flex-1 px-4 flex flex-col justify-center items-center"> <div className="flex-1 px-4 flex flex-col justify-center items-center">
@ -60,7 +57,7 @@ const Cart: FC<Props> = ({ fields, customData }) => {
<h2 className="pt-6 text-xl font-light text-center"> <h2 className="pt-6 text-xl font-light text-center">
We couldnt process the purchase. Please check your card We couldnt process the purchase. Please check your card
information and try again. information and try again.
</h2> </h2>
</div> </div>
) : success ? ( ) : success ? (
<div className="flex-1 px-4 flex flex-col justify-center items-center"> <div className="flex-1 px-4 flex flex-col justify-center items-center">
@ -69,14 +66,14 @@ const Cart: FC<Props> = ({ fields, customData }) => {
</span> </span>
<h2 className="pt-6 text-xl font-light text-center"> <h2 className="pt-6 text-xl font-light text-center">
Thank you for your order. Thank you for your order.
</h2> </h2>
</div> </div>
) : ( ) : (
<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>
@ -127,10 +156,10 @@ const Cart: FC<Props> = ({ fields, customData }) => {
Continue Shopping Continue Shopping
</Button> </Button>
) : ( ) : (
<Button href="/checkout" Component="a" width="100%"> <Button href="/checkout" Component="a" width="100%">
Proceed to Checkout Proceed to Checkout
</Button> </Button>
)} )}
</div> </div>
</div> </div>
</div> </div>

View File

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

View File

@ -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 }}) => {

View File

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

View File

@ -8,7 +8,7 @@ import { Module } from '@agility/nextjs'
interface Fields { interface Fields {
} }
const Orders: Module<Fields> = ({ }) => { const Orders: Module<Fields> = ({ }) => {
return ( return (
<Container> <Container>
<Text variant="pageHeading">My Orders</Text> <Text variant="pageHeading">My Orders</Text>
@ -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>

View File

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

View File

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

View File

@ -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'
@ -12,34 +12,30 @@ interface Fields {
} }
const ProfileModule:Module<Fields> = ({ module: {fields}}) => { 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>
)} )}
</Container>
{ !data && )
<Text variant="body">{fields.notLoggedInMessage}</Text>
}
</Container>
)
} }
export default ProfileModule export default ProfileModule

View File

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

View File

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

View File

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

View 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}

View File

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

View File

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

View 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 }

View File

@ -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,14 +6,16 @@ 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 {
categories,
brands,
}
return {
categories,
brands
}
} }

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -5,20 +5,14 @@ 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 getModuleData from "framework/module-data"
import getProduct from '@framework/api/operations/get-product'
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[] }>) {
@ -43,11 +37,13 @@ export async function getStaticProps({ preview, params, locale, locales, default
let rebuildFrequency = 10 let rebuildFrequency = 10
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',
} }
} }

View File

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

View File

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