mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
Merge branch 'master' into arzafran/responsive-bottom-grid
This commit is contained in:
@@ -70,8 +70,8 @@ const LoginView: FC<Props> = () => {
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<Input placeholder="Email" onChange={setEmail} />
|
||||
<Input placeholder="Password" onChange={setPassword} />
|
||||
<Input type="email" placeholder="Email" onChange={setEmail} />
|
||||
<Input type="password" placeholder="Password" onChange={setPassword} />
|
||||
|
||||
<Button
|
||||
variant="slim"
|
||||
|
@@ -59,7 +59,7 @@ const SignUpView: FC<Props> = () => {
|
||||
}, [handleValidation])
|
||||
|
||||
return (
|
||||
<div className="w-96 flex flex-col justify-between p-3">
|
||||
<div className="w-80 flex flex-col justify-between p-3">
|
||||
<div className="flex justify-center pb-12 ">
|
||||
<Logo width="64px" height="64px" />
|
||||
</div>
|
||||
@@ -69,8 +69,8 @@ const SignUpView: FC<Props> = () => {
|
||||
)}
|
||||
<Input placeholder="First Name" onChange={setFirstName} />
|
||||
<Input placeholder="Last Name" onChange={setLastName} />
|
||||
<Input placeholder="Email" onChange={setEmail} />
|
||||
<Input placeholder="Password" onChange={setPassword} />
|
||||
<Input type="email" placeholder="Email" onChange={setEmail} />
|
||||
<Input type="password" placeholder="Password" onChange={setPassword} />
|
||||
<span className="text-accents-8">
|
||||
<span className="inline-block align-middle ">
|
||||
<Info width="15" height="15" />
|
||||
|
@@ -1,2 +1,15 @@
|
||||
.root {
|
||||
@apply h-full flex flex-col;
|
||||
}
|
||||
|
||||
.root.empty {
|
||||
@apply bg-secondary text-secondary;
|
||||
}
|
||||
|
||||
.root.success {
|
||||
@apply bg-green text-white;
|
||||
}
|
||||
|
||||
.root.error {
|
||||
@apply bg-red text-white;
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import { useUI } from '@components/ui/context'
|
||||
import useCart from '@lib/bigcommerce/cart/use-cart'
|
||||
import usePrice from '@lib/bigcommerce/use-price'
|
||||
import CartItem from '../CartItem'
|
||||
import s from './CartSidebarView.module.css'
|
||||
|
||||
const CartSidebarView: FC = () => {
|
||||
const { data, isEmpty } = useCart()
|
||||
@@ -32,10 +33,10 @@ const CartSidebarView: FC = () => {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn('h-full flex flex-col', {
|
||||
'bg-secondary text-secondary': isEmpty,
|
||||
'bg-red text-white': error,
|
||||
'bg-green text-white': success,
|
||||
className={cn(s.root, {
|
||||
[s.empty]: error,
|
||||
[s.empty]: success,
|
||||
[s.empty]: isEmpty,
|
||||
})}
|
||||
>
|
||||
<header className="px-4 pt-6 pb-4 sm:px-6">
|
||||
@@ -56,7 +57,7 @@ const CartSidebarView: FC = () => {
|
||||
</header>
|
||||
|
||||
{isEmpty ? (
|
||||
<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">
|
||||
<span className="border border-dashed border-primary rounded-full flex items-center justify-center w-16 h-16 p-12 bg-secondary text-secondary">
|
||||
<Bag className="absolute" />
|
||||
</span>
|
||||
|
@@ -6,7 +6,7 @@ import s from './Featurebar.module.css'
|
||||
interface Props {
|
||||
className?: string
|
||||
title: string
|
||||
description: string
|
||||
description?: string
|
||||
hide?: boolean
|
||||
action?: React.ReactNode
|
||||
}
|
||||
|
@@ -77,8 +77,7 @@ const Layout: FC<Props> = ({ children, pageProps }) => {
|
||||
{modalView === 'FORGOT_VIEW' && <ForgotPassword />}
|
||||
</Modal>
|
||||
<Featurebar
|
||||
title="This site uses cookies to improve your experience."
|
||||
description="By clicking, you agree to our Privacy Policy."
|
||||
title="This site uses cookies to improve your experience. By clicking, you agree to our Privacy Policy."
|
||||
hide={acceptedCookies}
|
||||
action={
|
||||
<Button className="mx-5" onClick={() => setAcceptedCookies(true)}>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
}
|
||||
|
||||
.item {
|
||||
@apply mr-6 cursor-pointer relative transition ease-in-out duration-100 text-primary flex items-center outline-none text-primary;
|
||||
@apply mr-6 cursor-pointer relative transition ease-in-out duration-100 flex items-center outline-none text-primary;
|
||||
|
||||
&:hover {
|
||||
@apply text-accents-6 transition scale-110 duration-100;
|
||||
|
@@ -83,6 +83,7 @@
|
||||
.simple {
|
||||
& .squareBg {
|
||||
@apply bg-accents-0 !important;
|
||||
background-image: url("data:image/svg+xml,%3Csvg width='48' height='46' viewBox='0 0 48 46' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cline opacity='0.05' x1='9.41421' y1='8' x2='21' y2='19.5858' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cline opacity='0.05' x1='1' y1='-1' x2='17.3848' y2='-1' transform='matrix(-0.707107 0.707107 0.707107 0.707107 40 8)' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cline opacity='0.05' x1='1' y1='-1' x2='17.3848' y2='-1' transform='matrix(0.707107 -0.707107 -0.707107 -0.707107 8 38)' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cline opacity='0.05' x1='38.5858' y1='38' x2='27' y2='26.4142' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E%0A");
|
||||
}
|
||||
|
||||
& .productTitle {
|
||||
|
@@ -1,19 +1,18 @@
|
||||
import React, { FC, ReactNode, Component } from 'react'
|
||||
import type { FC } from 'react'
|
||||
import cn from 'classnames'
|
||||
import Link from 'next/link'
|
||||
import type { ProductNode } from '@lib/bigcommerce/api/operations/get-all-products'
|
||||
import usePrice from '@lib/bigcommerce/use-price'
|
||||
import { Heart } from '@components/icons'
|
||||
import { EnhancedImage } from '@components/core'
|
||||
import s from './ProductCard.module.css'
|
||||
import WishlistButton from '@components/wishlist/WishlistButton'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: ReactNode[] | Component[] | any[]
|
||||
product: ProductNode
|
||||
variant?: 'slim' | 'simple'
|
||||
imgWidth: number
|
||||
imgHeight: number
|
||||
imgWidth: number | string
|
||||
imgHeight: number | string
|
||||
priority?: boolean
|
||||
}
|
||||
|
||||
@@ -25,7 +24,7 @@ const ProductCard: FC<Props> = ({
|
||||
imgHeight,
|
||||
priority,
|
||||
}) => {
|
||||
const src = p.images.edges?.[0]?.node.urlOriginal!
|
||||
const src = p.images.edges?.[0]?.node?.urlOriginal!
|
||||
const { price } = usePrice({
|
||||
amount: p.prices?.price?.value,
|
||||
baseAmount: p.prices?.retailPrice?.value,
|
||||
@@ -65,9 +64,11 @@ const ProductCard: FC<Props> = ({
|
||||
</h3>
|
||||
<span className={s.productPrice}>{price}</span>
|
||||
</div>
|
||||
<div className={s.wishlistButton}>
|
||||
<Heart />
|
||||
</div>
|
||||
<WishlistButton
|
||||
className={s.wishlistButton}
|
||||
productId={p.entityId}
|
||||
variant={p.variants.edges?.[0]!}
|
||||
/>
|
||||
</div>
|
||||
<div className={cn(s.imageContainer)}>
|
||||
<EnhancedImage
|
||||
|
@@ -1,5 +1,5 @@
|
||||
.root {
|
||||
@apply text-accents-1 cursor-pointer inline-flex px-10 rounded-sm leading-6 bg-secondary transition ease-in-out duration-150 shadow-sm font-semibold text-center justify-center uppercase py-4 uppercase text-center border border-transparent items-center;
|
||||
@apply bg-secondary text-accents-1 cursor-pointer inline-flex px-10 rounded-sm leading-6 transition ease-in-out duration-150 shadow-sm font-semibold text-center justify-center uppercase py-4 border border-transparent items-center;
|
||||
}
|
||||
|
||||
.root:hover {
|
||||
|
@@ -62,7 +62,7 @@ const Sidebar: FC<Props> = ({ className, children, open = false, onClose }) => {
|
||||
leaveFrom="translate-x-0"
|
||||
leaveTo="translate-x-full"
|
||||
>
|
||||
<div className="h-full w-screen max-w-md">
|
||||
<div className="h-full md:w-screen md:max-w-md">
|
||||
<div className="h-full flex flex-col text-base bg-accents-1 shadow-xl overflow-y-auto">
|
||||
{children}
|
||||
</div>
|
||||
|
65
components/wishlist/WishlistButton/WishlistButton.tsx
Normal file
65
components/wishlist/WishlistButton/WishlistButton.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import React, { FC, useState } from 'react'
|
||||
import cn from 'classnames'
|
||||
import type { ProductNode } from '@lib/bigcommerce/api/operations/get-all-products'
|
||||
import useAddItem from '@lib/bigcommerce/wishlist/use-add-item'
|
||||
import useWishlist from '@lib/bigcommerce/wishlist/use-wishlist'
|
||||
import useCustomer from '@lib/bigcommerce/use-customer'
|
||||
import { Heart } from '@components/icons'
|
||||
import { useUI } from '@components/ui/context'
|
||||
|
||||
type Props = {
|
||||
productId: number
|
||||
variant: NonNullable<ProductNode['variants']['edges']>[0]
|
||||
} & React.ButtonHTMLAttributes<HTMLButtonElement>
|
||||
|
||||
const WishlistButton: FC<Props> = ({
|
||||
productId,
|
||||
variant,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const addItem = useAddItem()
|
||||
const { data } = useWishlist()
|
||||
const { data: customer } = useCustomer()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const { openModal, setModalView } = useUI()
|
||||
const isInWishlist = data?.items?.some(
|
||||
(item) =>
|
||||
item.product_id === productId &&
|
||||
item.variant_id === variant?.node.entityId
|
||||
)
|
||||
|
||||
const addToWishlist = async (e: any) => {
|
||||
e.preventDefault()
|
||||
setLoading(true)
|
||||
|
||||
// A login is required before adding an item to the wishlist
|
||||
if (!customer) {
|
||||
setModalView('LOGIN_VIEW')
|
||||
return openModal()
|
||||
}
|
||||
|
||||
try {
|
||||
await addItem({
|
||||
productId,
|
||||
variantId: variant?.node.entityId!,
|
||||
})
|
||||
|
||||
setLoading(false)
|
||||
} catch (err) {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
className={cn({ 'opacity-50': loading }, className)}
|
||||
onClick={addToWishlist}
|
||||
>
|
||||
<Heart fill={isInWishlist ? 'white' : 'none'} />
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
export default WishlistButton
|
1
components/wishlist/WishlistButton/index.ts
Normal file
1
components/wishlist/WishlistButton/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './WishlistButton'
|
Reference in New Issue
Block a user