forked from crowetic/commerce
Changes
This commit is contained in:
parent
fc34856e50
commit
7f70cfd868
@ -12,7 +12,7 @@ const CartItem = ({
|
||||
item,
|
||||
currencyCode,
|
||||
}: {
|
||||
item: any
|
||||
item: CartItem
|
||||
currencyCode: string
|
||||
}) => {
|
||||
const { price } = usePrice({
|
||||
@ -55,7 +55,7 @@ const CartItem = ({
|
||||
try {
|
||||
// If this action succeeds then there's no need to do `setRemoving(true)`
|
||||
// because the component will be removed from the view
|
||||
await removeItem({ id: item.id })
|
||||
await removeItem({ id: String(item.id) })
|
||||
} catch (error) {
|
||||
setRemoving(false)
|
||||
}
|
||||
@ -77,16 +77,14 @@ const CartItem = ({
|
||||
<div className="w-16 h-16 bg-violet relative overflow-hidden">
|
||||
<Image
|
||||
className={s.productImage}
|
||||
src={item.image_url}
|
||||
width={150}
|
||||
height={150}
|
||||
alt="Product Image"
|
||||
// The cart item image is already optimized and very small in size
|
||||
src={item.images[0].url}
|
||||
alt={item.images[0].alt}
|
||||
unoptimized
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 flex flex-col text-base">
|
||||
{/** TODO: Replace this. No `path` found at Cart */}
|
||||
<Link href={`/product/${item.url.split('/')[3]}`}>
|
||||
<span className="font-bold mb-5 text-lg cursor-pointer">
|
||||
{item.name}
|
||||
@ -115,7 +113,10 @@ const CartItem = ({
|
||||
</div>
|
||||
<div className="flex flex-col justify-between space-y-2 text-base">
|
||||
<span>{price}</span>
|
||||
<button className="flex justify-end" onClick={handleRemove}>
|
||||
<button
|
||||
className="flex justify-end outline-none"
|
||||
onClick={handleRemove}
|
||||
>
|
||||
<Trash />
|
||||
</button>
|
||||
</div>
|
||||
|
@ -16,19 +16,17 @@ const CartSidebarView: FC = () => {
|
||||
const { price: subTotal } = usePrice(
|
||||
data && {
|
||||
amount: data.base_amount,
|
||||
currencyCode: data.currency.code,
|
||||
currencyCode: data.currency?.code || 'USD',
|
||||
}
|
||||
)
|
||||
const { price: total } = usePrice(
|
||||
data && {
|
||||
amount: data.cart_amount,
|
||||
currencyCode: data.currency.code,
|
||||
currencyCode: data.currency?.code || 'USD',
|
||||
}
|
||||
)
|
||||
const handleClose = () => closeSidebar()
|
||||
|
||||
const items = data?.line_items.physical_items ?? []
|
||||
|
||||
const error = null
|
||||
const success = null
|
||||
|
||||
@ -95,7 +93,7 @@ const CartSidebarView: FC = () => {
|
||||
My Cart
|
||||
</h2>
|
||||
<ul className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-accents-3 border-t border-accents-3">
|
||||
{items.map((item: any) => (
|
||||
{data.products.map((item: any) => (
|
||||
<CartItem
|
||||
key={item.id}
|
||||
item={item}
|
||||
|
@ -146,7 +146,7 @@ const ProductView: FC<Props> = ({ product }) => {
|
||||
className={s.button}
|
||||
onClick={addToCart}
|
||||
loading={loading}
|
||||
disabled={!variant}
|
||||
disabled={!variant && product.options.length > 0}
|
||||
>
|
||||
Add to Cart
|
||||
</Button>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Product } from 'framework/types'
|
||||
import getAllProducts, { ProductEdge } from '../../operations/get-all-products'
|
||||
import type { ProductsHandlers } from '../products'
|
||||
|
||||
@ -6,6 +7,7 @@ const SORT: { [key: string]: string | undefined } = {
|
||||
trending: 'total_sold',
|
||||
price: 'price',
|
||||
}
|
||||
|
||||
const LIMIT = 12
|
||||
|
||||
// Return current cart info
|
||||
@ -44,21 +46,25 @@ const getProducts: ProductsHandlers['getProducts'] = async ({
|
||||
const { data } = await config.storeApiFetch<{ data: { id: number }[] }>(
|
||||
url.pathname + url.search
|
||||
)
|
||||
|
||||
const entityIds = data.map((p) => p.id)
|
||||
const found = entityIds.length > 0
|
||||
|
||||
// We want the GraphQL version of each product
|
||||
const graphqlData = await getAllProducts({
|
||||
variables: { first: LIMIT, entityIds },
|
||||
config,
|
||||
})
|
||||
|
||||
// Put the products in an object that we can use to get them by id
|
||||
const productsById = graphqlData.products.reduce<{
|
||||
[k: number]: ProductEdge
|
||||
[k: number]: Product
|
||||
}>((prods, p) => {
|
||||
prods[p.node.entityId] = p
|
||||
prods[p.id] = p
|
||||
return prods
|
||||
}, {})
|
||||
const products: ProductEdge[] = found ? [] : graphqlData.products
|
||||
|
||||
const products: Product[] = found ? [] : graphqlData.products
|
||||
|
||||
// Populate the products array with the graphql products, in the order
|
||||
// assigned by the list of entity ids
|
||||
|
@ -4,11 +4,11 @@ import createApiHandler, {
|
||||
BigcommerceHandler,
|
||||
} from '../utils/create-api-handler'
|
||||
import { BigcommerceApiError } from '../utils/errors'
|
||||
import type { ProductEdge } from '../operations/get-all-products'
|
||||
import getProducts from './handlers/get-products'
|
||||
import { Product } from 'framework/types'
|
||||
|
||||
export type SearchProductsData = {
|
||||
products: ProductEdge[]
|
||||
products: Product[]
|
||||
found: boolean
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ async function getAllProducts({
|
||||
})
|
||||
}
|
||||
|
||||
return { products: products.map(({ node }) => normalizeProduct(node)) }
|
||||
return { products: products.map(({ node }) => normalizeProduct(node as any)) }
|
||||
}
|
||||
|
||||
export default getAllProducts
|
||||
|
@ -111,7 +111,7 @@ async function getProduct({
|
||||
setProductLocaleMeta(product)
|
||||
}
|
||||
|
||||
return { product: normalizeProduct(product) }
|
||||
return { product: normalizeProduct(product as any) }
|
||||
}
|
||||
|
||||
return {}
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { Product as BCProduct } from '@framework/schema'
|
||||
import { Cart, CartItem, Product } from '../../types'
|
||||
import { Product as BigCommerceProduct } from '@framework/schema'
|
||||
|
||||
function normalizeProductOption({
|
||||
node: {
|
||||
@ -14,7 +15,7 @@ function normalizeProductOption({
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeProduct(productNode: BCProduct): Product {
|
||||
export function normalizeProduct(productNode: BigCommerceProduct): Product {
|
||||
const {
|
||||
entityId: id,
|
||||
images,
|
||||
@ -67,12 +68,47 @@ export function normalizeProduct(productNode: BCProduct): Product {
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizeCart({ data, ...rest }: any) {
|
||||
export function normalizeCart({ data, ...rest }: any): Cart {
|
||||
return {
|
||||
...rest,
|
||||
data: {
|
||||
products: data?.line_items?.physical_items ?? [],
|
||||
products: data?.line_items?.physical_items.map(itemsToProducts) ?? [],
|
||||
...data,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function itemsToProducts({
|
||||
id,
|
||||
name,
|
||||
quantity,
|
||||
product_id,
|
||||
variant_id,
|
||||
image_url,
|
||||
list_price,
|
||||
sale_price,
|
||||
extended_list_price,
|
||||
extended_sale_price,
|
||||
...rest
|
||||
}: any): CartItem {
|
||||
return {
|
||||
id,
|
||||
name,
|
||||
prices: {
|
||||
listPrice: list_price,
|
||||
salePrice: sale_price,
|
||||
extendedListPrice: extended_list_price,
|
||||
extendedSalePrice: extended_sale_price,
|
||||
},
|
||||
images: [
|
||||
{
|
||||
alt: name,
|
||||
url: image_url,
|
||||
},
|
||||
],
|
||||
productId: product_id,
|
||||
variantId: variant_id,
|
||||
quantity,
|
||||
...rest,
|
||||
}
|
||||
}
|
||||
|
19
framework/types.d.ts
vendored
19
framework/types.d.ts
vendored
@ -1,3 +1,5 @@
|
||||
import { CartItem } from '@components/cart'
|
||||
|
||||
interface Entity {
|
||||
id: string | number
|
||||
[prop: string]: any
|
||||
@ -12,6 +14,7 @@ interface Product extends Entity {
|
||||
variants: ProductVariant[]
|
||||
price: ProductPrice
|
||||
options: ProductOption[]
|
||||
sku?: string
|
||||
}
|
||||
|
||||
interface ProductOption extends Entity {
|
||||
@ -37,8 +40,11 @@ interface ProductVariant {
|
||||
interface ProductPrice {
|
||||
value: number
|
||||
currencyCode: 'USD' | 'ARS' | string | undefined
|
||||
retailValue?: number
|
||||
saleValue?: number
|
||||
retailPrice?: number
|
||||
salePrice?: number
|
||||
listPrice?: number
|
||||
extendedSalePrice?: number
|
||||
extendedListPrice?: number
|
||||
}
|
||||
|
||||
interface Cart extends Entity {
|
||||
@ -46,7 +52,14 @@ interface Cart extends Entity {
|
||||
currency: { code: string }
|
||||
taxIncluded?: boolean
|
||||
totalAmmount: number | string
|
||||
products: Pick<Product, 'id' | 'name' | 'prices'>[]
|
||||
products: Pick<Product, 'id' | 'name' | 'prices'> & CartItem[]
|
||||
}
|
||||
|
||||
interface CartItem extends Entity {
|
||||
quantity: number
|
||||
productId: Product['id']
|
||||
variantId: ProductVariant['id']
|
||||
images: ProductImage[]
|
||||
}
|
||||
|
||||
interface Wishlist extends Entity {
|
||||
|
@ -60,6 +60,7 @@
|
||||
"next": "^10.0.5",
|
||||
"next-seo": "^4.11.0",
|
||||
"next-themes": "^0.0.4",
|
||||
"normalizr": "^3.6.1",
|
||||
"postcss-nesting": "^7.0.1",
|
||||
"react": "^16.14.0",
|
||||
"react-dom": "^16.14.0",
|
||||
|
@ -29,20 +29,18 @@ export default function Cart() {
|
||||
return <div>Loading</div>
|
||||
}
|
||||
|
||||
console.log('Cart Data', data)
|
||||
|
||||
// const { price: subTotal } = usePrice(
|
||||
// data && {
|
||||
// amount: data.base_amount,
|
||||
// currencyCode: data.currency.code,
|
||||
// }
|
||||
// )
|
||||
// const { price: total } = usePrice(
|
||||
// data && {
|
||||
// amount: data.cart_amount,
|
||||
// currencyCode: data.currency.code,
|
||||
// }
|
||||
// )
|
||||
const { price: subTotal } = usePrice(
|
||||
data && {
|
||||
amount: data.base_amount,
|
||||
currencyCode: data.currency.code,
|
||||
}
|
||||
)
|
||||
const { price: total } = usePrice(
|
||||
data && {
|
||||
amount: data.cart_amount,
|
||||
currencyCode: data.currency.code,
|
||||
}
|
||||
)
|
||||
|
||||
// const items = data?.line_items.physical_items ?? []
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
import { Layout } from '@components/common'
|
||||
|
||||
export default function Home() {
|
||||
return <>Hello</>
|
||||
}
|
||||
|
||||
Home.Layout = Layout
|
@ -3,16 +3,29 @@ import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
|
||||
import Link from 'next/link'
|
||||
import { useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import { getConfig } from '@framework/api'
|
||||
import getAllPages from '@framework/api/operations/get-all-pages'
|
||||
import getSiteInfo from '@framework/api/operations/get-site-info'
|
||||
import useSearch from '@framework/product/use-search'
|
||||
|
||||
import { Layout } from '@components/common'
|
||||
import { ProductCard } from '@components/product'
|
||||
import { Container, Grid, Skeleton } from '@components/ui'
|
||||
|
||||
import { getConfig } from '@framework/api'
|
||||
import getAllPages from '@framework/api/operations/get-all-pages'
|
||||
import getSiteInfo from '@framework/api/operations/get-site-info'
|
||||
import useSearch from '@framework/product/use-search'
|
||||
|
||||
import rangeMap from '@lib/range-map'
|
||||
|
||||
// TODO(bc) Remove this. This should come from the API
|
||||
import getSlug from '@lib/get-slug'
|
||||
|
||||
// TODO (bc) : Remove or standarize this.
|
||||
const SORT = Object.entries({
|
||||
'latest-desc': 'Latest arrivals',
|
||||
'trending-desc': 'Trending',
|
||||
'price-asc': 'Price: Low to high',
|
||||
'price-desc': 'Price: High to low',
|
||||
})
|
||||
|
||||
import {
|
||||
filterQuery,
|
||||
getCategoryPath,
|
||||
@ -27,19 +40,11 @@ export async function getStaticProps({
|
||||
const config = getConfig({ locale })
|
||||
const { pages } = await getAllPages({ config, preview })
|
||||
const { categories, brands } = await getSiteInfo({ config, preview })
|
||||
|
||||
return {
|
||||
props: { pages, categories, brands },
|
||||
}
|
||||
}
|
||||
|
||||
const SORT = Object.entries({
|
||||
'latest-desc': 'Latest arrivals',
|
||||
'trending-desc': 'Trending',
|
||||
'price-asc': 'Price: Low to high',
|
||||
'price-desc': 'Price: High to low',
|
||||
})
|
||||
|
||||
export default function Search({
|
||||
categories,
|
||||
brands,
|
||||
@ -76,7 +81,6 @@ export default function Search({
|
||||
} else {
|
||||
setToggleFilter(!toggleFilter)
|
||||
}
|
||||
|
||||
setActiveFilter(filter)
|
||||
}
|
||||
|
||||
@ -333,14 +337,16 @@ export default function Search({
|
||||
|
||||
{data ? (
|
||||
<Grid layout="normal">
|
||||
{data.products.map(({ node }) => (
|
||||
{data.products.map((product) => (
|
||||
<ProductCard
|
||||
variant="simple"
|
||||
key={node.path}
|
||||
key={product.path}
|
||||
className="animated fadeIn"
|
||||
product={node}
|
||||
imgWidth={480}
|
||||
imgHeight={480}
|
||||
product={product}
|
||||
imgProps={{
|
||||
width: 480,
|
||||
height: 480,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Grid>
|
||||
|
@ -28,7 +28,7 @@
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"./framework/types.d.ts",
|
||||
"framework/types.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
"**/*.js"
|
||||
|
@ -5195,6 +5195,11 @@ normalize.css@^8.0.1:
|
||||
resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3"
|
||||
integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg==
|
||||
|
||||
normalizr@^3.6.1:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/normalizr/-/normalizr-3.6.1.tgz#d367ab840e031ff382141b8d81ce279292ff69fe"
|
||||
integrity sha512-8iEmqXmPtll8PwbEFrbPoDxVw7MKnNvt3PZzR2Xvq9nggEEOgBlNICPXYzyZ4w4AkHUzCU998mdatER3n2VaMA==
|
||||
|
||||
npmlog@^4.0.1, npmlog@^4.1.2:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
|
||||
|
Loading…
x
Reference in New Issue
Block a user