mirror of
https://github.com/vercel/commerce.git
synced 2025-05-18 07:26:59 +00:00
Adding Quantity Component
This commit is contained in:
parent
fe324696d7
commit
f8f8cb3494
@ -6,23 +6,6 @@
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.actions {
|
||||
@apply flex p-1 border-accent-2 border items-center justify-center w-12 text-accent-7;
|
||||
transition-property: border-color, background, color, transform, box-shadow;
|
||||
transition-duration: 0.15s;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
.actions:hover {
|
||||
@apply bg-accent-1 border-accent-3 text-accent-9;
|
||||
transition: border-color;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.actions:focus {
|
||||
@apply bg-accent-2 outline-none;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
appearance: textfield;
|
||||
@apply w-8 border-accent-2 border mx-3 rounded text-center text-sm text-black;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ChangeEvent, useEffect, useState } from 'react'
|
||||
import { ChangeEvent, FocusEventHandler, useEffect, useState } from 'react'
|
||||
import cn from 'classnames'
|
||||
import Image from 'next/image'
|
||||
import Link from 'next/link'
|
||||
@ -9,6 +9,7 @@ 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
|
||||
@ -28,6 +29,10 @@ const CartItem = ({
|
||||
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,
|
||||
@ -35,43 +40,22 @@ const CartItem = ({
|
||||
currencyCode,
|
||||
})
|
||||
|
||||
const updateItem = useUpdateItem({ item })
|
||||
const removeItem = useRemoveItem()
|
||||
const [quantity, setQuantity] = useState<number | ''>(item.quantity)
|
||||
const [removing, setRemoving] = useState(false)
|
||||
|
||||
const updateQuantity = async (val: number) => {
|
||||
await updateItem({ quantity: val })
|
||||
const handleChange = async ({
|
||||
target: { value },
|
||||
}: ChangeEvent<HTMLInputElement>) => {
|
||||
setQuantity(Number(value))
|
||||
await updateItem({ quantity: Number(value) })
|
||||
}
|
||||
|
||||
const handleQuantity = (e: ChangeEvent<HTMLInputElement>) => {
|
||||
const val = !e.target.value ? '' : Number(e.target.value)
|
||||
|
||||
if (!val || (Number.isInteger(val) && val >= 0)) {
|
||||
setQuantity(val)
|
||||
}
|
||||
}
|
||||
|
||||
const handleBlur = () => {
|
||||
const val = Number(quantity)
|
||||
if (val !== item.quantity) {
|
||||
updateQuantity(val)
|
||||
}
|
||||
}
|
||||
|
||||
const increaseQuantity = (n = 1) => {
|
||||
const increaseQuantity = async (n = 1) => {
|
||||
const val = Number(quantity) + n
|
||||
if (Number.isInteger(val) && val >= 0) {
|
||||
setQuantity(val)
|
||||
updateQuantity(val)
|
||||
}
|
||||
await updateItem({ quantity: val })
|
||||
}
|
||||
|
||||
const handleRemove = async () => {
|
||||
setRemoving(true)
|
||||
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(item)
|
||||
} catch (error) {
|
||||
setRemoving(false)
|
||||
@ -152,38 +136,13 @@ const CartItem = ({
|
||||
</div>
|
||||
</div>
|
||||
{variant === 'default' && (
|
||||
<div className="flex flex-row h-9">
|
||||
<button className={s.actions} onClick={handleRemove}>
|
||||
<Cross width={20} height={20} />
|
||||
</button>
|
||||
<label className="w-full border-accent-2 border ml-2">
|
||||
<input
|
||||
type="number"
|
||||
max={99}
|
||||
min={0}
|
||||
className="bg-transparent px-4 w-full h-full focus:outline-none"
|
||||
<Quantity
|
||||
value={quantity}
|
||||
onChange={handleQuantity}
|
||||
onBlur={handleBlur}
|
||||
handleRemove={handleRemove}
|
||||
handleChange={handleChange}
|
||||
increase={() => increaseQuantity(1)}
|
||||
decrease={() => increaseQuantity(-1)}
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => increaseQuantity(-1)}
|
||||
className={s.actions}
|
||||
style={{ marginLeft: '-1px' }}
|
||||
>
|
||||
<Minus width={18} height={18} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => increaseQuantity(1)}
|
||||
className={cn(s.actions)}
|
||||
style={{ marginLeft: '-1px' }}
|
||||
>
|
||||
<Plus width={18} height={18} />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
|
@ -1,2 +0,0 @@
|
||||
.root {
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import React, { FC } from 'react'
|
||||
import s from './Quantifier.module.css'
|
||||
|
||||
export interface QuantifierProps {}
|
||||
|
||||
const Quantifier: FC<QuantifierProps> = ({}) => {
|
||||
return <div></div>
|
||||
}
|
||||
|
||||
export default Quantifier
|
@ -1,2 +0,0 @@
|
||||
export { default } from './Quantifier'
|
||||
export * from './Quantifier'
|
22
components/ui/Quantity/Quantity.module.css
Normal file
22
components/ui/Quantity/Quantity.module.css
Normal file
@ -0,0 +1,22 @@
|
||||
.actions {
|
||||
@apply flex p-1 border-accent-2 border items-center justify-center w-12 text-accent-7;
|
||||
transition-property: border-color, background, color, transform, box-shadow;
|
||||
transition-duration: 0.15s;
|
||||
transition-timing-function: ease;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.actions:hover {
|
||||
@apply border bg-accent-1 border-accent-3 text-accent-9;
|
||||
transition: border-color;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.actions:focus {
|
||||
@apply outline-none;
|
||||
}
|
||||
|
||||
.input {
|
||||
@apply bg-transparent px-4 w-full h-full focus:outline-none;
|
||||
user-select: none;
|
||||
}
|
62
components/ui/Quantity/Quantity.tsx
Normal file
62
components/ui/Quantity/Quantity.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import React, { FC } from 'react'
|
||||
import s from './Quantity.module.css'
|
||||
import { Cross, Plus, Minus } from '@components/icons'
|
||||
import cn from 'classnames'
|
||||
export interface QuantityProps {
|
||||
value: number
|
||||
increase: () => any
|
||||
decrease: () => any
|
||||
handleRemove: React.MouseEventHandler<HTMLButtonElement>
|
||||
handleChange: React.ChangeEventHandler<HTMLInputElement>
|
||||
max?: number
|
||||
}
|
||||
|
||||
const Quantity: FC<QuantityProps> = ({
|
||||
value,
|
||||
increase,
|
||||
decrease,
|
||||
handleChange,
|
||||
handleRemove,
|
||||
max = 6,
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex flex-row h-9">
|
||||
<button className={s.actions} onClick={handleRemove}>
|
||||
<Cross width={20} height={20} />
|
||||
</button>
|
||||
<label className="w-full border-accent-2 border ml-2">
|
||||
<input
|
||||
className={s.input}
|
||||
onChange={(e) =>
|
||||
Number(e.target.value) < max + 1 ? handleChange(e) : () => {}
|
||||
}
|
||||
value={value}
|
||||
type="number"
|
||||
max={max}
|
||||
min="0"
|
||||
readOnly
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
onClick={decrease}
|
||||
className={s.actions}
|
||||
style={{ marginLeft: '-1px' }}
|
||||
disabled={value <= 1}
|
||||
>
|
||||
<Minus width={18} height={18} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={increase}
|
||||
className={cn(s.actions)}
|
||||
style={{ marginLeft: '-1px' }}
|
||||
disabled={value < 1 || value >= max}
|
||||
>
|
||||
<Plus width={18} height={18} />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Quantity
|
2
components/ui/Quantity/index.ts
Normal file
2
components/ui/Quantity/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { default } from './Quantity'
|
||||
export * from './Quantity'
|
@ -11,4 +11,5 @@ export { default as Modal } from './Modal'
|
||||
export { default as Text } from './Text'
|
||||
export { default as Input } from './Input'
|
||||
export { default as Collapse } from './Collapse'
|
||||
export { default as Quantity } from './Quantity'
|
||||
export { useUI } from './context'
|
||||
|
Loading…
x
Reference in New Issue
Block a user