Merge branch 'master' into storefront-data-hooks-imports

This commit is contained in:
B
2020-10-27 01:27:18 -03:00
committed by GitHub
20 changed files with 221 additions and 108 deletions

View File

@@ -1,9 +1,7 @@
import { FC, useEffect, useState, useCallback } from 'react'
import { validate } from 'email-validator'
import { Info } from '@components/icons'
import { useUI } from '@components/ui/context'
import { Logo, Button, Input } from '@components/ui'
import useSignup from '@bigcommerce/storefront-data-hooks/use-signup'
interface Props {}
@@ -15,27 +13,15 @@ const ForgotPassword: FC<Props> = () => {
const [dirty, setDirty] = useState(false)
const [disabled, setDisabled] = useState(false)
const signup = useSignup()
const { setModalView, closeModal } = useUI()
const handleSignup = async () => {
const handleResetPassword = async (e: React.SyntheticEvent<EventTarget>) => {
e.preventDefault()
if (!dirty && !disabled) {
setDirty(true)
handleValidation()
}
// try {
// setLoading(true)
// setMessage('')
// await signup({
// email,
// })
// setLoading(false)
// closeModal()
// } catch ({ errors }) {
// setMessage(errors[0].message)
// setLoading(false)
// }
}
const handleValidation = useCallback(() => {
@@ -50,7 +36,10 @@ const ForgotPassword: FC<Props> = () => {
}, [handleValidation])
return (
<div className="w-80 flex flex-col justify-between p-3">
<form
onSubmit={handleResetPassword}
className="w-80 flex flex-col justify-between p-3"
>
<div className="flex justify-center pb-12 ">
<Logo width="64px" height="64px" />
</div>
@@ -63,7 +52,7 @@ const ForgotPassword: FC<Props> = () => {
<div className="pt-2 w-full flex flex-col">
<Button
variant="slim"
onClick={() => handleSignup()}
type="submit"
loading={loading}
disabled={disabled}
>
@@ -82,7 +71,7 @@ const ForgotPassword: FC<Props> = () => {
</a>
</span>
</div>
</div>
</form>
)
}

View File

@@ -18,7 +18,9 @@ const LoginView: FC<Props> = () => {
const login = useLogin()
const handleLogin = async () => {
const handleLogin = async (e: React.SyntheticEvent<EventTarget>) => {
e.preventDefault()
if (!dirty && !disabled) {
setDirty(true)
handleValidation()
@@ -54,7 +56,10 @@ const LoginView: FC<Props> = () => {
}, [handleValidation])
return (
<div className="w-80 flex flex-col justify-between p-3">
<form
onSubmit={handleLogin}
className="w-80 flex flex-col justify-between p-3"
>
<div className="flex justify-center pb-12 ">
<Logo width="64px" height="64px" />
</div>
@@ -75,7 +80,7 @@ const LoginView: FC<Props> = () => {
<Button
variant="slim"
onClick={() => handleLogin()}
type="submit"
loading={loading}
disabled={disabled}
>
@@ -92,7 +97,7 @@ const LoginView: FC<Props> = () => {
</a>
</div>
</div>
</div>
</form>
)
}

View File

@@ -21,7 +21,9 @@ const SignUpView: FC<Props> = () => {
const signup = useSignup()
const { setModalView, closeModal } = useUI()
const handleSignup = async () => {
const handleSignup = async (e: React.SyntheticEvent<EventTarget>) => {
e.preventDefault()
if (!dirty && !disabled) {
setDirty(true)
handleValidation()
@@ -59,7 +61,10 @@ const SignUpView: FC<Props> = () => {
}, [handleValidation])
return (
<div className="w-80 flex flex-col justify-between p-3">
<form
onSubmit={handleSignup}
className="w-80 flex flex-col justify-between p-3"
>
<div className="flex justify-center pb-12 ">
<Logo width="64px" height="64px" />
</div>
@@ -83,7 +88,7 @@ const SignUpView: FC<Props> = () => {
<div className="pt-2 w-full flex flex-col">
<Button
variant="slim"
onClick={() => handleSignup()}
type="submit"
loading={loading}
disabled={disabled}
>
@@ -102,7 +107,7 @@ const SignUpView: FC<Props> = () => {
</a>
</span>
</div>
</div>
</form>
)
}

View File

@@ -2,7 +2,7 @@ import { FC } from 'react'
import cn from 'classnames'
import { UserNav } from '@components/core'
import { Button } from '@components/ui'
import { ArrowLeft, Bag, Cross, Check } from '@components/icons'
import { Bag, Cross, Check } from '@components/icons'
import { useUI } from '@components/ui/context'
import useCart from '@bigcommerce/storefront-data-hooks/cart/use-cart'
import usePrice from '@bigcommerce/storefront-data-hooks/use-price'
@@ -47,11 +47,11 @@ const CartSidebarView: FC = () => {
aria-label="Close panel"
className="hover:text-gray-500 transition ease-in-out duration-150"
>
<ArrowLeft className="h-6 w-6" />
<Cross className="h-6 w-6" />
</button>
</div>
<div className="space-y-1">
<UserNav />
<UserNav className="" />
</div>
</div>
</header>

View File

@@ -0,0 +1,9 @@
.link {
& > svg {
@apply transform duration-75 ease-linear;
}
&:hover > svg {
@apply scale-110;
}
}

View File

@@ -7,7 +7,7 @@ import getSlug from '@utils/get-slug'
import { Github } from '@components/icons'
import { Logo, Container } from '@components/ui'
import { I18nWidget } from '@components/core'
import s from './Footer.module.css'
interface Props {
className?: string
children?: any
@@ -83,7 +83,9 @@ const Footer: FC<Props> = ({ className, pages }) => {
</div>
<div className="col-span-1 lg:col-span-6 flex items-start lg:justify-end text-primary">
<div className="flex space-x-6 items-center h-10">
<Github />
<a href="https://github.com/vercel/commerce" className={s.link}>
<Github />
</a>
<I18nWidget />
</div>
</div>

View File

@@ -6,21 +6,52 @@ import { Menu } from '@headlessui/react'
import { DoubleChevron } from '@components/icons'
import s from './I18nWidget.module.css'
const LOCALES_MAP: Record<string, string> = {
es: 'Español',
'en-US': 'English',
interface LOCALE_DATA {
name: string
img: {
filename: string
alt: string
}
}
const LOCALES_MAP: Record<string, LOCALE_DATA> = {
es: {
name: 'Español',
img: {
filename: 'flag-es-co.svg',
alt: 'Bandera Colombiana',
},
},
'en-US': {
name: 'English',
img: {
filename: 'flag-en-us.svg',
alt: 'US Flag',
},
},
}
const I18nWidget: FC = () => {
const { locale, locales, defaultLocale = 'en-US' } = useRouter()
const {
locale,
locales,
defaultLocale = 'en-US',
asPath: currentPath,
} = useRouter()
const options = locales?.filter((val) => val !== locale)
const currentLocale = locale || defaultLocale
return (
<nav className={s.root}>
<Menu>
<Menu.Button className={s.button} aria-label="Language selector">
<img className="mr-2" src="/flag-us.png" alt="US Flag" />
<span className="mr-2">{LOCALES_MAP[locale || defaultLocale]}</span>
<img
className="block mr-2 w-5"
src={`/${LOCALES_MAP[currentLocale].img.filename}`}
alt={LOCALES_MAP[currentLocale].img.alt}
/>
<span className="mr-2">{LOCALES_MAP[currentLocale].name}</span>
{options && (
<span>
<DoubleChevron />
@@ -33,9 +64,9 @@ const I18nWidget: FC = () => {
{options.map((locale) => (
<Menu.Item key={locale}>
{({ active }) => (
<Link href="/" locale={locale}>
<Link href={currentPath} locale={locale}>
<a className={cn(s.item, { [s.active]: active })}>
{LOCALES_MAP[locale]}
{LOCALES_MAP[locale].name}
</a>
</Link>
)}

View File

@@ -4,6 +4,7 @@ import { useTheme } from 'next-themes'
import cn from 'classnames'
import s from './DropdownMenu.module.css'
import { Moon, Sun } from '@components/icons'
import { useUI } from '@components/ui/context'
import { Menu, Transition } from '@headlessui/react'
import useLogout from '@bigcommerce/storefront-data-hooks/use-logout'
import { useRouter } from 'next/router'
@@ -32,6 +33,8 @@ const DropdownMenu: FC<DropdownMenuProps> = ({ open = false }) => {
const logout = useLogout()
const { pathname } = useRouter()
const { closeSidebarIfPresent } = useUI()
return (
<Transition
show={open}
@@ -51,6 +54,7 @@ const DropdownMenu: FC<DropdownMenuProps> = ({ open = false }) => {
className={cn(s.link, {
[s.active]: pathname === href,
})}
onClick={closeSidebarIfPresent}
>
{name}
</a>

View File

@@ -21,21 +21,18 @@ const UserNav: FC<Props> = ({ className, children, ...props }) => {
const { data } = useCart()
const { data: customer } = useCustomer()
const { openSidebar, closeSidebar, displaySidebar, openModal } = useUI()
const { toggleSidebar, closeSidebarIfPresent, openModal } = useUI()
const itemsCount = Object.values(data?.line_items ?? {}).reduce(countItems, 0)
return (
<nav className={cn(s.root, className)}>
<div className={s.mainContainer}>
<ul className={s.list}>
<li
className={s.item}
onClick={(e) => (displaySidebar ? closeSidebar() : openSidebar())}
>
<li className={s.item} onClick={toggleSidebar}>
<Bag />
{itemsCount > 0 && <span className={s.bagCount}>{itemsCount}</span>}
</li>
<Link href="/wishlist">
<li className={s.item}>
<li className={s.item} onClick={closeSidebarIfPresent}>
<Heart />
</li>
</Link>

View File

@@ -31,56 +31,56 @@ const ProductCard: FC<Props> = ({
currencyCode: p.prices?.price?.currencyCode!,
})
if (variant === 'slim') {
return (
<div className="relative overflow-hidden box-border">
<div className="absolute inset-0 flex items-center justify-end mr-8 z-20">
<span className="bg-black text-white inline-block p-3 font-bold text-xl break-words">
{p.name}
</span>
</div>
<EnhancedImage
src={p.images.edges?.[0]?.node.urlOriginal!}
alt={p.name}
width={imgWidth}
height={imgHeight}
priority={priority}
quality="90"
/>
</div>
)
}
return (
<Link href={`/product${p.path}`}>
<a
className={cn(s.root, { [s.simple]: variant === 'simple' }, className)}
>
<div className={s.squareBg} />
<div className="flex flex-row justify-between box-border w-full z-20 absolute">
<div className="absolute top-0 left-0 pr-16 max-w-full">
<h3 className={s.productTitle}>
<span>{p.name}</span>
</h3>
<span className={s.productPrice}>{price}</span>
{variant === 'slim' ? (
<div className="relative overflow-hidden box-border">
<div className="absolute inset-0 flex items-center justify-end mr-8 z-20">
<span className="bg-black text-white inline-block p-3 font-bold text-xl break-words">
{p.name}
</span>
</div>
<EnhancedImage
src={p.images.edges?.[0]?.node.urlOriginal!}
alt={p.name}
width={imgWidth}
height={imgHeight}
priority={priority}
quality="90"
/>
</div>
<WishlistButton
className={s.wishlistButton}
productId={p.entityId}
variant={p.variants.edges?.[0]!}
/>
</div>
<div className={s.imageContainer}>
<EnhancedImage
alt={p.name}
className={cn('w-full object-cover', s['product-image'])}
src={src}
width={imgWidth}
height={imgHeight}
priority={priority}
quality="90"
/>
</div>
) : (
<>
<div className={s.squareBg} />
<div className="flex flex-row justify-between box-border w-full z-20 absolute">
<div className="absolute top-0 left-0 pr-16 max-w-full">
<h3 className={s.productTitle}>
<span>{p.name}</span>
</h3>
<span className={s.productPrice}>{price}</span>
</div>
<WishlistButton
className={s.wishlistButton}
productId={p.entityId}
variant={p.variants.edges?.[0]!}
/>
</div>
<div className={s.imageContainer}>
<EnhancedImage
alt={p.name}
className={cn('w-full object-cover', s['product-image'])}
src={src}
width={imgWidth}
height={imgHeight}
priority={priority}
quality="90"
/>
</div>
</>
)}
</a>
</Link>
)

View File

@@ -13,6 +13,7 @@ import { HTMLContent } from '@components/core'
import useAddItem from '@bigcommerce/storefront-data-hooks/cart/use-add-item'
import type { ProductNode } from '@bigcommerce/storefront-data-hooks/api/operations/get-product'
import { getProductOptions } from '../helpers'
import WishlistButton from '@components/wishlist/WishlistButton'
interface Props {
className?: string
@@ -143,9 +144,11 @@ const ProductView: FC<Props> = ({ product, className }) => {
</div>
{/* TODO make it work */}
<div className={s.wishlistButton}>
<Heart />
</div>
<WishlistButton
className={s.wishlistButton}
productId={product.entityId}
variant={product.variants.edges?.[0]!}
/>
</div>
</Container>
)

View File

@@ -131,6 +131,12 @@ export const UIProvider: FC = (props) => {
const openSidebar = () => dispatch({ type: 'OPEN_SIDEBAR' })
const closeSidebar = () => dispatch({ type: 'CLOSE_SIDEBAR' })
const toggleSidebar = () =>
state.displaySidebar
? dispatch({ type: 'CLOSE_SIDEBAR' })
: dispatch({ type: 'OPEN_SIDEBAR' })
const closeSidebarIfPresent = () =>
state.displaySidebar && dispatch({ type: 'CLOSE_SIDEBAR' })
const openDropdown = () => dispatch({ type: 'OPEN_DROPDOWN' })
const closeDropdown = () => dispatch({ type: 'CLOSE_DROPDOWN' })
@@ -149,6 +155,8 @@ export const UIProvider: FC = (props) => {
...state,
openSidebar,
closeSidebar,
toggleSidebar,
closeSidebarIfPresent,
openDropdown,
closeDropdown,
openModal,

View File

@@ -62,9 +62,10 @@ const WishlistButton: FC<Props> = ({
return (
<button
{...props}
aria-label="Add to wishlist"
className={cn({ 'opacity-50': loading }, className)}
onClick={handleWishlistChange}
{...props}
>
<Heart fill={itemInWishlist ? 'var(--pink)' : 'none'} />
</button>