mirror of
https://github.com/vercel/commerce.git
synced 2025-07-29 21:21:23 +00:00
.vscode
assets
components
auth
cart
CartItem
CartItem.module.css
CartItem.tsx
index.ts
CartSidebarView
index.ts
checkout
common
icons
product
ui
wishlist
search.tsx
config
framework
lib
pages
public
.editorconfig
.env.template
.gitignore
.prettierignore
.prettierrc
README.md
codegen.bigcommerce.json
codegen.json
commerce.config.json
global.d.ts
license.md
next-env.d.ts
next.config.js
package.json
postcss.config.js
swell-js.d.ts
tailwind.config.js
tsconfig.json
yarn.lock
* Custom Checkout Progress * Updates to Checkout * Custom Checkout Progress * Adding tabs * Adding Collapse * Adding Collapse * Improving Sidebar Scroll * Modif footer * Changes * More design updates * sidebar cart * More design updates * More design updates * More design updates * More design updates * Types * Types * Design Updates * More changes * More changes * More changes * Changes * Changes * Changes * New tailwind required changes * Sidebar Styling issues with Mobile * Latest changes - Normalizing cart * Styling Fixes * New changes * Changes * latest * Refactor and Renaming some UI Props * Adding Quantity Component * Adding Rating Component * Rating Component * More updates * User Select disabled, plus hidding horizontal scroll bars * Changes * Adding ProductOptions Component and more helpers * Styling updates * Styling updates * Fix for slim tags * Missmatch with RightArrow * Footer updates and some styles * Latest Updates * Latest Updates * Latest Updates * Removing Portal, since it's not needed. We might add it later I'd rather not to. * Removing Portal, since it's not needed. We might add it later I'd rather not to. * Sam backdrop filter * General UI Improvements * General UI Improvements * Search now with Geist Colors * Now with Geist Colors * Changes * Scroll for Mobile on IOs devises * LoadingDots Working (: * Changes * More Changes * Perf changes * More perf changes * Fade to the Nametags in the ProductCard * changes * Search issue ui * Search issue ui * Make sure to only refresh navbar and modals when required * Index revalidate * Fixed image issue * hide album scroll on windows * Fix scrollbar * Changing * Adding 404 with Layout * Removing Toast * Adding Assets * Adding Assets * Progress with LocalProvider * New productTag * Only images for the drop * changes * Empty SWRhooks * Adding Local Provider * Working local * Working view of a LocalProvider * More updates * Changes * Removed react-ticker * default to local if no env available * default to local if no env available * add missing `@` to css import * rewrite search rewrites to multiple pages * allow requests in getStaticProps to execute in parallel * make type import explicit * add a tsconfig.js file * use local provider in tsconfig.js * avoid a circular dependency * Saleor was not in the providers list * avoid circular dependency in bigcommerce * Adding more to the Local Provider (#366) * Adding more data * Adding more data * optimize assets (#370) * Optimize assets (#372) * optimize assets * remove assets * remove assets * cart enabled * Adding saleor * Changes with Webpack * Changes Co-authored-by: Luis Alvarez <luis@vercel.com> Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com> Co-authored-by: Shu Ding <g@shud.in>
152 lines
4.6 KiB
TypeScript
152 lines
4.6 KiB
TypeScript
import { ChangeEvent, FocusEventHandler, useEffect, useState } from 'react'
|
|
import cn from 'classnames'
|
|
import Image from 'next/image'
|
|
import Link from 'next/link'
|
|
import s from './CartItem.module.css'
|
|
import { Trash, Plus, Minus, Cross } from '@components/icons'
|
|
import { useUI } from '@components/ui/context'
|
|
import type { LineItem } from '@commerce/types/cart'
|
|
import usePrice from '@framework/product/use-price'
|
|
import useUpdateItem from '@framework/cart/use-update-item'
|
|
import useRemoveItem from '@framework/cart/use-remove-item'
|
|
import Quantity from '@components/ui/Quantity'
|
|
|
|
type ItemOption = {
|
|
name: string
|
|
nameId: number
|
|
value: string
|
|
valueId: number
|
|
}
|
|
|
|
const CartItem = ({
|
|
item,
|
|
variant = 'default',
|
|
currencyCode,
|
|
...rest
|
|
}: {
|
|
variant?: 'default' | 'display'
|
|
item: LineItem
|
|
currencyCode: string
|
|
}) => {
|
|
const { closeSidebarIfPresent } = useUI()
|
|
const [removing, setRemoving] = useState(false)
|
|
const [quantity, setQuantity] = useState<number>(item.quantity)
|
|
const removeItem = useRemoveItem()
|
|
const updateItem = useUpdateItem({ item })
|
|
|
|
const { price } = usePrice({
|
|
amount: item.variant.price * item.quantity,
|
|
baseAmount: item.variant.listPrice * item.quantity,
|
|
currencyCode,
|
|
})
|
|
|
|
const handleChange = async ({
|
|
target: { value },
|
|
}: ChangeEvent<HTMLInputElement>) => {
|
|
setQuantity(Number(value))
|
|
await updateItem({ quantity: Number(value) })
|
|
}
|
|
|
|
const increaseQuantity = async (n = 1) => {
|
|
const val = Number(quantity) + n
|
|
setQuantity(val)
|
|
await updateItem({ quantity: val })
|
|
}
|
|
|
|
const handleRemove = async () => {
|
|
setRemoving(true)
|
|
try {
|
|
await removeItem(item)
|
|
} catch (error) {
|
|
setRemoving(false)
|
|
}
|
|
}
|
|
|
|
// TODO: Add a type for this
|
|
const options = (item as any).options
|
|
|
|
useEffect(() => {
|
|
// Reset the quantity state if the item quantity changes
|
|
if (item.quantity !== Number(quantity)) {
|
|
setQuantity(item.quantity)
|
|
}
|
|
}, [item.quantity])
|
|
|
|
return (
|
|
<li
|
|
className={cn(s.root, {
|
|
'opacity-50 pointer-events-none': removing,
|
|
})}
|
|
{...rest}
|
|
>
|
|
<div className="flex flex-row space-x-4 py-4">
|
|
<div className="w-16 h-16 bg-violet relative overflow-hidden cursor-pointer z-0">
|
|
<Link href={`/product/${item.path}`}>
|
|
<Image
|
|
onClick={() => closeSidebarIfPresent()}
|
|
className={s.productImage}
|
|
width={150}
|
|
height={150}
|
|
src={item.variant.image!.url}
|
|
alt={item.variant.image!.altText}
|
|
unoptimized
|
|
/>
|
|
</Link>
|
|
</div>
|
|
<div className="flex-1 flex flex-col text-base">
|
|
<Link href={`/product/${item.path}`}>
|
|
<span
|
|
className={s.productName}
|
|
onClick={() => closeSidebarIfPresent()}
|
|
>
|
|
{item.name}
|
|
</span>
|
|
</Link>
|
|
{options && options.length > 0 && (
|
|
<div className="flex items-center pb-1">
|
|
{options.map((option: ItemOption, i: number) => (
|
|
<div
|
|
key={`${item.id}-${option.name}`}
|
|
className="text-sm font-semibold text-accent-7 inline-flex items-center justify-center"
|
|
>
|
|
{option.name}
|
|
{option.name === 'Color' ? (
|
|
<span
|
|
className="mx-2 rounded-full bg-transparent border w-5 h-5 p-1 text-accent-9 inline-flex items-center justify-center overflow-hidden"
|
|
style={{
|
|
backgroundColor: `${option.value}`,
|
|
}}
|
|
></span>
|
|
) : (
|
|
<span className="mx-2 rounded-full bg-transparent border h-5 p-1 text-accent-9 inline-flex items-center justify-center overflow-hidden">
|
|
{option.value}
|
|
</span>
|
|
)}
|
|
{i === options.length - 1 ? '' : <span className="mr-3" />}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
{variant === 'display' && (
|
|
<div className="text-sm tracking-wider">{quantity}x</div>
|
|
)}
|
|
</div>
|
|
<div className="flex flex-col justify-between space-y-2 text-sm">
|
|
<span>{price}</span>
|
|
</div>
|
|
</div>
|
|
{variant === 'default' && (
|
|
<Quantity
|
|
value={quantity}
|
|
handleRemove={handleRemove}
|
|
handleChange={handleChange}
|
|
increase={() => increaseQuantity(1)}
|
|
decrease={() => increaseQuantity(-1)}
|
|
/>
|
|
)}
|
|
</li>
|
|
)
|
|
}
|
|
|
|
export default CartItem
|