mirror of
https://github.com/vercel/commerce.git
synced 2025-06-18 13:11:23 +00:00
Add cart item options like color and size
This commit is contained in:
parent
742ac5786e
commit
7659358a63
@ -8,6 +8,13 @@ import useUpdateItem from '@framework/cart/use-update-item'
|
|||||||
import useRemoveItem from '@framework/cart/use-remove-item'
|
import useRemoveItem from '@framework/cart/use-remove-item'
|
||||||
import s from './CartItem.module.css'
|
import s from './CartItem.module.css'
|
||||||
|
|
||||||
|
type ItemOption = {
|
||||||
|
name: string,
|
||||||
|
nameId: number,
|
||||||
|
value: string,
|
||||||
|
valueId: number
|
||||||
|
}
|
||||||
|
|
||||||
const CartItem = ({
|
const CartItem = ({
|
||||||
item,
|
item,
|
||||||
currencyCode,
|
currencyCode,
|
||||||
@ -88,11 +95,19 @@ const CartItem = ({
|
|||||||
<div className="flex-1 flex flex-col text-base">
|
<div className="flex-1 flex flex-col text-base">
|
||||||
{/** TODO: Replace this. No `path` found at Cart */}
|
{/** TODO: Replace this. No `path` found at Cart */}
|
||||||
<Link href={`/product/${item.url.split('/')[3]}`}>
|
<Link href={`/product/${item.url.split('/')[3]}`}>
|
||||||
<span className="font-bold mb-5 text-lg cursor-pointer">
|
<span className="font-bold mb-2 text-lg cursor-pointer">
|
||||||
{item.name}
|
{item.name}
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
|
{item.options && item.options.length > 0 ? (
|
||||||
|
<div className="flex flex-col mb-2">
|
||||||
|
{item.options.map((option:ItemOption) =>
|
||||||
|
<span key={`${item.id}-${option.name}`} className="text-sm">
|
||||||
|
{`${option.name}: ${option.value}`}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<button type="button" onClick={() => increaseQuantity(-1)}>
|
<button type="button" onClick={() => increaseQuantity(-1)}>
|
||||||
<Minus width={18} height={18} />
|
<Minus width={18} height={18} />
|
||||||
|
@ -38,15 +38,14 @@ const ProductView: FC<Props> = ({ product }) => {
|
|||||||
size: null,
|
size: null,
|
||||||
color: null,
|
color: null,
|
||||||
})
|
})
|
||||||
const variant =
|
const variant = getCurrentVariant(product, choices)
|
||||||
getCurrentVariant(product, choices) || product.variants.edges?.[0]
|
|
||||||
|
|
||||||
const addToCart = async () => {
|
const addToCart = async () => {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
try {
|
try {
|
||||||
await addItem({
|
await addItem({
|
||||||
productId: product.entityId,
|
productId: product.entityId,
|
||||||
variantId: product.variants.edges?.[0]?.node.entityId!,
|
variantId: variant?.node.entityId!,
|
||||||
})
|
})
|
||||||
openSidebar()
|
openSidebar()
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
@ -156,7 +155,7 @@ const ProductView: FC<Props> = ({ product }) => {
|
|||||||
<WishlistButton
|
<WishlistButton
|
||||||
className={s.wishlistButton}
|
className={s.wishlistButton}
|
||||||
productId={product.entityId}
|
productId={product.entityId}
|
||||||
variant={product.variants.edges?.[0]!}
|
variant={variant!}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -32,8 +32,10 @@ export function getProductOptions(product: ProductNode) {
|
|||||||
export function getCurrentVariant(product: ProductNode, opts: SelectedOptions) {
|
export function getCurrentVariant(product: ProductNode, opts: SelectedOptions) {
|
||||||
const variant = product.variants.edges?.find((edge) => {
|
const variant = product.variants.edges?.find((edge) => {
|
||||||
const { node } = edge ?? {}
|
const { node } = edge ?? {}
|
||||||
|
const numberOfDefinedOpts = Object.values(opts).filter(value => value !== null).length;
|
||||||
|
const numberOfEdges = node?.productOptions?.edges?.length;
|
||||||
|
|
||||||
return Object.entries(opts).every(([key, value]) =>
|
const isEdgeEqualToOption = ([key, value]:[string, string | null]) =>
|
||||||
node?.productOptions.edges?.find((edge) => {
|
node?.productOptions.edges?.find((edge) => {
|
||||||
if (
|
if (
|
||||||
edge?.node.__typename === 'MultipleChoiceOption' &&
|
edge?.node.__typename === 'MultipleChoiceOption' &&
|
||||||
@ -43,9 +45,12 @@ export function getCurrentVariant(product: ProductNode, opts: SelectedOptions) {
|
|||||||
(valueEdge) => valueEdge?.node.label === value
|
(valueEdge) => valueEdge?.node.label === value
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
)
|
|
||||||
|
return numberOfDefinedOpts === numberOfEdges ?
|
||||||
|
Object.entries(opts).every(isEdgeEqualToOption)
|
||||||
|
: Object.entries(opts).some(isEdgeEqualToOption)
|
||||||
})
|
})
|
||||||
|
|
||||||
return variant
|
return variant ?? product.variants.edges?.[0]
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,8 @@ const addItem: CartHandlers['addItem'] = async ({
|
|||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
const { data } = cartId
|
const { data } = cartId
|
||||||
? await config.storeApiFetch(`/v3/carts/${cartId}/items`, options)
|
? await config.storeApiFetch(`/v3/carts/${cartId}/items?include=line_items.physical_items.options`, options)
|
||||||
: await config.storeApiFetch('/v3/carts', options)
|
: await config.storeApiFetch('/v3/carts?include=line_items.physical_items.options', options)
|
||||||
|
|
||||||
// Create or update the cart cookie
|
// Create or update the cart cookie
|
||||||
res.setHeader(
|
res.setHeader(
|
||||||
|
@ -12,7 +12,7 @@ const getCart: CartHandlers['getCart'] = async ({
|
|||||||
|
|
||||||
if (cartId) {
|
if (cartId) {
|
||||||
try {
|
try {
|
||||||
result = await config.storeApiFetch(`/v3/carts/${cartId}`)
|
result = await config.storeApiFetch(`/v3/carts/${cartId}?include=line_items.physical_items.options`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof BigcommerceApiError && error.status === 404) {
|
if (error instanceof BigcommerceApiError && error.status === 404) {
|
||||||
// Remove the cookie if it exists but the cart wasn't found
|
// Remove the cookie if it exists but the cart wasn't found
|
||||||
|
@ -15,7 +15,7 @@ const removeItem: CartHandlers['removeItem'] = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await config.storeApiFetch<{ data: any } | null>(
|
const result = await config.storeApiFetch<{ data: any } | null>(
|
||||||
`/v3/carts/${cartId}/items/${itemId}`,
|
`/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`,
|
||||||
{ method: 'DELETE' }
|
{ method: 'DELETE' }
|
||||||
)
|
)
|
||||||
const data = result?.data ?? null
|
const data = result?.data ?? null
|
||||||
|
@ -16,7 +16,7 @@ const updateItem: CartHandlers['updateItem'] = async ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await config.storeApiFetch(
|
const { data } = await config.storeApiFetch(
|
||||||
`/v3/carts/${cartId}/items/${itemId}`,
|
`/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`,
|
||||||
{
|
{
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user